Current section

Files

Jump to
magma lib magma document_struct parser.ex
Raw

lib/magma/document_struct/parser.ex

defmodule Magma.DocumentStruct.Parser do
@moduledoc false
alias Magma.DocumentStruct
alias Magma.DocumentStruct.Section
alias Panpipe.AST.Header
def parse(content) when is_binary(content) do
with {:ok, document} <-
content
|> String.trim()
|> Panpipe.ast(from: DocumentStruct.pandoc_extension()) do
to_section(document)
end
end
def to_section(%Panpipe.Document{children: children}), do: to_section(children)
def to_section(ast_elements) when is_list(ast_elements) do
{prologue, remaining} = extract_prologue(ast_elements)
{:ok,
DocumentStruct.new(
prologue: prologue,
sections: section_tree(remaining)
)}
end
defp extract_prologue(children) do
take_until_next_header(children)
end
defp section_tree([]), do: []
defp section_tree([%Header{level: level} = header | rest]) do
{content, remaining} = take_until_next_header(rest)
{sub_sections, remaining} = take_until_next_outer_section(remaining, level)
[Section.new(header, content, section_tree(sub_sections)) | section_tree(remaining)]
end
defp take_until_next_header(list, acc \\ [])
defp take_until_next_header([], acc),
do: {Enum.reverse(acc), []}
defp take_until_next_header([%Header{} | _] = elements, acc),
do: {Enum.reverse(acc), elements}
defp take_until_next_header([element | rest], acc),
do: take_until_next_header(rest, [element | acc])
defp take_until_next_outer_section(list, outer_level, acc \\ [])
defp take_until_next_outer_section([], _outer_level, acc),
do: {Enum.reverse(acc), []}
defp take_until_next_outer_section([%Header{level: level} | _] = remaining, outer_level, acc)
when level <= outer_level do
{Enum.reverse(acc), remaining}
end
defp take_until_next_outer_section([content | remaining], outer_level, acc) do
take_until_next_outer_section(remaining, outer_level, [content | acc])
end
end