Skip to main content

markdown_it/parser/
main.rs

1use crate::common::ruler::Ruler;
2use crate::common::sourcemap::SourcePos;
3use crate::common::TypeKey;
4use crate::parser::block::{self, BlockParser};
5use crate::parser::core::{Root, *};
6use crate::parser::extset::MarkdownItExtSet;
7use crate::parser::inline::{self, InlineParser};
8use crate::parser::linkfmt::{LinkFormatter, MDLinkFormatter};
9use crate::Node;
10
11type RuleFn = fn(&mut Node, &MarkdownIt);
12
13/// Main parser struct, created once and reused for parsing multiple documents.
14pub struct MarkdownIt {
15    /// Block-level tokenizer.
16    pub block: BlockParser,
17
18    /// Inline-level tokenizer.
19    pub inline: InlineParser,
20
21    /// Link validator and formatter.
22    pub link_formatter: Box<dyn LinkFormatter>,
23
24    /// Storage for custom data used in plugins.
25    pub ext: MarkdownItExtSet,
26
27    /// Maximum depth of the generated AST, exists to prevent recursion
28    /// (if markdown source reaches this depth, deeply nested structures
29    /// will be parsed as plain text).
30    /// TODO: doesn't work
31    #[doc(hidden)]
32    pub max_nesting: u32,
33
34    /// Maximum allowed indentation for syntax blocks
35    /// default i32::MAX, indented code blocks will set this to 4
36    pub max_indent: i32,
37
38    ruler: Ruler<TypeKey, RuleFn>,
39}
40
41impl std::fmt::Debug for MarkdownIt {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        f.debug_struct("MarkdownIt")
44            .field("block", &self.block)
45            .field("inline", &self.inline)
46            .field("link_formatter", &self.link_formatter)
47            .field("ext", &self.ext)
48            .field("max_nesting", &self.max_nesting)
49            .field("max_indent", &self.max_indent)
50            .field("ruler", &self.ruler)
51            .finish()
52    }
53}
54
55impl MarkdownIt {
56    pub fn new() -> Self {
57        Self::default()
58    }
59
60    pub fn parse(&self, src: &str) -> Node {
61        let mut node = Node::new(Root::new(src.to_owned()));
62        node.srcmap = Some(SourcePos::new(0, src.len()));
63
64        for rule in self.ruler.iter() {
65            rule(&mut node, self);
66            debug_assert!(
67                node.is::<Root>(),
68                "root node of the AST must always be Root"
69            );
70        }
71        node
72    }
73
74    pub fn add_rule<T: CoreRule>(&mut self) -> RuleBuilder<'_, RuleFn> {
75        let item = self.ruler.add(TypeKey::of::<T>(), T::run);
76        RuleBuilder::new(item)
77    }
78
79    pub fn has_rule<T: CoreRule>(&mut self) -> bool {
80        self.ruler.contains(TypeKey::of::<T>())
81    }
82
83    pub fn remove_rule<T: CoreRule>(&mut self) {
84        self.ruler.remove(TypeKey::of::<T>());
85    }
86}
87
88impl Default for MarkdownIt {
89    fn default() -> Self {
90        let mut md = Self {
91            block: BlockParser::new(),
92            inline: InlineParser::new(),
93            link_formatter: Box::new(MDLinkFormatter::new()),
94            ext: MarkdownItExtSet::new(),
95            max_nesting: 100,
96            ruler: Ruler::new(),
97            max_indent: i32::MAX,
98        };
99        block::builtin::add(&mut md);
100        inline::builtin::add(&mut md);
101        md
102    }
103}