Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-core/src/object.rs')
-rw-r--r--helix-core/src/object.rs62
1 files changed, 61 insertions, 1 deletions
diff --git a/helix-core/src/object.rs b/helix-core/src/object.rs
index 0df105f1..9593b882 100644
--- a/helix-core/src/object.rs
+++ b/helix-core/src/object.rs
@@ -1,4 +1,5 @@
-use crate::{syntax::TreeCursor, Range, RopeSlice, Selection, Syntax};
+use crate::{movement::Direction, syntax::TreeCursor, Range, RopeSlice, Selection, Syntax};
+use tree_sitter::{Node, Tree};
pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
let cursor = &mut syntax.walk();
@@ -40,6 +41,65 @@ pub fn select_next_sibling(syntax: &Syntax, text: RopeSlice, selection: Selectio
})
}
+fn find_parent_with_more_children(mut node: Node) -> Option<Node> {
+ while let Some(parent) = node.parent() {
+ if parent.child_count() > 1 {
+ return Some(parent);
+ }
+
+ node = parent;
+ }
+
+ None
+}
+
+pub fn select_all_siblings(tree: &Tree, text: RopeSlice, selection: Selection) -> Selection {
+ let root_node = &tree.root_node();
+
+ selection.transform_iter(|range| {
+ let from = text.char_to_byte(range.from());
+ let to = text.char_to_byte(range.to());
+
+ root_node
+ .descendant_for_byte_range(from, to)
+ .and_then(find_parent_with_more_children)
+ .map(|parent| select_children(parent, text, range.direction()))
+ .unwrap_or_else(|| vec![range].into_iter())
+ })
+}
+
+fn select_children(
+ node: Node,
+ text: RopeSlice,
+ direction: Direction,
+) -> <Vec<Range> as std::iter::IntoIterator>::IntoIter {
+ let mut cursor = node.walk();
+
+ node.named_children(&mut cursor)
+ .map(|child| {
+ let from = text.byte_to_char(child.start_byte());
+ let to = text.byte_to_char(child.end_byte());
+
+ if direction == Direction::Backward {
+ Range::new(to, from)
+ } else {
+ Range::new(from, to)
+ }
+ })
+ .collect::<Vec<_>>()
+ .into_iter()
+}
+
+fn find_sibling_recursive<F>(node: Node, sibling_fn: F) -> Option<Node>
+where
+ F: Fn(Node) -> Option<Node>,
+{
+ sibling_fn(node).or_else(|| {
+ node.parent()
+ .and_then(|node| find_sibling_recursive(node, sibling_fn))
+ })
+}
+
pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
select_node_impl(syntax, text, selection, |cursor| {
while !cursor.goto_prev_sibling() {