Autumn (Autumn v0.4.0)

View Source
Autumn logo

Syntax highlighter powered by Tree-sitter and Neovim themes.

https://autumnus.dev

Features

  • 🌳 60+ languages with tree-sitter parsing
  • 🎨 120+ Neovim themes
  • 📝 HTML output with inline or linked styles
  • 🖥️ 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.3"}
  ]
end

Usage

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"><span 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"><span class="line" data-line="1"><span style="color: #c678dd;">#!/usr/bin/env bash</span>
</span><span 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 directly in the :theme option, or use Autumn.Theme.get/1 to get a specific theme struct if you need to inspect or manipulate its styles.

# Using theme name
iex> Autumn.highlight!("setTimeout(fun, 5000);", language: "js", theme: "github_light")
~s|<pre class="athl" style="color: #1f2328; background-color: #ffffff;"><code class="language-javascript" translate="no" tabindex="0"><span 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", 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"><span 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 three output formatters:

Both HTML formatters wrap each line in a <span 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.

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 in data-highlight attributes
  • :highlight_lines - highlight specific lines with custom styling
  • :header - wrap the highlighted code with custom HTML elements

Line Highlighting

# Default: theme-based highlighting using cursorline from current theme
highlight_lines = %{
  lines: [2..4, 6]  # Mix integers and ranges for flexible line specification
  # style defaults to :theme, which uses the cursorline highlight from theme
}

# Or with explicit theme styling  
theme_highlight_lines = %{
  lines: [1..2],
  style: :theme  # uses cursorline highlight from theme
}

# Or with custom CSS styling
custom_highlight_lines = %{
  lines: [2..4, 6],  # Multiple lines: 2..4, Single line: 6
  style: "background-color: #fff3cd; border-left: 3px solid #ffc107;"
}

Autumn.highlight!(code, language: "elixir", formatter: {:html_inline, highlight_lines: highlight_lines})

Custom HTML Wrapper

# Wrap code with custom HTML elements
header = %{
  open_tag: "<div class='code-wrapper' data-language='elixir'>",
  close_tag: "</div>"
}

Autumn.highlight!(code, language: "elixir", formatter: {:html_inline, header: header})

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

Line Highlighting with CSS Classes

# Highlight lines with a CSS class
highlight_lines = %{
  lines: [1..3, 7..8],
  class: "highlighted-line"
}

Autumn.highlight!(code, language: "elixir", formatter: {:html_linked, highlight_lines: highlight_lines})

You'll need to style the CSS class in your stylesheet:

.highlighted-line {
  background-color: #fff3cd;
  border-left: 3px solid #ffc107;
}

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 want

Then add the stylesheet to your template:

<link phx-track-static rel="stylesheet" href={~p"/themes/dracula.css"} />

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, italic: true})

Options:

  • :italic - enable italic styles (if supported by your terminal)

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.

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.

Highlights source code and outputs into a formatted string.

Same as highlight/2 but raises in case of failure.

Types

formatter()

@type formatter() ::
  :html_inline
  | {:html_inline,
     theme: theme(),
     pre_class: String.t(),
     italic: boolean(),
     include_highlights: boolean(),
     highlight_lines: %{
       lines: [pos_integer() | Range.t()],
       style: :theme | String.t()
     },
     header: %{open_tag: String.t(), close_tag: String.t()}}
  | :html_linked
  | {:html_linked,
     pre_class: String.t(),
     highlight_lines: %{lines: [pos_integer() | Range.t()], class: String.t()},
     header: %{open_tag: String.t(), close_tag: String.t()}}
  | :terminal
  | {:terminal, [{:theme, theme()}]}

Highlighter formatter and its options.

Available formatters: :html_inline, :html_linked, :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 with class representing 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.
  • :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 a data-highlight attribute. Useful for debugging.
    • :highlight_lines (map - default: nil) - highlight specific lines with custom styling: %{lines: [pos_integer() | Range.t()], style: :theme | String.t()}. The :style field is optional and defaults to :theme, which uses the cursorline highlight from the current theme. You can also pass a CSS string for custom styling.

    • :header (map - default: nil) - wrap the highlighted code with custom HTML elements: %{open_tag: String.t(), close_tag: String.t()}.
  • html_linked:

    • :pre_class (String.t/0 - default: nil) - the CSS class to append into the wrapping <pre> tag.
    • :highlight_lines (map - default: nil) - highlight specific lines with custom CSS class: %{lines: [pos_integer() | Range.t()], class: String.t()}.

    • :header (map - default: nil) - wrap the highlighted code with custom HTML elements: %{open_tag: String.t(), close_tag: String.t()}.
  • terminal:

    • :theme (theme/0 - default: nil) - the theme to apply styles on the highlighted source code.

