Autumn (Autumn v0.6.0)
View Source
Syntax highlighter powered by Tree-sitter and Neovim themes.
Features
- 🌳 70+ languages with tree-sitter parsing
- 🎨 120+ Neovim themes
- 📝 HTML output with inline styles or CSS classes
- 🖥️ Terminal output with ANSI colors
- 🔍 Language auto-detection
- 🎯 Customizable formatting options
- ✨ Line highlighting with custom styling
- 🎁 Custom HTML wrappers for code blocks
Installation
def deps do
[
{:autumn, "~> 0.5"}
]
endUsage
Basic Usage (HTML Inline)
iex> Autumn.highlight!("Atom.to_string(:elixir)", language: "elixir")
~s|<pre class="athl" style="color: #abb2bf; background-color: #282c34;"><code class="language-elixir" translate="no" tabindex="0"><div class="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>|See the HTML Linked and Terminal formatters below for more options.
Language Auto-detection
iex> Autumn.highlight!("#!/usr/bin/env bash\nID=1")
~s|<pre class="athl" style="color: #abb2bf; background-color: #282c34;"><code class="language-bash" translate="no" tabindex="0"><div class="line" data-line="1"><span style="color: #c678dd;">#!/usr/bin/env bash</span>
</div><div class="line" data-line="2"><span style="color: #d19a66;">ID</span><span style="color: #56b6c2;">=</span><span style="color: #d19a66;">1</span>
</span></code></pre>|Themes
Themes are sourced from popular Neovim colorschemes.
Use Autumn.available_themes/0 to list all available themes. You can specify a theme by name in the formatter options, or use Autumn.Theme.get/1 to get a specific theme struct if you need to inspect or manipulate its styles.
# Using theme name in formatter options
iex> Autumn.highlight!("setTimeout(fun, 5000);", language: "js", formatter: {:html_inline, theme: "github_light"})
~s|<pre class="athl" style="color: #1f2328; background-color: #ffffff;"><code class="language-javascript" translate="no" tabindex="0"><div class="line" data-line="1"><span style="color: #6639ba;">setTimeout</span><span style="color: #1f2328;">(</span><span style="color: #1f2328;">fun</span><span style="color: #1f2328;">,</span> <span style="color: #0550ae;">5000</span><span style="color: #1f2328;">)</span><span style="color: #1f2328;">;</span>
</span></code></pre>|
# Using theme struct
iex> theme = Autumn.Theme.get("github_light")
iex> Autumn.highlight!("setTimeout(fun, 5000);", language: "js", formatter: {:html_inline, theme: theme})Bring Your Own Theme
You can also load custom themes from JSON files or strings:
# Load from JSON file
{:ok, theme} = Autumn.Theme.from_file("/path/to/your/theme.json")
Autumn.highlight!("your code", theme: theme)
# Load from JSON string
theme_json = ~s({"name": "my_theme", "appearance": "dark", "highlights": {"comment": {"fg": "#808080"}}})
{:ok, theme} = Autumn.Theme.from_json(theme_json)
Autumn.highlight!("your code", theme: theme)Incomplete or Malformed code
It's also capable of handling incomplete or malformed code, useful for streaming like in a ChatGPT interface:
iex> Autumn.highlight!("const header = document.getEl", language: "js")
~s|<pre class="athl" style="color: #abb2bf; background-color: #282c34;"><code class="language-javascript" translate="no" tabindex="0"><div class="line" data-line="1"><span style="color: #c678dd;">const</span> <span style="color: #abb2bf;">header</span> <span style="color: #abb2bf;">=</span> <span style="color: #e86671;">document</span><span style="color: #848b98;">.</span><span style="color: #56b6c2;">getEl</span>
</span></code></pre>|Formatters
Autumn supports four output formatters:
All HTML formatters wrap each line in a <div class="line"> element with a data-line attribute containing the line number, making it easy to add line numbers or implement line-based features in your application.
See the Livebook examples and t:formatter/0 for more.
HTML Inline (Default)
Generates HTML with inline styles for each token:
iex> Autumn.highlight!("Atom.to_string(:elixir)", language: "elixir", formatter: :html_inline)
# or with options
iex> Autumn.highlight!("Atom.to_string(:elixir)", language: "elixir", formatter: {:html_inline, pre_class: "my-code", italic: true, include_highlights: true})Options:
:pre_class- CSS class for the<pre>tag:italic- enable italic styles:include_highlights- include highlight scope names indata-highlightattributes:highlight_lines- highlight specific lines with custom styling:header- wrap the highlighted code with custom HTML elements
HTML Linked
Generates HTML with CSS classes for styling:
iex> Autumn.highlight!("Atom.to_string(:elixir)", language: "elixir", formatter: :html_linked)
# or with options
iex> Autumn.highlight!("Atom.to_string(:elixir)", language: "elixir", formatter: {:html_linked, pre_class: "my-code"})Options:
:pre_class- CSS class for the<pre>tag:highlight_lines- highlight specific lines with custom CSS class:header- wrap the highlighted code with custom HTML elements
To use linked styles, you need to include one of the available CSS themes in your app.
For Phoenix apps, add this to your endpoint.ex:
plug Plug.Static,
at: "/themes",
from: {:autumn, "priv/static/css/"},
only: ["dracula.css"] # choose any theme you wantThen add the stylesheet to your template:
<link phx-track-static rel="stylesheet" href={~p"/themes/dracula.css"} />HTML Multi-Themes
Generates HTML with CSS custom properties (variables) for multiple themes, enabling light/dark mode support. Inspired by Shiki Dual Themes.
# Basic dual theme with CSS variables
iex> Autumn.highlight!("Atom.to_string(:elixir)",
language: "elixir",
formatter: {:html_multi_themes,
themes: [light: "github_light", dark: "github_dark"]
}
)
# With light-dark() function for automatic theme switching
iex> Autumn.highlight!("Atom.to_string(:elixir)",
language: "elixir",
formatter: {:html_multi_themes,
themes: [light: "github_light", dark: "github_dark"],
default_theme: "light-dark()"
}
)The generated HTML includes CSS custom properties like --athl-light, --athl-dark, --athl-{theme}-bg, and font styling variables (-font-style, -font-weight, -text-decoration) that can be used with CSS media queries or JavaScript for theme switching:
/* Automatic light/dark mode based on system preference */
@media (prefers-color-scheme: dark) {
.athl,
.athl span {
color: var(--athl-dark) !important;
background-color: var(--athl-dark-bg) !important;
font-style: var(--athl-dark-font-style) !important;
font-weight: var(--athl-dark-font-weight) !important;
text-decoration: var(--athl-dark-text-decoration) !important;
}
}
/* Manual control with class-based switching */
html.dark .athl,
html.dark .athl span {
color: var(--athl-dark) !important;
background-color: var(--athl-dark-bg) !important;
font-style: var(--athl-dark-font-style) !important;
font-weight: var(--athl-dark-font-weight) !important;
text-decoration: var(--athl-dark-text-decoration) !important;
}Options:
:themes(required) - keyword list mapping theme identifiers to theme names, e.g.,[light: "github_light", dark: "github_dark"]:default_theme- controls inline color rendering: theme identifier for inline colors,"light-dark()"for CSS function, ornilfor CSS variables only:css_variable_prefix- custom CSS variable prefix (default:"--athl"):pre_class- CSS class for the<pre>tag:italic- enable italic styles:include_highlights- include highlight scope names indata-highlightattributes:highlight_lines- highlight specific lines with custom styling:header- wrap the highlighted code with custom HTML elements
Terminal
Generates ANSI escape codes for terminal output:
iex> Autumn.highlight!("Atom.to_string(:elixir)", language: "elixir", formatter: :terminal)
# or with options
iex> Autumn.highlight!("Atom.to_string(:elixir)", language: "elixir", formatter: {:terminal, theme: "github_light"})Options:
:theme- theme to apply styles
Samples
Visit https://autumnus.dev to check out some examples.
Acknowledgements
- Logo created by by pongsakornRed - Flaticon
- Logo font designed by Astigmatic
- Makeup for setting up the baseline and for the inspiration
- Inkjet for the Rust implementation up to v0.2 and for the inspiration
Summary
Types
Highlighter formatter and its options.
Wraps the highlighted code with custom open and close HTML tags.
Highlight lines options for Inline HTML formatter.
Highlight lines options for Linked HTML formatter.
Options for HTML Multi-Themes formatter.
A language name, filename, or path with extension.
Theme used to apply styles on the highlighted source code.
Functions
Returns the list of all available languages.
Returns the list of all available themes.
Returns all default options.
Highlights source code and outputs into a formatted string.
Same as highlight/2 but raises in case of failure.
Validates the given options against the options schema.
Types
@type formatter() :: :html_inline | {:html_inline, theme: theme(), pre_class: String.t(), italic: boolean(), include_highlights: boolean(), highlight_lines: html_inline_highlight_lines(), header: header()} | :html_linked | {:html_linked, pre_class: String.t(), highlight_lines: html_linked_highlight_lines(), header: header()} | :html_multi_themes | {:html_multi_themes, themes: keyword(theme()), default_theme: String.t(), css_variable_prefix: String.t(), pre_class: String.t(), italic: boolean(), include_highlights: boolean(), highlight_lines: html_inline_highlight_lines(), header: header()} | :terminal | {:terminal, [{:theme, theme()}]}
Highlighter formatter and its options.
Available formatters: :html_inline, :html_linked, :html_multi_themes, :terminal
: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="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.
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, []}Available Options:
html_inline::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.: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.:header(header/0- default:nil) - wrap the highlighted code with custom open and close HTML tags.
html_linked::pre_class(String.t/0- default:nil) - the CSS class to append into the wrapping<pre>tag.:highlight_lines(html_linked_highlight_lines/0- default:nil) - highlight specific lines either using thehighlightedclass from themes or with a custom CSS class.:header(header/0- default:nil) - wrap the highlighted code with custom open and close HTML tags.
html_multi_themes::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"--athl"if nil). Generates variables like--athl-light(color),--athl-light-bg(background),--athl-light-font-style, etc.:pre_class(String.t/0- default:nil) - the CSS class to append into the wrapping<pre>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).:header(header/0- default:nil) - wrap the highlighted code with custom open and close HTML tags.
terminal::theme(theme/0- default:nil) - the theme to apply styles on the highlighted source code.
Examples
Inline HTML formatter with default options
:html_inlineInline 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, highlight_lines: %{lines: [2..4, 6], style: :theme}}
# style: :theme is the default
{:html_inline, highlight_lines: %{lines: [1, 2, 3]}}
# explicitly use theme style
{:html_inline, highlight_lines: %{lines: [1, 2, 3], style: :theme}}
# overrides default style
{:html_inline, highlight_lines: %{lines: [1, 3..5, 8], style: "background-color: #fff3cd; border-left: 3px solid #ffc107;"}}
# with only class and no style
{:html_inline, 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 `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"}}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, 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 = Autumn.Theme.get("github_light")
dark_theme = Autumn.Theme.get("github_dark")
{:html_multi_themes, themes: [light: light_theme, dark: dark_theme]}Terminal formatter
:terminal
{:terminal, theme: "github_light"}See https://docs.rs/autumnus/latest/autumnus/enum.FormatterOption.html for more info.
Wraps the highlighted code with custom open and close HTML tags.
@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() :: %{ themes: keyword(theme()), default_theme: String.t() | nil, css_variable_prefix: String.t() | nil, pre_class: String.t() | nil, italic: boolean(), include_highlights: boolean(), highlight_lines: html_inline_highlight_lines() | nil, 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 language() :: String.t() | nil
A language name, filename, or path with extension.
See Autumn.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 options() :: [ language: language(), formatter: formatter(), theme: struct() | binary() | nil, inline_style: boolean(), pre_class: binary() | nil ]
:language(Autumn.language/0) - The language used to highlight source code. You can also pass a filename or extension, for eg:"enum.ex"or just"ex". If no language is provided, the highlighter will try to guess it based on the content of the given source code. UseAutumn.available_languages/0to list all available languages. The default value isnil.:formatter(Autumn.formatter/0) - Formatter to apply on the highlighted source code. See the type doc for more info. The default value is{:html_inline, [theme: "onedark"]}.: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.
See each option type for more info.
@type theme() :: String.t() | Autumn.Theme.t() | nil
Theme used to apply styles on the highlighted source code.
See Autumn.available_themes/0 to list all available themes or check out a list of available themes.
Functions
@spec available_languages() :: %{ required(id :: String.t()) => {name :: String.t(), [extension :: String.t()]} }
Returns the list of all available languages.
Example
iex> Autumn.available_languages()
%{
"diff" => {"Diff", ["*.diff"]},
"lua" => {"Lua", ["*.lua"]},
"javascript" => {"JavaScript", ["*.cjs", "*.js", "*.mjs", "*.snap", "*.jsx"]},
"elixir" => {"Elixir", ["*.ex", "*.exs"]},
...
}
iex> Autumn.available_languages()["elixir"]
{"Elixir", ["*.ex", "*.exs"]}
@spec available_themes() :: [name :: String.t()]
Returns the list of all available themes.
Use Autumn.Theme.get/1 to get the actual theme struct.
Example
iex> Autumn.available_themes()
["github_light", "github_dark", "catppuccin_frappe", "catppuccin_latte", "nightfox", ...]
@spec default_options() :: options()
Returns all default options.
Highlights source code and outputs into a formatted string.
Options
See options/0.
Examples
Defining the language name:
iex> Autumn.highlight("Atom.to_string(:elixir)", language: "elixir")
{
:ok,
<pre class="athl" style="color: #abb2bf; background-color: #282c34;"><code class="language-elixir" translate="no" tabindex="0"><div class="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>
</div></code></pre>
}Guessing the language based on the provided source code:
iex> Autumn.highlight("#!/usr/bin/env bash\nID=1")
{:ok, "<pre class="athl" ...><code class="language-bash" ...>...</code></pre>"}With custom options:
iex> Autumn.highlight("Atom.to_string(:elixir)", language: "example.ex", formatter: {:html_inline, pre_class: "example-elixir"})
{:ok, "<pre class="athl example-elixir" ...><code ...>...</code></pre>"}Terminal formatter:
iex> Autumn.highlight("Atom.to_string(:elixir)", language: "elixir", formatter: :terminal)
{: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> Autumn.highlight(code, language: "elixir", formatter: {:html_inline, highlight_lines: highlight_lines})
# Line 2 will be highlighted with the theme's `highlighted` style:
<div class="line" style="background-color: #414858;" data-line="2">...</div>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> Autumn.highlight(code, language: "elixir", formatter: {:html_linked, highlight_lines: highlight_lines})
# Line 2 will contain a `highlighted` class:
<div class="line highlighted" data-line="2">...Wrapping with custom HTML:
iex> header = %{
...> open_tag: "<figure><span>file: example.exs</span>",
...> close_tag: "</figure>"
...> }
iex> Autumn.highlight("IO.puts('hello')", language: "elixir", formatter: {:html_inline, header: header})
# Returns: "<div class='code-block' data-lang='elixir'><pre class='athl'>...</pre></div>"
{:ok, "<figure><span>file: example.exs</span><pre...><code ...>...</code></pre></figure>"}See https://docs.rs/autumnus/latest/autumnus/fn.highlight.html for more info.
Same as highlight/2 but raises in case of failure.
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> Autumn.validate_options!(language: "elixir")
[language: "elixir", formatter: {:html_inline, [header: nil, highlight_lines: nil, include_highlights: false, italic: false, pre_class: nil, theme: "onedark"]}]
iex> Autumn.validate_options!(formatter: {:html_inline, theme: "dracula"})
[language: nil, formatter: {:html_inline, [theme: "dracula", ...]}]
iex> Autumn.validate_options!(language: :invalid)
** (NimbleOptions.ValidationError)