defmodule Autumn do
@external_resource "README.md"
@moduledoc "README.md"
|> File.read!()
|> String.split("<!-- MDOC -->")
|> Enum.fetch!(1)
alias Autumn.Native
@typedoc """
A language name, filename, or extesion.
## Examples
- "elixir"
- "main.rb"
- ".rs"
- "php"
An invalid language or `nil` will fallback to rendering plain text
using the background and foreground colors defined by the current theme.
"""
@type lang_filename_ext :: String.t() | nil
@doc """
Highlights the `source_code` using the tree-sitter grammar for `lang_filename_ext`.
## Options
* `:theme` (default `"onedark"`) - accepts any theme listed [here](https://github.com/leandrocp/autumn/tree/main/priv/themes),
you should pass the filename without special chars and without extension.
For example you should pass `theme: "adwaita_dark"` to use the [Adwaita Dark](https://github.com/leandrocp/autumn/blob/main/priv/themes/adwaita-dark.toml) theme
or pass `theme: "penumbra"` to use the [Penumbra+](https://github.com/leandrocp/autumn/blob/main/priv/themes/penumbra%2B.toml) theme, and so on.
* `:pre_class` (default: `"autumn highlight"`) - the CSS class to inject into the `<pre>` tag.
* `:code_class` (deafult: `nil`) - the CSS class to inject into the `<code>` tag, it's dynamically generated as `"language-{name}` when the value is `nil`.
"""
@spec highlight(lang_filename_ext(), String.t(), keyword()) ::
{:ok, String.t()} | {:error, term()}
def highlight(lang_filename_ext, source_code, opts \\ []) do
lang = language(lang_filename_ext)
theme = Keyword.get(opts, :theme, "onedark")
pre_class = Keyword.get(opts, :pre_class, "autumn highlight")
code_class = Keyword.get(opts, :code_class, nil)
Native.highlight(lang, source_code, theme, pre_class, code_class)
end
@doc """
Same as `highlight/3` but raises in case of failure.
"""
@spec highlight!(lang_filename_ext(), String.t(), keyword()) :: String.t()
def highlight!(lang_filename_ext, source_code, opts \\ []) do
case highlight(lang_filename_ext, source_code, opts) do
{:ok, highlighted} ->
highlighted
{:error, error} ->
raise """
failed to highlight source code for #{lang_filename_ext}
Got:
#{inspect(error)}
"""
end
end
@doc false
def language(nil = _lang_filename_ext), do: "plain"
def language(lang_filename_ext) do
lang_filename_ext
|> String.downcase()
|> Path.basename()
|> do_language
end
defp do_language(<<"."::binary, ext::binary>>), do: ext
defp do_language(lang) when is_binary(lang) do
case lang |> Path.basename() |> Path.extname() do
"" -> lang
ext -> do_language(ext)
end
end
end