diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 389efcdd0b..eb2d7ecf41 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -302,6 +302,7 @@ "x": "vim::VisualDelete", "y": "vim::VisualYank", "p": "vim::VisualPaste", + "s": "vim::Substitute", "r": [ "vim::PushOperator", "Replace" diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index c72fffbc21..19d000d397 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -481,17 +481,17 @@ pub(crate) fn normal_replace(text: Arc, cx: &mut WindowContext) { pub fn substitute(vim: &mut Vim, count: usize, cx: &mut WindowContext) { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { - let selection = editor.selections.newest::(cx); - - let end = if selection.start == selection.end { - selection.start + Point::new(0, 1) - } else { - selection.end - }; - - editor.buffer().update(cx, |buffer, cx| { - buffer.edit([(selection.start..end, "")], None, cx) - }) + let selections = editor.selections.all::(cx); + for selection in selections.into_iter().rev() { + let end = if selection.start == selection.end { + selection.start + Point::new(0, 1) + } else { + selection.end + }; + editor.buffer().update(cx, |buffer, cx| { + buffer.edit([(selection.start..end, "")], None, cx) + }) + } }) }); vim.switch_mode(Mode::Insert, true, cx) diff --git a/crates/vim/src/test.rs b/crates/vim/src/test.rs index ec8998adc9..293a4813e6 100644 --- a/crates/vim/src/test.rs +++ b/crates/vim/src/test.rs @@ -99,12 +99,22 @@ async fn test_buffer_search(cx: &mut gpui::TestAppContext) { }) } - #[gpui::test] async fn test_substitute(cx: &mut gpui::TestAppContext) { let mut cx = VimTestContext::new(cx, true).await; + // supports a single cursor cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal); cx.simulate_keystrokes(["s", "x"]); cx.assert_editor_state("xˇbc\n"); + + // supports a selection + cx.set_state(indoc! {"a«bcˇ»\n"}, Mode::Visual { line: false }); + cx.simulate_keystrokes(["s", "x"]); + cx.assert_editor_state("axˇ\n"); + + // supports multiple cursors + cx.set_state(indoc! {"a«bcˇ»deˇfg\n"}, Mode::Normal); + cx.simulate_keystrokes(["s", "x"]); + cx.assert_editor_state("axˇdexˇg\n"); }