Skip to main content

snapper_fmt/parser/
plaintext.rs

1use crate::parser::{FormatParser, Region};
2
3/// Trivial parser: everything is prose, blank lines are preserved.
4pub struct PlaintextParser;
5
6impl FormatParser for PlaintextParser {
7    fn parse(&self, input: &str) -> Vec<Region> {
8        let mut regions = Vec::new();
9        let mut current_prose = String::new();
10        let mut pragma_off = false;
11
12        for line in input.lines() {
13            // Check for snapper:off/on pragmas
14            if let Some(on) = super::check_pragma(line) {
15                if !current_prose.is_empty() {
16                    regions.push(Region::Prose(current_prose.clone()));
17                    current_prose.clear();
18                }
19                pragma_off = !on;
20                regions.push(Region::Structure(format!("{line}\n")));
21                continue;
22            }
23
24            if pragma_off {
25                if !current_prose.is_empty() {
26                    regions.push(Region::Prose(current_prose.clone()));
27                    current_prose.clear();
28                }
29                regions.push(Region::Structure(format!("{line}\n")));
30                continue;
31            }
32
33            if line.trim().is_empty() {
34                // Flush accumulated prose
35                if !current_prose.is_empty() {
36                    regions.push(Region::Prose(current_prose.clone()));
37                    current_prose.clear();
38                }
39                regions.push(Region::BlankLines(format!("{line}\n")));
40            } else {
41                if !current_prose.is_empty() {
42                    current_prose.push(' ');
43                }
44                current_prose.push_str(line.trim());
45            }
46        }
47
48        // Flush remaining prose
49        if !current_prose.is_empty() {
50            regions.push(Region::Prose(current_prose));
51        }
52
53        regions
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn simple_paragraph() {
63        let input = "Hello world. This is a test.\nAnother line here.";
64        let regions = PlaintextParser.parse(input);
65        assert_eq!(
66            regions,
67            vec![Region::Prose(
68                "Hello world. This is a test. Another line here.".to_string()
69            )]
70        );
71    }
72
73    #[test]
74    fn two_paragraphs() {
75        let input = "First paragraph.\n\nSecond paragraph.";
76        let regions = PlaintextParser.parse(input);
77        assert_eq!(
78            regions,
79            vec![
80                Region::Prose("First paragraph.".to_string()),
81                Region::BlankLines("\n".to_string()),
82                Region::Prose("Second paragraph.".to_string()),
83            ]
84        );
85    }
86
87    #[test]
88    fn empty_input() {
89        let regions = PlaintextParser.parse("");
90        assert!(regions.is_empty());
91    }
92}