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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
mod state;
pub use state::*;
mod rule;
pub use rule::*;
#[doc(hidden)]
pub mod builtin;
use crate::{MarkdownIt, Node};
use crate::common::{ErasedSet, TypeKey};
use crate::common::ruler::Ruler;
use crate::parser::inline::InlineRoot;
type RuleFn = fn (&mut BlockState, bool) -> bool;
#[derive(Debug, Default)]
pub struct BlockParser {
ruler: Ruler<TypeKey, RuleFn>,
}
impl BlockParser {
pub fn new() -> Self {
Self::default()
}
pub fn tokenize(&self, state: &mut BlockState) {
let mut has_empty_lines = false;
while state.line < state.line_max {
state.line = state.skip_empty_lines(state.line);
if state.line >= state.line_max { break; }
if state.line_indent(state.line) < 0 { break; }
if state.level >= state.md.max_nesting {
state.line = state.line_max;
break;
}
let mut ok = false;
let prev_line = state.line;
for rule in self.ruler.iter() {
ok = rule(state, false);
if ok {
assert!(state.line > prev_line, "block rule didn't increment state.line");
break;
}
}
if !ok {
let mut content = state.get_line(state.line).to_owned();
content.push('\n');
let node = Node::new(InlineRoot {
content,
mapping: vec![(0, state.line_offsets[state.line].first_nonspace)],
});
state.node.children.push(node);
state.line += 1;
}
state.tight = !has_empty_lines;
if state.is_empty(state.line - 1) {
has_empty_lines = true;
}
if state.line < state.line_max && state.is_empty(state.line) {
has_empty_lines = true;
state.line += 1;
}
}
}
pub fn parse(&self, src: &str, node: Node, md: &MarkdownIt, env: &mut ErasedSet) -> Node {
let mut state = BlockState::new(src, md, env, node);
self.tokenize(&mut state);
state.node
}
pub fn add_rule<T: BlockRule>(&mut self) -> RuleBuilder<RuleFn> {
let item = self.ruler.add(TypeKey::of::<T>(), T::run);
RuleBuilder::new(item)
}
pub fn has_rule<T: BlockRule>(&mut self) -> bool {
self.ruler.contains(TypeKey::of::<T>())
}
pub fn remove_rule<T: BlockRule>(&mut self) {
self.ruler.remove(TypeKey::of::<T>());
}
}