-module(glemtext). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([parse/1]). -export_type([gem_element/0]). -type gem_element() :: {text, binary()} | {link, binary(), gleam@option:option(binary())} | {heading, integer(), binary()} | {list_item, binary()} | {blockquote, binary()} | {preformatted, gleam@option:option(binary()), binary()}. -spec until_nl(binary()) -> boolean(). until_nl(C) -> C /= <<"\n"/utf8>>. -spec get_line(list(binary())) -> {list(binary()), list(binary())}. get_line(In) -> Line = begin _pipe = In, gleam@list:take_while(_pipe, fun until_nl/1) end, Rest = begin _pipe@1 = In, _pipe@2 = gleam@list:drop_while(_pipe@1, fun until_nl/1), gleam@list:drop(_pipe@2, 1) end, {Line, Rest}. -spec parse_text(list(binary())) -> {gem_element(), list(binary())}. parse_text(In) -> {Line, Rest} = get_line(In), Line@1 = gleam@string:join(Line, <<""/utf8>>), {{text, Line@1}, Rest}. -spec take_preformatted_lines(list(binary())) -> {list(binary()), list(binary())}. take_preformatted_lines(In) -> {Line, Rest} = get_line(In), case Line of [<<"`"/utf8>>, <<"`"/utf8>>, <<"`"/utf8>> | Rest@1] -> {_, Rest@2} = get_line(Rest@1), {[], Rest@2}; [] -> {[], []}; _ -> {Next, In@1} = take_preformatted_lines(Rest), Line@1 = begin _pipe = Line, gleam@string:join(_pipe, <<""/utf8>>) end, {[Line@1 | Next], In@1} end. -spec drop_lines(list(binary())) -> list(binary()). drop_lines(In) -> case In of [<<"\n"/utf8>> | Rest] -> drop_lines(Rest); _ -> In end. -spec drop_ws(list(binary())) -> list(binary()). drop_ws(In) -> case In of [<<" "/utf8>> | Rest] -> drop_ws(Rest); [<<"\t"/utf8>> | Rest@1] -> drop_ws(Rest@1); _ -> In end. -spec parse_blockquote(list(binary())) -> {gem_element(), list(binary())}. parse_blockquote(In) -> {Line, Rest} = get_line(In), Line@1 = begin _pipe = Line, _pipe@1 = drop_ws(_pipe), gleam@string:join(_pipe@1, <<""/utf8>>) end, {{blockquote, Line@1}, Rest}. -spec parse_preformatted(list(binary())) -> {gem_element(), list(binary())}. parse_preformatted(In) -> {Line, Rest} = get_line(In), Alt = begin _pipe = Line, _pipe@1 = drop_ws(_pipe), gleam@string:join(_pipe@1, <<""/utf8>>) end, Alt@1 = case Alt of <<""/utf8>> -> none; _ -> {some, Alt} end, {Pre_lines, In@1} = take_preformatted_lines(Rest), Pre_lines@1 = begin _pipe@2 = Pre_lines, gleam@string:join(_pipe@2, <<"\n"/utf8>>) end, {{preformatted, Alt@1, Pre_lines@1}, In@1}. -spec parse_heading(integer(), list(binary())) -> {gem_element(), list(binary())}. parse_heading(Level, In) -> {Line, Rest} = get_line(In), Line@1 = begin _pipe = Line, _pipe@1 = drop_ws(_pipe), gleam@string:join(_pipe@1, <<""/utf8>>) end, {{heading, Level, Line@1}, Rest}. -spec parse_link(list(binary())) -> {gem_element(), list(binary())}. parse_link(In) -> {Line, Rest} = get_line(In), {Url, Linerest} = begin _pipe = Line, _pipe@1 = drop_ws(_pipe), gleam@list:split_while( _pipe@1, fun(C) -> not ((C =:= <<" "/utf8>>) orelse (C =:= <<"\t"/utf8>>)) end ) end, Url@1 = gleam@string:join(Url, <<""/utf8>>), Label = begin _pipe@2 = Linerest, _pipe@3 = drop_ws(_pipe@2), gleam@string:join(_pipe@3, <<""/utf8>>) end, Label@1 = case Label of <<""/utf8>> -> none; _ -> {some, Label} end, {{link, Url@1, Label@1}, Rest}. -spec parse_list(list(binary())) -> {gem_element(), list(binary())}. parse_list(In) -> {Line, Rest} = get_line(In), Line@1 = begin _pipe = Line, _pipe@1 = drop_ws(_pipe), gleam@string:join(_pipe@1, <<""/utf8>>) end, {{list_item, Line@1}, Rest}. -spec parse_document(list(binary()), list(gem_element())) -> list(gem_element()). parse_document(In, Ast) -> case In of [<<"="/utf8>>, <<">"/utf8>> | Rest] -> {Link, In@1} = parse_link(Rest), parse_document(In@1, [Link | Ast]); [<<"*"/utf8>>, <<" "/utf8>> | Rest@1] -> {Item, In@2} = parse_list(Rest@1), parse_document(In@2, [Item | Ast]); [<<">"/utf8>> | Rest@2] -> {Quote, In@3} = parse_blockquote(Rest@2), parse_document(In@3, [Quote | Ast]); [<<"#"/utf8>>, <<" "/utf8>> | Rest@3] -> {Heading, In@4} = parse_heading(1, Rest@3), parse_document(In@4, [Heading | Ast]); [<<"#"/utf8>>, <<"#"/utf8>>, <<" "/utf8>> | Rest@4] -> {Heading@1, In@5} = parse_heading(2, Rest@4), parse_document(In@5, [Heading@1 | Ast]); [<<"#"/utf8>>, <<"#"/utf8>>, <<"#"/utf8>>, <<" "/utf8>> | Rest@5] -> {Heading@2, In@6} = parse_heading(3, Rest@5), parse_document(In@6, [Heading@2 | Ast]); [<<"`"/utf8>>, <<"`"/utf8>>, <<"`"/utf8>> | Rest@6] -> {Preformatted, In@7} = parse_preformatted(Rest@6), parse_document(In@7, [Preformatted | Ast]); [] -> Ast; _ -> {Text, In@8} = parse_text(In), parse_document(In@8, [Text | Ast]) end. -spec parse(binary()) -> list(gem_element()). parse(Text) -> _pipe = Text, _pipe@1 = gleam@string:replace(_pipe, <<"\r\n"/utf8>>, <<"\n"/utf8>>), _pipe@2 = gleam@string:to_graphemes(_pipe@1), _pipe@3 = parse_document(_pipe@2, []), gleam@list:reverse(_pipe@3).