Skip to main content

textlane_html/actions/hast/
visit.rs

1use textlane_core::hast::{Element, Node};
2
3use crate::models::visit::Visit;
4
5/// Call `visitor` on every element under `node`, in document order, with the tag names of
6/// its element ancestors, outermost first. A `template`'s content is not visited.
7pub fn visit_elements<'a>(
8    node: &mut Node<'a>,
9    mut visitor: impl FnMut(&mut Element<'a>, &[&'a str]) -> Visit,
10) {
11    let mut ancestors: Vec<&'a str> = vec![];
12    // Explicit, as a tree nests as deep as its input does
13    let mut stack: Vec<(&mut Node<'a>, usize)> = vec![(node, 0)];
14    while let Some((node, depth)) = stack.pop() {
15        ancestors.truncate(depth);
16        let children = match node {
17            Node::Root(root) => &mut root.children,
18            Node::Element(element) => {
19                match visitor(element, &ancestors) {
20                    Visit::Stop => return,
21                    Visit::Skip => continue,
22                    Visit::Continue => {}
23                }
24                ancestors.push(element.tag_name);
25                &mut element.children
26            }
27            _ => continue,
28        };
29        let depth = ancestors.len();
30        for child in children.iter_mut().rev() {
31            stack.push((child, depth));
32        }
33    }
34}
35
36#[cfg(test)]
37#[path = "visit_unit.rs"]
38mod unit;