@@ -11,6 +11,7 @@ use helix_core::{
11 object, pos_at_coords,
11 object, pos_at_coords,
12 regex::{self, Regex, RegexBuilder},
12 regex::{self, Regex, RegexBuilder},
13 search, selection, shellwords, surround, textobject,
13 search, selection, shellwords, surround, textobject,
14 unicode::width::UnicodeWidthChar,
15 unicode::width::UnicodeWidthChar,
15 LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril,
16 LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril,
16 Transaction,
17 Transaction,
@@ -363,6 +364,8 @@ impl MappableCommand {
363 rotate_selection_contents_backward, "Rotate selections contents backward",
364 rotate_selection_contents_backward, "Rotate selections contents backward",
364 expand_selection, "Expand selection to parent syntax node",
365 expand_selection, "Expand selection to parent syntax node",
365 shrink_selection, "Shrink selection to previously expanded syntax node",
366 shrink_selection, "Shrink selection to previously expanded syntax node",
367+ select_next_sibling, "Select the next sibling in the syntax tree",
368+ select_prev_sibling, "Select the previous sibling in the syntax tree",
366 jump_forward, "Jump forward on jumplist",
369 jump_forward, "Jump forward on jumplist",
367 jump_backward, "Jump backward on jumplist",
370 jump_backward, "Jump backward on jumplist",
368 save_selection, "Save the current selection to the jumplist",
371 save_selection, "Save the current selection to the jumplist",
@@ -5502,7 +5505,7 @@ fn expand_selection(cx: &mut Context) {
5502 // save current selection so it can be restored using shrink_selection
5505 // save current selection so it can be restored using shrink_selection
5503 view.object_selections.push(current_selection.clone());
5506 view.object_selections.push(current_selection.clone());
5505− let selection = object::expand_selection(syntax, text, current_selection);
5508+ let selection = object::expand_selection(syntax, text, current_selection.clone());
5506 doc.set_selection(view.id, selection);
5509 doc.set_selection(view.id, selection);
@@ -5528,7 +5531,7 @@ fn shrink_selection(cx: &mut Context) {
5528 // if not previous selection, shrink to first child
5531 // if not previous selection, shrink to first child
5529 if let Some(syntax) = doc.syntax() {
5532 if let Some(syntax) = doc.syntax() {
5530 let text = doc.text().slice(..);
5533 let text = doc.text().slice(..);
5531− let selection = object::shrink_selection(syntax, text, current_selection);
5534+ let selection = object::shrink_selection(syntax, text, current_selection.clone());
5532 doc.set_selection(view.id, selection);
5535 doc.set_selection(view.id, selection);
@@ -5536,6 +5539,33 @@ fn shrink_selection(cx: &mut Context) {
5536 cx.editor.last_motion = Some(Motion(Box::new(motion)));
5539 cx.editor.last_motion = Some(Motion(Box::new(motion)));
5542+fn select_sibling_impl<F>(cx: &mut Context, sibling_fn: &'static F)
5544+ F: Fn(Node) -> Option<Node>,
5546+ let motion = |editor: &mut Editor| {
5547+ let (view, doc) = current!(editor);
5549+ if let Some(syntax) = doc.syntax() {
5550+ let text = doc.text().slice(..);
5551+ let current_selection = doc.selection(view.id);
5553+ object::select_sibling(syntax, text, current_selection.clone(), sibling_fn);
5554+ doc.set_selection(view.id, selection);
5558+ cx.editor.last_motion = Some(Motion(Box::new(motion)));
5561+fn select_next_sibling(cx: &mut Context) {
5562+ select_sibling_impl(cx, &|node| Node::next_sibling(&node))
5565+fn select_prev_sibling(cx: &mut Context) {
5566+ select_sibling_impl(cx, &|node| Node::prev_sibling(&node))
5539fn match_brackets(cx: &mut Context) {
5569fn match_brackets(cx: &mut Context) {
5540 let (view, doc) = current!(cx.editor);
5570 let (view, doc) = current!(cx.editor);