rustla/parser/state_machine/
block_quote.rs

1/*!
2Contains the transition function for parsing attributions inside block quotes.
3
4Copyright © 2020 Santtu Söderholm
5*/
6
7use super::*;
8use crate::parser::types_and_aliases::IndentedBlockResult;
9
10/// A function that generates attribution nodes inside a block quote.
11/// An attribution ends block quotes, so encountering one makes the parser focus on the parent of the current node.
12pub fn attribution(
13    src_lines: &Vec<String>,
14    base_indent: usize,
15    section_level: &mut usize,
16    line_cursor: &mut LineCursor,
17    mut doctree: DocTree,
18    captures: &regex::Captures,
19    pattern_name: &Pattern,
20) -> TransitionResult {
21
22    let match_len = captures.get(0).unwrap().as_str().chars().count() + base_indent;
23    let attribution_line_indent = captures.get(1).unwrap().as_str().chars().count() + base_indent;
24
25    match Parser::parent_indent_matches(doctree.shared_data(), attribution_line_indent) {
26        IndentationMatch::JustRight => {
27            // Attempt to create attribution node inside current block quote and focus on the parent node
28
29            let current_line = if let Some(line) = src_lines.get(line_cursor.relative_offset()) {
30                line
31            } else {
32                panic!("Found an attribution marker on line {} but the line doesn't exist? Computer says no...", line_cursor.sum_total())
33            };
34
35            let line_after_marker = Parser::line_suffix(current_line, match_len - base_indent);
36
37            let empty_after_marker = line_after_marker.as_str().trim().is_empty();
38
39            let first_indent = if empty_after_marker {
40                None
41            } else {
42                Some(match_len)
43            };
44
45            let next_indent = if let Some((indent, offset)) =
46                Parser::indent_on_subsequent_lines(src_lines, line_cursor.relative_offset())
47            {
48                if offset == 0 && indent >= attribution_line_indent {
49                    Some(indent)
50                } else {
51                    Some(match_len)
52                }
53            } else {
54                Some(match_len)
55            };
56
57            let (attribution_string, offset) = if let IndentedBlockResult::Ok {lines, minimum_indent, offset, blank_finish } =
58                Parser::read_indented_block(
59                    src_lines,
60                    line_cursor.relative_offset(),
61                    true,
62                    true,
63                    next_indent,
64                    first_indent,
65                    true,
66                ) {
67                    (lines.join(" ").trim().to_string(), offset)
68            } else {
69                panic!(
70                    "Could not read comment block on line {}...",
71                    line_cursor.sum_total()
72                )
73            };
74
75            doctree = match doctree.push_data(
76        TreeNodeType::Attribution {
77                    raw_text: attribution_string,
78                }
79            ) {
80                Ok(tree) => tree,
81                Err(tree) => {
82                    return TransitionResult::Failure {
83                        message: format!(
84                            "Node insertion error on line {}. Computer says no...",
85                            line_cursor.sum_total()
86                        ),
87                        doctree: tree,
88                    }
89                }
90            };
91            doctree = doctree.focus_on_parent();
92
93            TransitionResult::Success {
94                doctree: doctree,
95                push_or_pop: PushOrPop::Pop,
96                line_advance: LineAdvance::Some(offset),
97            }
98        }
99        IndentationMatch::TooMuch => {
100            // Create another block quote
101            doctree = match doctree.push_data_and_focus(
102                TreeNodeType::BlockQuote {
103                    body_indent: attribution_line_indent,
104                }
105            ) {
106                Ok(tree) => tree,
107                Err(tree) => {
108                    return TransitionResult::Failure {
109                        message: format!(
110                            "Node insertion error on line {}. Computer says no...",
111                            line_cursor.sum_total()
112                        ),
113                        doctree: tree,
114                    }
115                }
116            };
117
118            return TransitionResult::Success {
119                doctree: doctree,
120                push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
121                line_advance: LineAdvance::None,
122            };
123        }
124        _ => {
125            doctree = doctree.focus_on_parent();
126            TransitionResult::Success {
127                doctree: doctree,
128                push_or_pop: PushOrPop::Pop,
129                line_advance: LineAdvance::None,
130            }
131        }
132    }
133}