1use crate::{
3 parser::ast::Node,
4 trim::{TrimHint, TrimState},
5};
6
7#[derive(Debug)]
9pub struct NodeEvent<'a> {
10 pub node: &'a Node<'a>,
12 pub trim: TrimState,
14 pub first: bool,
16 pub last: bool,
18}
19
20impl<'a> NodeEvent<'a> {
21 pub fn new(
23 node: &'a Node,
24 trim: TrimState,
25 first: bool,
26 last: bool,
27 ) -> Self {
28 Self {
29 node,
30 trim,
31 first,
32 last,
33 }
34 }
35}
36
37pub struct BranchIter<'source> {
42 node: &'source Node<'source>,
43 children: Option<std::slice::Iter<'source, Node<'source>>>,
44}
45
46impl<'source> BranchIter<'source> {
47 pub fn new(node: &'source Node) -> Self {
49 Self {
50 node,
51 children: None,
52 }
53 }
54
55 pub fn event(self, hint: Option<TrimHint>) -> EventIter<'source> {
61 EventIter::new(self, hint)
62 }
63}
64
65impl<'source> Iterator for BranchIter<'source> {
66 type Item = &'source Node<'source>;
67
68 fn next(&mut self) -> Option<Self::Item> {
69 let iter = match *self.node {
70 Node::Document(ref node) => {
71 Some(self.children.get_or_insert(node.nodes().iter()))
72 }
73 Node::Block(ref node) => {
74 Some(self.children.get_or_insert(node.nodes().iter()))
75 }
76 Node::Text(_)
77 | Node::Link(_)
78 | Node::Statement(_)
79 | Node::RawStatement(_)
80 | Node::RawComment(_)
81 | Node::Comment(_) => None,
82 };
83
84 if let Some(it) = iter {
85 let child = it.next();
86 if child.is_none() {
87 self.children.take();
88 }
89 child
90 } else {
91 None
92 }
93 }
94}
95
96pub struct EventIter<'source> {
105 iter: std::iter::Peekable<BranchIter<'source>>,
106 prev_trim_after: Option<bool>,
107 hint: Option<TrimHint>,
108}
109
110impl<'source> EventIter<'source> {
111 pub(crate) fn new(
113 nodes: BranchIter<'source>,
114 hint: Option<TrimHint>,
115 ) -> Self {
116 let iter = nodes.peekable();
117 Self {
118 iter,
119 hint,
120 prev_trim_after: None,
121 }
122 }
123}
124
125impl<'source> Iterator for EventIter<'source> {
126 type Item = NodeEvent<'source>;
127
128 fn next(&mut self) -> Option<Self::Item> {
129 let node = self.iter.next();
130 let peek = self.iter.peek();
131
132 let first = self.prev_trim_after.is_none();
133
134 let start = if let Some(trim_after) = self.prev_trim_after.take() {
136 trim_after
138 } else {
139 if let Some(hint) = self.hint.take() {
140 hint.after
141 } else {
142 false
143 }
144 };
145
146 let mut end = false;
148 if let Some(next) = peek {
149 if next.trim().before {
150 end = true;
151 }
152 }
153
154 if let Some(ref current) = node {
155 self.prev_trim_after = Some(current.trim().after);
156
157 let should_clear_trim = match current {
161 Node::Block(_) => true,
162 _ => false,
163 };
164
165 if should_clear_trim {
166 self.prev_trim_after = None;
167 }
168 }
169
170 let state = TrimState::from((start, end));
171
172 node.map(|n| NodeEvent::new(n, state, first, peek.is_none()))
173 }
174}