1//! Paragraph
2//!
3//! This is the default rule if nothing else matches.
4//!
5//! <https://spec.commonmark.org/0.30/#paragraph>
6use crate::parser::block::{BlockRule, BlockState};
7use crate::parser::inline::InlineRoot;
8use crate::{MarkdownIt, Node, NodeValue, Renderer};
9
10pub fn add(md: &mut MarkdownIt) {
11 md.block.add_rule::<ParagraphScanner>()
12 .after_all();
13}
14
15#[derive(Debug)]
16pub struct Paragraph;
17
18impl NodeValue for Paragraph {
19 fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
20 fmt.cr();
21 fmt.open("p", &node.attrs);
22 fmt.contents(&node.children);
23 fmt.close("p");
24 fmt.cr();
25 }
26}
27
28#[doc(hidden)]
29pub struct ParagraphScanner;
30impl BlockRule for ParagraphScanner {
31 fn check(_: &mut BlockState) -> Option<()> {
32 None // can't interrupt anything
33 }
34
35 fn run(state: &mut BlockState) -> Option<(Node, usize)> {
36 let start_line = state.line;
37 let mut next_line = start_line;
38
39 // jump line-by-line until empty one or EOF
40 'outer: loop {
41 next_line += 1;
42
43 if next_line >= state.line_max || state.is_empty(next_line) { break; }
44
45 // this may be a code block normally, but after paragraph
46 // it's considered a lazy continuation regardless of what's there
47 if state.line_indent(next_line) >= state.md.max_indent { continue; }
48
49 // quirk for blockquotes, this line should already be checked by that rule
50 if state.line_offsets[next_line].indent_nonspace < 0 { continue; }
51
52 // Some tags can terminate paragraph without empty line.
53 let old_state_line = state.line;
54 state.line = next_line;
55 if state.test_rules_at_line() {
56 state.line = old_state_line;
57 break 'outer;
58 }
59 state.line = old_state_line;
60 }
61
62 let (content, mapping) = state.get_lines(start_line, next_line, state.blk_indent, false);
63
64 let mut node = Node::new(Paragraph);
65 node.children.push(Node::new(InlineRoot::new(content, mapping)));
66 Some((node, next_line - start_line))
67 }
68}