Custom Theme

View Source
Mix.install([
  {:mdex, ">= 0.11.3"},
  {:kino, "~> 0.16"}
])

Intro

MDEx uses Lumis for syntax highlighting, which supports customizable themes. This example shows how to modify an existing theme by changing styles for specific syntax elements like function calls.

Customization

Below we'll customize the github_light theme but you can work with any %Lumis.Theme{} or build one from scratch.

theme = Lumis.Theme.get("github_light")

function_call_style =
  %Lumis.Theme.Style{
    fg: "#d1242f",
    bg: "#e4b7be",
    bold: true
  }

new_theme = put_in(
  theme,
  [Access.key!(:highlights), Access.key!("function.call")],
  function_call_style
)
%Lumis.Theme{
  name: "github_light",
  appearance: :light,
  revision: "c106c9472154d6b2c74b74565616b877ae8ed31d",
  highlights: %{
    "function.macro" => %Lumis.Theme.Style{
      fg: "#6639ba",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "variable.builtin" => %Lumis.Theme.Style{
      fg: "#0550ae",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "markup.list.checked" => %Lumis.Theme.Style{
      fg: "#116329",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "character" => %Lumis.Theme.Style{
      fg: "#0a3069",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "string.special.symbol" => %Lumis.Theme.Style{
      fg: "#0550ae",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "markup.strong" => %Lumis.Theme.Style{
      fg: "#1f2328",
      bg: nil,
      bold: true,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "markup.list.unchecked" => %Lumis.Theme.Style{
      fg: "#57606a",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "variable.parameter.builtin" => %Lumis.Theme.Style{
      fg: "#0550ae",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "character.special" => %Lumis.Theme.Style{
      fg: "#1f2328",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "boolean" => %Lumis.Theme.Style{
      fg: "#0550ae",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "string.escape" => %Lumis.Theme.Style{
      fg: "#0a3069",
      bg: nil,
      bold: true,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    "keyword.exception" => %Lumis.Theme.Style{
      fg: "#0550ae",
      bg: nil,
      bold: false,
      italic: false,
      text_decoration: %Lumis.Theme.TextDecoration{underline: nil, strikethrough: false}
    },
    ...
  }
}
options = [
  syntax_highlight: [formatter: {:html_inline, theme: new_theme}]
]

"""
# Elixir
```elixir
# elixir example

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
```ruby
# ruby example

def fibonacci(n)
  return n if (0..1).include?(n)
  (fibonacci(n - 1) + fibonacci(n - 2))
end
```

# Rust
```rust
// rust example

fn fibonacci(n: u32) -> u32 {
  match n {
    0 => 1,
    1 => 1,
    _ => fibonacci(n - 1) + fibonacci(n - 2),
  }
}
```
"""
|> MDEx.to_html!(options)
|> Kino.HTML.new()