1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! A simple markdown parser that can write formatted text to the terminal
//!
//! Entrypoint is `MdStream::parse_str(...)`
use std::io;

use termcolor::{Buffer, BufferWriter, ColorChoice};
mod parse;
mod term;

/// An AST representation of a Markdown document
#[derive(Clone, Debug, Default, PartialEq)]
pub struct MdStream<'a>(Vec<MdTree<'a>>);

impl<'a> MdStream<'a> {
    /// Parse a markdown string to a tokenstream
    #[must_use]
    pub fn parse_str(s: &str) -> MdStream<'_> {
        parse::entrypoint(s)
    }

    /// Write formatted output to a termcolor buffer
    pub fn write_termcolor_buf(&self, buf: &mut Buffer) -> io::Result<()> {
        term::entrypoint(self, buf)
    }
}

/// Create a termcolor buffer with the `Always` color choice
pub fn create_stdout_bufwtr() -> BufferWriter {
    BufferWriter::stdout(ColorChoice::Always)
}

/// A single tokentree within a Markdown document
#[derive(Clone, Debug, PartialEq)]
pub enum MdTree<'a> {
    /// Leaf types
    Comment(&'a str),
    CodeBlock {
        txt: &'a str,
        lang: Option<&'a str>,
    },
    CodeInline(&'a str),
    Strong(&'a str),
    Emphasis(&'a str),
    Strikethrough(&'a str),
    PlainText(&'a str),
    /// [Foo](www.foo.com) or simple anchor <www.foo.com>
    Link {
        disp: &'a str,
        link: &'a str,
    },
    /// `[Foo link][ref]`
    RefLink {
        disp: &'a str,
        id: Option<&'a str>,
    },
    /// [ref]: www.foo.com
    LinkDef {
        id: &'a str,
        link: &'a str,
    },
    /// Break bewtween two paragraphs (double `\n`), not directly parsed but
    /// added later
    ParagraphBreak,
    /// Break bewtween two lines (single `\n`)
    LineBreak,
    HorizontalRule,
    Heading(u8, MdStream<'a>),
    OrderedListItem(u16, MdStream<'a>),
    UnorderedListItem(MdStream<'a>),
}

impl<'a> From<Vec<MdTree<'a>>> for MdStream<'a> {
    fn from(value: Vec<MdTree<'a>>) -> Self {
        Self(value)
    }
}