@@ -11,6 +11,7 @@ use helix_core::{
1111 object, pos_at_coords,
1212 regex::{self, Regex, RegexBuilder},
1313 search, selection, shellwords, surround, textobject,
14+ tree_sitter::Node,
1415 unicode::width::UnicodeWidthChar,
1516 LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril,
1617 Transaction,
@@ -363,6 +364,8 @@ impl MappableCommand {
363364 rotate_selection_contents_backward, "Rotate selections contents backward",
364365 expand_selection, "Expand selection to parent syntax node",
365366 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",
366369 jump_forward, "Jump forward on jumplist",
367370 jump_backward, "Jump backward on jumplist",
368371 save_selection, "Save the current selection to the jumplist",
@@ -5502,7 +5505,7 @@ fn expand_selection(cx: &mut Context) {
55025505 // save current selection so it can be restored using shrink_selection
55035506 view.object_selections.push(current_selection.clone());
55045507
5505− let selection = object::expand_selection(syntax, text, current_selection);
5508+ let selection = object::expand_selection(syntax, text, current_selection.clone());
55065509 doc.set_selection(view.id, selection);
55075510 }
55085511 };
@@ -5528,7 +5531,7 @@ fn shrink_selection(cx: &mut Context) {
55285531 // if not previous selection, shrink to first child
55295532 if let Some(syntax) = doc.syntax() {
55305533 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());
55325535 doc.set_selection(view.id, selection);
55335536 }
55345537 };
@@ -5536,6 +5539,33 @@ fn shrink_selection(cx: &mut Context) {
55365539 cx.editor.last_motion = Some(Motion(Box::new(motion)));
55375540}
55385541
5542+fn select_sibling_impl<F>(cx: &mut Context, sibling_fn: &'static F)
5543+where
5544+ F: Fn(Node) -> Option<Node>,
5545+{
5546+ let motion = |editor: &mut Editor| {
5547+ let (view, doc) = current!(editor);
5548+
5549+ if let Some(syntax) = doc.syntax() {
5550+ let text = doc.text().slice(..);
5551+ let current_selection = doc.selection(view.id);
5552+ let selection =
5553+ object::select_sibling(syntax, text, current_selection.clone(), sibling_fn);
5554+ doc.set_selection(view.id, selection);
5555+ }
5556+ };
5557+ motion(cx.editor);
5558+ cx.editor.last_motion = Some(Motion(Box::new(motion)));
5559+}
5560+
5561+fn select_next_sibling(cx: &mut Context) {
5562+ select_sibling_impl(cx, &|node| Node::next_sibling(&node))
5563+}
5564+
5565+fn select_prev_sibling(cx: &mut Context) {
5566+ select_sibling_impl(cx, &|node| Node::prev_sibling(&node))
5567+}
5568+
55395569fn match_brackets(cx: &mut Context) {
55405570 let (view, doc) = current!(cx.editor);
55415571