<!-- livebook:{"persist_outputs":true} -->
# Lumis syntax highlighting
```elixir
Mix.install([
{:mdex, "~> 0.12"},
{:lumis, "~> 0.1"},
{:kino, "~> 0.16"}
],
config: [mdex_native: [syntax_highlighter: :lumis]]
)
```
## What Lumis does
[Lumis](https://hex.pm/packages/lumis) highlights code with Tree-sitter. It ships themes converted from Neovim colorschemes and gives you a few HTML formatters.
To use Lumis, add `{:lumis, "~> 0.1"}` to your deps and configure `:mdex_native` with `syntax_highlighter: :lumis` before compiling dependencies. This notebook does both in `Mix.install/2` above.
Then use `engine: :lumis` to enable Lumis for a render:
<!-- livebook:{"force_markdown":true} -->
```elixir
syntax_highlight: [engine: :lumis, opts: [formatter: {:html_inline, theme: "github_light"}]]
```
The older Lumis API is still supported for existing code, but it is no longer recommended:
<!-- livebook:{"force_markdown":true} -->
```elixir
syntax_highlight: [formatter: {:html_inline, theme: "github_light"}]
```
For new code, pass Lumis options under `:opts` and set the engine explicitly.
The language still comes from the Markdown fence. One formatter can handle different languages in the same document.
## Inline styles
Use `:html_inline` when the generated HTML needs to stand on its own. This is useful for docs, feeds, emails, or anything where carrying a stylesheet around is a hassle.
````elixir
options = [
syntax_highlight: [engine: :lumis, opts: [formatter: {:html_inline, theme: "catppuccin_latte"}]]
]
"""
# Inline formatter
```elixir
def fib(n), do: fib(n, 1, 1)
def fib(0, _a, _b), do: []
def fib(n, a, b) when n > 0 do
[a | fib(n - 1, b, a + b)]
end
```
```ruby
def fibonacci(n)
return n if (0..1).include?(n)
(fibonacci(n - 1) + fibonacci(n - 2))
end
```
```rust
fn fibonacci(n: u32) -> u32 {
match n {
0 => 1,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
```
"""
|> MDEx.to_html!(options)
|> Kino.HTML.new()
````
## Linked CSS
Use `:html_linked` when your app owns the CSS. Lumis writes token classes, and your stylesheet supplies the colors.
````elixir
theme_css =
:lumis
|> :code.priv_dir()
|> Path.join("static/css/github_light.css")
|> File.read!()
options = [
syntax_highlight: [engine: :lumis, opts: [formatter: :html_linked]]
]
html =
~S|
# Linked formatter
```elixir
def render(assigns) do
~H"""
<pre><code>{@body}</code></pre>
"""
end
```
|
|> MDEx.to_html!(options)
Kino.HTML.new("""
<style>#{theme_css}</style>
#{html}
""")
````
## Formatter options
Lumis formatter options live under `opts: [formatter: ...]`. See the [Lumis formatter type](https://lumis.hexdocs.pm/Lumis.html#t:formatter/0) for the full shape:
<!-- livebook:{"force_markdown":true} -->
```elixir
syntax_highlight: [
engine: :lumis,
opts: [
formatter: {:html_inline, theme: "github_light", pre_class: "code", include_highlights: true}
]
]
```
For automatic light/dark mode, see `examples/light_dark_theme.livemd`. For custom theme structs, see `examples/custom_theme.livemd`.
Code fence decorators such as `highlight_lines`, `theme`, and `pre_class` are Lumis options too. See `examples/code_block_decorators.livemd`.
Theme names such as `github_light`, `github_dark`, and `catppuccin_latte` come from Lumis. You can inspect them with `Lumis.available_themes/0`.