From b29e295e1b33ff1e1d46dfdc3b8439220de9f612 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 25 Sep 2023 15:23:14 -0600 Subject: [PATCH] vim: Add multicursor shortcuts - g n / g N to select next/previous - g > / g < to select next/previous replacing current - g a to select all matches --- assets/keymaps/vim.json | 15 ++++++++++++ crates/vim/src/visual.rs | 50 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 9e69240d27..e43a17449f 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -125,6 +125,21 @@ "g shift-t": "pane::ActivatePrevItem", "g d": "editor::GoToDefinition", "g shift-d": "editor::GoToTypeDefinition", + "g n": "vim::SelectNext", + "g shift-n": "vim::SelectPrevious", + "g >": [ + "editor::SelectNext", + { + "replace_newest": true + } + ], + "g <": [ + "editor::SelectPrevious", + { + "replace_newest": true + } + ], + "g a": "editor::SelectAllMatches", "g s": "outline::Toggle", "g shift-s": "project_symbols::Toggle", "g .": "editor::ToggleCodeActions", // zed specific diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs index f59b1fe167..eac823de61 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -1,3 +1,4 @@ +use anyhow::Result; use std::{cmp, sync::Arc}; use collections::HashMap; @@ -28,6 +29,8 @@ actions!( VisualDelete, VisualYank, OtherEnd, + SelectNext, + SelectPrevious, ] ); @@ -46,6 +49,9 @@ pub fn init(cx: &mut AppContext) { cx.add_action(other_end); cx.add_action(delete); cx.add_action(yank); + + cx.add_action(select_next); + cx.add_action(select_previous); } pub fn visual_motion(motion: Motion, times: Option, cx: &mut WindowContext) { @@ -384,6 +390,50 @@ pub(crate) fn visual_replace(text: Arc, cx: &mut WindowContext) { }); } +pub fn select_next( + _: &mut Workspace, + _: &SelectNext, + cx: &mut ViewContext, +) -> Result<()> { + Vim::update(cx, |vim, cx| { + let count = + vim.take_count(cx) + .unwrap_or_else(|| if vim.state().mode.is_visual() { 1 } else { 2 }); + vim.update_active_editor(cx, |editor, cx| { + for _ in 0..count { + match editor.select_next(&Default::default(), cx) { + Err(a) => return Err(a), + _ => {} + } + } + Ok(()) + }) + }) + .unwrap_or(Ok(())) +} + +pub fn select_previous( + _: &mut Workspace, + _: &SelectPrevious, + cx: &mut ViewContext, +) -> Result<()> { + Vim::update(cx, |vim, cx| { + let count = + vim.take_count(cx) + .unwrap_or_else(|| if vim.state().mode.is_visual() { 1 } else { 2 }); + vim.update_active_editor(cx, |editor, cx| { + for _ in 0..count { + match editor.select_previous(&Default::default(), cx) { + Err(a) => return Err(a), + _ => {} + } + } + Ok(()) + }) + }) + .unwrap_or(Ok(())) +} + #[cfg(test)] mod test { use indoc::indoc;