unidok-parser 0.2.0

Parser for the Unidok document format
Documentation
use unidok_repr::ast::blocks::BlockAst;
use unidok_repr::ast::html::{ElemContentAst, HtmlNodeAst};
use unidok_repr::ast::macros::BlockMacroContent;
use unidok_repr::ast::segments::SegmentAst;
use unidok_repr::ast::AstData;

pub(crate) fn accumulate_block_data(
    parsed: &[BlockAst],
    data: &mut AstData,
    no_toc: bool,
    text: &str,
) {
    for parsed in parsed {
        accumulate_single_block_data(parsed, data, no_toc, text)
    }
}

fn accumulate_single_block_data(parsed: &BlockAst, data: &mut AstData, no_toc: bool, text: &str) {
    match parsed {
        BlockAst::CodeBlock(c) => accumulate_block_data(&c.lines, data, no_toc, text),
        BlockAst::Paragraph(p) => accumulate_segment_data(&p.segments, data, no_toc, text),
        BlockAst::Heading(h) => {
            if !no_toc {
                data.headings.push(h.clone());
            }

            accumulate_segment_data(&h.segments, data, no_toc, text)
        }
        BlockAst::Table(t) => {
            for row in &t.rows {
                for cell in &row.cells {
                    accumulate_segment_data(&cell.segments, data, no_toc, text);
                }
            }
        }
        BlockAst::ThematicBreak(_) => {}
        BlockAst::List(l) => {
            for item in &l.items {
                accumulate_block_data(item, data, no_toc, text);
            }
        }
        BlockAst::Quote(q) => accumulate_block_data(&q.content, data, no_toc, text),
        BlockAst::BlockMacro(b) => {
            let no_toc = match b.name.to_str(text) {
                "NOTOC" => true,
                _ => no_toc,
            };
            match &b.content {
                BlockMacroContent::Prefixed(p) => {
                    accumulate_single_block_data(p, data, no_toc, text)
                }
                BlockMacroContent::Braces(b) => accumulate_block_data(b, data, no_toc, text),
                BlockMacroContent::None => {}
            }
        }
        BlockAst::BlockHtml(b) => accumulate_html(b, data, no_toc, text),
        BlockAst::Comment(_) => {}
        BlockAst::LinkRefDef(l) => {
            let name = l.name.to_str(text).to_string();
            data.link_ref_defs.insert(name, l.clone());
        }
    }
}

fn accumulate_segment_data(parsed: &[SegmentAst], data: &mut AstData, no_toc: bool, text: &str) {
    for parsed in parsed {
        accumulate_single_segment_data(parsed, data, no_toc, text)
    }
}

fn accumulate_single_segment_data(
    parsed: &SegmentAst,
    data: &mut AstData,
    no_toc: bool,
    text: &str,
) {
    match parsed {
        SegmentAst::LineBreak => {}
        SegmentAst::Text(_) => {}
        SegmentAst::Text2(_) => {}
        SegmentAst::Text3(_) => {}
        SegmentAst::Escaped(_) => {}
        SegmentAst::Substitution(_) => {}
        SegmentAst::Limiter => {}
        SegmentAst::Braces(b) => {
            accumulate_segment_data(&b.segments, data, no_toc, text);
        }
        SegmentAst::Math(_) => {}
        SegmentAst::Link(l) => {
            if let Some(inner_text) = &l.text {
                accumulate_segment_data(inner_text, data, no_toc, text);
            }
        }
        SegmentAst::Image(i) => {
            if let Some(alt) = &i.alt {
                accumulate_segment_data(alt, data, no_toc, text);
            }
        }
        SegmentAst::InlineMacro(i) => {
            let no_toc = match i.name.to_str(text) {
                "NOTOC" => true,
                _ => no_toc,
            };
            accumulate_single_segment_data(&i.segment, data, no_toc, text);
        }
        SegmentAst::InlineHtml(i) => accumulate_html(i, data, no_toc, text),
        SegmentAst::HtmlEntity(_) => {}
        SegmentAst::Format(f) => accumulate_segment_data(&f.segments, data, no_toc, text),
        SegmentAst::Code(c) => accumulate_segment_data(&c.segments, data, no_toc, text),
    }
}

fn accumulate_html(node: &HtmlNodeAst, data: &mut AstData, no_toc: bool, text: &str) {
    match node {
        HtmlNodeAst::Element(e) => {
            if let Some(c) = &e.content {
                match c {
                    ElemContentAst::Blocks(b) => accumulate_block_data(b, data, no_toc, text),
                    ElemContentAst::Inline(i) => accumulate_segment_data(i, data, no_toc, text),
                    ElemContentAst::Verbatim(_) => {}
                }
            }
        }
        HtmlNodeAst::CData(_) => {}
        HtmlNodeAst::Comment(_) => {}
        HtmlNodeAst::Doctype(_) => {}
    }
}