# CLI Behavior (/cli/behavior)

## Input sources

- if a path is provided, Lumis reads that file
- if no path is provided, Lumis reads from stdin
- you can pipe content directly into `lumis highlight` or any `lumis dump`
  command
- terminal output is the default highlight formatter unless you pass
  `--formatter`

```bash
cat main.rs | lumis highlight -l rust
echo 'fn main() {}' | lumis highlight -l rust
```

## When to set `--language`

Pass `--language` when you already know the correct parser and do not want detection to depend on the filename or input content.

```bash
lumis highlight main.txt --language rust
```

## When to rely on auto-detection

Omit `--language` when the path, shebang, or source content should drive detection.

```bash
lumis highlight main.rs
```

If no language can be inferred, plaintext is the safe fallback for highlighting.
Dump commands instead ask you to pass `--language`, because they need a parser.

## Parser and query debugging

Use `lumis dump tree` to inspect named syntax nodes as branch lines with
language and range metadata. `--text`, `--highlights`, and `--injections` add
source text, resolved highlight-query results, and injected syntax trees. Text
uses an 80-character middle preview by default; use `--text=<limit>` or
`--text=full` to change it. Syntax nodes use `[name]`; resolved highlights use
`@name`. Use `lumis dump
events` when you need the raw highlight event stream.

```bash
lumis dump tree component.svelte
lumis dump tree component.svelte \
  --injections --text --highlights
lumis dump tree component.svelte --format sexp
echo 'function increment() { count++; }' \
  | lumis dump events -l svelte
```

Both commands use the same path, stdin, language detection, parser download,
and cache behavior as `lumis highlight`. See the
[CLI command reference](/cli/commands#lumis-dump-tree) for output details.

## Theme selection

When `--theme` is omitted, Lumis uses `[highlight].theme` from its config file. On macOS and Linux, the default path is `${XDG_CONFIG_HOME:-~/.config}/lumis/config.toml`; on Windows it is `%XDG_CONFIG_HOME%/lumis/config.toml`, or `%APPDATA%/lumis/config.toml` when XDG is unset. The default value is `auto`.

```toml
[highlight]
theme = "auto"
```

For terminal output, `auto` asks for the background, foreground and ANSI accent colors in one exchange. It chooses a light or dark theme from the foreground against the background, or from background lightness if only the background is available. Monochrome themes and themes with poor default text contrast are excluded.

The closest backgrounds are considered first. Within a small background tolerance, the foreground and then the ANSI accents distinguish similar themes. This can recognize a theme whose background has been changed slightly, but cannot identify every terminal theme. Use an explicit `--theme` when you want a particular one, including a monochrome theme.

If the terminal reports no background, does not answer within one second, or has no close match, Lumis renders without a theme and explains why on stderr. Partial replies still work: foreground and ANSI colors are optional.

A terminal reply that arrives after Lumis exits can appear as text at the shell prompt. Set a theme explicitly if this happens; an explicit theme skips the terminal query.

Automatic selection only queries when stdout is a terminal and the formatter is `terminal`. Pipes, redirected output and HTML output render without a theme and print the reason on stderr. For colored output through a pager or styled HTML, select a theme explicitly:

```sh
lumis highlight main.rs --theme dracula | less -R
lumis highlight main.rs --formatter html-inline --theme github_light > main.html
```

An explicit `--theme` takes precedence over the config file. Set `XDG_CONFIG_HOME`, `LUMIS_CONFIG`, or `--config` to use a different config location.

## Parser cache lifecycle

Highlighting downloads, verifies and loads whatever a file turns out to need,
including languages injected inside it, and caches them for every later run. A
Markdown file with a fenced Rust block highlights that block; a language that
cannot be fetched leaves its own block plain rather than failing the file.

The CLI stores language-package metadata and integrity-verified parser WASM
files under the data directory. A cold cache resolves the runtime's compatible
package range, then loads the exact parser version and matching queries named
there. Parser filenames contain the package version and SHA-256 digest.

A compatible manifest already in the store is used as is and never checked
against the registry again. So a store staged during a build gives every run the
same parser and query bytes, with no network at run time, and two stores filled
on different days can hold different patch releases. Bytes that fail their
digest check are discarded and fetched again, so a damaged store repairs
itself.

- first use of a language downloads its parser
- `lumis languages download ...` persists selected parsers ahead of time, so no run
  pays for a download and the Wasmtime compile that follows it
- `lumis languages download ... --force` resolves the package range again and
  replaces valid cached parsers

```bash
lumis languages download rust javascript elixir
lumis languages download rust --force
```

Parsers you build or vendor yourself go in the same `parsers/` directory as
downloaded ones; `lumis --data-dir <dir> languages download ...` writes that layout.

## Data directory

Default location depends on the OS. Override it with:

- `--data-dir`
- `LUMIS_DATA_DIR`

The data dir stores:

- language-package metadata, as `parsers/<name>.lumis.json`
- parser WASM files, in the same `parsers/` directory
- custom theme JSON files

The metadata names the exact parser version, queries, and integrity digest, so a
directory holding both is self-sufficient offline.

## Local custom themes

Pass a JSON path directly to use a theme without installing it:

```sh
lumis highlight main.rs --theme ./my-theme.json
lumis themes show ./my-theme.json
lumis themes build-css ./my-theme.json > my-theme.css
```

Paths are relative to the current working directory unless absolute. A missing
or malformed explicit file produces an error rather than silently rendering
without a theme.

For short-name lookup, Lumis checks built-in names and then
`<data-dir>/themes/<name>.json`. `lumis themes list` discovers JSON files in that
folder and marks them `(file)`. The name is the filename stem: `my-theme.json`
is selected with `--theme my-theme`, regardless of the JSON's `name` field.
Use an explicit path to select a file whose stem matches a built-in theme.

The same lookup applies to `themes show`, `themes build-css`, and every
`--themes key:theme` pair in multi-theme HTML, so
`--themes dark:./my-theme.json` selects the same file as `--theme ./my-theme.json`.

See [Generate a theme from a Neovim colorscheme](/recipes/generate-theme-from-neovim-colorscheme)
for generation, loading examples, and license considerations, or
[CLI](/usage/cli) for highlight workflow examples.

## Nested languages and parser availability

Some formats depend on nested parsers. If embedded languages are missing from the cache, those nested regions cannot be fully highlighted.

If you work with mixed-language content, cache all relevant parsers.

## Verbose mode

Use `--verbose` to inspect cache hits, parser paths, and downloads.