# List languages and themes (/recipes/list-languages-and-themes)

Language metadata includes `id`, `name`, `parser`, `aliases`, `extensions`,
`globs`, Emacs modes and shebangs. Lists are sorted by id. JavaScript also
includes the npm parser `packageName`; Elixir includes the Hex `package_name`.

`themes.available()` and `Lumis.Theme.available/0` return theme names and
appearances. Rust's `themes::available()` returns complete themes. Use
`themes.get(name)`, `themes::get(name)`, or `Lumis.Theme.get/1` to look up one theme.

### JavaScript / TypeScript

```js
import * as languages from '@lumis-sh/lumis/languages';
import * as themes from '@lumis-sh/lumis/themes';

for (const language of languages.available()) {
  const {id, name, extensions} = language
  console.log(id, name, extensions)
}

for (const theme of themes.available()) {
  console.log(theme.name, theme.appearance)
}
```

### Rust

```rust
use lumis::{languages, themes};

for language in languages::available() {
    println!(
        "{} {} {:?}",
        language.id, language.name, language.extensions
    );
}

for theme in themes::available() {
    println!("{} {:?}", theme.name, theme.appearance);
}
```

### Elixir

```elixir
for language <- Lumis.Languages.available() do
  IO.inspect(
    {language.id, language.name, language.extensions}
  )
end

for theme <- Lumis.Theme.available() do
  IO.inspect({theme.name, theme.appearance})
end
```

### CLI

```bash
lumis languages list
lumis themes list
```


## Look one up by name

Aliases resolve the way highlighting resolves them, so `js` finds JavaScript.

How an unknown name is reported follows each host's convention: JavaScript / TypeScript
returns `undefined` and Elixir returns `nil`, both without raising, while Rust
returns `None` for an unknown language and an error for an unknown theme. The CLI exits non-zero.

### JavaScript / TypeScript

```js
import * as languages from '@lumis-sh/lumis/languages';
import * as themes from '@lumis-sh/lumis/themes';

// { id: 'javascript', name: 'JavaScript', ... }
languages.get('js')
languages.get('nope')  // undefined

themes.get('catppuccin_frappe')
```

If you know the theme name ahead of time, an individual import keeps the rest of the catalog out of
your bundle:

```js
import frappe from '@lumis-sh/themes/catppuccin_frappe'
```

### Rust

```rust
use lumis::{languages, themes};

if let Some(language) = languages::get("js") {
    println!("{:?}", language.extensions);
}

let theme = themes::get("catppuccin_frappe")?;
println!("{} {}", theme.name, theme.appearance);
```

### Elixir

```elixir
Lumis.Languages.get("js")
# %{id: "javascript", name: "JavaScript", ...}

Lumis.Languages.get("nope")
# nil

Lumis.Theme.get("catppuccin_frappe")

# %Lumis.Theme{name: "catppuccin_frappe",
#   appearance: "dark", ...}
```

### CLI

```bash
lumis languages show js
lumis themes show catppuccin_frappe
```


## Find the parser package

A language id is not always its parser name. EJS and ERB both use
`embedded-template`; MDX uses `markdown`. Read `parser` rather than building a
package name from the language id. This lookup does not load the parser.

### JavaScript / TypeScript

```js
import * as languages from '@lumis-sh/lumis/languages';

languages.get('ejs')?.parser      // 'embedded-template'
languages.get('ejs')?.packageName // '@lumis-sh/wasm-embedded-template'
languages.get('mdx')?.packageName // '@lumis-sh/wasm-markdown'
languages.get('text')?.parser    // undefined
```

Plaintext has neither `parser` nor `packageName`.

### Rust

```rust
use lumis::languages;

if let Some(language) = languages::get("ejs") {
    assert_eq!(language.parser, Some("embedded-template"));
}
assert_eq!(languages::get("text").unwrap().parser, None);
```

Plaintext has `parser: None`.

### Elixir

```elixir
Lumis.Languages.get("ejs").parser
# "embedded-template"

Lumis.Languages.get("ejs").package_name
# "lumis_wasm_embedded_template"

Lumis.Languages.get("mdx").package_name
# "lumis_wasm_markdown"

Lumis.Languages.get("text").package_name
# nil
```

Plaintext has `parser: nil` and `package_name: nil`.


## What is loaded right now

The catalog lists what Lumis knows about. This lists what can be highlighted
without a download, which is a smaller set — highlighting loads what a document
turns out to need.

Themes have no equivalent: every theme is compiled in, so there is nothing to
load and nothing that could be missing.

### JavaScript / TypeScript

```js
import * as languages from '@lumis-sh/lumis/languages';

languages.loaded() // ['json', 'rust']
```

### Rust

Languages are compiled in behind `lang-*` features, so everything in
`languages::available()` is ready to use.

### Elixir

```elixir
Lumis.Languages.load("elixir")
Lumis.Languages.loaded()
# ["elixir"]
```

Loading is global to the VM, so this is the same list in every process.

### CLI

There is nothing to list. Each invocation is a fresh process that loads what
the document needs and exits, so nothing stays loaded between runs.

What does persist is the parser cache on disk, which `lumis languages download`
fills so later runs skip the download:

```bash
lumis languages download rust javascript
```