-module(swatch).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/swatch.gleam").
-export([to_tokens/1, token_to_source/1, to_source/1, tokens_to_html/1, to_html/1, tokens_to_ansi/1, to_ansi/1]).
-export_type([token/0, attribute_head/0, mode/0, parenthesis/0, state/0, at_rule_context/0, attribute_position/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(
" Swatch is a CSS syntax highlighter.\n"
"\n"
" Use [`to_tokens`](#to_tokens) for classified tokens, or\n"
" [`to_html`](#to_html) / [`to_ansi`](#to_ansi) to render directly.\n"
"\n"
" Based on CSS Syntax Level 3.\n"
).
-type token() :: {whitespace, binary()} |
{comment, binary()} |
{selector, binary()} |
{class_selector, binary()} |
{id_selector, binary()} |
{pseudo_selector, binary()} |
{attribute_name, binary()} |
{attribute_value, binary()} |
{attribute_flag, binary()} |
{at_rule, binary()} |
{property, binary()} |
{variable, binary()} |
{string, binary()} |
{number, binary()} |
{unit, binary()} |
{hex_color, binary()} |
{function, binary()} |
{keyword, binary()} |
{important, binary()} |
{operator, binary()} |
{punctuation, binary()} |
{other, binary()}.
-type attribute_head() :: {head_emit,
list(token()),
list({swatch@internal@lexer:lex_token(), boolean()}),
attribute_position()} |
{head_close, list({swatch@internal@lexer:lex_token(), boolean()})} |
head_other.
-type mode() :: selector_mode | property_mode | value_mode | at_rule_mode.
-type parenthesis() :: grouping | {function_call, mode()}.
-type state() :: {state, mode(), list(mode()), list(parenthesis()), binary()}.
-type at_rule_context() :: {at_rule_context, mode(), list({binary(), mode()})}.
-type attribute_position() :: before_matcher |
after_matcher |
after_value |
after_flag.
-file("src/swatch.gleam", 760).
-spec initial_state() -> state().
initial_state() ->
{state, selector_mode, [], [], <<""/utf8>>}.
-file("src/swatch.gleam", 577).
-spec important_match_loop(
list({swatch@internal@lexer:lex_token(), boolean()}),
binary()
) -> {ok, {binary(), list({swatch@internal@lexer:lex_token(), boolean()})}} |
{error, nil}.
important_match_loop(Tokens, Acc) ->
case Tokens of
[{{lex_whitespace, S}, _} | Rest] ->
important_match_loop(Rest, <<Acc/binary, S/binary>>);
[{{lex_comment, S@1}, _} | Rest@1] ->
important_match_loop(Rest@1, <<Acc/binary, S@1/binary>>);
[{{lex_ident, Name}, _} | Rest@2] ->
case string:lowercase(Name) =:= <<"important"/utf8>> of
true ->
{ok, {<<Acc/binary, Name/binary>>, Rest@2}};
false ->
{error, nil}
end;
_ ->
{error, nil}
end.
-file("src/swatch.gleam", 571).
-spec important_match(list({swatch@internal@lexer:lex_token(), boolean()})) -> {ok,
{binary(), list({swatch@internal@lexer:lex_token(), boolean()})}} |
{error, nil}.
important_match(Tokens) ->
important_match_loop(Tokens, <<"!"/utf8>>).
-file("src/swatch.gleam", 480).
-spec leading_name(list({swatch@internal@lexer:lex_token(), boolean()})) -> {ok,
{binary(), list({swatch@internal@lexer:lex_token(), boolean()})}} |
{error, nil}.
leading_name(Tokens) ->
case Tokens of
[{{lex_ident, Name}, _} | Rest] ->
{ok, {Name, Rest}};
[{{lex_function, Name@1}, _} | Rest@1] ->
{ok, {Name@1, Rest@1}};
_ ->
{error, nil}
end.
-file("src/swatch.gleam", 231).
-spec head_flag(list({swatch@internal@lexer:lex_token(), boolean()})) -> boolean().
head_flag(Tokens) ->
case Tokens of
[{_, Flag} | _] ->
Flag;
[] ->
false
end.
-file("src/swatch.gleam", 442).
-spec promote_if_nested(state(), boolean()) -> state().
promote_if_nested(State, Nested) ->
case Nested of
true ->
{state,
selector_mode,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State)};
false ->
State
end.
-file("src/swatch.gleam", 490).
-spec classify_delim(
binary(),
list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())
) -> {list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())}.
classify_delim(S, Rest, State, Out) ->
case S of
<<"&"/utf8>> ->
State2 = case erlang:element(2, State) of
property_mode ->
{state,
selector_mode,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State)};
value_mode ->
{state,
selector_mode,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State)};
_ ->
State
end,
{Rest, State2, [{selector, <<"&"/utf8>>} | Out]};
<<"*"/utf8>> ->
State@1 = case erlang:element(2, State) of
property_mode ->
promote_if_nested(State, head_flag(Rest));
_ ->
State
end,
case erlang:element(2, State@1) of
selector_mode ->
{Rest, State@1, [{selector, <<"*"/utf8>>} | Out]};
_ ->
{Rest, State@1, [{operator, <<"*"/utf8>>} | Out]}
end;
<<"."/utf8>> ->
State@2 = case erlang:element(2, State) of
property_mode ->
promote_if_nested(State, head_flag(Rest));
_ ->
State
end,
case erlang:element(2, State@2) of
selector_mode ->
case leading_name(Rest) of
{ok, {Name, Rest2}} ->
{Rest2,
State@2,
[{class_selector, <<"."/utf8, Name/binary>>} |
Out]};
{error, _} ->
{Rest, State@2, [{punctuation, <<"."/utf8>>} | Out]}
end;
_ ->
{Rest, State@2, [{punctuation, <<"."/utf8>>} | Out]}
end;
<<"<"/utf8>> ->
case Rest of
[{{lex_delim, <<"="/utf8>>}, _} | Rest2@1] ->
{Rest2@1, State, [{operator, <<"<="/utf8>>} | Out]};
_ ->
{Rest, State, [{operator, <<"<"/utf8>>} | Out]}
end;
<<">"/utf8>> ->
case Rest of
[{{lex_delim, <<"="/utf8>>}, _} | Rest2@2] ->
{Rest2@2, State, [{operator, <<">="/utf8>>} | Out]};
_ ->
{Rest, State, [{operator, <<">"/utf8>>} | Out]}
end;
<<"|"/utf8>> ->
case Rest of
[{{lex_delim, <<"|"/utf8>>}, _} | Rest2@3] ->
{Rest2@3, State, [{operator, <<"||"/utf8>>} | Out]};
_ ->
{Rest, State, [{operator, <<"|"/utf8>>} | Out]}
end;
<<"!"/utf8>> ->
case important_match(Rest) of
{ok, {Text, Rest2@4}} ->
{Rest2@4, State, [{important, Text} | Out]};
{error, _} ->
{Rest, State, [{operator, <<"!"/utf8>>} | Out]}
end;
<<"/"/utf8>> ->
{Rest, State, [{operator, S} | Out]};
<<"~"/utf8>> ->
{Rest, State, [{operator, S} | Out]};
<<"="/utf8>> ->
{Rest, State, [{operator, S} | Out]};
<<"+"/utf8>> ->
{Rest, State, [{operator, S} | Out]};
<<"-"/utf8>> ->
{Rest, State, [{operator, S} | Out]};
_ ->
{Rest, State, [{other, S} | Out]}
end.
-file("src/swatch.gleam", 677).
-spec attribute_delim_head(
binary(),
list({swatch@internal@lexer:lex_token(), boolean()}),
attribute_position()
) -> attribute_head().
attribute_delim_head(D, Rest, Position) ->
case D of
<<"="/utf8>> ->
{head_emit, [{operator, <<"="/utf8>>}], Rest, after_matcher};
<<"~"/utf8>> ->
case Rest of
[{{lex_delim, <<"="/utf8>>}, _} | Rest2] ->
{head_emit,
[{operator, <<D/binary, "="/utf8>>}],
Rest2,
after_matcher};
_ ->
head_other
end;
<<"^"/utf8>> ->
case Rest of
[{{lex_delim, <<"="/utf8>>}, _} | Rest2] ->
{head_emit,
[{operator, <<D/binary, "="/utf8>>}],
Rest2,
after_matcher};
_ ->
head_other
end;
<<"$"/utf8>> ->
case Rest of
[{{lex_delim, <<"="/utf8>>}, _} | Rest2] ->
{head_emit,
[{operator, <<D/binary, "="/utf8>>}],
Rest2,
after_matcher};
_ ->
head_other
end;
<<"|"/utf8>> ->
case Rest of
[{{lex_delim, <<"="/utf8>>}, _} | Rest2@1] ->
{head_emit,
[{operator, <<"|="/utf8>>}],
Rest2@1,
after_matcher};
_ ->
{head_emit, [{operator, <<"|"/utf8>>}], Rest, Position}
end;
<<"*"/utf8>> ->
case Rest of
[{{lex_delim, <<"="/utf8>>}, _} | Rest2@2] ->
{head_emit,
[{operator, <<"*="/utf8>>}],
Rest2@2,
after_matcher};
[{{lex_delim, <<"|"/utf8>>}, _} | Rest2@3] ->
case Position of
before_matcher ->
{head_emit,
[{selector, <<"*"/utf8>>},
{operator, <<"|"/utf8>>}],
Rest2@3,
Position};
_ ->
head_other
end;
_ ->
head_other
end;
_ ->
head_other
end.
-file("src/swatch.gleam", 839).
-spec emit_attribute_identifier(binary(), attribute_position()) -> {token(),
attribute_position()}.
emit_attribute_identifier(Name, Position) ->
case Position of
before_matcher ->
{{attribute_name, Name}, before_matcher};
after_matcher ->
{{attribute_value, Name}, after_value};
after_value ->
{{attribute_flag, Name}, after_flag};
after_flag ->
{{other, Name}, after_flag}
end.
-file("src/swatch.gleam", 853).
-spec advance_past_attribute_value(attribute_position()) -> attribute_position().
advance_past_attribute_value(Position) ->
case Position of
after_matcher ->
after_value;
_ ->
Position
end.
-file("src/swatch.gleam", 649).
-spec attribute_head(
swatch@internal@lexer:lex_token(),
list({swatch@internal@lexer:lex_token(), boolean()}),
attribute_position()
) -> attribute_head().
attribute_head(Token, Rest, Position) ->
case Token of
lex_close_bracket ->
{head_close, Rest};
{lex_whitespace, S} ->
{head_emit, [{whitespace, S}], Rest, Position};
{lex_comment, S@1} ->
{head_emit, [{comment, S@1}], Rest, Position};
{lex_string, S@2} ->
{head_emit,
[{string, S@2}],
Rest,
advance_past_attribute_value(Position)};
{lex_ident, Name} ->
{Emitted, Position2} = emit_attribute_identifier(Name, Position),
{head_emit, [Emitted], Rest, Position2};
{lex_function, Name@1} ->
{Emitted@1, Position2@1} = emit_attribute_identifier(
Name@1,
Position
),
{head_emit, [Emitted@1], Rest, Position2@1};
{lex_delim, D} ->
attribute_delim_head(D, Rest, Position);
_ ->
head_other
end.
-file("src/swatch.gleam", 714).
-spec take_attribute_other_token_run(
list({swatch@internal@lexer:lex_token(), boolean()}),
attribute_position(),
binary()
) -> {binary(), list({swatch@internal@lexer:lex_token(), boolean()})}.
take_attribute_other_token_run(Tokens, Position, Acc) ->
case Tokens of
[] ->
{Acc, []};
[{Token, _} | Rest] ->
case attribute_head(Token, Rest, Position) of
head_other ->
take_attribute_other_token_run(
Rest,
Position,
<<Acc/binary,
(swatch@internal@lexer:lex_token_to_source(Token))/binary>>
);
_ ->
{Acc, Tokens}
end
end.
-file("src/swatch.gleam", 609).
-spec classify_attribute_body_loop(
list({swatch@internal@lexer:lex_token(), boolean()}),
attribute_position(),
list(token())
) -> {list({swatch@internal@lexer:lex_token(), boolean()}), list(token())}.
classify_attribute_body_loop(Tokens, Position, Out) ->
case Tokens of
[] ->
{[], Out};
[{Token, _} | Rest] ->
case attribute_head(Token, Rest, Position) of
{head_close, Remaining} ->
{Remaining, [{punctuation, <<"]"/utf8>>} | Out]};
{head_emit, Emitted, Remaining@1, Position2} ->
classify_attribute_body_loop(
Remaining@1,
Position2,
gleam@list:fold(
Emitted,
Out,
fun(Acc, T) -> [T | Acc] end
)
);
head_other ->
{Text, Remaining@2} = take_attribute_other_token_run(
Tokens,
Position,
<<""/utf8>>
),
classify_attribute_body_loop(
Remaining@2,
Position,
[{other, Text} | Out]
)
end
end.
-file("src/swatch.gleam", 596).
-spec classify_attribute_selector(
list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())
) -> {list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())}.
classify_attribute_selector(Rest, State, Out) ->
{Remaining, Out2} = classify_attribute_body_loop(
Rest,
before_matcher,
[{punctuation, <<"["/utf8>>} | Out]
),
{Remaining, State, Out2}.
-file("src/swatch.gleam", 766).
-spec at_prelude_grouping_level(binary(), list(parenthesis())) -> boolean().
at_prelude_grouping_level(At_rule, Stack) ->
(At_rule /= <<""/utf8>>) andalso case Stack of
[] ->
true;
[grouping | _] ->
true;
_ ->
false
end.
-file("src/swatch.gleam", 790).
-spec at_rule_context(binary()) -> at_rule_context().
at_rule_context(At_rule) ->
case string:lowercase(At_rule) of
<<"@scope"/utf8>> ->
{at_rule_context, selector_mode, []};
<<"@supports"/utf8>> ->
{at_rule_context,
property_mode,
[{<<"selector"/utf8>>, selector_mode}]};
<<"@container"/utf8>> ->
{at_rule_context,
property_mode,
[{<<"style"/utf8>>, property_mode},
{<<"scroll-state"/utf8>>, property_mode}]};
<<"@import"/utf8>> ->
{at_rule_context,
property_mode,
[{<<"supports"/utf8>>, property_mode}]};
_ ->
{at_rule_context, property_mode, []}
end.
-file("src/swatch.gleam", 825).
-spec prelude_parenthesis_mode(binary()) -> mode().
prelude_parenthesis_mode(At_rule) ->
erlang:element(2, at_rule_context(At_rule)).
-file("src/swatch.gleam", 814).
-spec function_context_flip(binary(), binary(), mode()) -> mode().
function_context_flip(Fn_name, At_rule, Current_mode) ->
case gleam@list:key_find(
erlang:element(3, at_rule_context(At_rule)),
Fn_name
) of
{ok, Mode} ->
Mode;
{error, _} ->
Current_mode
end.
-file("src/swatch.gleam", 469).
-spec classify_pseudo(
list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())
) -> {list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())}.
classify_pseudo(Rest, State, Out) ->
case leading_name(Rest) of
{ok, {Name, Rest2}} ->
{Rest2, State, [{pseudo_selector, <<":"/utf8, Name/binary>>} | Out]};
{error, _} ->
{Rest, State, [{punctuation, <<":"/utf8>>} | Out]}
end.
-file("src/swatch.gleam", 449).
-spec classify_colon(
list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())
) -> {list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())}.
classify_colon(Rest, State, Out) ->
State@1 = case erlang:element(2, State) of
property_mode ->
promote_if_nested(State, head_flag(Rest));
_ ->
State
end,
case {erlang:element(2, State@1), erlang:element(4, State@1)} of
{property_mode, _} ->
{Rest,
{state,
value_mode,
erlang:element(3, State@1),
erlang:element(4, State@1),
erlang:element(5, State@1)},
[{punctuation, <<":"/utf8>>} | Out]};
{selector_mode, _} ->
classify_pseudo(Rest, State@1, Out);
{at_rule_mode, []} ->
classify_pseudo(Rest, State@1, Out);
{_, _} ->
{Rest, State@1, [{punctuation, <<":"/utf8>>} | Out]}
end.
-file("src/swatch.gleam", 256).
-spec classify_one(
{swatch@internal@lexer:lex_token(), boolean()},
list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())
) -> {list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())}.
classify_one(Atoken, Rest, State, Out) ->
{Token, Flag} = Atoken,
case Token of
{lex_whitespace, S} ->
{Rest, State, [{whitespace, S} | Out]};
{lex_comment, S@1} ->
{Rest, State, [{comment, S@1} | Out]};
lex_cdo ->
{Rest, State, [{comment, <<"<!--"/utf8>>} | Out]};
lex_cdc ->
{Rest, State, [{comment, <<"-->"/utf8>>} | Out]};
{lex_string, S@2} ->
{Rest, State, [{string, S@2} | Out]};
{lex_url_body, S@3} ->
{Rest, State, [{string, S@3} | Out]};
{lex_number, N} ->
{Rest, State, [{number, N} | Out]};
{lex_percentage, N@1} ->
{Rest, State, [{unit, <<"%"/utf8>>}, {number, N@1} | Out]};
{lex_dimension, N@2, U} ->
{Rest, State, [{unit, U}, {number, N@2} | Out]};
{lex_urange, S@4} ->
{Rest, State, [{keyword, S@4} | Out]};
lex_comma ->
{Rest, State, [{punctuation, <<","/utf8>>} | Out]};
lex_close_bracket ->
{Rest, State, [{punctuation, <<"]"/utf8>>} | Out]};
lex_open_brace ->
State2 = {state,
property_mode,
[property_mode | erlang:element(3, State)],
erlang:element(4, State),
<<""/utf8>>},
{Rest, State2, [{punctuation, <<"{"/utf8>>} | Out]};
lex_close_brace ->
Stack2 = case erlang:element(3, State) of
[] ->
[];
[_ | Tail] ->
Tail
end,
Outer_mode = case Stack2 of
[] ->
selector_mode;
[Mode | _] ->
Mode
end,
State2@1 = {state,
Outer_mode,
Stack2,
erlang:element(4, State),
<<""/utf8>>},
{Rest, State2@1, [{punctuation, <<"}"/utf8>>} | Out]};
lex_semicolon ->
New_mode = case erlang:element(2, State) of
value_mode ->
property_mode;
at_rule_mode ->
case erlang:element(3, State) of
[Mode@1 | _] ->
Mode@1;
[] ->
selector_mode
end;
Other ->
Other
end,
State2@2 = {state,
New_mode,
erlang:element(3, State),
erlang:element(4, State),
<<""/utf8>>},
{Rest, State2@2, [{punctuation, <<";"/utf8>>} | Out]};
lex_colon ->
case Rest of
[{lex_colon, _} | Rest2] ->
case leading_name(Rest2) of
{ok, {Name, Rest3}} ->
{Rest3,
State,
[{pseudo_selector, <<"::"/utf8, Name/binary>>} |
Out]};
{error, _} ->
{Rest2, State, [{other, <<"::"/utf8>>} | Out]}
end;
_ ->
classify_colon(Rest, State, Out)
end;
{lex_at_keyword, S@5} ->
State2@3 = {state,
at_rule_mode,
erlang:element(3, State),
erlang:element(4, State),
S@5},
{Rest, State2@3, [{at_rule, S@5} | Out]};
{lex_hash, S@6} ->
State@1 = case erlang:element(2, State) of
property_mode ->
promote_if_nested(State, head_flag(Rest));
_ ->
State
end,
Name@1 = gleam@string:drop_start(S@6, 1),
Token@1 = case erlang:element(2, State@1) of
value_mode ->
case swatch@internal@lexer:is_valid_hex_color(Name@1) of
true ->
{hex_color, S@6};
false ->
{other, S@6}
end;
selector_mode ->
{id_selector, S@6};
_ ->
{other, S@6}
end,
{Rest, State@1, [Token@1 | Out]};
{lex_ident, Name@2} ->
case gleam_stdlib:string_starts_with(Name@2, <<"--"/utf8>>) of
true ->
{Rest, State, [{variable, Name@2} | Out]};
false ->
case erlang:element(2, State) of
selector_mode ->
{Rest, State, [{selector, Name@2} | Out]};
value_mode ->
{Rest, State, [{keyword, Name@2} | Out]};
at_rule_mode ->
{Rest, State, [{keyword, Name@2} | Out]};
property_mode ->
case head_flag(Rest) of
true ->
{Rest,
{state,
selector_mode,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State)},
[{selector, Name@2} | Out]};
false ->
{Rest, State, [{property, Name@2} | Out]}
end
end
end;
{lex_function, Name@3} ->
case Rest of
[{lex_open_paren, _} | After] ->
New_mode@1 = function_context_flip(
string:lowercase(Name@3),
string:lowercase(erlang:element(5, State)),
erlang:element(2, State)
),
State2@4 = {state,
New_mode@1,
erlang:element(3, State),
[{function_call, erlang:element(2, State)} |
erlang:element(4, State)],
erlang:element(5, State)},
{After,
State2@4,
[{punctuation, <<"("/utf8>>}, {function, Name@3} | Out]};
_ ->
{Rest, State, [{function, Name@3} | Out]}
end;
lex_open_paren ->
New_mode@2 = case at_prelude_grouping_level(
erlang:element(5, State),
erlang:element(4, State)
) of
true ->
prelude_parenthesis_mode(erlang:element(5, State));
false ->
erlang:element(2, State)
end,
State2@5 = {state,
New_mode@2,
erlang:element(3, State),
[grouping | erlang:element(4, State)],
erlang:element(5, State)},
{Rest, State2@5, [{punctuation, <<"("/utf8>>} | Out]};
lex_close_paren ->
{Popped, Rest_stack} = case erlang:element(4, State) of
[Head | Tail@1] ->
{{ok, Head}, Tail@1};
[] ->
{{error, nil}, []}
end,
New_mode@3 = case Popped of
{ok, {function_call, Restore_mode}} ->
Restore_mode;
{ok, grouping} ->
case at_prelude_grouping_level(
erlang:element(5, State),
Rest_stack
) of
true ->
at_rule_mode;
false ->
erlang:element(2, State)
end;
{error, _} ->
erlang:element(2, State)
end,
State2@6 = {state,
New_mode@3,
erlang:element(3, State),
Rest_stack,
erlang:element(5, State)},
{Rest, State2@6, [{punctuation, <<")"/utf8>>} | Out]};
lex_open_bracket ->
State@2 = case erlang:element(2, State) of
property_mode ->
promote_if_nested(State, Flag);
_ ->
State
end,
case erlang:element(2, State@2) of
selector_mode ->
classify_attribute_selector(Rest, State@2, Out);
_ ->
{Rest, State@2, [{punctuation, <<"["/utf8>>} | Out]}
end;
{lex_delim, S@7} ->
classify_delim(S@7, Rest, State, Out)
end.
-file("src/swatch.gleam", 242).
-spec classify_loop(
list({swatch@internal@lexer:lex_token(), boolean()}),
state(),
list(token())
) -> list(token()).
classify_loop(Tokens, State, Out) ->
case Tokens of
[] ->
lists:reverse(Out);
[Token | Rest] ->
{Rest2, State2, Out2} = classify_one(Token, Rest, State, Out),
classify_loop(Rest2, State2, Out2)
end.
-file("src/swatch.gleam", 238).
-spec classify(list(swatch@internal@lexer:lex_token())) -> list(token()).
classify(Tokens) ->
classify_loop(
gleam@list:zip(Tokens, swatch@internal@lexer:annotate_nested(Tokens)),
initial_state(),
[]
).
-file("src/swatch.gleam", 79).
?DOC(
" Tokenize some CSS source. The returned tokens, concatenated, will\n"
" reproduce the original source.\n"
).
-spec to_tokens(binary()) -> list(token()).
to_tokens(Code) ->
classify(swatch@internal@lexer:lex(Code)).
-file("src/swatch.gleam", 86).
?DOC(
" The verbatim source text a token was cut from, including any sigil or\n"
" delimiters (`.` for a class, the quotes of a string, `/* */` for a\n"
" comment).\n"
).
-spec token_to_source(token()) -> binary().
token_to_source(Token) ->
case Token of
{whitespace, S} ->
S;
{comment, S@1} ->
S@1;
{selector, S@2} ->
S@2;
{class_selector, S@3} ->
S@3;
{id_selector, S@4} ->
S@4;
{pseudo_selector, S@5} ->
S@5;
{attribute_name, S@6} ->
S@6;
{attribute_value, S@7} ->
S@7;
{attribute_flag, S@8} ->
S@8;
{at_rule, S@9} ->
S@9;
{property, S@10} ->
S@10;
{variable, S@11} ->
S@11;
{string, S@12} ->
S@12;
{number, S@13} ->
S@13;
{unit, S@14} ->
S@14;
{hex_color, S@15} ->
S@15;
{function, S@16} ->
S@16;
{keyword, S@17} ->
S@17;
{important, S@18} ->
S@18;
{operator, S@19} ->
S@19;
{punctuation, S@20} ->
S@20;
{other, S@21} ->
S@21
end.
-file("src/swatch.gleam", 116).
?DOC(
" Concatenate a token list back into source text — the inverse of\n"
" [`to_tokens`](#to_tokens). `to_source(to_tokens(css)) == css` holds for\n"
" any input.\n"
).
-spec to_source(list(token())) -> binary().
to_source(Tokens) ->
_pipe = Tokens,
_pipe@1 = gleam@list:map(_pipe, fun token_to_source/1),
erlang:list_to_binary(_pipe@1).
-file("src/swatch.gleam", 891).
-spec wrap(binary(), binary()) -> binary().
wrap(Class, Content) ->
<<<<<<<<"<span class=\""/utf8, Class/binary>>/binary, "\">"/utf8>>/binary,
(houdini:escape(Content))/binary>>/binary,
"</span>"/utf8>>.
-file("src/swatch.gleam", 864).
-spec token_to_html(token()) -> binary().
token_to_html(Token) ->
case Token of
{whitespace, S} ->
S;
{comment, S@1} ->
wrap(<<"hl-comment"/utf8>>, S@1);
{selector, S@2} ->
wrap(<<"hl-selector"/utf8>>, S@2);
{class_selector, S@3} ->
wrap(<<"hl-class"/utf8>>, S@3);
{id_selector, S@4} ->
wrap(<<"hl-id"/utf8>>, S@4);
{pseudo_selector, S@5} ->
wrap(<<"hl-pseudo"/utf8>>, S@5);
{attribute_name, S@6} ->
wrap(<<"hl-attribute"/utf8>>, S@6);
{attribute_value, S@7} ->
wrap(<<"hl-attribute-value"/utf8>>, S@7);
{attribute_flag, S@8} ->
wrap(<<"hl-attribute-flag"/utf8>>, S@8);
{at_rule, S@9} ->
wrap(<<"hl-at-rule"/utf8>>, S@9);
{property, S@10} ->
wrap(<<"hl-property"/utf8>>, S@10);
{variable, S@11} ->
wrap(<<"hl-variable"/utf8>>, S@11);
{string, S@12} ->
wrap(<<"hl-string"/utf8>>, S@12);
{number, S@13} ->
wrap(<<"hl-number"/utf8>>, S@13);
{unit, S@14} ->
wrap(<<"hl-unit"/utf8>>, S@14);
{hex_color, S@15} ->
wrap(<<"hl-hex"/utf8>>, S@15);
{function, S@16} ->
wrap(<<"hl-function"/utf8>>, S@16);
{keyword, S@17} ->
wrap(<<"hl-keyword"/utf8>>, S@17);
{important, S@18} ->
wrap(<<"hl-important"/utf8>>, S@18);
{operator, S@19} ->
wrap(<<"hl-operator"/utf8>>, S@19);
{punctuation, S@20} ->
wrap(<<"hl-punctuation"/utf8>>, S@20);
{other, S@21} ->
wrap(<<"hl-other"/utf8>>, S@21)
end.
-file("src/swatch.gleam", 184).
?DOC(
" Render an already-tokenized list as HTML. Like [`to_html`](#to_html) but\n"
" skips re-tokenizing, for callers that already hold the token list.\n"
).
-spec tokens_to_html(list(token())) -> binary().
tokens_to_html(Tokens) ->
_pipe = Tokens,
_pipe@1 = gleam@list:map(_pipe, fun token_to_html/1),
erlang:list_to_binary(_pipe@1).
-file("src/swatch.gleam", 176).
?DOC(
" Render CSS source as HTML. Each token is wrapped in a `<span>` with a\n"
" CSS class describing its kind. Wrap the result in\n"
" `<pre><code>...</code></pre>` and style the classes below.\n"
"\n"
" | Token | CSS class |\n"
" | -------------- | ------------------ |\n"
" | Whitespace | (no wrapper) |\n"
" | Comment | hl-comment |\n"
" | Selector | hl-selector |\n"
" | ClassSelector | hl-class |\n"
" | IdSelector | hl-id |\n"
" | PseudoSelector | hl-pseudo |\n"
" | AttributeName | hl-attribute |\n"
" | AttributeValue | hl-attribute-value |\n"
" | AttributeFlag | hl-attribute-flag |\n"
" | AtRule | hl-at-rule |\n"
" | Property | hl-property |\n"
" | Variable | hl-variable |\n"
" | String | hl-string |\n"
" | Number | hl-number |\n"
" | Unit | hl-unit |\n"
" | HexColor | hl-hex |\n"
" | Function | hl-function |\n"
" | Keyword | hl-keyword |\n"
" | Important | hl-important |\n"
" | Operator | hl-operator |\n"
" | Punctuation | hl-punctuation |\n"
" | Other | hl-other |\n"
"\n"
" Starter stylesheet:\n"
"\n"
" ```css\n"
" pre code .hl-comment { color: #6a737d; font-style: italic }\n"
" pre code .hl-selector { color: #d73a49 }\n"
" pre code .hl-class { color: #6f42c1 }\n"
" pre code .hl-id { color: #6f42c1 }\n"
" pre code .hl-pseudo { color: #6f42c1 }\n"
" pre code .hl-attribute { color: #6f42c1 }\n"
" pre code .hl-attribute-value { color: #032f62 }\n"
" pre code .hl-attribute-flag { color: #6f42c1 }\n"
" pre code .hl-at-rule { color: #d73a49 }\n"
" pre code .hl-property { color: #005cc5 }\n"
" pre code .hl-variable { color: #e36209 }\n"
" pre code .hl-string { color: #032f62 }\n"
" pre code .hl-number { color: #005cc5 }\n"
" pre code .hl-unit { color: #005cc5 }\n"
" pre code .hl-hex { color: #005cc5 }\n"
" pre code .hl-function { color: #6f42c1 }\n"
" pre code .hl-keyword { color: #22863a }\n"
" pre code .hl-important { color: #d73a49; font-weight: bold }\n"
" pre code .hl-operator { color: #d73a49 }\n"
" pre code .hl-punctuation { color: #24292e }\n"
" pre code .hl-other { color: #24292e }\n"
" ```\n"
).
-spec to_html(binary()) -> binary().
to_html(Code) ->
_pipe = Code,
_pipe@1 = to_tokens(_pipe),
tokens_to_html(_pipe@1).
-file("src/swatch.gleam", 897).
-spec token_to_ansi(token()) -> binary().
token_to_ansi(Token) ->
case Token of
{whitespace, S} ->
gleam_community@ansi:reset(S);
{comment, S@1} ->
gleam_community@ansi:italic(gleam_community@ansi:gray(S@1));
{selector, S@2} ->
gleam_community@ansi:yellow(S@2);
{class_selector, S@3} ->
gleam_community@ansi:yellow(S@3);
{id_selector, S@4} ->
gleam_community@ansi:yellow(S@4);
{pseudo_selector, S@5} ->
gleam_community@ansi:yellow(S@5);
{attribute_name, S@6} ->
gleam_community@ansi:yellow(S@6);
{attribute_value, S@7} ->
gleam_community@ansi:green(S@7);
{attribute_flag, S@8} ->
gleam_community@ansi:yellow(S@8);
{at_rule, S@9} ->
gleam_community@ansi:magenta(S@9);
{property, S@10} ->
gleam_community@ansi:cyan(S@10);
{variable, S@11} ->
gleam_community@ansi:cyan(S@11);
{string, S@12} ->
gleam_community@ansi:green(S@12);
{number, S@13} ->
gleam_community@ansi:green(S@13);
{unit, S@14} ->
gleam_community@ansi:green(S@14);
{hex_color, S@15} ->
gleam_community@ansi:green(S@15);
{function, S@16} ->
gleam_community@ansi:blue(S@16);
{keyword, S@17} ->
gleam_community@ansi:yellow(S@17);
{important, S@18} ->
gleam_community@ansi:bold(gleam_community@ansi:red(S@18));
{operator, S@19} ->
gleam_community@ansi:magenta(S@19);
{punctuation, S@20} ->
gleam_community@ansi:reset(S@20);
{other, S@21} ->
gleam_community@ansi:reset(S@21)
end.
-file("src/swatch.gleam", 214).
?DOC(
" Render an already-tokenized list for the terminal. Like\n"
" [`to_ansi`](#to_ansi), but skips re-tokenizing for callers that already\n"
" hold the token list.\n"
).
-spec tokens_to_ansi(list(token())) -> binary().
tokens_to_ansi(Tokens) ->
_pipe = Tokens,
_pipe@1 = gleam@list:map(_pipe, fun token_to_ansi/1),
erlang:list_to_binary(_pipe@1).
-file("src/swatch.gleam", 205).
?DOC(
" Render CSS source for the terminal using ANSI color escapes.\n"
"\n"
" | Token | Color |\n"
" | --------------------------------------------------------------------------------------------- | ----------- |\n"
" | Selector, ClassSelector, IdSelector, PseudoSelector, AttributeName, AttributeFlag, Keyword | yellow |\n"
" | Property, Variable | cyan |\n"
" | String, Number, Unit, HexColor, AttributeValue | green |\n"
" | Function | blue |\n"
" | AtRule, Operator | magenta |\n"
" | Important | bold red |\n"
" | Comment | italic gray |\n"
" | Whitespace, Punctuation, Other | reset |\n"
"\n"
" Structural tokens use `ansi.reset` so an unclosed attribute from\n"
" upstream text can't bleed into characters like `{` and `}`.\n"
).
-spec to_ansi(binary()) -> binary().
to_ansi(Code) ->
_pipe = Code,
_pipe@1 = to_tokens(_pipe),
tokens_to_ansi(_pipe@1).