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.rs | 159 |
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) + } }) } |