text_document_common/parser_tools/
list_grouper.rs1use crate::entities::ListStyle;
2use crate::types::EntityId;
3
4#[derive(Default)]
10pub struct ListGrouper {
11 active: Vec<Option<(EntityId, ListStyle)>>,
13}
14
15impl ListGrouper {
16 pub fn new() -> Self {
17 Self::default()
18 }
19
20 pub fn try_reuse(&mut self, style: &ListStyle, indent: u32) -> Option<EntityId> {
24 let idx = indent as usize;
25 self.active.truncate(idx + 1);
27 if let Some(Some((id, existing_style))) = self.active.get(idx)
28 && existing_style == style
29 {
30 return Some(*id);
31 }
32 None
33 }
34
35 pub fn register(&mut self, id: EntityId, style: ListStyle, indent: u32) {
37 let idx = indent as usize;
38 while self.active.len() <= idx {
39 self.active.push(None);
40 }
41 self.active[idx] = Some((id, style));
42 }
43
44 pub fn reset(&mut self) {
46 self.active.clear();
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn first_item_returns_none() {
56 let mut g = ListGrouper::new();
57 assert!(g.try_reuse(&ListStyle::Decimal, 0).is_none());
58 }
59
60 #[test]
61 fn consecutive_same_style_reuses() {
62 let mut g = ListGrouper::new();
63 g.register(42, ListStyle::Decimal, 0);
64 assert_eq!(g.try_reuse(&ListStyle::Decimal, 0), Some(42));
65 }
66
67 #[test]
68 fn different_style_creates_new() {
69 let mut g = ListGrouper::new();
70 g.register(42, ListStyle::Decimal, 0);
71 assert!(g.try_reuse(&ListStyle::Disc, 0).is_none());
72 }
73
74 #[test]
75 fn different_indent_creates_new() {
76 let mut g = ListGrouper::new();
77 g.register(42, ListStyle::Decimal, 0);
78 assert!(g.try_reuse(&ListStyle::Decimal, 1).is_none());
79 }
80
81 #[test]
82 fn reset_clears_all() {
83 let mut g = ListGrouper::new();
84 g.register(42, ListStyle::Decimal, 0);
85 g.reset();
86 assert!(g.try_reuse(&ListStyle::Decimal, 0).is_none());
87 }
88
89 #[test]
90 fn nested_indent_resumes_outer() {
91 let mut g = ListGrouper::new();
92 g.register(10, ListStyle::Decimal, 0);
93 g.register(20, ListStyle::LowerAlpha, 1);
94 assert_eq!(g.try_reuse(&ListStyle::Decimal, 0), Some(10));
96 }
97
98 #[test]
99 fn nested_indent_different_style_creates_new() {
100 let mut g = ListGrouper::new();
101 g.register(10, ListStyle::Decimal, 0);
102 g.register(20, ListStyle::LowerAlpha, 1);
103 assert!(g.try_reuse(&ListStyle::Disc, 0).is_none());
105 }
106}