From e833d1af8d8ba7b3445b07df7356108886cb40aa Mon Sep 17 00:00:00 2001 From: Hans Date: Wed, 12 Nov 2025 21:04:24 +0800 Subject: [PATCH] vim: Fix change surround adding unwanted spaces with quotes (#42431) Update `Vim.change_surround` in order to ensure that there's no overlapping edits by keeping track of where the open string range ends and ensuring that the closing string range start does not go lower than the open string range end. Closes #42316 Release Notes: - Fix vim's change surrounds `cs` inserting spaces with quotes by preventing overlapping edits --------- Co-authored-by: dino --- crates/vim/src/surrounds.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/crates/vim/src/surrounds.rs b/crates/vim/src/surrounds.rs index bc817e2d4871a0be07e8c100b332f5630dcec711..579ab7842096f1e5cb1bb4c70e2fd8f4256355d0 100644 --- a/crates/vim/src/surrounds.rs +++ b/crates/vim/src/surrounds.rs @@ -282,6 +282,7 @@ impl Vim { // that the end replacement string does not exceed // this value. Helpful when dealing with newlines. let mut edit_len = 0; + let mut open_range_end = 0; let mut chars_and_offset = display_map .buffer_chars_at(range.start.to_offset(&display_map, Bias::Left)) .peekable(); @@ -290,11 +291,11 @@ impl Vim { if ch.to_string() == will_replace_pair.start { let mut open_str = pair.start.clone(); let start = offset; - let mut end = start + 1; + open_range_end = start + 1; while let Some((next_ch, _)) = chars_and_offset.next() - && next_ch.to_string() == " " + && next_ch == ' ' { - end += 1; + open_range_end += 1; if preserve_space { open_str.push(next_ch); @@ -305,8 +306,8 @@ impl Vim { open_str.push(' '); }; - edit_len = end - start; - edits.push((start..end, open_str)); + edit_len = open_range_end - start; + edits.push((start..open_range_end, open_str)); anchors.push(start..start); break; } @@ -323,8 +324,9 @@ impl Vim { let mut start = offset; let end = start + 1; while let Some((next_ch, _)) = reverse_chars_and_offsets.next() - && next_ch.to_string() == " " + && next_ch == ' ' && close_str.len() < edit_len - 1 + && start > open_range_end { start -= 1; @@ -1236,6 +1238,23 @@ mod test { Mode::Normal, ); + // test spaces with quote change surrounds + cx.set_state( + indoc! {" + fn test_surround() { + \"ˇ \" + };"}, + Mode::Normal, + ); + cx.simulate_keystrokes("c s \" '"); + cx.assert_state( + indoc! {" + fn test_surround() { + ˇ' ' + };"}, + Mode::Normal, + ); + // Currently, the same test case but using the closing bracket `]` // actually removes a whitespace before the closing bracket, something // that might need to be fixed?