lssg_lib/lmarkdown/
mod.rs1use std::io::Read;
2
3use crate::{char_reader::CharReader, parse_error::ParseError};
4
5mod lexer;
6pub use lexer::*;
7
8pub fn parse_lmarkdown(input: impl Read) -> Result<Vec<Token>, ParseError> {
9 let mut reader = CharReader::new(input);
10
11 let mut tokens = vec![];
12
13 loop {
14 match lexer::read_token(&mut reader)? {
15 Token::EOF => break,
16 t => tokens.push(t),
17 }
18 }
19 let mut reduced_tokens = vec![];
21 for mut token in tokens.into_iter() {
22 if let Some(Token::Paragraph { tokens: a }) = reduced_tokens.last_mut() {
23 if let Token::Paragraph { tokens: b } = &mut token {
24 if let Some(Token::Text { text: text_a }) = a.first_mut() {
25 if let Some(Token::Text { text: text_b }) = b.first_mut() {
26 text_a.push('\n');
27 *text_a += text_b;
28 b.drain(0..1);
29 }
30 }
31 a.append(b);
32 continue;
33 }
34 }
35 reduced_tokens.push(token)
36 }
37
38 Ok(reduced_tokens)
39}
40
41#[cfg(test)]
42mod tests {
43 use std::{collections::HashMap, io::Cursor};
44
45 use toml::Table;
46
47 use crate::html::to_attributes;
48
49 use super::*;
50
51 #[test]
52 fn test_text_that_looks_like_html() {
53 let input = r#"# Rust > c++
54Lots of people say Rust > c++. even though it might be
55< then c++. Who knows?
56<nonclosing>
57This should be text
58"#;
59 let expected = vec![
60 Token::Heading {
61 depth: 1,
62 tokens: vec![Token::Text {
63 text: "Rust > c++".into(),
64 }],
65 },
66 Token::Paragraph {
67 tokens: vec![Token::Text {
68 text: "Lots of people say Rust > c++. even though it might be
69< then c++. Who knows?
70<nonclosing>
71This should be text"
72 .into(),
73 }],
74 },
75 ];
76
77 let reader: Box<dyn Read> = Box::new(Cursor::new(input));
78 let tokens = parse_lmarkdown(reader).unwrap();
79 assert_eq!(tokens, expected);
80 }
81
82 #[test]
83 fn test_comments() {
84 let input = r#"<!--[default]
85title="asdf"
86-->
87<!-- another comment -->
88paragraph <!-- inline comment -->
89<!--
90another comment
91-->
92"#;
93 let mut attributes_table = Table::new();
94 let mut default_table = Table::new();
95 default_table.insert("title".into(), "asdf".into());
96 attributes_table.insert("default".into(), toml::Value::Table(default_table));
97 let expected = vec![
98 Token::Attributes {
99 table: attributes_table,
100 },
101 Token::Comment {
102 raw: " another comment ".into(),
103 },
104 Token::Paragraph {
105 tokens: vec![
106 Token::Text {
107 text: "paragraph ".into(),
108 },
109 Token::Comment {
110 raw: " inline comment ".into(),
111 },
112 ],
113 },
114 Token::Comment {
115 raw: "\nanother comment\n".into(),
116 },
117 ];
118
119 let reader: Box<dyn Read> = Box::new(Cursor::new(input));
120 let tokens = parse_lmarkdown(reader).unwrap();
121 assert_eq!(expected, tokens);
122 }
123
124 #[test]
125 fn test_links() {
126 let input = r#"# A [test](test.com)
127<div>
128[<b>bold</b>](bold.com)
129<a href="link.com">[other](other.com)</a>
130</div>"#;
131 let mut attributes_table = Table::new();
132 let mut default_table = Table::new();
133 default_table.insert("title".into(), "asdf".into());
134 attributes_table.insert("default".into(), toml::Value::Table(default_table));
135 let expected = vec![
136 Token::Heading {
137 depth: 1,
138 tokens: vec![
139 Token::Text { text: "A ".into() },
140 Token::Link {
141 tokens: vec![Token::Text {
142 text: "test".into(),
143 }],
144 href: "test.com".into(),
145 },
146 ],
147 },
148 Token::Html {
149 tag: "div".into(),
150 attributes: HashMap::new(),
151 tokens: vec![
152 Token::Link {
153 tokens: vec![Token::Html {
154 tag: "b".into(),
155 attributes: HashMap::new(),
156 tokens: vec![Token::Text {
157 text: "bold".into(),
158 }],
159 }],
160 href: "bold.com".into(),
161 },
162 Token::Text { text: "\n".into() },
163 Token::Html {
164 tag: "a".into(),
165 attributes: to_attributes([("href", "link.com")]),
166 tokens: vec![Token::Link {
167 tokens: vec![Token::Text {
168 text: "other".into(),
169 }],
170 href: "other.com".into(),
171 }],
172 },
173 ],
174 },
175 ];
176
177 let reader: Box<dyn Read> = Box::new(Cursor::new(input));
178 let tokens = parse_lmarkdown(reader).unwrap();
179 assert_eq!(expected, tokens);
180 }
181}