markdown_utils/
parsers.rs

1pub struct MarkdownLineByLineSkippingCodeblocksParser<'a> {
2    lines_iterator: std::str::Lines<'a>,
3    current_fenced_codeblock_delimiter: String,
4}
5
6impl MarkdownLineByLineSkippingCodeblocksParser<'_> {
7    pub fn new(text: &str) -> MarkdownLineByLineSkippingCodeblocksParser {
8        MarkdownLineByLineSkippingCodeblocksParser {
9            lines_iterator: text.lines(),
10            current_fenced_codeblock_delimiter: "".to_string(), 
11        }
12    }
13}
14
15impl Iterator for MarkdownLineByLineSkippingCodeblocksParser<'_> {
16    type Item = String;
17
18    fn next(&mut self) -> Option<String> {
19        let line = self.lines_iterator.next();
20        if line == None {
21            return None;
22        }
23        if self.current_fenced_codeblock_delimiter == "" {
24            let trimmed_line = line?.trim();
25            if trimmed_line.starts_with("```") || trimmed_line.starts_with("~~~") {
26                // enter fenced codeblock
27                self.current_fenced_codeblock_delimiter =
28                    trimmed_line[0..3].to_string();
29            } else if !line?.starts_with("    ") || line?.starts_with("     ") {
30                // don't enter indented code block (4 spaces)
31                // but yes in nested content (+4 spaces)
32                return Some(line?.to_string());
33            } else {
34                return self.next();
35            }
36        } else if line?.trim_start().starts_with(
37            &self.current_fenced_codeblock_delimiter
38        ) {
39            self.current_fenced_codeblock_delimiter = "".to_string();
40        }
41        return self.next();
42    }
43}