pulldown-cmark-ast 0.1.0

An AST for pulldown-cmark
Documentation
use std::{
    io::{self, Read as _},
    process,
};

use ariadne::{Color, Label, Report, ReportKind, Source};
use pulldown_cmark::{Options, Tag};
use pulldown_cmark_ast::{Ast, Group, Span, Spanned, Tree};

fn main() {
    let mut txt = String::new();

    eprintln!("reading from stdin...");
    if let Err(e) = io::stdin().read_to_string(&mut txt) {
        eprintln!("Error reading from stdin: {}", e);
        process::exit(1)
    };

    let ast = pulldown_cmark_ast::Ast::new_ext(&txt, Options::all());
    let mut labels = vec![];
    visit_ast(&mut labels, &ast);

    Report::build(ReportKind::Custom("info", Color::Blue), (), 0)
        .with_labels(labels)
        .finish()
        .print(Source::from(txt))
        .unwrap();
}

fn visit_ast(labels: &mut Vec<Label>, ast: &Ast) {
    let Ast(trees) = ast;
    for tree in trees {
        let span;
        let (text, Span(span)) = match tree {
            Tree::Group(Group {
                tag:
                    Spanned {
                        item: tag,
                        span: Span(begin_span),
                    },
                stream,
                end_span: Span(end_span),
            }) => {
                let text = match tag {
                    Tag::Paragraph => "paragraph",
                    Tag::Heading { .. } => "heading",
                    Tag::BlockQuote(_) => "block-quote",
                    Tag::CodeBlock(_) => "code-block",
                    Tag::HtmlBlock => "html-block",
                    Tag::List(_) => "list",
                    Tag::Item => "item",
                    Tag::FootnoteDefinition(_) => "footnote-definition",
                    Tag::Table(_) => "table",
                    Tag::TableHead => "table-head",
                    Tag::TableRow => "table-row",
                    Tag::TableCell => "table-cell",
                    Tag::Emphasis => "emphasis",
                    Tag::Strong => "strong",
                    Tag::Strikethrough => "strikethrough",
                    Tag::Link { .. } => "link",
                    Tag::Image { .. } => "image",
                    Tag::MetadataBlock(_) => "metadata-block",
                };
                span = Span(begin_span.start..end_span.end);
                visit_ast(labels, stream);

                (text, &span)
            }
            Tree::Text(Spanned { span, .. }) => ("text", span),
            Tree::Code(Spanned { span, .. }) => ("code", span),
            Tree::Html(Spanned { span, .. }) => ("html", span),
            Tree::InlineHtml(Spanned { span, .. }) => ("inline-html", span),
            Tree::FootnoteReference(Spanned { span, .. }) => ("footnote-reference", span),
            Tree::SoftBreak(span) => ("soft-break", span),
            Tree::HardBreak(span) => ("hard-break", span),
            Tree::Rule(span) => ("rule", span),
            Tree::TaskListMarker(Spanned { span, .. }) => ("task-list-marker", span),
            Tree::InlineMath(Spanned { span, .. }) => ("inline-math", span),
            Tree::DisplayMath(Spanned { span, .. }) => ("display-math", span),
        };
        labels.push(Label::new(span.clone()).with_message(text))
    }
}