-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, <>); [{{lex_comment, S@1}, _} | Rest@1] -> important_match_loop(Rest@1, <>); [{{lex_ident, Name}, _} | Rest@2] -> case string:lowercase(Name) =:= <<"important"/utf8>> of true -> {ok, {<>, 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, <> -> case Rest of [{{lex_delim, <<"="/utf8>>}, _} | Rest2] -> {head_emit, [{operator, <> -> case Rest of [{{lex_delim, <<"="/utf8>>}, _} | Rest2] -> {head_emit, [{operator, <> -> 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, 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_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) -> <<<<<<<<">/binary, "\">"/utf8>>/binary, (houdini:escape(Content))/binary>>/binary, ""/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 `` with a\n" " CSS class describing its kind. Wrap the result in\n" " `
...
` 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).