diff --git a/helix-core/src/object.rs b/helix-core/src/object.rs index 28629235fa58..17a393caf277 100644 --- a/helix-core/src/object.rs +++ b/helix-core/src/object.rs @@ -1,4 +1,4 @@ -use crate::{syntax::TreeCursor, Range, RopeSlice, Selection, Syntax}; +use crate::{movement::Direction, syntax::TreeCursor, Range, RopeSlice, Selection, Syntax}; pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { let cursor = &mut syntax.walk(); @@ -25,19 +25,31 @@ 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(); - }) + 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; + 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 { @@ -81,13 +93,19 @@ fn select_children<'n>( } pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { - select_node_impl(syntax, text, selection, |cursor| { - while !cursor.goto_prev_sibling() { - if !cursor.goto_parent() { - break; + select_node_impl( + syntax, + text, + selection, + |cursor| { + while !cursor.goto_prev_sibling() { + if !cursor.goto_parent() { + break; + } } - } - }) + }, + Some(Direction::Backward), + ) } fn select_node_impl( @@ -95,6 +113,7 @@ fn select_node_impl( text: RopeSlice, selection: Selection, motion: F, + direction: Option, ) -> Selection where F: Fn(&mut TreeCursor), @@ -113,6 +132,6 @@ where let from = text.byte_to_char(node.start_byte()); let to = text.byte_to_char(node.end_byte()); - Range::new(from, to).with_direction(range.direction()) + Range::new(from, to).with_direction(direction.unwrap_or_else(|| range.direction())) }) } diff --git a/helix-term/tests/test/commands/movement.rs b/helix-term/tests/test/commands/movement.rs index 1f33b3944200..b2471f6359bb 100644 --- a/helix-term/tests/test/commands/movement.rs +++ b/helix-term/tests/test/commands/movement.rs @@ -726,3 +726,83 @@ async fn select_all_children() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn test_select_next_sibling() -> anyhow::Result<()> { + let tests = vec![ + // basic test + ( + indoc! {r##" + fn inc(x: usize) -> usize { x + 1 #[}|]# + fn dec(x: usize) -> usize { x - 1 } + fn ident(x: usize) -> usize { x } + "##}, + "", + indoc! {r##" + fn inc(x: usize) -> usize { x + 1 } + #[fn dec(x: usize) -> usize { x - 1 }|]# + fn ident(x: usize) -> usize { x } + "##}, + ), + // direction is not preserved and is always forward. + ( + indoc! {r##" + fn inc(x: usize) -> usize { x + 1 #[}|]# + fn dec(x: usize) -> usize { x - 1 } + fn ident(x: usize) -> usize { x } + "##}, + "", + indoc! {r##" + fn inc(x: usize) -> usize { x + 1 } + fn dec(x: usize) -> usize { x - 1 } + #[fn ident(x: usize) -> usize { x }|]# + "##}, + ), + ]; + + for test in tests { + test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_select_prev_sibling() -> anyhow::Result<()> { + let tests = vec![ + // basic test + ( + indoc! {r##" + fn inc(x: usize) -> usize { x + 1 } + fn dec(x: usize) -> usize { x - 1 } + #[|f]#n ident(x: usize) -> usize { x } + "##}, + "", + indoc! {r##" + fn inc(x: usize) -> usize { x + 1 } + #[|fn dec(x: usize) -> usize { x - 1 }]# + fn ident(x: usize) -> usize { x } + "##}, + ), + // direction is not preserved and is always backward. + ( + indoc! {r##" + fn inc(x: usize) -> usize { x + 1 } + fn dec(x: usize) -> usize { x - 1 } + #[|f]#n ident(x: usize) -> usize { x } + "##}, + "", + indoc! {r##" + #[|fn inc(x: usize) -> usize { x + 1 }]# + fn dec(x: usize) -> usize { x - 1 } + fn ident(x: usize) -> usize { x } + "##}, + ), + ]; + + for test in tests { + test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?; + } + + Ok(()) +} diff --git a/helix-term/tests/test/movement.rs b/helix-term/tests/test/movement.rs index 9ecaf6bb094f..3fa850929dd2 100644 --- a/helix-term/tests/test/movement.rs +++ b/helix-term/tests/test/movement.rs @@ -666,7 +666,7 @@ async fn tree_sitter_motions_work_across_injections() -> anyhow::Result<()> { ( "", "", - "", + "", ), ) .await?;