Skip to main content

src/spruce@highlight.erl

-module(spruce@highlight).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/spruce/highlight.gleam").
-export([dark_theme/0, light_theme/0, adaptive_theme/0, language/1, highlight_with/4, highlight_named_with/4, highlight/3]).
-export_type([theme/0, language/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(" Syntax highlighting for source code using spruce styles.\n").

-opaque theme() :: {theme,
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style(),
        spruce@style:style()}.

-opaque language() :: {language, binary(), smalto@grammar:grammar()}.

-file("src/spruce/highlight.gleam", 76).
?DOC(" Build a syntax highlighting theme for dark terminal backgrounds.\n").
-spec dark_theme() -> theme().
dark_theme() ->
    {theme,
        begin
            _pipe = spruce@style:new(),
            _pipe@1 = spruce@style:bold(_pipe),
            spruce@style:fg(_pipe@1, {hex, 16#c4b5fd})
        end,
        begin
            _pipe@2 = spruce@style:new(),
            spruce@style:fg(_pipe@2, {hex, 16#86efac})
        end,
        begin
            _pipe@3 = spruce@style:new(),
            spruce@style:fg(_pipe@3, {hex, 16#fbbf24})
        end,
        begin
            _pipe@4 = spruce@style:new(),
            _pipe@5 = spruce@style:dim(_pipe@4),
            spruce@style:fg(_pipe@5, {hex, 16#94a3b8})
        end,
        begin
            _pipe@6 = spruce@style:new(),
            spruce@style:fg(_pipe@6, {hex, 16#7dd3fc})
        end,
        begin
            _pipe@7 = spruce@style:new(),
            spruce@style:fg(_pipe@7, {hex, 16#f0abfc})
        end,
        begin
            _pipe@8 = spruce@style:new(),
            spruce@style:fg(_pipe@8, {hex, 16#cbd5e1})
        end,
        begin
            _pipe@9 = spruce@style:new(),
            spruce@style:fg(_pipe@9, {hex, 16#67e8f9})
        end,
        begin
            _pipe@10 = spruce@style:new(),
            spruce@style:fg(_pipe@10, {hex, 16#93c5fd})
        end,
        begin
            _pipe@11 = spruce@style:new(),
            spruce@style:fg(_pipe@11, {hex, 16#e2e8f0})
        end,
        begin
            _pipe@12 = spruce@style:new(),
            spruce@style:fg(_pipe@12, {hex, 16#fca5a5})
        end,
        begin
            _pipe@13 = spruce@style:new(),
            spruce@style:fg(_pipe@13, {hex, 16#f9a8d4})
        end,
        begin
            _pipe@14 = spruce@style:new(),
            spruce@style:fg(_pipe@14, {hex, 16#60a5fa})
        end,
        begin
            _pipe@15 = spruce@style:new(),
            spruce@style:fg(_pipe@15, {hex, 16#fcd34d})
        end,
        begin
            _pipe@16 = spruce@style:new(),
            spruce@style:fg(_pipe@16, {hex, 16#a7f3d0})
        end,
        begin
            _pipe@17 = spruce@style:new(),
            spruce@style:fg(_pipe@17, {hex, 16#93c5fd})
        end,
        begin
            _pipe@18 = spruce@style:new(),
            spruce@style:fg(_pipe@18, {hex, 16#fda4af})
        end}.

-file("src/spruce/highlight.gleam", 99).
?DOC(" Build a syntax highlighting theme for light terminal backgrounds.\n").
-spec light_theme() -> theme().
light_theme() ->
    {theme,
        begin
            _pipe = spruce@style:new(),
            _pipe@1 = spruce@style:bold(_pipe),
            spruce@style:fg(_pipe@1, {hex, 16#6d28d9})
        end,
        begin
            _pipe@2 = spruce@style:new(),
            spruce@style:fg(_pipe@2, {hex, 16#15803d})
        end,
        begin
            _pipe@3 = spruce@style:new(),
            spruce@style:fg(_pipe@3, {hex, 16#92400e})
        end,
        begin
            _pipe@4 = spruce@style:new(),
            _pipe@5 = spruce@style:dim(_pipe@4),
            spruce@style:fg(_pipe@5, {hex, 16#64748b})
        end,
        begin
            _pipe@6 = spruce@style:new(),
            spruce@style:fg(_pipe@6, {hex, 16#0369a1})
        end,
        begin
            _pipe@7 = spruce@style:new(),
            spruce@style:fg(_pipe@7, {hex, 16#a21caf})
        end,
        begin
            _pipe@8 = spruce@style:new(),
            spruce@style:fg(_pipe@8, {hex, 16#475569})
        end,
        begin
            _pipe@9 = spruce@style:new(),
            spruce@style:fg(_pipe@9, {hex, 16#0e7490})
        end,
        begin
            _pipe@10 = spruce@style:new(),
            spruce@style:fg(_pipe@10, {hex, 16#1d4ed8})
        end,
        begin
            _pipe@11 = spruce@style:new(),
            spruce@style:fg(_pipe@11, {hex, 16#334155})
        end,
        begin
            _pipe@12 = spruce@style:new(),
            spruce@style:fg(_pipe@12, {hex, 16#be123c})
        end,
        begin
            _pipe@13 = spruce@style:new(),
            spruce@style:fg(_pipe@13, {hex, 16#be185d})
        end,
        begin
            _pipe@14 = spruce@style:new(),
            spruce@style:fg(_pipe@14, {hex, 16#2563eb})
        end,
        begin
            _pipe@15 = spruce@style:new(),
            spruce@style:fg(_pipe@15, {hex, 16#b45309})
        end,
        begin
            _pipe@16 = spruce@style:new(),
            spruce@style:fg(_pipe@16, {hex, 16#047857})
        end,
        begin
            _pipe@17 = spruce@style:new(),
            spruce@style:fg(_pipe@17, {hex, 16#1d4ed8})
        end,
        begin
            _pipe@18 = spruce@style:new(),
            spruce@style:fg(_pipe@18, {hex, 16#be123c})
        end}.

-file("src/spruce/highlight.gleam", 122).
?DOC(" Build the default syntax highlighting theme with adaptive light/dark colors.\n").
-spec adaptive_theme() -> theme().
adaptive_theme() ->
    Adapt = fun(Light, Dark) ->
        spruce@style:adaptive({hex, Light}, {hex, Dark})
    end,
    {theme,
        begin
            _pipe = spruce@style:new(),
            _pipe@1 = spruce@style:bold(_pipe),
            spruce@style:fg(_pipe@1, Adapt(16#6d28d9, 16#c4b5fd))
        end,
        begin
            _pipe@2 = spruce@style:new(),
            spruce@style:fg(_pipe@2, Adapt(16#15803d, 16#86efac))
        end,
        begin
            _pipe@3 = spruce@style:new(),
            spruce@style:fg(_pipe@3, Adapt(16#92400e, 16#fbbf24))
        end,
        begin
            _pipe@4 = spruce@style:new(),
            _pipe@5 = spruce@style:dim(_pipe@4),
            spruce@style:fg(_pipe@5, Adapt(16#64748b, 16#94a3b8))
        end,
        begin
            _pipe@6 = spruce@style:new(),
            spruce@style:fg(_pipe@6, Adapt(16#0369a1, 16#7dd3fc))
        end,
        begin
            _pipe@7 = spruce@style:new(),
            spruce@style:fg(_pipe@7, Adapt(16#a21caf, 16#f0abfc))
        end,
        begin
            _pipe@8 = spruce@style:new(),
            spruce@style:fg(_pipe@8, Adapt(16#475569, 16#cbd5e1))
        end,
        begin
            _pipe@9 = spruce@style:new(),
            spruce@style:fg(_pipe@9, Adapt(16#0e7490, 16#67e8f9))
        end,
        begin
            _pipe@10 = spruce@style:new(),
            spruce@style:fg(_pipe@10, Adapt(16#1d4ed8, 16#93c5fd))
        end,
        begin
            _pipe@11 = spruce@style:new(),
            spruce@style:fg(_pipe@11, Adapt(16#334155, 16#e2e8f0))
        end,
        begin
            _pipe@12 = spruce@style:new(),
            spruce@style:fg(_pipe@12, Adapt(16#be123c, 16#fca5a5))
        end,
        begin
            _pipe@13 = spruce@style:new(),
            spruce@style:fg(_pipe@13, Adapt(16#be185d, 16#f9a8d4))
        end,
        begin
            _pipe@14 = spruce@style:new(),
            spruce@style:fg(_pipe@14, Adapt(16#2563eb, 16#60a5fa))
        end,
        begin
            _pipe@15 = spruce@style:new(),
            spruce@style:fg(_pipe@15, Adapt(16#b45309, 16#fcd34d))
        end,
        begin
            _pipe@16 = spruce@style:new(),
            spruce@style:fg(_pipe@16, Adapt(16#047857, 16#a7f3d0))
        end,
        begin
            _pipe@17 = spruce@style:new(),
            spruce@style:fg(_pipe@17, Adapt(16#1d4ed8, 16#93c5fd))
        end,
        begin
            _pipe@18 = spruce@style:new(),
            spruce@style:fg(_pipe@18, Adapt(16#be123c, 16#fda4af))
        end}.

-file("src/spruce/highlight.gleam", 221).
-spec ok(binary(), smalto@grammar:grammar()) -> {ok, language()} | {error, nil}.
ok(Name, Grammar) ->
    {ok, {language, Name, Grammar}}.

-file("src/spruce/highlight.gleam", 148).
?DOC(" Resolve a language name or alias to a smalto-backed language.\n").
-spec language(binary()) -> {ok, language()} | {error, nil}.
language(Name) ->
    case string:lowercase(Name) of
        <<"bash"/utf8>> ->
            ok(<<"bash"/utf8>>, smalto@languages@bash:grammar());

        <<"sh"/utf8>> ->
            ok(<<"bash"/utf8>>, smalto@languages@bash:grammar());

        <<"shell"/utf8>> ->
            ok(<<"bash"/utf8>>, smalto@languages@bash:grammar());

        <<"zsh"/utf8>> ->
            ok(<<"bash"/utf8>>, smalto@languages@bash:grammar());

        <<"c"/utf8>> ->
            ok(<<"c"/utf8>>, smalto@languages@c:grammar());

        <<"cpp"/utf8>> ->
            ok(<<"cpp"/utf8>>, smalto@languages@cpp:grammar());

        <<"c++"/utf8>> ->
            ok(<<"cpp"/utf8>>, smalto@languages@cpp:grammar());

        <<"csharp"/utf8>> ->
            ok(<<"csharp"/utf8>>, smalto@languages@csharp:grammar());

        <<"c#"/utf8>> ->
            ok(<<"csharp"/utf8>>, smalto@languages@csharp:grammar());

        <<"cs"/utf8>> ->
            ok(<<"csharp"/utf8>>, smalto@languages@csharp:grammar());

        <<"css"/utf8>> ->
            ok(<<"css"/utf8>>, smalto@languages@css:grammar());

        <<"dart"/utf8>> ->
            ok(<<"dart"/utf8>>, smalto@languages@dart:grammar());

        <<"dockerfile"/utf8>> ->
            ok(<<"dockerfile"/utf8>>, smalto@languages@dockerfile:grammar());

        <<"docker"/utf8>> ->
            ok(<<"dockerfile"/utf8>>, smalto@languages@dockerfile:grammar());

        <<"elixir"/utf8>> ->
            ok(<<"elixir"/utf8>>, smalto@languages@elixir:grammar());

        <<"erlang"/utf8>> ->
            ok(<<"erlang"/utf8>>, smalto@languages@erlang:grammar());

        <<"fsharp"/utf8>> ->
            ok(<<"fsharp"/utf8>>, smalto@languages@fsharp:grammar());

        <<"gleam"/utf8>> ->
            ok(<<"gleam"/utf8>>, smalto@languages@gleam:grammar());

        <<"go"/utf8>> ->
            ok(<<"go"/utf8>>, smalto@languages@go:grammar());

        <<"golang"/utf8>> ->
            ok(<<"go"/utf8>>, smalto@languages@go:grammar());

        <<"haskell"/utf8>> ->
            ok(<<"haskell"/utf8>>, smalto@languages@haskell:grammar());

        <<"html"/utf8>> ->
            ok(<<"html"/utf8>>, smalto@languages@html:grammar());

        <<"java"/utf8>> ->
            ok(<<"java"/utf8>>, smalto@languages@java:grammar());

        <<"javascript"/utf8>> ->
            ok(<<"javascript"/utf8>>, smalto@languages@javascript:grammar());

        <<"js"/utf8>> ->
            ok(<<"javascript"/utf8>>, smalto@languages@javascript:grammar());

        <<"json"/utf8>> ->
            ok(<<"json"/utf8>>, smalto@languages@json:grammar());

        <<"kotlin"/utf8>> ->
            ok(<<"kotlin"/utf8>>, smalto@languages@kotlin:grammar());

        <<"kt"/utf8>> ->
            ok(<<"kotlin"/utf8>>, smalto@languages@kotlin:grammar());

        <<"lua"/utf8>> ->
            ok(<<"lua"/utf8>>, smalto@languages@lua:grammar());

        <<"markdown"/utf8>> ->
            ok(<<"markdown"/utf8>>, smalto@languages@markdown:grammar());

        <<"md"/utf8>> ->
            ok(<<"markdown"/utf8>>, smalto@languages@markdown:grammar());

        <<"nginx"/utf8>> ->
            ok(<<"nginx"/utf8>>, smalto@languages@nginx:grammar());

        <<"php"/utf8>> ->
            ok(<<"php"/utf8>>, smalto@languages@php:grammar());

        <<"python"/utf8>> ->
            ok(<<"python"/utf8>>, smalto@languages@python:grammar());

        <<"py"/utf8>> ->
            ok(<<"python"/utf8>>, smalto@languages@python:grammar());

        <<"razor"/utf8>> ->
            ok(<<"razor"/utf8>>, smalto@languages@razor:grammar());

        <<"reactjsx"/utf8>> ->
            ok(<<"reactjsx"/utf8>>, smalto@languages@reactjsx:grammar());

        <<"jsx"/utf8>> ->
            ok(<<"reactjsx"/utf8>>, smalto@languages@reactjsx:grammar());

        <<"reacttsx"/utf8>> ->
            ok(<<"reacttsx"/utf8>>, smalto@languages@reacttsx:grammar());

        <<"tsx"/utf8>> ->
            ok(<<"reacttsx"/utf8>>, smalto@languages@reacttsx:grammar());

        <<"ruby"/utf8>> ->
            ok(<<"ruby"/utf8>>, smalto@languages@ruby:grammar());

        <<"rb"/utf8>> ->
            ok(<<"ruby"/utf8>>, smalto@languages@ruby:grammar());

        <<"rust"/utf8>> ->
            ok(<<"rust"/utf8>>, smalto@languages@rust:grammar());

        <<"rs"/utf8>> ->
            ok(<<"rust"/utf8>>, smalto@languages@rust:grammar());

        <<"scala"/utf8>> ->
            ok(<<"scala"/utf8>>, smalto@languages@scala:grammar());

        <<"sql"/utf8>> ->
            ok(<<"sql"/utf8>>, smalto@languages@sql:grammar());

        <<"swift"/utf8>> ->
            ok(<<"swift"/utf8>>, smalto@languages@swift:grammar());

        <<"toml"/utf8>> ->
            ok(<<"toml"/utf8>>, smalto@languages@toml:grammar());

        <<"typescript"/utf8>> ->
            ok(<<"typescript"/utf8>>, smalto@languages@typescript:grammar());

        <<"ts"/utf8>> ->
            ok(<<"typescript"/utf8>>, smalto@languages@typescript:grammar());

        <<"xml"/utf8>> ->
            ok(<<"xml"/utf8>>, smalto@languages@xml:grammar());

        <<"yaml"/utf8>> ->
            ok(<<"yaml"/utf8>>, smalto@languages@yaml:grammar());

        <<"yml"/utf8>> ->
            ok(<<"yaml"/utf8>>, smalto@languages@yaml:grammar());

        <<"zig"/utf8>> ->
            ok(<<"zig"/utf8>>, smalto@languages@zig:grammar());

        _ ->
            {error, nil}
    end.

-file("src/spruce/highlight.gleam", 225).
-spec render_token(spruce:spruce(), smalto@token:token(), theme()) -> binary().
render_token(Sp, Token, Theme) ->
    case Token of
        {keyword, Value} ->
            spruce@style:render(Sp, erlang:element(2, Theme), Value);

        {string, Value@1} ->
            spruce@style:render(Sp, erlang:element(3, Theme), Value@1);

        {number, Value@2} ->
            spruce@style:render(Sp, erlang:element(4, Theme), Value@2);

        {comment, Value@3} ->
            spruce@style:render(Sp, erlang:element(5, Theme), Value@3);

        {function, Value@4} ->
            spruce@style:render(Sp, erlang:element(6, Theme), Value@4);

        {operator, Value@5} ->
            spruce@style:render(Sp, erlang:element(7, Theme), Value@5);

        {punctuation, Value@6} ->
            spruce@style:render(Sp, erlang:element(8, Theme), Value@6);

        {type, Value@7} ->
            spruce@style:render(Sp, erlang:element(9, Theme), Value@7);

        {module, Value@8} ->
            spruce@style:render(Sp, erlang:element(10, Theme), Value@8);

        {variable, Value@9} ->
            spruce@style:render(Sp, erlang:element(11, Theme), Value@9);

        {constant, Value@10} ->
            spruce@style:render(Sp, erlang:element(12, Theme), Value@10);

        {builtin, Value@11} ->
            spruce@style:render(Sp, erlang:element(13, Theme), Value@11);

        {tag, Value@12} ->
            spruce@style:render(Sp, erlang:element(14, Theme), Value@12);

        {attribute, Value@13} ->
            spruce@style:render(Sp, erlang:element(15, Theme), Value@13);

        {selector, Value@14} ->
            spruce@style:render(Sp, erlang:element(16, Theme), Value@14);

        {property, Value@15} ->
            spruce@style:render(Sp, erlang:element(17, Theme), Value@15);

        {regex, Value@16} ->
            spruce@style:render(Sp, erlang:element(18, Theme), Value@16);

        {whitespace, Value@17} ->
            Value@17;

        {other, Value@17} ->
            Value@17;

        {custom, _, Value@17} ->
            Value@17
    end.

-file("src/spruce/highlight.gleam", 210).
?DOC(" Highlight code with a resolved language and explicit theme.\n").
-spec highlight_with(spruce:spruce(), binary(), language(), theme()) -> binary().
highlight_with(Sp, Code, Language, Theme) ->
    _pipe = smalto:to_tokens(Code, erlang:element(3, Language)),
    _pipe@1 = gleam@list:map(
        _pipe,
        fun(_capture) -> render_token(Sp, _capture, Theme) end
    ),
    gleam@string:join(_pipe@1, <<""/utf8>>).

-file("src/spruce/highlight.gleam", 197).
?DOC(" Highlight code with a string language name and explicit theme.\n").
-spec highlight_named_with(spruce:spruce(), binary(), binary(), theme()) -> binary().
highlight_named_with(Sp, Code, Name, Theme) ->
    case language(Name) of
        {ok, Language} ->
            highlight_with(Sp, Code, Language, Theme);

        {error, nil} ->
            Code
    end.

-file("src/spruce/highlight.gleam", 192).
?DOC(
    " Highlight code with the default adaptive theme, or return code unchanged for\n"
    " unknown languages.\n"
).
-spec highlight(spruce:spruce(), binary(), binary()) -> binary().
highlight(Sp, Code, Name) ->
    highlight_named_with(Sp, Code, Name, adaptive_theme()).