-module(kirala@markdown@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([pop_grapheme/1, ret_string_trim/1, ret_string/1, parse/2, parse_all/1]). -export_type([align/0, list_type/0, parse_res/0, token_res/0, url_data/0, token/0, src_pos/0]). -type align() :: align_left | align_right | align_center. -type list_type() :: std_list | ordered_list | checked_list | unchecked_list. -type parse_res() :: {parse_res, binary(), binary()}. -type token_res() :: {token_res, token(), binary()}. -type url_data() :: {url_plain, binary()} | {url_foot_note, binary()}. -type token() :: {line, list(token())} | {line_indent, integer(), list(token())} | {text, binary()} | {bold, token()} | {italic, token()} | {strike_through, token()} | {marked_text, token()} | {inserted_text, token()} | {note, binary(), token()} | {h, integer(), integer(), token()} | {code_block, binary(), binary(), binary()} | {code_span, binary()} | {code_line, binary()} | {block_quote, integer(), token()} | {list_item, list_type(), integer(), token()} | {url, url_data()} | {url_link, binary(), url_data()} | {img_link, binary(), binary(), url_data()} | {foot_note, binary(), token()} | {foot_note_url_def, binary(), binary(), binary()} | {table, list(token()), list(align()), list(list(token()))} | {definition_of, token()} | {definition, list(token())} | {definition_is, binary(), token()} | hr. -type src_pos() :: {src_pos, integer(), integer()}. -spec pop_grapheme(binary()) -> {binary(), binary()}. pop_grapheme(Src) -> case gleam@string:pop_grapheme(Src) of {ok, {Chr, Rest}} -> {Chr, Rest}; _ -> {<<""/utf8>>, <<""/utf8>>} end. -spec ret_string_trim(binary()) -> binary(). ret_string_trim(Bitstr) -> gleam@string:trim(Bitstr). -spec ret_string(binary()) -> binary(). ret_string(Bitstr) -> Bitstr. -spec get_indent_nextchar(integer(), binary()) -> {integer(), binary()}. get_indent_nextchar(Indent, Src) -> case Src of <<""/utf8>> -> {0, <<""/utf8>>}; <<" "/utf8, Rest/binary>> -> get_indent_nextchar(Indent + 1, Rest); <<"\t"/utf8, Rest/binary>> -> get_indent_nextchar(Indent + 1, Rest); <<"\n\r"/utf8, Rest@1/binary>> -> {0, <<""/utf8>>}; <<"\r\n"/utf8, Rest@1/binary>> -> {0, <<""/utf8>>}; <<"\n"/utf8, Rest@1/binary>> -> {0, <<""/utf8>>}; <<"\r"/utf8, Rest@1/binary>> -> {0, <<""/utf8>>}; _ -> {Chr, Rest@2} = pop_grapheme(Src), {Indent, Chr} end. -spec get_nextchar(binary()) -> binary(). get_nextchar(Src) -> case Src of <<""/utf8>> -> <<""/utf8>>; <<" "/utf8, Rest/binary>> -> get_nextchar(Rest); <<"\t"/utf8, Rest/binary>> -> get_nextchar(Rest); <<"\n\r"/utf8, Rest/binary>> -> get_nextchar(Rest); <<"\r\n"/utf8, Rest/binary>> -> get_nextchar(Rest); <<"\n"/utf8, Rest/binary>> -> get_nextchar(Rest); <<"\r"/utf8, Rest/binary>> -> get_nextchar(Rest); _ -> {Chr, Rest@1} = pop_grapheme(Src), Chr end. -spec get_line(binary(), binary()) -> parse_res(). get_line(Src, Acc) -> case Src of <<""/utf8>> -> {parse_res, ret_string_trim(Acc), <<""/utf8>>}; <<"\n\r"/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; <<"\r\n"/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; <<"\n"/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; <<"\r"/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; _ -> {Chr, Rest@1} = pop_grapheme(Src), get_line(Rest@1, <>) end. -spec string_end_with(binary(), binary()) -> boolean(). string_end_with(Src, End_with) -> Slen = gleam@string:length(Src), Elen = gleam@string:length(End_with), Endstr = gleam@string:slice(Src, Slen - Elen, Elen), Endstr =:= End_with. -spec string_skip_first(binary()) -> binary(). string_skip_first(Src) -> gleam@string:slice(Src, 1, gleam@string:length(Src) - 1). -spec is_img_url_(binary(), list(binary())) -> boolean(). is_img_url_(Url, Exts) -> case Exts of [] -> false; [Ext | Rest] -> case string_end_with(Url, Ext) of true -> true; _ -> is_img_url_(Url, Rest) end end. -spec is_img_url(binary()) -> boolean(). is_img_url(Url) -> is_img_url_( Url, [<<".jpg"/utf8>>, <<".jpeg"/utf8>>, <<".png"/utf8>>, <<".gif"/utf8>>] ). -spec decode_url_(binary(), binary()) -> parse_res(). decode_url_(Src, Acc) -> case Src of <<""/utf8>> -> {parse_res, ret_string_trim(Acc), <<""/utf8>>}; <<" "/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; <<"\n\r"/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; <<"\r\n"/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; <<"\n"/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; <<"\r"/utf8, Rest/binary>> -> {parse_res, ret_string_trim(Acc), Rest}; _ -> {Chr, Rest@1} = pop_grapheme(Src), decode_url_(Rest@1, <>) end. -spec decode_url(binary()) -> token_res(). decode_url(Src) -> {parse_res, Url, Rest} = decode_url_(Src, <<""/utf8>>), T = case is_img_url(Url) of true -> {img_link, <<""/utf8>>, <<""/utf8>>, {url_plain, Url}}; _ -> {url, {url_plain, Url}} end, {token_res, T, Rest}. -spec decode_codeblock_(binary(), binary()) -> parse_res(). decode_codeblock_(Src, Acc) -> case Src of <<"```"/utf8, Rest/binary>> -> {parse_res, _, Rest2} = get_line(Rest, <<""/utf8>>), {parse_res, ret_string(Acc), Rest2}; _ -> {Chr, Rest@1} = pop_grapheme(Src), decode_codeblock_(Rest@1, <>) end. -spec decode_codeblock(binary()) -> token_res(). decode_codeblock(Src) -> {parse_res, Inf, Rest0} = get_line(Src, <<""/utf8>>), {Syntax@2, Filename@1} = case gleam@string:split(Inf, <<":"/utf8>>) of [Syntax] -> {Syntax, <<""/utf8>>}; [Syntax@1, Filename] -> {Syntax@1, Filename}; Unhandable -> {Inf, <<""/utf8>>} end, {parse_res, Code, Rest1} = decode_codeblock_(Rest0, <<""/utf8>>), {token_res, {code_block, Syntax@2, Filename@1, Code}, Rest1}. -spec get_until(binary(), binary()) -> parse_res(). get_until(Src, Terminator) -> case gleam@string:split_once(Src, Terminator) of {ok, {Left, Right}} -> {parse_res, Left, Right}; _ -> {parse_res, Src, <<""/utf8>>} end. -spec get_until1(binary(), binary()) -> parse_res(). get_until1(Src, Terminator) -> get_until(Src, Terminator). -spec get_until2(binary(), binary()) -> parse_res(). get_until2(Src, Terminator) -> get_until(Src, Terminator). -spec get_until3(binary(), binary()) -> parse_res(). get_until3(Src, Terminator) -> get_until(Src, Terminator). -spec get_until4(binary(), binary()) -> parse_res(). get_until4(Src, Terminator) -> get_until(Src, Terminator). -spec decode_codespan(binary()) -> token_res(). decode_codespan(Src) -> {parse_res, Str, Rest} = get_until1(Src, <<"`"/utf8>>), {token_res, {code_span, Str}, Rest}. -spec decode_hr(binary()) -> token_res(). decode_hr(Src) -> {parse_res, Str, Rest} = get_line(Src, <<""/utf8>>), {token_res, hr, Rest}. -spec decode_footnote_urldef(binary()) -> token_res(). decode_footnote_urldef(Src) -> {parse_res, Line, Rest} = get_line(Src, <<""/utf8>>), {parse_res, Id, Lrest} = get_until2(Line, <<"]:"/utf8>>), {parse_res, Xurl, Lrest2} = get_line(Lrest, <<""/utf8>>), {Url@2, Alt@1} = case gleam@string:split(Xurl, <<" \""/utf8>>) of [Url] -> {Url, <<""/utf8>>}; [Url@1, Alt] -> case gleam@string:split(Alt, <<"\""/utf8>>) of [Str] -> {Url@1, Str}; [Str@1 | _] -> {Url@1, Str@1}; _ -> {Url@1, Alt} end; _ -> {Xurl, <<""/utf8>>} end, {token_res, {foot_note_url_def, Id, Url@2, Alt@1}, Rest}. -spec decode_imglink(binary()) -> token_res(). decode_imglink(Src) -> {parse_res, Caption, Rest} = get_until1(Src, <<"]"/utf8>>), case get_nextchar(Rest) of <<"["/utf8>> -> {parse_res, _, Rest2} = get_until1(Rest, <<"["/utf8>>), {parse_res, Url, Rest3} = get_until1(Rest2, <<"]"/utf8>>), {token_res, {img_link, Caption, <<""/utf8>>, {url_foot_note, Url}}, Rest3}; _ -> {parse_res, _, Rest2@1} = get_until1(Rest, <<"("/utf8>>), {parse_res, Xurl, Rest3@1} = get_until1(Rest2@1, <<")"/utf8>>), {Url@3, Alt@1} = case gleam@string:split(Xurl, <<" \""/utf8>>) of [Url@1] -> {Url@1, <<""/utf8>>}; [Url@2, Alt] -> case gleam@string:split(Alt, <<"\""/utf8>>) of [Str] -> {Url@2, Str}; _ -> {Url@2, Alt} end; _ -> {Xurl, <<""/utf8>>} end, {token_res, {img_link, Caption, Alt@1, {url_plain, Url@3}}, Rest3@1} end. -spec decode_footnote_link(binary()) -> token_res(). decode_footnote_link(Src) -> {parse_res, Id, Rest} = get_until1(Src, <<"]"/utf8>>), {token_res, {url, {url_foot_note, Id}}, Rest}. -spec decode_urllink(binary()) -> token_res(). decode_urllink(Src) -> {parse_res, Line, Rest} = get_line(Src, <<""/utf8>>), {parse_res, Urlid, Rest@1} = get_until2(Line, <<"]:"/utf8>>), {parse_res, Caption, Rest@2} = get_until1(Line, <<"]"/utf8>>), case {Urlid, Caption} of {<<""/utf8>>, _} -> case get_nextchar(Rest@2) of <<"["/utf8>> -> {parse_res, _, Rest2} = get_until1(Rest@2, <<"["/utf8>>), {parse_res, Url, Rest3} = get_until1(Rest2, <<"]"/utf8>>), {token_res, {url_link, Caption, {url_foot_note, Url}}, Rest3}; _ -> {parse_res, _, Rest2@1} = get_until1(Rest@2, <<"("/utf8>>), {parse_res, Url@1, Rest3@1} = get_until1( Rest2@1, <<")"/utf8>> ), {token_res, {url_link, Caption, {url_plain, Url@1}}, Rest3@1} end; _ -> decode_footnote_urldef(Src) end. -spec decode_text(binary(), binary()) -> token_res(). decode_text(Src, Acc) -> case Src of <<""/utf8>> -> {token_res, {text, ret_string(Acc)}, <<""/utf8>>}; <<"https://"/utf8, Rest/binary>> -> {token_res, {text, ret_string(Acc)}, Src}; <<"http://"/utf8, Rest/binary>> -> {token_res, {text, ret_string(Acc)}, Src}; <<"!["/utf8, Rest/binary>> -> {token_res, {text, ret_string(Acc)}, Src}; <<"["/utf8, Rest/binary>> -> {token_res, {text, ret_string(Acc)}, Src}; <<"`"/utf8, Rest/binary>> -> {token_res, {text, ret_string(Acc)}, Src}; <<" **"/utf8, Rest/binary>> -> {token_res, {text, ret_string(Acc)}, Src}; <<" *"/utf8, Rest/binary>> -> {token_res, {text, ret_string(Acc)}, Src}; <<"~~ "/utf8, Rest/binary>> -> {token_res, {text, ret_string(Acc)}, Src}; _ -> {Chr, Rest@1} = pop_grapheme(Src), decode_text(Rest@1, <>) end. -spec list_remove_last(list(FKF)) -> list(FKF). list_remove_last(L) -> _assert_subject = gleam@list:reverse(L), [_ | Tail] = case _assert_subject of [_ | _] -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"kirala/markdown/parser"/utf8>>, function => <<"list_remove_last"/utf8>>, line => 504}) end, _pipe = Tail, gleam@list:reverse(_pipe). -spec char_int(binary()) -> integer(). char_int(C) -> _assert_subject = gleam@string:to_utf_codepoints(C), [Cp] = case _assert_subject of [_] -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"kirala/markdown/parser"/utf8>>, function => <<"char_int"/utf8>>, line => 554}) end, gleam@string:utf_codepoint_to_int(Cp). -spec parse_(integer(), binary(), integer()) -> token_res(). parse_(Lineno, Src, Indent) -> case Src of <<""/utf8>> -> {token_res, {line, []}, <<""/utf8>>}; <<" "/utf8, Rest/binary>> -> parse_(Lineno, Rest, Indent + 1); <<"#######"/utf8, Rest@1/binary>> -> decode_h(Lineno, 7, Rest@1); <<"######"/utf8, Rest@2/binary>> -> decode_h(Lineno, 6, Rest@2); <<"#####"/utf8, Rest@3/binary>> -> decode_h(Lineno, 5, Rest@3); <<"####"/utf8, Rest@4/binary>> -> decode_h(Lineno, 4, Rest@4); <<"###"/utf8, Rest@5/binary>> -> decode_h(Lineno, 3, Rest@5); <<"##"/utf8, Rest@6/binary>> -> decode_h(Lineno, 2, Rest@6); <<"#"/utf8, Rest@7/binary>> -> decode_h(Lineno, 1, Rest@7); <<"```"/utf8, Rest@8/binary>> -> decode_codeblock(Rest@8); <<":::"/utf8, Rest@9/binary>> -> decode_note(Rest@9); <<"---"/utf8, Rest@10/binary>> -> decode_hr(Rest@10); <<"___"/utf8, Rest@11/binary>> -> decode_hr(Rest@11); <<"***"/utf8, Rest@12/binary>> -> decode_hr(Rest@12); <<"> > > "/utf8, Rest@13/binary>> -> decode_blockquote(3, Rest@13); <<">> "/utf8, Rest@14/binary>> -> decode_blockquote(2, Rest@14); <<"> "/utf8, Rest@15/binary>> -> decode_blockquote(1, Rest@15); <<"- [x] "/utf8, Rest@16/binary>> -> decode_checklist(Indent, true, Rest@16); <<"- [ ] "/utf8, Rest@17/binary>> -> decode_checklist(Indent, false, Rest@17); <<"[^"/utf8, Rest@18/binary>> -> decode_footnote(Rest@18); <<"*["/utf8, Rest@19/binary>> -> decode_footnote(Rest@19); <<"* "/utf8, Rest@20/binary>> -> decode_list(Indent, Rest@20); <<"+ "/utf8, Rest@20/binary>> -> decode_list(Indent, Rest@20); <<"- "/utf8, Rest@20/binary>> -> decode_list(Indent, Rest@20); <<"|"/utf8, Rest@21/binary>> -> decode_table(Rest@21); <<": "/utf8, Rest@22/binary>> -> decode_definition(Indent, Rest@22); <<":"/utf8, Rest@23/binary>> -> decode_definition_is(Indent, Rest@23); _ -> {C1, Rest1} = pop_grapheme(Src), {C2, Rest2} = pop_grapheme(Rest1), {C3, Rest3} = pop_grapheme(Rest2), case {char_int(C1), char_int(C2), char_int(C3)} of {U1, 16#2e, _} when (16#30 =< U1) andalso (U1 =< 16#39) -> decode_ordered_list(Indent, Rest2); {U1@1, U2, 16#2e} when (((16#30 =< U1@1) andalso (U1@1 =< 16#39)) andalso (16#30 =< U2)) andalso (U2 =< 16#39) -> decode_ordered_list(Indent, Rest3); {_, _, _} -> decode_line2(Indent, Src) end end. -spec decode_note(binary()) -> token_res(). decode_note(Src) -> {parse_res, Title, Rest0} = get_line(Src, <<""/utf8>>), {parse_res, Code, Rest1} = get_until3(Rest0, <<":::"/utf8>>), {token_res, T, _} = parse(0, Code), {token_res, {note, Title, T}, Rest1}. -spec parse(integer(), binary()) -> token_res(). parse(Lineno, Src) -> parse_(Lineno, Src, 1). -spec parse_all_(integer(), binary(), list(token())) -> list(token()). parse_all_(Lineno, Src, Acc) -> case gleam@string:length(Src) of 0 -> gleam@list:reverse(Acc); _ -> {token_res, T, Rest} = parse(Lineno, Src), parse_all_(Lineno + 1, Rest, [T | Acc]) end. -spec parse_all(binary()) -> list(token()). parse_all(Src) -> parse_all_(1, Src, []). -spec decode_bold(binary(), binary()) -> token_res(). decode_bold(Src, Terminator) -> {parse_res, Str, Rest} = get_until2(Src, Terminator), {token_res, T, _} = decode_line(Str), {token_res, {bold, T}, Rest}. -spec decode_line(binary()) -> token_res(). decode_line(Src) -> {parse_res, Linestr, Rest} = get_line(Src, <<""/utf8>>), Line = Linestr, Ts = decode_line_(<<<<" "/utf8, Line/binary>>/binary, " "/utf8>>, []), {token_res, {line, Ts}, Rest}. -spec decode_line_(binary(), list(token())) -> list(token()). decode_line_(Src, Acc) -> case Src of <<""/utf8>> -> gleam@list:reverse(Acc); _ -> {token_res, T, Rest} = decode_line__(Src), decode_line_(Rest, [T | Acc]) end. -spec decode_line__(binary()) -> token_res(). decode_line__(Src) -> case Src of <<"`"/utf8, Rest/binary>> -> decode_codespan(Rest); <<" **"/utf8, Rest@1/binary>> -> decode_bold(Rest@1, <<"**"/utf8>>); <<" __"/utf8, Rest@2/binary>> -> decode_bold(Rest@2, <<"__"/utf8>>); <<" *"/utf8, Rest@3/binary>> -> decode_italic(Rest@3, <<"*"/utf8>>); <<" _"/utf8, Rest@4/binary>> -> decode_italic(Rest@4, <<"_"/utf8>>); <<" ~~"/utf8, Rest@5/binary>> -> decode_strikethrough(Rest@5); <<"https://"/utf8, Rest@6/binary>> -> decode_url(Src); <<"http://"/utf8, Rest@7/binary>> -> decode_url(Src); <<"!["/utf8, Rest@8/binary>> -> decode_imglink(Rest@8); <<"[^"/utf8, Rest@9/binary>> -> decode_footnote_link(Rest@9); <<"["/utf8, Rest@10/binary>> -> decode_urllink(Rest@10); <<" =="/utf8, Rest@11/binary>> -> decode_marked_text(Rest@11); <<" ++"/utf8, Rest@12/binary>> -> decode_inserted_text(Rest@12); _ -> decode_text(Src, <<""/utf8>>) end. -spec decode_definition_(integer(), binary(), list(token())) -> token_res(). decode_definition_(Nindent, Src, Acc) -> case get_indent_nextchar(0, Src) of {Next_indent, _} when Next_indent =/= 0 -> {token_res, T, Rest} = decode_line(Src), decode_definition_(Nindent, Rest, [T | Acc]); {Next_indent@1, _} -> {token_res, {definition, gleam@list:reverse(Acc)}, Src} end. -spec decode_definition(integer(), binary()) -> token_res(). decode_definition(Indent, Src) -> {token_res, T, Rest} = decode_line(Src), decode_definition_(Indent, Rest, [T]). -spec decode_definition_is(integer(), binary()) -> token_res(). decode_definition_is(Indent, Src) -> {parse_res, Str, Rest} = get_line(Src, <<""/utf8>>), case gleam@string:split_once(Str, <<" "/utf8>>) of {ok, {Left, Right}} -> {token_res, T, _} = decode_line( begin _pipe = Right, gleam@string:trim(_pipe) end ), {token_res, {definition_is, gleam@string:trim(Left), T}, Rest}; _ -> {token_res, T@1, _} = decode_line( begin _pipe@1 = Str, gleam@string:trim(_pipe@1) end ), {token_res, {definition, [T@1]}, Rest} end. -spec decode_ordered_list(integer(), binary()) -> token_res(). decode_ordered_list(Indent, Src) -> {token_res, T, Rest} = decode_line(Src), {token_res, {list_item, ordered_list, Indent, T}, Rest}. -spec decode_list(integer(), binary()) -> token_res(). decode_list(Indent, Src) -> {token_res, T, Rest} = decode_line(Src), {token_res, {list_item, std_list, Indent, T}, Rest}. -spec decode_checklist(integer(), boolean(), binary()) -> token_res(). decode_checklist(Indent, Check, Src) -> {token_res, T, Rest} = decode_line(Src), case Check of true -> {token_res, {list_item, checked_list, Indent, T}, Rest}; _ -> {token_res, {list_item, unchecked_list, Indent, T}, Rest} end. -spec decode_blockquote(integer(), binary()) -> token_res(). decode_blockquote(Indent, Src) -> {token_res, T, Rest} = decode_line(Src), {token_res, {block_quote, Indent, T}, Rest}. -spec decode_h(integer(), integer(), binary()) -> token_res(). decode_h(Id, N, Src) -> {token_res, T, Rest} = decode_line(Src), {token_res, {h, Id, N, T}, Rest}. -spec decode_italic(binary(), binary()) -> token_res(). decode_italic(Src, Terminator) -> {parse_res, Str, Rest} = get_until1(Src, Terminator), {token_res, T, _} = decode_line(Str), {token_res, {italic, T}, Rest}. -spec decode_strikethrough(binary()) -> token_res(). decode_strikethrough(Src) -> {parse_res, Str, Rest} = get_until3(Src, <<"~~ "/utf8>>), {token_res, T, _} = decode_line(Str), {token_res, {strike_through, T}, Rest}. -spec decode_marked_text(binary()) -> token_res(). decode_marked_text(Src) -> {parse_res, Str, Rest} = get_until3(Src, <<"== "/utf8>>), {token_res, T, _} = decode_line(Str), {token_res, {marked_text, T}, Rest}. -spec decode_inserted_text(binary()) -> token_res(). decode_inserted_text(Src) -> {parse_res, Str, Rest} = get_until3(Src, <<"++ "/utf8>>), {token_res, T, _} = decode_line(Str), {token_res, {inserted_text, T}, Rest}. -spec decode_footnote(binary()) -> token_res(). decode_footnote(Src) -> {parse_res, Line, Rest} = get_line(Src, <<""/utf8>>), {parse_res, Id, Lrest} = get_until2(Line, <<"]:"/utf8>>), {token_res, T, _} = decode_line(Lrest), {token_res, {foot_note, Id, T}, Rest}. -spec decode_line2(integer(), binary()) -> token_res(). decode_line2(Indent, Src) -> case Indent of I when I >= 2 -> {parse_res, Linestr, Rest} = get_line(Src, <<""/utf8>>), {token_res, {code_line, Linestr}, Rest}; _ -> {parse_res, Linestr@1, Rest@1} = get_line(Src, <<""/utf8>>), Line = Linestr@1, Ts = decode_line_( <<<<" "/utf8, Line/binary>>/binary, " "/utf8>>, [] ), case get_nextchar(Rest@1) of <<":"/utf8>> -> {token_res, {definition_of, {line, Ts}}, Rest@1}; _ -> {token_res, {line_indent, Indent, Ts}, Rest@1} end end. -spec decode_table_row(binary()) -> {list(token()), binary()}. decode_table_row(Src) -> {parse_res, Header, Rest} = get_line(Src, <<""/utf8>>), Splitted = begin _pipe = gleam@string:split(Header, <<"|"/utf8>>), list_remove_last(_pipe) end, Tlist = gleam@list:map( Splitted, fun(Str) -> {token_res, T, _} = decode_line(Str), T end ), {Tlist, Rest}. -spec decode_table_items(binary(), list(list(token()))) -> {list(list(token())), binary()}. decode_table_items(Src, Acc) -> case Src of <<"|"/utf8, Rest/binary>> -> {Trow, Rest2} = decode_table_row(Rest), decode_table_items(Rest2, [Trow | Acc]); _ -> {gleam@list:reverse(Acc), Src} end. -spec decode_table(binary()) -> token_res(). decode_table(Src) -> {Header, Rest} = decode_table_row(Src), {parse_res, Align_line, Rest2} = get_line(Rest, <<""/utf8>>), Splitted_align = begin _pipe = gleam@string:split(Align_line, <<"|"/utf8>>), list_remove_last(_pipe) end, Aligns = gleam@list:map( Splitted_align, fun(A) -> case string_end_with(A, <<"-:"/utf8>>) of true -> align_right; _ -> align_left end end ), {Lines, Rest3} = decode_table_items(Rest2, []), {token_res, {table, Header, Aligns, Lines}, Rest3}.