-module(section). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([get_attrs/1, get_sections_rec/4, get_sections/1]). -export_type([section/0]). -type section() :: {text, binary(), integer(), cx:context()} | {tag, binary(), gleam@dict:dict(binary(), binary()), list(section()), integer(), cx:context()}. -spec get_attrs_rec(binary(), gleam@dict:dict(binary(), binary())) -> gleam@dict:dict(binary(), binary()). get_attrs_rec(S, Acc) -> {Attr_name, S1, _} = grapheme_util:get_name_ignore_ws(S), case Attr_name of <<""/utf8>> -> Acc; _ -> case S1 of <<"="/utf8, S2/binary>> -> {_, S3} = grapheme_util:get_whitespace(S2), case S3 of <<"\""/utf8, S4/binary>> -> {Attr_value, S5} = grapheme_util:get_chars_matching_func( S4, <<""/utf8>>, fun grapheme_util:is_not_double_quote/1 ), case S5 of <<"\""/utf8, Rest/binary>> -> get_attrs_rec( Rest, begin _pipe = Acc, gleam@dict:insert( _pipe, Attr_name, Attr_value ) end ); _ -> logging:log( error, <<"Expected end double quote for attribute name: "/utf8, Attr_name/binary>> ), Acc end; <<"'"/utf8, S4@1/binary>> -> {Attr_value@1, S5@1} = grapheme_util:get_chars_matching_func( S4@1, <<""/utf8>>, fun grapheme_util:is_not_single_quote/1 ), case S5@1 of <<"'"/utf8, Rest@1/binary>> -> get_attrs_rec( Rest@1, begin _pipe@1 = Acc, gleam@dict:insert( _pipe@1, Attr_name, Attr_value@1 ) end ); _ -> logging:log( error, <<"Expected end single quote for attribute name: "/utf8, Attr_name/binary>> ), Acc end; _ -> {Attr_value@2, Rest@2} = grapheme_util:get_chars_matching_func( S3, <<""/utf8>>, fun grapheme_util:is_not_whitespace/1 ), get_attrs_rec( Rest@2, begin _pipe@2 = Acc, gleam@dict:insert( _pipe@2, Attr_name, Attr_value@2 ) end ) end; _ -> get_attrs_rec( S1, begin _pipe@3 = Acc, gleam@dict:insert(_pipe@3, Attr_name, <<""/utf8>>) end ) end end. -spec get_attrs(binary()) -> gleam@dict:dict(binary(), binary()). get_attrs(S) -> get_attrs_rec(S, gleam@dict:new()). -spec insert_section_into_child_dict( list(pre_section:raw_tag()), section(), gleam@dict:dict(integer(), list(section())) ) -> gleam@dict:dict(integer(), list(section())). insert_section_into_child_dict(Tag_stack, Doc_section, Child_dict) -> case gleam@list:first(Tag_stack) of {ok, Parent_tag} -> case gleam@dict:get(Child_dict, erlang:element(3, Parent_tag)) of {ok, Children} -> gleam@dict:insert( Child_dict, erlang:element(3, Parent_tag), [Doc_section | Children] ); {error, _} -> _pipe = gleam@dict:new(), gleam@dict:insert( _pipe, erlang:element(3, Parent_tag), [Doc_section] ) end; {error, _} -> Child_dict end. -spec sort_sections(section(), section()) -> gleam@order:order(). sort_sections(Section1, Section2) -> case Section1 of {tag, _, _, _, Start1, _} -> case Section2 of {tag, _, _, _, Start2, _} -> gleam@int:compare(Start1, Start2); {text, _, Start2@1, _} -> gleam@int:compare(Start1, Start2@1) end; {text, _, Start1@1, _} -> case Section2 of {tag, _, _, _, Start2@2, _} -> gleam@int:compare(Start1@1, Start2@2); {text, _, Start2@3, _} -> gleam@int:compare(Start1@1, Start2@3) end end. -spec get_children(gleam@dict:dict(integer(), list(section())), integer()) -> list(section()). get_children(Child_dict, Start) -> case gleam@dict:get(Child_dict, Start) of {ok, Children} -> gleam@list:sort(Children, fun sort_sections/2); {error, _} -> [] end. -spec get_sections_rec( list(pre_section:raw_section()), list(pre_section:raw_tag()), list(section()), gleam@dict:dict(integer(), list(section())) ) -> list(section()). get_sections_rec(Sections, Tag_stack, Acc, Child_dict) -> case gleam@list:first(Sections) of {ok, Doc_section} -> case Doc_section of {raw_text_section, Text, Start, _} -> Text_tag = {text, Text, Start, cx:dict()}, Acc@1 = case gleam@list:first(Tag_stack) of {ok, _} -> Acc; {error, _} -> [Text_tag | Acc] end, get_sections_rec( gleam@list:drop(Sections, 1), Tag_stack, Acc@1, insert_section_into_child_dict( Tag_stack, Text_tag, Child_dict ) ); {raw_tag_section, Tag} -> case erlang:element(5, Tag) of true -> case gleam@list:first(Tag_stack) of {ok, Opening_tag} -> Section_tag = {tag, erlang:element(2, Tag), get_attrs( erlang:element(7, Opening_tag) ), get_children( Child_dict, erlang:element(3, Opening_tag) ), erlang:element(3, Opening_tag), cx:dict()}, Acc@2 = case begin _pipe = gleam@list:drop(Tag_stack, 1), gleam@list:first(_pipe) end of {ok, _} -> Acc; {error, _} -> [Section_tag | Acc] end, get_sections_rec( gleam@list:drop(Sections, 1), gleam@list:drop(Tag_stack, 1), Acc@2, insert_section_into_child_dict( gleam@list:drop(Tag_stack, 1), Section_tag, Child_dict ) ); {error, _} -> gleam@list:sort(Acc, fun sort_sections/2) end; false -> case erlang:element(6, Tag) of true -> Section_tag@1 = {tag, erlang:element(2, Tag), get_attrs(erlang:element(7, Tag)), [], erlang:element(3, Tag), cx:dict()}, Acc@3 = case gleam@list:first(Tag_stack) of {ok, _} -> Acc; {error, _} -> [Section_tag@1 | Acc] end, get_sections_rec( gleam@list:drop(Sections, 1), Tag_stack, Acc@3, insert_section_into_child_dict( Tag_stack, Section_tag@1, Child_dict ) ); false -> get_sections_rec( gleam@list:drop(Sections, 1), [Tag | Tag_stack], Acc, Child_dict ) end end end; {error, _} -> gleam@list:sort(Acc, fun sort_sections/2) end. -spec get_sections(list(pre_section:raw_section())) -> list(section()). get_sections(Raw_sections) -> gleam@list:sort( get_sections_rec(Raw_sections, [], [], gleam@dict:new()), fun sort_sections/2 ).