Syntax highlighter powered by Tree-sitter and Neovim themes.
Features
- 110+ Tree-sitter languages - Fast, accurate, and updated syntax parsing
- 250+ built-in Neovim themes - Updated and curated themes from the Neovim community
- Built-in formatters - HTML (inline/linked), Terminal (ANSI), Multi-theme (light/dark), BBCode
- Custom formatters - Build your own output
- Language auto-detection - File extension, shebang, and emacs-mode support
- Line highlighting - Mark and style individual lines, with custom HTML wrappers
- Streaming-friendly - Handles incomplete code
- Parsers are dependencies - Declared in
mix.exs, compiled on first use
Installation
Add Lumis and a parser for each language you highlight:
def deps do
[
{:lumis, "~> 0.9"},
{:lumis_wasm_elixir, "~> 0.26.0"}
]
endUsage
iex> Lumis.highlight!("Atom.to_string(:elixir)", formatter: {:html_inline, language: "elixir", theme: "github_light"})The language is optional — Lumis detects it from the source, a filename, or a
shebang. The theme is optional too, but there is no default: without one,
:html_inline emits spans with no colors. Themes are named:
theme: "github_light", or a Lumis.Theme struct built from your own JSON.
Formatters decide the output: :html_inline, :html_linked,
:html_multi_themes, :terminal, :bbcode_scoped, or your own.
For your own, implement Lumis.Formatter and build the output with
Lumis.Formatter.HTML or Lumis.Formatter.ANSI, which hold the same pieces the
built-in formatters use.
Parsers
A parser is an ordinary dependency: add {:lumis_wasm_elixir, "~> 0.26.0"} and
mix deps.get delivers the bytes. Highlighting loads whatever a document
needs, including languages injected inside it, and keeps them for every
later request. Loading is global to the VM, so only the first process pays.
A language no dependency supplies is not fetched. A document's own language
missing is an error — Lumis.ParserError with the package to add — and a
language injected inside it missing costs that block its highlighting, not the
document. So add the ones a document can inject too, not only the ones it
names: Markdown fences reach
whatever language they label, HTML reaches css and javascript, and Elixir
reaches comment. A bundle package installs a set at once, such as
{:lumis_wasm_bundle_web, "~> 0.1"}, and the language catalog at
docs.lumis.sh lists every package name.
# move the compile off the first request
Lumis.Languages.load(["elixir", "html", "javascript", "css"])Application startup
Warm parsers from your application's start/2 so production does not compile
them on the first request:
def start(_type, _args) do
Lumis.Languages.async_load(~w(elixir html javascript css))
Supervisor.start_link(children(), strategy: :one_for_one, name: MyApp.Supervisor)
endIt returns immediately, so the boot never waits on a compile, and a failed warm-up is logged rather than able to stop the application from starting.
See the deployment guide for the full lifecycle example, bundles, and custom data directories.
The NIF is precompiled. Set LUMIS_BUILD=1 to build it from source instead, or
LUMIS_USE_LEGACY_ARTIFACTS=1 to take the legacy-CPU variant on a machine
without the newer instruction sets.
It downloads from GitHub Releases, mirrored to Cloudflare R2. Set
config :lumis, artifact_source: :cloudflare or LUMIS_ARTIFACT_SOURCE=cloudflare
to use the mirror when GitHub is down.
Documentation
Guides for configuration, releases, Phoenix, formatters, themes and recipes are at docs.lumis.sh.
API reference: hexdocs.pm/lumis.
Acknowledgements
Summary
Types
Highlight lines options for the BBCode formatter.
Highlighter formatter and its options.
Wraps the highlighted code with custom open and close HTML tags.
Options for highlight_events/3.
HTML attributes represented as an ordered keyword list.
Highlight lines options for Inline HTML formatter.
Highlight lines options for Linked HTML formatter.
Options for HTML Multi-Themes formatter.
What an HTML formatter writes around the highlighted tokens.
A language name, filename, or path with extension.
What Lumis knows about one language.
Highlight lines options for the Terminal formatter.
Theme used to apply styles on the highlighted source code.
A built-in theme's name and appearance, without its highlight data.
Functions
Returns every available language and what the catalog knows about it, sorted by id.
Returns every built-in theme's name and appearance, sorted by name.
Returns all default options.
Highlights source code and outputs into a formatted string.
Same as highlight/2 but raises Lumis.HighlightError in case of failure.
Highlights source into the event stream a custom formatter receives, without
rendering it.
Same as highlight_events/3 but raises Lumis.HighlightError in case of failure.
Returns the ids of the languages loaded into this VM, sorted.
Validates the given options against the options schema.
Types
@type bbcode_highlight_lines() :: %{lines: [pos_integer() | Range.t()]} | nil
Highlight lines options for the BBCode formatter.
@type formatter() :: :html_inline | {:html_inline, language: language(), structure: html_structure(), theme: theme(), pre_class: String.t(), pre_attrs: html_attrs(), code_attrs: html_attrs(), italic: boolean(), include_highlights: boolean(), highlight_lines: html_inline_highlight_lines(), line_numbers: boolean(), header: header()} | :html_linked | {:html_linked, language: language(), structure: html_structure(), pre_class: String.t(), pre_attrs: html_attrs(), code_attrs: html_attrs(), highlight_lines: html_linked_highlight_lines(), line_numbers: boolean(), header: header()} | :html_multi_themes | {:html_multi_themes, language: language(), structure: html_structure(), themes: keyword(theme()), default_theme: String.t(), css_variable_prefix: String.t(), pre_class: String.t(), pre_attrs: html_attrs(), code_attrs: html_attrs(), italic: boolean(), include_highlights: boolean(), highlight_lines: html_inline_highlight_lines(), line_numbers: boolean(), header: header()} | :terminal | {:terminal, language: language(), theme: theme(), background: :theme | String.t() | nil, width: pos_integer() | nil, highlight_lines: terminal_highlight_lines(), line_numbers: boolean()} | :bbcode_scoped | {:bbcode_scoped, language: language(), highlight_lines: bbcode_highlight_lines()} | module() | {module(), keyword()}
Highlighter formatter and its options.
Available formatters: :html_inline, :html_linked, :html_multi_themes, :terminal, :bbcode_scoped
:html_inline- generates<span>tags with inline styles for each token, for example:<span style="color: #6eb4bff;">Atom</span>.:html_linked- generates<span>tags withclassrepresenting the token type, for example:<span class="l-keyword-special">Atom</span>. Must link an external CSS in order to render colors, see more at HTML Linked.:html_multi_themes- generates HTML with CSS custom properties (variables) for multiple themes, enabling light/dark mode support. Inspired by Shiki Dual Themes.:terminal- generates ANSI escape codes for terminal output.:bbcode_scoped- generates nested BBCode tags using highlight scope names, for example:[keyword-elixir]defmodule[/keyword-elixir].
You can either pass the formatter as an atom to use default options or a tuple with the formatter name and options, so both are equivalent:
# passing only the formatter name like below:
:html_inline
# is the same as passing an empty list of options:
{:html_inline, []}A custom formatter can be any module implementing Lumis.Formatter, passed
either directly or with options:
{MyFormatter, language: "elixir"}Available Options:
html_inline::language(language/0- default:nil) - the language used by the formatter. When omitted, Lumis tries to auto-detect it from the source.:structure(html_structure/0- default::block) -:blockwrites a<pre><code>block;:inlinewrites only the token spans, for markup the page already owns, and ignores the options that configure a block.:theme(theme/0- default:nil) - the theme to apply styles on the highlighted source code.:pre_class(String.t/0- default:nil) - the CSS class to append into the wrapping<pre>tag.:pre_attrs(html_attrs/0- default:[]) - attributes merged into the wrapping<pre>tag.:code_attrs(html_attrs/0- default:[]) - attributes merged into the nested<code>tag.:italic(boolean/0- default:false) - enable italic style for the highlighted code.:include_highlights(boolean/0- default:false) - include the highlight scope name in adata-highlightattribute. Useful for debugging.:highlight_lines(html_inline_highlight_lines/0- default:nil) - highlight specific lines either using the themehighlightedstyle or with custom CSS styling.:line_numbers(boolean/0- default:false) - open each line with a<span class="l-line-number">gutter carrying its number.:header(header/0- default:nil) - wrap the highlighted code with custom open and close HTML tags.
html_linked::language(language/0- default:nil) - the language used by the formatter. When omitted, Lumis tries to auto-detect it from the source.:structure(html_structure/0- default::block) -:blockwrites a<pre><code>block;:inlinewrites only the token spans, for markup the page already owns, and ignores the options that configure a block.:pre_class(String.t/0- default:nil) - the CSS class to append into the wrapping<pre>tag.:pre_attrs(html_attrs/0- default:[]) - attributes merged into the wrapping<pre>tag.:code_attrs(html_attrs/0- default:[]) - attributes merged into the nested<code>tag.:highlight_lines(html_linked_highlight_lines/0- default:nil) - highlight specific lines either using thel-highlightedclass from themes or with a custom CSS class.:line_numbers(boolean/0- default:false) - open each line with a<span class="l-line-number">gutter carrying its number.:header(header/0- default:nil) - wrap the highlighted code with custom open and close HTML tags.
html_multi_themes::language(language/0- default:nil) - the language used by the formatter. When omitted, Lumis tries to auto-detect it from the source.:structure(html_structure/0- default::block) -:blockwrites a<pre><code>block;:inlinewrites only the token spans, for markup the page already owns, and ignores the options that configure a block.:themes(keyword(theme())- required) - keyword list of theme identifiers to theme names/structs. Theme identifiers become CSS class names and CSS variable prefixes. Example:[light: "github_light", dark: "github_dark"].:default_theme(String.t/0- default:nil) - controls inline color rendering: specify a theme identifier for inline colors, use"light-dark()"for CSS light-dark() function, ornilfor CSS variables only.:css_variable_prefix(String.t/0- default:nil) - CSS variable prefix (defaults to"--lumis"if nil). Generates variables like--lumis-light(color),--lumis-light-bg(background),--lumis-light-font-style, etc.:pre_class(String.t/0- default:nil) - the CSS class to append into the wrapping<pre>tag.:pre_attrs(html_attrs/0- default:[]) - attributes merged into the wrapping<pre>tag.:code_attrs(html_attrs/0- default:[]) - attributes merged into the nested<code>tag.:italic(boolean/0- default:false) - enable italic style for the highlighted code.:include_highlights(boolean/0- default:false) - include the highlight scope name in adata-highlightattribute.:highlight_lines(html_inline_highlight_lines/0- default:nil) - highlight specific lines (same as html_inline).:line_numbers(boolean/0- default:false) - open each line with a<span class="l-line-number">gutter carrying its number.:header(header/0- default:nil) - wrap the highlighted code with custom open and close HTML tags.
terminal::language(language/0- default:nil) - the language used by the formatter. When omitted, Lumis tries to auto-detect it from the source.:theme(theme/0- default:nil) - the theme to apply styles on the highlighted source code.:background(:theme | t:String.t/0 | nil- default:nil) - fallback background behavior:nilinherits the output background,:themeuses the theme's normal background color, and a string uses that color.:width(pos_integer() | nil- default:nil) - pad each rendered terminal line to the given width. This is most useful with:background.:highlight_lines(terminal_highlight_lines/0- default:nil) - paint specific lines with a background colour, either:backgroundor the theme'shighlightedbackground.:line_numbers(boolean/0- default:false) - prefix each line with its number, right-aligned to the widest one and dimmed with the theme'scommentcolour.
bbcode_scoped::language(language/0- default:nil) - available when passed as{:bbcode_scoped, ...}.:highlight_lines(bbcode_highlight_lines/0- default:nil) - wrap specific lines in[highlighted]...[/highlighted].
Examples
Inline HTML formatter with default options
:html_inlineThere is no default theme, so this emits <span> tags without any style attribute.
Pass :theme to get colors, or use :html_linked to style the output with a CSS file.
Inline HTML formatter with custom options
{:html_inline, theme: "onedark", pre_class: "example-01", include_highlights: true}HTML Inline: highlight specific lines
# apply theme's `highlighted` style
{:html_inline, theme: "onedark", highlight_lines: %{lines: [2..4, 6], style: :theme}}
# style: :theme is the default
{:html_inline, theme: "onedark", highlight_lines: %{lines: [1, 2, 3]}}
# explicitly use theme style
{:html_inline, theme: "onedark", highlight_lines: %{lines: [1, 2, 3], style: :theme}}
# overrides default style
{:html_inline, theme: "onedark", highlight_lines: %{lines: [1, 3..5, 8], style: "background-color: #fff3cd; border-left: 3px solid #ffc107;"}}
# with only class and no style
{:html_inline, theme: "onedark", highlight_lines: %{lines: [1, 2, 3], style: nil, class: "transition-colors duration-500 w-full inline-block bg-yellow-500"}}HTML Linked: highlight specific lines
# use default `l-highlighted` class (already present in themes)
{:html_linked, highlight_lines: %{lines: [2..4, 6]}}
# use custom class
{:html_linked, highlight_lines: %{lines: [1, 2, 3], class: "error-line"}}Inline structure: highlight code inside a sentence
# only the token spans, to put inside a `<code>` the page already has
{:html_inline, theme: "onedark", structure: :inline}Wrap with custom open and close HTML tags
header = %{
open_tag: "<div class="code-header"><span>file: app.ex</span>",
close_tag: "</div>"
}
{:html_inline, theme: "onedark", header: header}HTML Multi-Themes: Light/Dark mode support
# Basic dual theme with CSS variables
{:html_multi_themes, themes: [light: "github_light", dark: "github_dark"]}
# With light-dark() function for automatic theme switching based on system preference
{:html_multi_themes,
themes: [light: "github_light", dark: "github_dark"],
default_theme: "light-dark()"}
# With inline colors for default theme and CSS variables for others
{:html_multi_themes,
themes: [light: "github_light", dark: "github_dark"],
default_theme: "light"}
# Multiple themes with custom prefix
{:html_multi_themes,
themes: [light: "github_light", dark: "github_dark", dim: "catppuccin_frappe"],
css_variable_prefix: "--code"}
# With Theme structs instead of strings
light_theme = Lumis.Theme.get("github_light")
dark_theme = Lumis.Theme.get("github_dark")
{:html_multi_themes, themes: [light: light_theme, dark: dark_theme]}Terminal formatter
:terminal
{:terminal, theme: "github_light"}
{:terminal, theme: "dracula", background: :theme, width: 120}
{:terminal, theme: "dracula", background: "#282a36", width: 120}BBCode Scoped formatter
:bbcode_scopedEmits highlight scope names as tags, not standard forum-style BBCode like [b], [color], or [code].
See https://docs.rs/lumis/latest/lumis/enum.FormatterOption.html for more info.
Wraps the highlighted code with custom open and close HTML tags.
@type highlight_events_options() :: [ annotations: [keyword()], rainbow_brackets: boolean(), budget: keyword() ]
Options for highlight_events/3.
:annotations(keyword/0) - Caller-provided semantic ranges for this highlighting operation. Each is a keyword list with either an:offsetor a:positionrange and optional:data:annotations: [ [offset: {12, 23}, data: %{change: :added}], [position: {{1, 10}, {1, 21}}, data: %{change: :removed}] ]A formatter receives each opening event as
{:annotation_start, %{range: {start, end}, data: data}}, with the range resolved to byte offsets. An empty range is a point.The default value is
[].:rainbow_brackets(boolean/0) - Render nested brackets with rainbow bracket decorations. The default value isfalse.:budget(keyword/0) - The work one render is allowed to do:budget: [time_limit: 1_000, match_limit: 16_384]Both dimensions bound the same render, so they are one option.
nilselects the default for either key.The default value is
[].:time_limit- How long one render may take, in milliseconds,0for no bound, ornilfor the default of 5000.A render that runs out returns the whole file as plain text rather than an error, and HTML formatters mark it
data-lumis-budget="time". Loading a language is not counted against it.The default value is
nil.:match_limit- Bound on the query matches Tree-sitter keeps in progress at once, for the highlight and bracket queries alike, ornilfor the default.Tree-sitter walks its whole pool of in-progress matches before it emits each capture, so the bound is what keeps highlighting linear on documents whose markup nests deeply enough to keep many matches open at once. Raising it recovers matches that would otherwise be dropped on such documents, at that cost.
The default value is
nil.
HTML attributes represented as an ordered keyword list.
A string value writes name="value". true writes the bare name HTML gives
boolean attributes such as hidden, and false removes an attribute Lumis
would otherwise generate.
@type html_inline_highlight_lines() :: %{ lines: [pos_integer() | Range.t()], style: :theme | String.t() | nil, class: String.t() | nil } | nil
Highlight lines options for Inline HTML formatter.
@type html_linked_highlight_lines() :: %{lines: [pos_integer() | Range.t()], class: String.t()} | nil
Highlight lines options for Linked HTML formatter.
@type html_multi_themes_options() :: %{ structure: html_structure(), themes: keyword(theme()), default_theme: String.t() | nil, css_variable_prefix: String.t() | nil, pre_class: String.t() | nil, pre_attrs: html_attrs(), code_attrs: html_attrs(), italic: boolean(), include_highlights: boolean(), highlight_lines: html_inline_highlight_lines() | nil, line_numbers: boolean(), header: header() } | nil
Options for HTML Multi-Themes formatter.
The themes are specified as a keyword list where keys are CSS identifiers (atoms) and values are theme names (strings) or Theme structs.
@type html_structure() :: :block | :inline
What an HTML formatter writes around the highlighted tokens.
:block is a <pre><code> block holding one <span class="l-line"> per line.
:inline is the token spans and the text between them, and nothing else, for
a <code> or other element the page already owns. Lines are separated by
\n and the last one has no terminator, as in a block. :pre_class,
:pre_attrs, :code_attrs, :highlight_lines, :line_numbers and :header
have no effect. The theme's text and background color are not written either,
because a block writes them on its <pre>; put
Lumis.Formatter.HTML.pre_attrs/1 on your own element to keep them.
@type language() :: String.t() | nil
A language name, filename, or path with extension.
See Lumis.available_languages/0 to list all available languages or check out a list of available languages.
Examples
- "elixir"
- ".ex"
- "app.ex"
- "lib/app.ex"
@type language_info() :: %{ id: String.t(), name: String.t(), aliases: [String.t()], extensions: [String.t()], globs: [String.t()], emacs_modes: [String.t()], shebangs: [String.t()] }
What Lumis knows about one language.
@type options() :: [ language: language(), formatter: formatter(), theme: struct() | binary() | nil, inline_style: boolean(), pre_class: binary() | nil, annotations: [keyword()], rainbow_brackets: boolean(), budget: keyword() ]
:language(Lumis.language/0) - This option is deprecated. Use the :language option inside the formatter tuple instead, eg: {:html_inline, language: "elixir"}:formatter(Lumis.formatter/0) - Formatter to apply on the highlighted source code. See the type doc for more info. The default value is{:html_inline, []}.:theme- This option is deprecated. Use :formatter instead.:inline_style(boolean/0) - This option is deprecated. Use :formatter instead.:pre_class- This option is deprecated. Use :formatter instead.:annotations(keyword/0) - Caller-provided semantic ranges for this highlighting operation. Each is a keyword list with either an:offsetor a:positionrange and optional:data:annotations: [ [offset: {12, 23}, data: %{change: :added}], [position: {{1, 10}, {1, 21}}, data: %{change: :removed}] ]A formatter receives each opening event as
{:annotation_start, %{range: {start, end}, data: data}}, with the range resolved to byte offsets. An empty range is a point.The default value is
[].:rainbow_brackets(boolean/0) - Render nested brackets with rainbow bracket decorations. The default value isfalse.:budget(keyword/0) - The work one render is allowed to do:budget: [time_limit: 1_000, match_limit: 16_384]Both dimensions bound the same render, so they are one option.
nilselects the default for either key.The default value is
[].:time_limit- How long one render may take, in milliseconds,0for no bound, ornilfor the default of 5000.A render that runs out returns the whole file as plain text rather than an error, and HTML formatters mark it
data-lumis-budget="time". Loading a language is not counted against it.The default value is
nil.:match_limit- Bound on the query matches Tree-sitter keeps in progress at once, for the highlight and bracket queries alike, ornilfor the default.Tree-sitter walks its whole pool of in-progress matches before it emits each capture, so the bound is what keeps highlighting linear on documents whose markup nests deeply enough to keep many matches open at once. Raising it recovers matches that would otherwise be dropped on such documents, at that cost.
The default value is
nil.
See each option type for more info.
@type terminal_highlight_lines() :: %{lines: [pos_integer() | Range.t()], background: String.t() | nil} | nil
Highlight lines options for the Terminal formatter.
@type theme() :: String.t() | Lumis.Theme.t() | nil
Theme used to apply styles on the highlighted source code.
See Lumis.available_themes/0 to list all available themes or check out a list of available themes.
A built-in theme's name and appearance, without its highlight data.
Functions
@spec available_languages() :: [language_info()]
Returns every available language and what the catalog knows about it, sorted by id.
Example
iex> Lumis.available_languages() |> Enum.find(&(&1.id == "elixir"))
%{
id: "elixir",
name: "Elixir",
aliases: [],
extensions: ["*.ex", "*.exs"],
globs: ["*.ex", "*.exs"],
emacs_modes: ["elixir"],
shebangs: ["elixir"]
}
@spec available_themes() :: [theme_info()]
Returns every built-in theme's name and appearance, sorted by name.
Use Lumis.Theme.get/2 to get the actual theme struct.
Example
iex> Lumis.available_themes() |> Enum.find(&(&1.name == "github_light"))
%{name: "github_light", appearance: "light"}
@spec default_options() :: options()
Returns all default options.
@spec highlight(String.t(), options()) :: {:ok, String.t()} | {:error, Lumis.RenderError.t()}
Highlights source code and outputs into a formatted string.
A language whose parser is not installed as a dependency renders as plain text.
Invalid options still raise, because those are a caller mistake rather than a runtime condition.
Options
See options/0.
Examples
Defining the language name:
iex> Lumis.highlight("Atom.to_string(:elixir)", formatter: {:html_inline, language: "elixir"})
{
:ok,
<pre class="lumis" style="color: #abb2bf; background-color: #282c34;"><code class="language-elixir" translate="no" tabindex="0"><span class="l-line" data-line="1"><span style="color: #e5c07b;">Atom</span><span style="color: #56b6c2;">.</span><span style="color: #61afef;">to_string</span><span style="color: #c678dd;">(</span><span style="color: #e06c75;">:elixir</span><span style="color: #c678dd;">)</span></span></code></pre>
}Guessing the language based on the provided source code:
iex> Lumis.highlight("#!/usr/bin/env bash\nID=1")
{:ok, "<pre class="lumis" ...><code class="language-bash" ...>...</code></pre>"}With custom options:
iex> Lumis.highlight("Atom.to_string(:elixir)", formatter: {:html_inline, language: "example.ex", pre_class: "example-elixir"})
{:ok, "<pre class="lumis example-elixir" ...><code ...>...</code></pre>"}Terminal formatter:
iex> Lumis.highlight("Atom.to_string(:elixir)", formatter: {:terminal, language: "elixir"})
{:ok, "[0m[38;2;229;192;123mAtom[0m[0m[38;2;86;182;194m.[0m[0m[38;2;97;175;239mto_string[0m[0m[38;2;198;120;221m([0m[0m[38;2;224;108;117m:elixir[0m[0m[38;2;198;120;221m)[0m"}Highlighting specific lines in HTML Inline formatter:
iex> code = """
...> defmodule Example do
...> @lang = :elixir
...> def lang, do: @lang
...> end
...> """
iex> highlight_lines = %{lines: [2]}
iex> Lumis.highlight(code, formatter: {:html_inline, language: "elixir", highlight_lines: highlight_lines})
# Line 2 will be highlighted with the theme's `highlighted` style:
<span class="l-line" style="display: inline-block; width: 100%; min-height: 1lh; vertical-align: top; background-color: #414858;" data-line="2">...</span>Highlighting specific lines in HTML Linked formatter:
iex> code = """
...> defmodule Example do
...> @lang = :elixir
...> def lang, do: @lang
...> end
...> """
iex> highlight_lines = %{lines: [2]}
iex> Lumis.highlight(code, formatter: {:html_linked, language: "elixir", highlight_lines: highlight_lines})
# Line 2 will contain a `l-highlighted` class:
<span class="l-line l-highlighted" data-line="2">...Wrapping with custom HTML:
iex> header = %{
...> open_tag: "<figure><span>file: example.exs</span>",
...> close_tag: "</figure>"
...> }
iex> Lumis.highlight("IO.puts('hello')", formatter: {:html_inline, language: "elixir", header: header})
{:ok, "<figure><span>file: example.exs</span><pre...><code ...>...</code></pre></figure>"}See https://docs.rs/lumis/latest/lumis/fn.highlight.html for more info.
Same as highlight/2 but raises Lumis.HighlightError in case of failure.
@spec highlight_events(String.t(), String.t() | nil, highlight_events_options()) :: {:ok, [Lumis.Formatter.event(term())]} | {:error, Lumis.RenderError.t()}
Highlights source into the event stream a custom formatter receives, without
rendering it.
Reach for it when a formatter's single string is the wrong shape for the result, such as one HTML fragment per line:
{:ok, events} = Lumis.highlight_events(source, "elixir")
Lumis.Formatter.HTML.render_lines_from_events(source, events, attrs)language is a language name, a file name or path, or nil to detect it from
source. A language whose parser is not installed comes back as one plain
:source event.
The counterpart of highlight_events in Rust and highlightEvents() in
JavaScript.
Options
See highlight_events_options/0.
Example
iex> {:ok, events} = Lumis.highlight_events("x = 1", "elixir")
iex> Enum.take(events, 3)
[{:start, %{scope: "variable", language: "elixir"}}, {:source, %{start: 0, end: 1}}, :end]
@spec highlight_events!(String.t(), String.t() | nil, highlight_events_options()) :: [ Lumis.Formatter.event(term()) ]
Same as highlight_events/3 but raises Lumis.HighlightError in case of failure.
@spec loaded_languages() :: [id :: String.t()]
Returns the ids of the languages loaded into this VM, sorted.
The complement of available_languages/0: what can be highlighted right now
without a download. Loading is global to the VM, so this is the same list in
every process.
Example
iex> Lumis.Languages.load("elixir")
iex> Lumis.loaded_languages()
["elixir"]
Validates the given options against the options schema.
This function validates the provided options using NimbleOptions and the defined schema. It ensures that all options are valid and properly typed before being passed to the highlighting functions.
Examples
iex> Lumis.validate_options!(formatter: {:html_inline, language: "elixir"})
[formatter: {:html_inline, [header: nil, line_numbers: nil, highlight_lines: nil, include_highlights: false, italic: false, pre_class: nil, theme: nil, language: "elixir"]}]
iex> Lumis.validate_options!(formatter: {:html_inline, theme: "dracula"})
[formatter: {:html_inline, [theme: "dracula", ...]}]
iex> Lumis.validate_options!(language: :invalid)
** (NimbleOptions.ValidationError)