-module(commonmark@internal@parser@inline). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([parse_text/1]). -export_type([inline_state/0]). -type inline_state() :: {text_accumulator, list(binary())} | {autolink_accumulator, list(binary())}. -spec replace_null_byte(integer()) -> integer(). replace_null_byte(N) -> case N of 0 -> 16#fffd; _ -> N end. -spec finalise_plain_text(list(binary()), boolean(), boolean()) -> binary(). finalise_plain_text(Graphemes, Trim_end, Trim_start) -> _pipe = Graphemes, _pipe@1 = gleam@list:drop_while( _pipe, fun(G) -> Trim_end andalso ((G =:= <<" "/utf8>>) orelse (G =:= <<"\t"/utf8>>)) end ), _pipe@2 = lists:reverse(_pipe@1), _pipe@3 = gleam@list:drop_while( _pipe@2, fun(G@1) -> Trim_start andalso ((G@1 =:= <<" "/utf8>>) orelse (G@1 =:= <<"\t"/utf8>>)) end ), gleam@string:join(_pipe@3, <<""/utf8>>). -spec translate_numerical_entity({ok, integer()} | {error, nil}, list(binary())) -> {ok, {list(binary()), binary()}} | {error, nil}. translate_numerical_entity(Codepoint, Rest) -> _pipe = Codepoint, _pipe@1 = gleam@result:map(_pipe, fun replace_null_byte/1), _pipe@2 = gleam@result:'try'(_pipe@1, fun gleam@string:utf_codepoint/1), gleam@result:map( _pipe@2, fun(Cp) -> {Rest, gleam_stdlib:utf_codepoint_list_to_string([Cp])} end ). -spec match_entity(list(binary())) -> {ok, {list(binary()), binary()}} | {error, nil}. match_entity(Input) -> _pipe = commonmark@internal@parser@entity:match_html_entity(Input), gleam@result:try_recover( _pipe, fun(_) -> _assert_subject = gleam@regex:from_string( <<"^#([0-9]{1,7});"/utf8>> ), {ok, Dec_entity} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"commonmark/internal/parser/inline"/utf8>>, function => <<"match_entity"/utf8>>, line => 54}) end, _assert_subject@1 = gleam@regex:from_string( <<"^#[xX]([0-9a-fA-F]{1,6});"/utf8>> ), {ok, Hex_entity} = case _assert_subject@1 of {ok, _} -> _assert_subject@1; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail@1, module => <<"commonmark/internal/parser/inline"/utf8>>, function => <<"match_entity"/utf8>>, line => 55}) end, Potential = begin _pipe@1 = gleam@list:take(Input, 9), gleam@string:join(_pipe@1, <<""/utf8>>) end, case {gleam@regex:scan(Dec_entity, Potential), gleam@regex:scan(Hex_entity, Potential)} of {[{match, Full, [{some, N}]}], _} -> _pipe@2 = N, _pipe@3 = gleam@int:parse(_pipe@2), translate_numerical_entity( _pipe@3, gleam@list:drop(Input, gleam@string:length(Full)) ); {_, [{match, Full@1, [{some, N@1}]}]} -> _pipe@4 = N@1, _pipe@5 = gleam@int:base_parse(_pipe@4, 16), translate_numerical_entity( _pipe@5, gleam@list:drop(Input, gleam@string:length(Full@1)) ); {_, _} -> {error, nil} end end ). -spec do_parse_text( list(binary()), inline_state(), list(commonmark@ast:inline_node()) ) -> list(commonmark@ast:inline_node()). do_parse_text(Text, State, Acc) -> case {State, Text} of {{autolink_accumulator, Ts}, []} -> [{plain_text, begin _pipe = [<<"<"/utf8>> | lists:reverse(Ts)], gleam@string:join(_pipe, <<""/utf8>>) end} | Acc]; {{text_accumulator, Ts@1}, []} -> _pipe@1 = [{plain_text, finalise_plain_text(Ts@1, true, true)} | Acc], lists:reverse(_pipe@1); {{text_accumulator, Ts@2}, [<<" "/utf8>>, <<" "/utf8>>, <<"\n"/utf8>> | Gs]} -> do_parse_text( Gs, {text_accumulator, []}, [hard_line_break, {plain_text, finalise_plain_text(Ts@2, true, true)} | Acc] ); {{text_accumulator, Ts@2}, [<<"\\"/utf8>>, <<"\n"/utf8>> | Gs]} -> do_parse_text( Gs, {text_accumulator, []}, [hard_line_break, {plain_text, finalise_plain_text(Ts@2, true, true)} | Acc] ); {{autolink_accumulator, Ts@3}, [<<" "/utf8>>, <<" "/utf8>>, <<"\n"/utf8>> | Gs@1]} -> do_parse_text( Gs@1, {text_accumulator, []}, [hard_line_break, {plain_text, begin _pipe@2 = lists:reverse([<<"<"/utf8>> | Ts@3]), gleam@string:join(_pipe@2, <<""/utf8>>) end} | Acc] ); {{autolink_accumulator, Ts@3}, [<<"\\"/utf8>>, <<"\n"/utf8>> | Gs@1]} -> do_parse_text( Gs@1, {text_accumulator, []}, [hard_line_break, {plain_text, begin _pipe@2 = lists:reverse([<<"<"/utf8>> | Ts@3]), gleam@string:join(_pipe@2, <<""/utf8>>) end} | Acc] ); {{text_accumulator, Ts@4}, [<<"\n"/utf8>> | Gs@2]} -> do_parse_text( Gs@2, {text_accumulator, []}, [soft_line_break, {plain_text, finalise_plain_text(Ts@4, true, true)} | Acc] ); {{autolink_accumulator, Ts@5}, [<<"\n"/utf8>> | Gs@3]} -> do_parse_text( Gs@3, {text_accumulator, []}, [soft_line_break, {plain_text, begin _pipe@3 = lists:reverse([<<"<"/utf8>> | Ts@5]), gleam@string:join(_pipe@3, <<""/utf8>>) end} | Acc] ); {{text_accumulator, Ts@6}, [<<"\\"/utf8>>, G | Gs@4]} -> case gleam@list:contains( [<<"!"/utf8>>, <<"\""/utf8>>, <<"#"/utf8>>, <<"$"/utf8>>, <<"%"/utf8>>, <<"&"/utf8>>, <<"'"/utf8>>, <<"("/utf8>>, <<")"/utf8>>, <<"*"/utf8>>, <<"+"/utf8>>, <<","/utf8>>, <<"-"/utf8>>, <<"."/utf8>>, <<"/"/utf8>>, <<":"/utf8>>, <<";"/utf8>>, <<"<"/utf8>>, <<"="/utf8>>, <<">"/utf8>>, <<"?"/utf8>>, <<"@"/utf8>>, <<"["/utf8>>, <<"]"/utf8>>, <<"\\"/utf8>>, <<"^"/utf8>>, <<"_"/utf8>>, <<"`"/utf8>>, <<"{"/utf8>>, <<"|"/utf8>>, <<"}"/utf8>>, <<"~"/utf8>>], G ) of true -> do_parse_text(Gs@4, {text_accumulator, [G | Ts@6]}, Acc); false -> do_parse_text( Gs@4, {text_accumulator, [G, <<"\\"/utf8>> | Ts@6]}, Acc ) end; {{text_accumulator, Ts@7}, [<<"&"/utf8>> | Gs@5]} -> case match_entity(Gs@5) of {ok, {Rest, Replacement}} -> do_parse_text( Rest, {text_accumulator, [Replacement | Ts@7]}, Acc ); {error, _} -> do_parse_text( Gs@5, {text_accumulator, [<<"&"/utf8>> | Ts@7]}, Acc ) end; {{text_accumulator, Ts@8}, [<<"<"/utf8>> | Gs@6]} -> do_parse_text( Gs@6, {autolink_accumulator, []}, [{plain_text, finalise_plain_text(Ts@8, false, false)} | Acc] ); {{autolink_accumulator, Ts@9}, [<<"\t"/utf8>> = Space | Gs@7]} -> do_parse_text( Gs@7, {text_accumulator, [Space | lists:append(Ts@9, [<<"<"/utf8>>])]}, Acc ); {{autolink_accumulator, Ts@9}, [<<" "/utf8>> = Space | Gs@7]} -> do_parse_text( Gs@7, {text_accumulator, [Space | lists:append(Ts@9, [<<"<"/utf8>>])]}, Acc ); {{autolink_accumulator, Ts@10}, [<<">"/utf8>> | Gs@8]} -> do_parse_text( Gs@8, {text_accumulator, []}, [commonmark@internal@parser@helpers:parse_autolink( finalise_plain_text(Ts@10, false, false) ) | Acc] ); {{autolink_accumulator, Ts@11}, [G@1 | Gs@9]} -> do_parse_text(Gs@9, {autolink_accumulator, [G@1 | Ts@11]}, Acc); {{text_accumulator, Ts@12}, [G@2 | Gs@10]} -> do_parse_text(Gs@10, {text_accumulator, [G@2 | Ts@12]}, Acc) end. -spec parse_text(binary()) -> list(commonmark@ast:inline_node()). parse_text(Text) -> _pipe = Text, _pipe@1 = gleam@string:to_graphemes(_pipe), do_parse_text(_pipe@1, {text_accumulator, []}, []).