-module(contour). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/contour.gleam"). -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", 249). -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, <<<>/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] ); [pipe, {space, S@1}, {name, M@1}, dot, {name, N@1}, left_paren | In@2] -> loop( In@2, [{other, <<"("/utf8>>}, {function, N@1}, {other, <<"."/utf8>>}, {module, M@1}, {whitespace, S@1}, {operator, <<"|>"/utf8>>} | Out] ); [pipe, {space, S@2}, {name, M@2}, dot, {name, N@2} | In@3] -> loop( In@3, [{function, N@2}, {other, <<"."/utf8>>}, {module, M@2}, {whitespace, S@2}, {operator, <<"|>"/utf8>>} | Out] ); [{name, N@3}, left_paren | In@4] -> loop(In@4, [{other, <<"("/utf8>>}, {function, N@3} | Out]); [{comment_module, C} | In@5] -> loop(In@5, [{comment, <<"////"/utf8, C/binary>>} | Out]); [{comment_doc, C@1} | In@6] -> loop(In@6, [{comment, <<"///"/utf8, C@1/binary>>} | Out]); [{comment_normal, C@2} | In@7] -> loop(In@7, [{comment, <<"//"/utf8, C@2/binary>>} | Out]); [{int, I} | In@8] -> loop(In@8, [{number, I} | Out]); [{float, I@1} | In@9] -> loop(In@9, [{number, I@1} | Out]); [{string, S@3} | In@10] -> loop( In@10, [{string, <<<<"\""/utf8, S@3/binary>>/binary, "\""/utf8>>} | Out] ); [import, {space, S@4}, {name, M@3} | In@11] -> {In@12, M@4} = loop_import(In@11, M@3), loop( In@12, [{module, M@4}, {whitespace, S@4}, {keyword, <<"import"/utf8>>} | Out] ); [import | In@13] -> loop(In@13, [{keyword, <<"import"/utf8>>} | Out]); [at, {name, N@4} | In@14] -> loop(In@14, [{keyword, <<"@"/utf8, N@4/binary>>} | Out]); [as | In@15] -> loop(In@15, [{keyword, <<"as"/utf8>>} | Out]); [assert | In@16] -> loop(In@16, [{keyword, <<"assert"/utf8>>} | Out]); [auto | In@17] -> loop(In@17, [{keyword, <<"auto"/utf8>>} | Out]); ['case' | In@18] -> loop(In@18, [{keyword, <<"case"/utf8>>} | Out]); [const | In@19] -> loop(In@19, [{keyword, <<"const"/utf8>>} | Out]); [delegate | In@20] -> loop(In@20, [{keyword, <<"delegate"/utf8>>} | Out]); [derive | In@21] -> loop(In@21, [{keyword, <<"derive"/utf8>>} | Out]); [echo | In@22] -> loop(In@22, [{keyword, <<"echo"/utf8>>} | Out]); ['else' | In@23] -> loop(In@23, [{keyword, <<"else"/utf8>>} | Out]); [fn | In@24] -> loop(In@24, [{keyword, <<"fn"/utf8>>} | Out]); ['if' | In@25] -> loop(In@25, [{keyword, <<"if"/utf8>>} | Out]); [implement | In@26] -> loop(In@26, [{keyword, <<"implement"/utf8>>} | Out]); ['let' | In@27] -> loop(In@27, [{keyword, <<"let"/utf8>>} | Out]); [macro | In@28] -> loop(In@28, [{keyword, <<"macro"/utf8>>} | Out]); [opaque | In@29] -> loop(In@29, [{keyword, <<"opaque"/utf8>>} | Out]); [panic | In@30] -> loop(In@30, [{keyword, <<"panic"/utf8>>} | Out]); [pub | In@31] -> loop(In@31, [{keyword, <<"pub"/utf8>>} | Out]); [test | In@32] -> loop(In@32, [{keyword, <<"test"/utf8>>} | Out]); [todo | In@33] -> loop(In@33, [{keyword, <<"todo"/utf8>>} | Out]); [type | In@34] -> loop(In@34, [{keyword, <<"type"/utf8>>} | Out]); [use | In@35] -> loop(In@35, [{keyword, <<"use"/utf8>>} | Out]); [amper_amper | In@36] -> loop(In@36, [{operator, <<"&&"/utf8>>} | Out]); [bang | In@37] -> loop(In@37, [{operator, <<"!"/utf8>>} | Out]); [equal_equal | In@38] -> loop(In@38, [{operator, <<"=="/utf8>>} | Out]); [greater | In@39] -> loop(In@39, [{operator, <<">"/utf8>>} | Out]); [greater_dot | In@40] -> loop(In@40, [{operator, <<">."/utf8>>} | Out]); [greater_equal | In@41] -> loop(In@41, [{operator, <<">="/utf8>>} | Out]); [greater_equal_dot | In@42] -> loop(In@42, [{operator, <<">=."/utf8>>} | Out]); [greater_greater | In@43] -> loop(In@43, [{operator, <<">>"/utf8>>} | Out]); [less | In@44] -> loop(In@44, [{operator, <<"<"/utf8>>} | Out]); [less_dot | In@45] -> loop(In@45, [{operator, <<"<."/utf8>>} | Out]); [less_equal | In@46] -> loop(In@46, [{operator, <<"<="/utf8>>} | Out]); [less_equal_dot | In@47] -> loop(In@47, [{operator, <<"<=."/utf8>>} | Out]); [less_greater | In@48] -> loop(In@48, [{operator, <<"<>"/utf8>>} | Out]); [minus | In@49] -> loop(In@49, [{operator, <<"-"/utf8>>} | Out]); [minus_dot | In@50] -> loop(In@50, [{operator, <<"-."/utf8>>} | Out]); [not_equal | In@51] -> loop(In@51, [{operator, <<"!="/utf8>>} | Out]); [percent | In@52] -> loop(In@52, [{operator, <<"%"/utf8>>} | Out]); [pipe | In@53] -> loop(In@53, [{operator, <<"|>"/utf8>>} | Out]); [plus | In@54] -> loop(In@54, [{operator, <<"+"/utf8>>} | Out]); [plus_dot | In@55] -> loop(In@55, [{operator, <<"+."/utf8>>} | Out]); [slash | In@56] -> loop(In@56, [{operator, <<"/"/utf8>>} | Out]); [slash_dot | In@57] -> loop(In@57, [{operator, <<"/."/utf8>>} | Out]); [star | In@58] -> loop(In@58, [{operator, <<"*"/utf8>>} | Out]); [star_dot | In@59] -> loop(In@59, [{operator, <<"*."/utf8>>} | Out]); [v_bar_v_bar | In@60] -> loop(In@60, [{operator, <<"||"/utf8>>} | Out]); [at | In@61] -> loop(In@61, [{other, <<"@"/utf8>>} | Out]); [colon | In@62] -> loop(In@62, [{other, <<":"/utf8>>} | Out]); [comma | In@63] -> loop(In@63, [{other, <<","/utf8>>} | Out]); [dot | In@64] -> loop(In@64, [{other, <<"."/utf8>>} | Out]); [dot_dot | In@65] -> loop(In@65, [{other, <<".."/utf8>>} | Out]); [equal | In@66] -> loop(In@66, [{other, <<"="/utf8>>} | Out]); [hash | In@67] -> loop(In@67, [{other, <<"#"/utf8>>} | Out]); [left_arrow | In@68] -> loop(In@68, [{other, <<"<-"/utf8>>} | Out]); [left_brace | In@69] -> loop(In@69, [{other, <<"{"/utf8>>} | Out]); [left_paren | In@70] -> loop(In@70, [{other, <<"("/utf8>>} | Out]); [left_square | In@71] -> loop(In@71, [{other, <<"["/utf8>>} | Out]); [less_less | In@72] -> loop(In@72, [{other, <<"<<"/utf8>>} | Out]); [right_arrow | In@73] -> loop(In@73, [{other, <<"->"/utf8>>} | Out]); [right_brace | In@74] -> loop(In@74, [{other, <<"}"/utf8>>} | Out]); [right_paren | In@75] -> loop(In@75, [{other, <<")"/utf8>>} | Out]); [right_square | In@76] -> loop(In@76, [{other, <<"]"/utf8>>} | Out]); [v_bar | In@77] -> loop(In@77, [{other, <<"|"/utf8>>} | Out]); [{name, N@5} | In@78] -> loop(In@78, [{other, N@5} | Out]); [{discard_name, Name} | In@79] -> loop(In@79, [{other, <<"_"/utf8, Name/binary>>} | Out]); [{upper_name, N@6} | In@80] -> loop(In@80, [{variant, N@6} | Out]); [{unexpected_grapheme, S@5} | In@81] -> loop(In@81, [{other, S@5} | Out]); [{unterminated_string, S@6} | In@82] -> loop(In@82, [{other, S@6} | Out]); [end_of_file | In@83] -> loop(In@83, 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 ``\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 `
...
` 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} -> <>; {keyword, S@1} -> <<<<<"/utf8>>/binary, (houdini:escape(S@1))/binary>>/binary, "
"/utf8>>; {string, S@2} -> <<<<<"/utf8>>/binary, (houdini:escape(S@2))/binary>>/binary, ""/utf8>>; {number, S@3} -> <<<<<"/utf8>>/binary, (houdini:escape(S@3))/binary>>/binary, ""/utf8>>; {module, S@4} -> <<<<<"/utf8>>/binary, (houdini:escape(S@4))/binary>>/binary, ""/utf8>>; {variant, S@5} -> <<<<<"/utf8>>/binary, (houdini:escape(S@5))/binary>>/binary, ""/utf8>>; {function, S@6} -> <<<<<"/utf8>>/binary, (houdini:escape(S@6))/binary>>/binary, ""/utf8>>; {operator, S@7} -> <<<<<"/utf8>>/binary, (houdini:escape(S@7))/binary>>/binary, ""/utf8>>; {comment, S@8} -> <<<<<"/utf8>>/binary, (houdini:escape(S@8))/binary>>/binary, ""/utf8>>; {other, S@9} -> <> end end).