vim: Ensure surrounding markers contain cursor for Helix surround operations (#47163)

Closes #47155, introduced by #44317

I naively trusted `crates/vim/src/object.rs:1624`'s
`surrounding_markers` to check whether the cursor is actually
surrounded, but it has nearest match fallback behavior, apparently by
design as indicated by `test_anyquotes_object` in the same file.

Release Notes:

- Fixed Helix surround operations falling back to closest match if
cursor not surrounded

Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
This commit is contained in:
Leon QadirieandJakub Konka authored and GitHub committed 2026-04-23 18:45:26 +00:00
1 parent 1bf35a3655
commit d21b897862
1 file changed
+62 -6
+62 -6
View File
@@ -37,6 +37,24 @@ fn find_nearest_surrounding_pair(
best_pair
}
fn surrounding_markers_containing_cursor(
display_map: &DisplaySnapshot,
cursor: DisplayPoint,
open_marker: char,
close_marker: char,
) -> Option<std::ops::Range<DisplayPoint>> {
let range = surrounding_markers(display_map, cursor, true, true, open_marker, close_marker)?;
let cursor_offset = cursor.to_offset(display_map, Bias::Left);
let start_offset = range.start.to_offset(display_map, Bias::Left);
let end_offset = range.end.to_offset(display_map, Bias::Right);
if cursor_offset >= start_offset && cursor_offset <= end_offset {
Some(range)
} else {
None
}
}
fn selection_cursor(map: &DisplaySnapshot, selection: &Selection<DisplayPoint>) -> DisplayPoint {
if selection.reversed || selection.is_empty() {
selection.head()
@@ -134,9 +152,12 @@ impl Vim {
continue;
};
if let Some(range) =
surrounding_markers(display_map, cursor, true, true, open_marker, close_marker)
{
if let Some(range) = surrounding_markers_containing_cursor(
display_map,
cursor,
open_marker,
close_marker,
) {
let open_start = range.start.to_offset(display_map, Bias::Left);
let open_end = open_start + open_marker.len_utf8();
let close_end = range.end.to_offset(display_map, Bias::Left);
@@ -188,9 +209,12 @@ impl Vim {
continue;
};
if let Some(range) =
surrounding_markers(display_map, cursor, true, true, open_marker, close_marker)
{
if let Some(range) = surrounding_markers_containing_cursor(
display_map,
cursor,
open_marker,
close_marker,
) {
let open_start = range.start.to_offset(display_map, Bias::Left);
let open_end = open_start + open_marker.len_utf8();
let close_end = range.end.to_offset(display_map, Bias::Left);
@@ -259,6 +283,22 @@ mod test {
cx.simulate_keystrokes("m d (");
cx.assert_state("hello woˇrld test", Mode::HelixNormal);
cx.set_state(
indoc! {"
\"heˇllo\"
fn world() {
}"},
Mode::HelixNormal,
);
cx.simulate_keystrokes("m d (");
cx.assert_state(
indoc! {"
\"heˇllo\"
fn world() {
}"},
Mode::HelixNormal,
);
cx.set_state("((woˇrld))", Mode::HelixNormal);
cx.simulate_keystrokes("m d (");
cx.assert_state("(woˇrld)", Mode::HelixNormal);
@@ -281,6 +321,22 @@ mod test {
cx.simulate_keystrokes("m r \" {");
cx.assert_state("hello {woˇrld} test", Mode::HelixNormal);
cx.set_state(
indoc! {"
\"heˇllo\"
fn world() {
}"},
Mode::HelixNormal,
);
cx.simulate_keystrokes("m r ( [");
cx.assert_state(
indoc! {"
\"heˇllo\"
fn world() {
}"},
Mode::HelixNormal,
);
cx.set_state("((woˇrld))", Mode::HelixNormal);
cx.simulate_keystrokes("m r ( [");
cx.assert_state("([woˇrld])", Mode::HelixNormal);