<!-- livebook:{"persist_outputs":true} -->

# Syntax highlighting

## Pick an engine

MDEx can highlight fenced code blocks with [Lumis](https://mdex.hexdocs.pm/lumis.html) or [Syntect](https://mdex.hexdocs.pm/syntect.html).

You must opt in to the syntax highlighter you want before `:mdex_native` is compiled.

If no highlighter is configured, fenced code blocks render normally without syntax highlighting and a language class which is useful to apply syntax highlighting after the document generation, for example to highlight using Makeup or Shiki.

## Lumis

Add Lumis to your deps if you want to use `engine: :lumis`, along with a parser for every
language you highlight:

<!-- livebook:{"force_markdown":true} -->

```elixir
{:lumis, "~> 0.10"},
{:lumis_wasm_elixir, "~> 0.26"},
{:lumis_wasm_rust, "~> 0.26"}
```

And configure `:mdex_native` to download the Lumis NIF:

<!-- livebook:{"force_markdown":true} -->

```elixir
import Config

config :mdex_native, syntax_highlighter: :lumis
```

Since Lumis v0.9, parsers are ordinary dependencies. Each language is its own
`lumis_wasm_*` package, nothing is compiled in and nothing is downloaded at runtime, so a
fence in a language you haven't installed renders as plain text. Bundles such as
`{:lumis_wasm_bundle_web, "~> 0.1"}` cover a set at once, and the
[language catalog](https://docs.lumis.sh/reference/languages) lists every package name.

## Syntect

Configure `:mdex_native` to download the Syntect NIF:

<!-- livebook:{"force_markdown":true} -->

```elixir
import Config

config :mdex_native, syntax_highlighter: :syntect
```

## Passing options

Syntax highlighting is configured through regular MDEx options:

<!-- livebook:{"force_markdown":true} -->

```elixir
MDEx.to_html!(markdown,
  syntax_highlight: [engine: :lumis, opts: [formatter: {:html_inline, theme: "github_light"}]]
)
```

Lumis also accepts `budget: [time_limit: 1_000, match_limit: 4096]` inside `:opts` to bound each code block. See [Highlighting budgets](https://mdex.hexdocs.pm/lumis.html#highlighting-budgets) for defaults and fallback behavior.

If another library calls MDEx for you, pass the same option through that library's MDEx configuration.

For example in Tableau:

<!-- livebook:{"force_markdown":true} -->

```elixir
config :tableau, :config,
  markdown: [
    mdex: [
      syntax_highlight: [engine: :lumis, opts: [formatter: {:html_inline, theme: "github_light"}]]
    ]
  ]
```

## More examples

See the [Lumis syntax highlighting](https://mdex.hexdocs.pm/lumis.html) guide for formatters, linked CSS, line highlights, light/dark themes, and code fence decorators.

See the [Syntect syntax highlighting](https://mdex.hexdocs.pm/syntect.html) to enable it and examples.

Note that Code fence decorators such as `highlight_lines` and per-block `theme` are exclusive Lumis options. See `examples/code_block_decorators.livemd` for those.
