vim: Add multicursor shortcuts (#3032)

Adding a few bindings to bring first class feeling multiselect to zed's
vim emulation.

gn and gN are similar to similar vim bindings, ga is similar to gA (and
I doubt we need vim's real ga), g> and g< are just made up.

Release Notes:

- vim: `g n` / `g N` to select next/previous
- vim: `g >` / `g <` to skip current selection and select next/previous
- vim: `g a` to select all
This commit is contained in:
Conrad Irwin 2023-09-25 17:18:12 -05:00 committed by GitHub
commit 42df5ef45e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 0 deletions

View file

@ -126,6 +126,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

View file

@ -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<usize>, cx: &mut WindowContext) {
@ -384,6 +390,50 @@ pub(crate) fn visual_replace(text: Arc<str>, cx: &mut WindowContext) {
});
}
pub fn select_next(
_: &mut Workspace,
_: &SelectNext,
cx: &mut ViewContext<Workspace>,
) -> 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<Workspace>,
) -> 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;