Current section
Files
Jump to
Current section
Files
src/contour.erl
-module(contour).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([to_tokens/1, to_ansi/1, to_html/1]).
-export_type([token/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.
-type token() :: {whitespace, binary()} |
{keyword, binary()} |
{string, binary()} |
{number, binary()} |
{variant, binary()} |
{function, binary()} |
{module, binary()} |
{operator, binary()} |
{comment, binary()} |
{other, binary()}.
-file("src/contour.gleam", 228).
-spec loop_import(list(glexer@token:token()), binary()) -> {list(glexer@token:token()),
binary()}.
loop_import(In, Module) ->
case In of
[slash, {name, N} | In@1] ->
loop_import(In@1, <<<<Module/binary, "/"/utf8>>/binary, N/binary>>);
_ ->
{In, Module}
end.
-file("src/contour.gleam", 124).
-spec loop(list(glexer@token:token()), list(token())) -> list(token()).
loop(In0, Out) ->
case In0 of
[] ->
lists:reverse(Out);
[{space, S} | In] ->
loop(In, [{whitespace, S} | Out]);
[{name, M}, dot, {name, N}, left_paren | In@1] ->
loop(
In@1,
[{other, <<"("/utf8>>},
{function, N},
{other, <<"."/utf8>>},
{module, M} |
Out]
);
[{name, N@1}, left_paren | In@2] ->
loop(In@2, [{other, <<"("/utf8>>}, {function, N@1} | Out]);
[{comment_module, C} | In@3] ->
loop(In@3, [{comment, <<"////"/utf8, C/binary>>} | Out]);
[{comment_doc, C@1} | In@4] ->
loop(In@4, [{comment, <<"///"/utf8, C@1/binary>>} | Out]);
[{comment_normal, C@2} | In@5] ->
loop(In@5, [{comment, <<"//"/utf8, C@2/binary>>} | Out]);
[{int, I} | In@6] ->
loop(In@6, [{number, I} | Out]);
[{float, I@1} | In@7] ->
loop(In@7, [{number, I@1} | Out]);
[{string, S@1} | In@8] ->
loop(
In@8,
[{string, <<<<"\""/utf8, S@1/binary>>/binary, "\""/utf8>>} |
Out]
);
[import, {space, S@2}, {name, M@1} | In@9] ->
{In@10, M@2} = loop_import(In@9, M@1),
loop(
In@10,
[{module, M@2},
{whitespace, S@2},
{keyword, <<"import"/utf8>>} |
Out]
);
[import | In@11] ->
loop(In@11, [{keyword, <<"import"/utf8>>} | Out]);
[at, {name, N@2} | In@12] ->
loop(In@12, [{keyword, <<"@"/utf8, N@2/binary>>} | Out]);
[as | In@13] ->
loop(In@13, [{keyword, <<"as"/utf8>>} | Out]);
[assert | In@14] ->
loop(In@14, [{keyword, <<"assert"/utf8>>} | Out]);
[auto | In@15] ->
loop(In@15, [{keyword, <<"auto"/utf8>>} | Out]);
['case' | In@16] ->
loop(In@16, [{keyword, <<"case"/utf8>>} | Out]);
[const | In@17] ->
loop(In@17, [{keyword, <<"const"/utf8>>} | Out]);
[delegate | In@18] ->
loop(In@18, [{keyword, <<"delegate"/utf8>>} | Out]);
[derive | In@19] ->
loop(In@19, [{keyword, <<"derive"/utf8>>} | Out]);
[echo | In@20] ->
loop(In@20, [{keyword, <<"echo"/utf8>>} | Out]);
['else' | In@21] ->
loop(In@21, [{keyword, <<"else"/utf8>>} | Out]);
[fn | In@22] ->
loop(In@22, [{keyword, <<"fn"/utf8>>} | Out]);
['if' | In@23] ->
loop(In@23, [{keyword, <<"if"/utf8>>} | Out]);
[implement | In@24] ->
loop(In@24, [{keyword, <<"implement"/utf8>>} | Out]);
['let' | In@25] ->
loop(In@25, [{keyword, <<"let"/utf8>>} | Out]);
[macro | In@26] ->
loop(In@26, [{keyword, <<"macro"/utf8>>} | Out]);
[opaque | In@27] ->
loop(In@27, [{keyword, <<"opaque"/utf8>>} | Out]);
[panic | In@28] ->
loop(In@28, [{keyword, <<"panic"/utf8>>} | Out]);
[pub | In@29] ->
loop(In@29, [{keyword, <<"pub"/utf8>>} | Out]);
[test | In@30] ->
loop(In@30, [{keyword, <<"test"/utf8>>} | Out]);
[todo | In@31] ->
loop(In@31, [{keyword, <<"todo"/utf8>>} | Out]);
[type | In@32] ->
loop(In@32, [{keyword, <<"type"/utf8>>} | Out]);
[use | In@33] ->
loop(In@33, [{keyword, <<"use"/utf8>>} | Out]);
[amper_amper | In@34] ->
loop(In@34, [{operator, <<"&&"/utf8>>} | Out]);
[bang | In@35] ->
loop(In@35, [{operator, <<"!"/utf8>>} | Out]);
[equal_equal | In@36] ->
loop(In@36, [{operator, <<"=="/utf8>>} | Out]);
[greater | In@37] ->
loop(In@37, [{operator, <<">"/utf8>>} | Out]);
[greater_dot | In@38] ->
loop(In@38, [{operator, <<">."/utf8>>} | Out]);
[greater_equal | In@39] ->
loop(In@39, [{operator, <<">="/utf8>>} | Out]);
[greater_equal_dot | In@40] ->
loop(In@40, [{operator, <<">=."/utf8>>} | Out]);
[greater_greater | In@41] ->
loop(In@41, [{operator, <<">>"/utf8>>} | Out]);
[less | In@42] ->
loop(In@42, [{operator, <<"<"/utf8>>} | Out]);
[less_dot | In@43] ->
loop(In@43, [{operator, <<"<."/utf8>>} | Out]);
[less_equal | In@44] ->
loop(In@44, [{operator, <<"<="/utf8>>} | Out]);
[less_equal_dot | In@45] ->
loop(In@45, [{operator, <<"<=."/utf8>>} | Out]);
[less_greater | In@46] ->
loop(In@46, [{operator, <<"<>"/utf8>>} | Out]);
[minus | In@47] ->
loop(In@47, [{operator, <<"-"/utf8>>} | Out]);
[minus_dot | In@48] ->
loop(In@48, [{operator, <<"-."/utf8>>} | Out]);
[not_equal | In@49] ->
loop(In@49, [{operator, <<"!="/utf8>>} | Out]);
[percent | In@50] ->
loop(In@50, [{operator, <<"%"/utf8>>} | Out]);
[pipe | In@51] ->
loop(In@51, [{operator, <<"|>"/utf8>>} | Out]);
[plus | In@52] ->
loop(In@52, [{operator, <<"+"/utf8>>} | Out]);
[plus_dot | In@53] ->
loop(In@53, [{operator, <<"+."/utf8>>} | Out]);
[slash | In@54] ->
loop(In@54, [{operator, <<"/"/utf8>>} | Out]);
[slash_dot | In@55] ->
loop(In@55, [{operator, <<"/."/utf8>>} | Out]);
[star | In@56] ->
loop(In@56, [{operator, <<"*"/utf8>>} | Out]);
[star_dot | In@57] ->
loop(In@57, [{operator, <<"*."/utf8>>} | Out]);
[v_bar_v_bar | In@58] ->
loop(In@58, [{operator, <<"||"/utf8>>} | Out]);
[at | In@59] ->
loop(In@59, [{other, <<"@"/utf8>>} | Out]);
[colon | In@60] ->
loop(In@60, [{other, <<":"/utf8>>} | Out]);
[comma | In@61] ->
loop(In@61, [{other, <<","/utf8>>} | Out]);
[dot | In@62] ->
loop(In@62, [{other, <<"."/utf8>>} | Out]);
[dot_dot | In@63] ->
loop(In@63, [{other, <<".."/utf8>>} | Out]);
[equal | In@64] ->
loop(In@64, [{other, <<"="/utf8>>} | Out]);
[hash | In@65] ->
loop(In@65, [{other, <<"#"/utf8>>} | Out]);
[left_arrow | In@66] ->
loop(In@66, [{other, <<"<-"/utf8>>} | Out]);
[left_brace | In@67] ->
loop(In@67, [{other, <<"{"/utf8>>} | Out]);
[left_paren | In@68] ->
loop(In@68, [{other, <<"("/utf8>>} | Out]);
[left_square | In@69] ->
loop(In@69, [{other, <<"["/utf8>>} | Out]);
[less_less | In@70] ->
loop(In@70, [{other, <<"<<"/utf8>>} | Out]);
[right_arrow | In@71] ->
loop(In@71, [{other, <<"->"/utf8>>} | Out]);
[right_brace | In@72] ->
loop(In@72, [{other, <<"}"/utf8>>} | Out]);
[right_paren | In@73] ->
loop(In@73, [{other, <<")"/utf8>>} | Out]);
[right_square | In@74] ->
loop(In@74, [{other, <<"]"/utf8>>} | Out]);
[v_bar | In@75] ->
loop(In@75, [{other, <<"|"/utf8>>} | Out]);
[{name, N@3} | In@76] ->
loop(In@76, [{other, N@3} | Out]);
[{discard_name, Name} | In@77] ->
loop(In@77, [{other, <<"_"/utf8, Name/binary>>} | Out]);
[{upper_name, N@4} | In@78] ->
loop(In@78, [{variant, N@4} | Out]);
[{unexpected_grapheme, S@3} | In@79] ->
loop(In@79, [{other, S@3} | Out]);
[{unterminated_string, S@4} | In@80] ->
loop(In@80, [{other, S@4} | Out]);
[end_of_file | In@81] ->
loop(In@81, Out)
end.
-file("src/contour.gleam", 27).
?DOC(
" Convert Gleam source code to a list of tokens, which you can then convert\n"
" into whatever format you want.\n"
"\n"
" If you wish to print to the terminal using ansi colours see `to_ansi`.\n"
).
-spec to_tokens(binary()) -> list(token()).
to_tokens(Code) ->
_pipe = glexer:new(Code),
_pipe@1 = glexer:lex(_pipe),
_pipe@2 = gleam@list:map(_pipe@1, fun gleam@pair:first/1),
loop(_pipe@2, []).
-file("src/contour.gleam", 47).
?DOC(
" Highlight source code using ansi colours!\n"
"\n"
" | Token | Colour |\n"
" | ----------------- | ----------- |\n"
" | Keyword | Yellow |\n"
" | Module | Cyan |\n"
" | Variant | Cyan |\n"
" | Function | Blue |\n"
" | Operator | Magenta |\n"
" | Comment | Italic grey |\n"
" | String, Number | Green |\n"
" | Whitespace, other | No colour |\n"
"\n"
" If you wish to use some other colours or other format entirely see\n"
" `to_tokens`.\n"
).
-spec to_ansi(binary()) -> binary().
to_ansi(Code) ->
_pipe = to_tokens(Code),
_pipe@1 = gleam@list:map(_pipe, fun(Token) -> case Token of
{whitespace, S} ->
gleam_community@ansi:reset(S);
{keyword, S@1} ->
gleam_community@ansi:yellow(S@1);
{string, S@2} ->
gleam_community@ansi:green(S@2);
{number, S@3} ->
gleam_community@ansi:green(S@3);
{module, S@4} ->
gleam_community@ansi:cyan(S@4);
{variant, S@5} ->
gleam_community@ansi:cyan(S@5);
{function, S@6} ->
gleam_community@ansi:blue(S@6);
{operator, S@7} ->
gleam_community@ansi:magenta(S@7);
{comment, S@8} ->
gleam_community@ansi:italic(gleam_community@ansi:gray(S@8));
{other, S@9} ->
gleam_community@ansi:reset(S@9)
end end),
gleam@string:concat(_pipe@1).
-file("src/contour.gleam", 98).
?DOC(
" Convert Gleam code into a HTML string! Each token is wrapped in a `<span>`\n"
" with a class indicating the type of token.\n"
"\n"
" | Token | CSS class |\n"
" | ----------------- | ----------- |\n"
" | Keyword | hl-keyword |\n"
" | Module | hl-module |\n"
" | Variant | hl-variant |\n"
" | Function | hl-function |\n"
" | Operator | hl-operator |\n"
" | Comment | hl-comment |\n"
" | Number | hl-number |\n"
" | String | hl-string |\n"
" | Whitespace, other | |\n"
"\n"
" Place the output within a `<pre><code>...</code></pre>` and add styling for\n"
" these CSS classes to get highlightin on your website. Here's some CSS you\n"
" could use:\n"
"\n"
" ```css\n"
" pre code .hl-comment { color: #d4d4d4; font-style: italic }\n"
" pre code .hl-function { color: #9ce7ff }\n"
" pre code .hl-keyword { color: #ffd596 }\n"
" pre code .hl-module { color: #ffddfa }\n"
" pre code .hl-number { color: #c8ffa7 }\n"
" pre code .hl-operator { color: #ffaff3 }\n"
" pre code .hl-string { color: #c8ffa7 }\n"
" pre code .hl-variant { color: #ffddfa }\n"
" ```\n"
"\n"
" If you wish to use some other format see `to_tokens`.\n"
).
-spec to_html(binary()) -> binary().
to_html(Code) ->
_pipe = to_tokens(Code),
gleam@list:fold(_pipe, <<""/utf8>>, fun(Acc, Token) -> case Token of
{whitespace, S} ->
<<Acc/binary, S/binary>>;
{keyword, S@1} ->
<<<<<<Acc/binary, "<span class=hl-keyword>"/utf8>>/binary,
(houdini:escape(S@1))/binary>>/binary,
"</span>"/utf8>>;
{string, S@2} ->
<<<<<<Acc/binary, "<span class=hl-string>"/utf8>>/binary,
(houdini:escape(S@2))/binary>>/binary,
"</span>"/utf8>>;
{number, S@3} ->
<<<<<<Acc/binary, "<span class=hl-number>"/utf8>>/binary,
(houdini:escape(S@3))/binary>>/binary,
"</span>"/utf8>>;
{module, S@4} ->
<<<<<<Acc/binary, "<span class=hl-module>"/utf8>>/binary,
(houdini:escape(S@4))/binary>>/binary,
"</span>"/utf8>>;
{variant, S@5} ->
<<<<<<Acc/binary, "<span class=hl-variant>"/utf8>>/binary,
(houdini:escape(S@5))/binary>>/binary,
"</span>"/utf8>>;
{function, S@6} ->
<<<<<<Acc/binary, "<span class=hl-function>"/utf8>>/binary,
(houdini:escape(S@6))/binary>>/binary,
"</span>"/utf8>>;
{operator, S@7} ->
<<<<<<Acc/binary, "<span class=hl-operator>"/utf8>>/binary,
(houdini:escape(S@7))/binary>>/binary,
"</span>"/utf8>>;
{comment, S@8} ->
<<<<<<Acc/binary, "<span class=hl-comment>"/utf8>>/binary,
(houdini:escape(S@8))/binary>>/binary,
"</span>"/utf8>>;
{other, S@9} ->
<<Acc/binary, (houdini:escape(S@9))/binary>>
end end).