Examples

:html_inline

{:html_inline, theme: "onedark", pre_class: "example-01", include_highlights: true}

# Highlighting specific lines with theme-based styling (default)
highlight_lines = %{
  lines: [2..4, 6]  # Range for multiple lines, integer for single line
  # style: :theme is the default - uses cursorline highlight from theme
}
{:html_inline, highlight_lines: highlight_lines}

# Or with custom CSS styling
custom_highlight_lines = %{
  lines: [1, 3..5, 8],  # Mix of single lines and ranges
  style: "background-color: #fff3cd; border-left: 3px solid #ffc107;"
}
{:html_inline, highlight_lines: custom_highlight_lines}

# Wrapping with custom HTML elements
header = %{
  open_tag: "<div class="code-wrapper" data-language="elixir">",
  close_tag: "</div>"
}
{:html_inline, header: header}

# Combining multiple features
{:html_inline, theme: "dracula", header: header, highlight_lines: highlight_lines}

{:html_linked, pre_class: "example-01"}

# HTML linked with line highlighting
linked_highlight_lines = %{
  lines: [1, 3..5],  # Single line 1, and range 3-5
  class: "highlighted-line"
}
{:html_linked, highlight_lines: linked_highlight_lines, header: header}

:terminal

{:terminal, theme: "github_light"}

See https://docs.rs/autumnus/latest/autumnus/enum.FormatterOption.html for more info.

language()

@type language() :: String.t() | nil

A language name, filename, or path with extension.

Examples

- "elixir"
- ".ex"
- "app.ex"
- "lib/app.ex"

options()

@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. Use Autumn.available_languages/0 to list all available languages. The default value is nil.

  • :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.

theme()

@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

available_languages()

@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"]}

available_themes()

@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", ...]

formatter_schema()

highlight(source, options \\ [])

@spec highlight(String.t(), options()) :: {:ok, String.t()} | {:error, term()}

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,
 ~s|<pre class="athl" style="color: #abb2bf; background-color: #282c34;"><code class="language-elixir" translate="no" tabindex="0"><span 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>|
}

Guessing the language based on the provided source code:

iex> Autumn.highlight("#!/usr/bin/env bash\nID=1")
{:ok,
 ~s|<pre class="athl" style="color: #abb2bf; background-color: #282c34;"><code class="language-bash" translate="no" tabindex="0"><span class="line" data-line="1"><span style="color: #c678dd;">#!/usr/bin/env bash</span>
 </span><span 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>|
}

With custom options:

iex> Autumn.highlight("Atom.to_string(:elixir)", language: "example.ex", formatter: {:html_inline, pre_class: "example-elixir"})
{:ok,
 ~s|<pre class="athl example-elixir" style="color: #abb2bf; background-color: #282c34;"><code class="language-elixir" translate="no" tabindex="0"><span 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>|
}

Terminal formatter:

iex> Autumn.highlight("Atom.to_string(:elixir)", language: "elixir", formatter: :terminal)
{:ok, "Atom.to_string(:elixir)"}

Highlighting specific lines:

iex> code = "defmodule Example do\n  def hello, do: :world\n  def goodbye, do: :farewell\nend"
iex> # Using default theme-based highlighting (cursorline from theme)
iex> highlight_lines = %{lines: [2..2]}
iex> Autumn.highlight(code, language: "elixir", formatter: {:html_inline, highlight_lines: highlight_lines})
# Returns HTML with line 2 highlighted using theme's cursorline style

iex> # Or with custom CSS styling
iex> custom_highlight_lines = %{
...>   lines: [2..2],
...>   style: "background-color: #fff3cd;"
...> }
iex> Autumn.highlight(code, language: "elixir", formatter: {:html_inline, highlight_lines: custom_highlight_lines})
# Returns HTML with line 2 highlighted with custom yellow background

Wrapping with custom HTML:

iex> header = %{
...>   open_tag: "<div class='code-block' data-lang='elixir'>",
...>   close_tag: "</div>"
...> }
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>"

See https://docs.rs/autumnus/latest/autumnus/fn.highlight.html for more info.

highlight(language, source, options)

This function is deprecated. Use highlight/2 instead.

highlight!(source, options \\ [])

@spec highlight!(
  String.t(),
  keyword()
) :: String.t()

Same as highlight/2 but raises in case of failure.

highlight!(language, source, options)

This function is deprecated. Use highlight!/2 instead.

options_schema()