Packages

Markdown parser and html renderer written in Gleam language both Erlang and Javascript target.

Current section

Files

Jump to
kirala_markdown src kirala@markdown@parser.erl
Raw

src/kirala@markdown@parser.erl

-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, <<Acc/binary, Chr/binary>>)
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, <<Acc/binary, Chr/binary>>)
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, <<Acc/binary, Chr/binary>>)
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, <<Acc/binary, Chr/binary>>)
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}.