org_rust_parser/element/
plain_list.rs1use crate::node_pool::NodeID;
2use crate::parse::parse_element;
3use crate::types::{Cursor, Expr, ParseOpts, Parseable, Parser, Result};
4
5use crate::element::Item;
6use crate::utils::variant_eq;
7
8use super::{BulletKind, CounterKind};
9
10#[derive(Debug, Clone)]
11pub struct PlainList {
12 pub children: Vec<NodeID>,
13 pub kind: ListKind,
14}
15
16#[derive(Debug, Clone, Copy)]
17pub enum ListKind {
18 Unordered,
19 Ordered(CounterKind),
20 Descriptive,
21}
22
23impl<'a> Parseable<'a> for PlainList {
24 fn parse(
25 parser: &mut Parser<'a>,
26 mut cursor: Cursor<'a>,
27 parent: Option<NodeID>,
28 mut parse_opts: ParseOpts,
29 ) -> Result<NodeID> {
30 let start = cursor.index;
34
35 if !parse_opts.from_list {
36 parse_opts.indentation_level += 1;
37 parse_opts.from_list = true;
38 }
39
40 let original_item_id = Item::parse(parser, cursor, parent, parse_opts)?;
41 let reserve_id = parser.pool.reserve_id();
42
43 let item_node = &mut parser.pool[original_item_id];
44 let kind = if let Expr::Item(item) = &item_node.obj {
45 find_kind(item)
46 } else {
47 unreachable!()
48 };
49 item_node.parent = Some(reserve_id);
50
51 let mut children: Vec<NodeID> = Vec::new();
52 children.push(original_item_id);
53
54 cursor.index = item_node.end;
55
56 while let Ok(element_id) = parse_element(parser, cursor, Some(reserve_id), parse_opts) {
57 let got_obj = &parser.pool[element_id];
58 match &got_obj.obj {
59 Expr::Item(item) => {
60 let item_kind = find_kind(item);
61 if !variant_eq(&item_kind, &kind) {
64 parser.cache.remove(&got_obj.start);
67 break;
68 } else {
69 children.push(element_id);
70 cursor.index = got_obj.end;
71 }
72 }
73 _ => {
74 break;
75 }
76 }
77 }
78 Ok(parser.alloc_with_id(
79 Self { children, kind },
80 start,
81 cursor.index,
82 parent,
83 reserve_id,
84 ))
85 }
86}
87
88fn find_kind(item: &Item) -> ListKind {
89 if let Some(tag) = item.tag {
90 ListKind::Descriptive
91 } else if let BulletKind::Ordered(counter_kind) = item.bullet {
92 ListKind::Ordered(counter_kind)
93 } else {
94 ListKind::Unordered
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use crate::{parse_org, Expr};
101
102 #[test]
103 fn basic_list() {
104 let input = r"
105- one
106";
107
108 let pool = parse_org(input);
109 pool.print_tree();
110 }
111
112 #[test]
113 fn list_two_items() {
114 let input = r"
115- one
116- two
117";
118
119 let pool = parse_org(input);
120 pool.print_tree();
121 }
122
123 #[test]
124 fn list_continued_item() {
125 let input = r"
126- one
127 abcdef
128- two
129";
130
131 let pool = parse_org(input);
132 pool.print_tree();
133 }
134
135 #[test]
136 fn list_space_ending() {
137 let input = r"
138- one
139 abcdef
140- two
141- three
142- four
143
144
145- five
146";
147
148 let pool = parse_org(input);
149 pool.print_tree();
150 }
151
152 #[test]
153 fn list_inconsistent_types() {
154 let input = r"
155- one
156 abcdef
1571. two
1582. three
1593. four
160- five
161- six
162";
163
164 let pool = parse_org(input);
165 pool.print_tree();
166 }
167
168 #[test]
169 fn list_elements_breaking_flow() {
170 let input = r"
171- one
172 abcdef
173- four
174this aint a list baby
175#+begin_src python
176not a list too
177#+end_src
178
179
180- five
181";
182
183 let pool = parse_org(input);
184 pool.print_tree();
185 }
186
187 #[test]
188 fn list_contained_elements() {
189 let input = r"
190- one
191 abcd
192 eif
193 #+begin_example
194 we are eating so good?
195 #+end_example
196
197- two
198";
199
200 let pool = parse_org(input);
201 pool.print_tree();
202 }
203
204 #[test]
205 fn nested_lists_basic() {
206 let input = r"
207- one
208 - two
209- three
210";
211
212 let pool = parse_org(input);
213 pool.print_tree();
214 }
215
216 #[test]
217 fn list_empty() {
218 let input = r"
219-
220-
221-
222-
223";
224
225 let pool = parse_org(input);
226 pool.print_tree();
227 }
228
229 #[test]
230 fn list_numbered_empty() {
231 let input = r"
2321.
2332.
2343.
2354.
236";
237
238 let pool = parse_org(input);
239 pool.print_tree();
240 }
241
242 #[test]
243 fn nested_list_2() {
244 let input = r"
245- one
246 - two
247 - three
248 - four
249- five
250";
251
252 let pool = parse_org(input);
253 pool.print_tree();
254 }
255
256 #[test]
257 fn nested_list_3() {
258 let input = r"
259- one
260 - two
261 - three
262 - four
263- five
264";
265
266 let pool = parse_org(input);
267 pool.print_tree();
268 }
269
270 #[test]
271 fn nested_list_4() {
272 let input = r"
2731. item 1
2742. [X] item 2
275 - some tag :: item 2.1
276";
277
278 let pool = parse_org(input);
279 pool.print_tree();
280 }
281
282 #[test]
283 fn blank_list() {
284 let input = r"1. item 1
285 abcdef
286
287 next one two three four five
288
289 more thangs more thangs more thangs
290 more thangs
291
2922. [X] item 2
293 - aome tag :: item 2.1
294";
295
296 let pool = parse_org(input);
297 pool.print_tree();
298 }
299
300 #[test]
301 fn combined_list() {
302 let input = r"
303- zero
304- one
305
306a*
307";
308 let pool = parse_org(input);
309 pool.print_tree();
310 }
311
312 #[test]
313 fn indent_list_prop() {
314 let input = r"
315- one
316- two
317 - qq
318
319
320 heyy
321";
322 let pool = parse_org(input);
323 pool.print_tree();
324 }
325
326 #[test]
327 fn list_no_item_with_sub_element() {
328 let input = r"- [X]
329 |a|a|a|a|
330
331-
332
333";
334
335 let pool = parse_org(input);
336 pool.print_tree();
337 }
338
339 #[test]
340 fn mixed_list() {
341 let input = r#"1. one
342- two
343"#;
344
345 let pool = parse_org(input);
346 assert_eq!(
347 pool.pool
348 .iter()
349 .filter(|x| matches!(x.obj, Expr::PlainList(_)))
350 .count(),
351 2
352 );
353 }
354}