diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 389efcdd0b64fac2225af2cdf7c61da7b26f0405..eb2d7ecf410c812ed50cf2023846a72224bd45d2 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 c72fffbc2145759634bf2b9688bbdca7b50163db..19d000d3970efcc0a1de248d41612558a55c0cb1 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 ec8998adc934c799195b25c744aa4791871d0b8d..293a4813e6409bba4ec07f7e37275e177badb5a7 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"); }