Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--helix-core/src/object.rs111
-rw-r--r--helix-core/src/selection.rs7
-rw-r--r--helix-term/tests/test/commands/movement.rs21
3 files changed, 68 insertions, 71 deletions
diff --git a/helix-core/src/object.rs b/helix-core/src/object.rs
index e0c02d0a..02e72859 100644
--- a/helix-core/src/object.rs
+++ b/helix-core/src/object.rs
@@ -25,38 +25,59 @@ pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection)
}
pub fn shrink_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
- select_node_impl(
- syntax,
- text,
- selection,
- |cursor| {
- cursor.goto_first_child();
- },
- None,
- )
+ selection.transform(move |range| {
+ let (from, to) = range.into_byte_range(text);
+ let mut cursor = syntax.walk();
+ cursor.reset_to_byte_range(from, to);
+
+ if let Some(node) = cursor
+ .into_iter()
+ .find(|node| node.is_named() && node.is_contained_within(from..to))
+ {
+ return Range::from_node(node, text, range.direction());
+ }
+
+ range
+ })
}
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;
- }
+ selection.transform(move |range| {
+ let (from, to) = range.into_byte_range(text);
+ let mut cursor = syntax.walk();
+ cursor.reset_to_byte_range(from, to);
+
+ while !cursor.goto_next_sibling() {
+ if !cursor.goto_parent() {
+ return range;
}
- },
- Some(Direction::Forward),
- )
+ }
+
+ Range::from_node(cursor.node(), text, Direction::Forward)
+ })
+}
+
+pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
+ selection.transform(move |range| {
+ let (from, to) = range.into_byte_range(text);
+ let mut cursor = syntax.walk();
+ cursor.reset_to_byte_range(from, to);
+
+ while !cursor.goto_previous_sibling() {
+ if !cursor.goto_parent() {
+ return range;
+ }
+ }
+
+ Range::from_node(cursor.node(), text, Direction::Backward)
+ })
}
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);
+ cursor.reset_to_byte_range(from, to);
if !cursor.goto_parent_with(|parent| parent.child_count() > 1) {
return vec![range].into_iter();
@@ -70,7 +91,7 @@ pub fn select_all_children(syntax: &Syntax, text: RopeSlice, selection: Selectio
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);
+ cursor.reset_to_byte_range(from, to);
select_children(&mut cursor, text, range).into_iter()
})
}
@@ -88,47 +109,3 @@ fn select_children(cursor: &mut TreeCursor, text: RopeSlice, range: Range) -> Ve
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 select_node_impl<F>(
- syntax: &Syntax,
- text: RopeSlice,
- selection: Selection,
- motion: F,
- direction: Option<Direction>,
-) -> Selection
-where
- F: Fn(&mut TreeCursor),
-{
- 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;
-
- 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()))
- })
-}
diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs
index 5bde08e3..1cc64c91 100644
--- a/helix-core/src/selection.rs
+++ b/helix-core/src/selection.rs
@@ -387,8 +387,11 @@ impl Range {
/// Converts this char range into an in order byte range, discarding
/// direction.
- pub fn into_byte_range(&self, text: RopeSlice) -> (usize, usize) {
- (text.char_to_byte(self.from()), text.char_to_byte(self.to()))
+ pub fn into_byte_range(&self, text: RopeSlice) -> (u32, u32) {
+ (
+ text.char_to_byte(self.from()) as u32,
+ text.char_to_byte(self.to()) as u32,
+ )
}
}
diff --git a/helix-term/tests/test/commands/movement.rs b/helix-term/tests/test/commands/movement.rs
index 93218be8..dd5a3bee 100644
--- a/helix-term/tests/test/commands/movement.rs
+++ b/helix-term/tests/test/commands/movement.rs
@@ -1039,15 +1039,32 @@ async fn expand_shrink_selection() -> anyhow::Result<()> {
// shrink with no expansion history defaults to first child
(
indoc! {r##"
+ #[(
+ Some(thing),
+ Some(other_thing),
+ )|]#
+ "##},
+ "<A-i>",
+ indoc! {r##"
(
#[Some(thing)|]#,
Some(other_thing),
)
"##},
- "<A-i>",
+ ),
+ // any movement cancels selection history and falls back to first child
+ (
+ indoc! {r##"
+ (
+ Some(#[thing|]#),
+ Some(#(other_thing|)#),
+ )
+
+ "##},
+ "<A-o><A-o><A-o>jkvkkk<A-i>",
indoc! {r##"
(
- #[Some|]#(thing),
+ #[|Some(thing)]#,
Some(other_thing),
)
"##},