Highlight
Highlight code with one Lumis workflow across CLI, Rust, Elixir, JavaScript / TypeScript, and Java.
This is the core Lumis workflow: choose a language, choose a formatter, then render output.
Simple example
import {highlight} from '@lumis-sh/lumis';
import {htmlInline} from '@lumis-sh/lumis/formatters';
import javascript from '@lumis-sh/lumis/langs/javascript';
import frappe from '@lumis-sh/themes/catppuccin_frappe';
const html = await highlight(
'const x = 1',
htmlInline({language: javascript, theme: frappe})
);
Options by runtime
| Need | CLI | Rust | Elixir | JavaScript / TypeScript | Java |
|---|---|---|---|---|---|
| Set language | --language | .language(...) | language: "..." | language: ... | withLang(...) |
| Set theme | --theme | .theme(...) | theme: "..." | theme: ... | withTheme(...) |
| Choose output | --formatter | builder type | formatter: ... | formatter factory | runtime-specific |
| Bound query matches | --match-limit | .match_limit(...) | match_limit: ... | matchLimit: ... | runtime-specific |
Language detection
If you omit the language, Lumis tries to detect it using:
- file extensions (
.rs,.js,.ex, etc.) - filenames (
Makefile,Dockerfile,Caddyfile) - shebangs (
#!/usr/bin/env python) - Emacs mode lines (
-*- mode: ruby -*-)
If detection fails, it falls back to plaintext.
Match limit
Tree-sitter walks its whole pool of in-progress matches before it emits each capture, so a query pattern that stays open across a large subtree costs more the deeper the document nests. Lumis bounds the number of matches kept in progress at 8192, for the highlight and bracket queries alike. HTML and the languages that embed it do not depend on that bound to stay fast, because their layers replay captures from finished matches; the bound is what keeps other languages linear when a query pattern stays open across a large subtree.
Raise it when a document is large enough that tree-sitter drops matches and scopes go missing, and accept the extra time. Tree-sitter accepts 1 to 65536; every runtime rejects anything else.
const html = await highlight(source, htmlInline({language: html_, theme: frappe}), {
matchLimit: 16384,
});
Incomplete code
Lumis handles incomplete or malformed code without crashing. Tree-sitter produces a partial syntax tree and Lumis highlights what it can. This is useful for streaming scenarios where code arrives in chunks (e.g., LLM output).
Next steps
- choose an output mode in Formatters
- pick or generate colors in Themes
- emphasize lines in Line Highlighting
- number lines in Line Numbers