Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-core/src/syntax/tree_cursor.rs')
| -rw-r--r-- | helix-core/src/syntax/tree_cursor.rs | 118 |
1 files changed, 111 insertions, 7 deletions
diff --git a/helix-core/src/syntax/tree_cursor.rs b/helix-core/src/syntax/tree_cursor.rs index d9d140c9..692d5890 100644 --- a/helix-core/src/syntax/tree_cursor.rs +++ b/helix-core/src/syntax/tree_cursor.rs @@ -90,6 +90,19 @@ impl<'a> TreeCursor<'a> { true } + pub fn goto_parent_with<P>(&mut self, predicate: P) -> bool + where + P: Fn(&Node) -> bool, + { + while self.goto_parent() { + if predicate(&self.node()) { + return true; + } + } + + false + } + /// Finds the injection layer that has exactly the same range as the given `range`. fn layer_id_of_byte_range(&self, search_range: Range<usize>) -> Option<LayerId> { let start_idx = self @@ -102,7 +115,7 @@ impl<'a> TreeCursor<'a> { .find_map(|range| (range.start == search_range.start).then_some(range.layer_id)) } - pub fn goto_first_child(&mut self) -> bool { + fn goto_first_child_impl(&mut self, named: bool) -> bool { // Check if the current node's range is an exact injection layer range. if let Some(layer_id) = self .layer_id_of_byte_range(self.node().byte_range()) @@ -111,8 +124,16 @@ impl<'a> TreeCursor<'a> { // Switch to the child layer. self.current = layer_id; self.cursor = self.layers[self.current].tree().root_node(); - true - } else if let Some(child) = self.cursor.child(0) { + return true; + } + + let child = if named { + self.cursor.named_child(0) + } else { + self.cursor.child(0) + }; + + if let Some(child) = child { // Otherwise descend in the current tree. self.cursor = child; true @@ -121,8 +142,22 @@ impl<'a> TreeCursor<'a> { } } - pub fn goto_next_sibling(&mut self) -> bool { - if let Some(sibling) = self.cursor.next_sibling() { + pub fn goto_first_child(&mut self) -> bool { + self.goto_first_child_impl(false) + } + + pub fn goto_first_named_child(&mut self) -> bool { + self.goto_first_child_impl(true) + } + + fn goto_next_sibling_impl(&mut self, named: bool) -> bool { + let sibling = if named { + self.cursor.next_named_sibling() + } else { + self.cursor.next_sibling() + }; + + if let Some(sibling) = sibling { self.cursor = sibling; true } else { @@ -130,8 +165,22 @@ impl<'a> TreeCursor<'a> { } } - pub fn goto_prev_sibling(&mut self) -> bool { - if let Some(sibling) = self.cursor.prev_sibling() { + pub fn goto_next_sibling(&mut self) -> bool { + self.goto_next_sibling_impl(false) + } + + pub fn goto_next_named_sibling(&mut self) -> bool { + self.goto_next_sibling_impl(true) + } + + fn goto_prev_sibling_impl(&mut self, named: bool) -> bool { + let sibling = if named { + self.cursor.prev_named_sibling() + } else { + self.cursor.prev_sibling() + }; + + if let Some(sibling) = sibling { self.cursor = sibling; true } else { @@ -139,6 +188,14 @@ impl<'a> TreeCursor<'a> { } } + pub fn goto_prev_sibling(&mut self) -> bool { + self.goto_prev_sibling_impl(false) + } + + pub fn goto_prev_named_sibling(&mut self) -> bool { + self.goto_prev_sibling_impl(true) + } + /// Finds the injection layer that contains the given start-end range. fn layer_id_containing_byte_range(&self, start: usize, end: usize) -> LayerId { let start_idx = self @@ -157,4 +214,51 @@ impl<'a> TreeCursor<'a> { let root = self.layers[self.current].tree().root_node(); self.cursor = root.descendant_for_byte_range(start, end).unwrap_or(root); } + + /// Returns an iterator over the children of the node the TreeCursor is on + /// at the time this is called. + pub fn children(&'a mut self) -> ChildIter { + let parent = self.node(); + + ChildIter { + cursor: self, + parent, + named: false, + } + } + + /// Returns an iterator over the named children of the node the TreeCursor is on + /// at the time this is called. + pub fn named_children(&'a mut self) -> ChildIter { + let parent = self.node(); + + ChildIter { + cursor: self, + parent, + named: true, + } + } +} + +pub struct ChildIter<'n> { + cursor: &'n mut TreeCursor<'n>, + parent: Node<'n>, + named: bool, +} + +impl<'n> Iterator for ChildIter<'n> { + type Item = Node<'n>; + + fn next(&mut self) -> Option<Self::Item> { + // first iteration, just visit the first child + if self.cursor.node() == self.parent { + self.cursor + .goto_first_child_impl(self.named) + .then(|| self.cursor.node()) + } else { + self.cursor + .goto_next_sibling_impl(self.named) + .then(|| self.cursor.node()) + } + } } |