From c89435154450e8d8878f6f03ff39c772b1cfc503 Mon Sep 17 00:00:00 2001 From: Dino Date: Tue, 2 Sep 2025 16:11:35 +0100 Subject: [PATCH] vim: Fix change surrounding quotes with whitespace within (#37321) This commit fixes a bug with Zed's vim mode surrounds plugin when dealing with replacing pairs with quote and the contents between the pairs had some whitespace within them. For example, with the following string: ``` ' str ' ``` If one was to use the `cs'"` command, to replace single quotes with double quotes, the result would actually be: ``` "str" ``` As the whitespace before and after the closing character was removed. This happens because of the way the plugin decides whether to add or remove whitespace after and before the opening and closing characters, repsectively. For example, using `cs{[` yields a different result from using `cs{]`, the former adds a space while the latter does not. However, since for quotes the opening and closing character is exactly the same, this behavior is not possible, so this commit updates the code in `vim::surrounds::Vim.change_surrounds` so that it never adds or removes whitespace when dealing with any type of quotes. Closes #12247 Release Notes: - Fixed whitespace handling when changing surrounding pairs to quotes in vim mode --- crates/vim/src/surrounds.rs | 43 ++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/crates/vim/src/surrounds.rs b/crates/vim/src/surrounds.rs index ca65204fab2a8ddd21e4788ca5c1e5cbe325447c..83500cf88b56c8f556887eb874901f50b6178018 100644 --- a/crates/vim/src/surrounds.rs +++ b/crates/vim/src/surrounds.rs @@ -240,7 +240,24 @@ impl Vim { newline: false, }, }; - let surround = pair.end != surround_alias((*text).as_ref()); + + // Determines whether space should be added/removed after + // and before the surround pairs. + // For example, using `cs{[` will add a space before and + // after the pair, while using `cs{]` will not, notice the + // use of the closing bracket instead of the opening bracket + // on the target object. + // In the case of quotes, the opening and closing is the + // same, so no space will ever be added or removed. + let surround = match target { + Object::Quotes + | Object::BackQuotes + | Object::AnyQuotes + | Object::MiniQuotes + | Object::DoubleQuotes => true, + _ => pair.end != surround_alias((*text).as_ref()), + }; + let (display_map, selections) = editor.selections.all_adjusted_display(cx); let mut edits = Vec::new(); let mut anchors = Vec::new(); @@ -1128,6 +1145,30 @@ mod test { ];"}, Mode::Normal, ); + + // test change quotes. + cx.set_state(indoc! {"' ˇstr '"}, Mode::Normal); + cx.simulate_keystrokes("c s ' \""); + cx.assert_state(indoc! {"ˇ\" str \""}, Mode::Normal); + + // test multi cursor change quotes + cx.set_state( + indoc! {" + ' ˇstr ' + some example text here + ˇ' str ' + "}, + Mode::Normal, + ); + cx.simulate_keystrokes("c s ' \""); + cx.assert_state( + indoc! {" + ˇ\" str \" + some example text here + ˇ\" str \" + "}, + Mode::Normal, + ); } #[gpui::test]