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.rs159
1 files changed, 51 insertions, 108 deletions
diff --git a/helix-core/src/object.rs b/helix-core/src/object.rs
index e0c02d0a..b06f4144 100644
--- a/helix-core/src/object.rs
+++ b/helix-core/src/object.rs
@@ -1,134 +1,77 @@
-use crate::{movement::Direction, syntax::TreeCursor, Range, RopeSlice, Selection, Syntax};
+use crate::{Range, RopeSlice, Selection, Syntax};
+use tree_sitter::Node;
pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
- let cursor = &mut syntax.walk();
-
- selection.transform(|range| {
- let from = text.char_to_byte(range.from()) as u32;
- let to = text.char_to_byte(range.to()) as u32;
-
- let byte_range = from..to;
- cursor.reset_to_byte_range(from, to);
-
- while cursor.node().byte_range() == byte_range {
- if !cursor.goto_parent() {
- break;
- }
+ select_node_impl(syntax, text, selection, |descendant, from, to| {
+ if descendant.start_byte() == from && descendant.end_byte() == to {
+ descendant.parent()
+ } else {
+ Some(descendant)
}
-
- let node = cursor.node();
- let from = text.byte_to_char(node.start_byte() as usize);
- let to = text.byte_to_char(node.end_byte() as usize);
-
- Range::new(to, from).with_direction(range.direction())
})
}
pub fn shrink_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
- select_node_impl(
- syntax,
- text,
- selection,
- |cursor| {
- cursor.goto_first_child();
- },
- None,
- )
-}
-
-pub fn select_next_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
- select_node_impl(
- syntax,
- text,
- selection,
- |cursor| {
- while !cursor.goto_next_sibling() {
- if !cursor.goto_parent() {
- break;
- }
- }
- },
- Some(Direction::Forward),
- )
-}
-
-pub fn select_all_siblings(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
- let mut cursor = syntax.walk();
- selection.transform_iter(move |range| {
- let (from, to) = range.into_byte_range(text);
- cursor.reset_to_byte_range(from as u32, to as u32);
-
- if !cursor.goto_parent_with(|parent| parent.child_count() > 1) {
- return vec![range].into_iter();
- }
-
- select_children(&mut cursor, text, range).into_iter()
+ select_node_impl(syntax, text, selection, |descendant, _from, _to| {
+ descendant.child(0).or(Some(descendant))
})
}
-pub fn select_all_children(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
- let mut cursor = syntax.walk();
- selection.transform_iter(move |range| {
- let (from, to) = range.into_byte_range(text);
- cursor.reset_to_byte_range(from as u32, to as u32);
- select_children(&mut cursor, text, range).into_iter()
+pub fn select_sibling<F>(
+ syntax: &Syntax,
+ text: RopeSlice,
+ selection: Selection,
+ sibling_fn: &F,
+) -> Selection
+where
+ F: Fn(Node) -> Option<Node>,
+{
+ select_node_impl(syntax, text, selection, |descendant, _from, _to| {
+ find_sibling_recursive(descendant, sibling_fn)
})
}
-fn select_children(cursor: &mut TreeCursor, text: RopeSlice, range: Range) -> Vec<Range> {
- let children = cursor
- .children()
- .filter(|child| child.is_named())
- .map(|child| Range::from_node(child, text, range.direction()))
- .collect::<Vec<_>>();
-
- if !children.is_empty() {
- children
- } else {
- vec![range]
- }
-}
-
-pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
- select_node_impl(
- syntax,
- text,
- selection,
- |cursor| {
- while !cursor.goto_previous_sibling() {
- if !cursor.goto_parent() {
- break;
- }
- }
- },
- Some(Direction::Backward),
- )
+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))
+ })
}
fn select_node_impl<F>(
syntax: &Syntax,
text: RopeSlice,
selection: Selection,
- motion: F,
- direction: Option<Direction>,
+ select_fn: F,
) -> Selection
where
- F: Fn(&mut TreeCursor),
+ F: Fn(Node, usize, usize) -> Option<Node>,
{
- let cursor = &mut syntax.walk();
+ let tree = syntax.tree();
selection.transform(|range| {
- let from = text.char_to_byte(range.from()) as u32;
- let to = text.char_to_byte(range.to()) as u32;
-
- cursor.reset_to_byte_range(from, to);
-
- motion(cursor);
-
- let node = cursor.node();
- let from = text.byte_to_char(node.start_byte() as usize);
- let to = text.byte_to_char(node.end_byte() as usize);
-
- Range::new(from, to).with_direction(direction.unwrap_or_else(|| range.direction()))
+ let from = text.char_to_byte(range.from());
+ let to = text.char_to_byte(range.to());
+
+ let node = match tree
+ .root_node()
+ .descendant_for_byte_range(from, to)
+ .and_then(|node| select_fn(node, from, to))
+ {
+ Some(node) => node,
+ None => return range,
+ };
+
+ let from = text.byte_to_char(node.start_byte());
+ let to = text.byte_to_char(node.end_byte());
+
+ if range.head < range.anchor {
+ Range::new(to, from)
+ } else {
+ Range::new(from, to)
+ }
})
}