Flesh out helix bindings (#28103)

This brings in a bunch of helix bindings (many of them from
infogulch/zed-helix-keymap) and implements helix-style delete.

Release Notes:

- vim: Expanded default helix-style keybindings in HelixNormal mode
This commit is contained in:
jneem 2025-04-05 01:21:15 +07:00 committed by GitHub
parent 558d61b907
commit 435fff94bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 111 additions and 12 deletions

View file

@ -335,22 +335,101 @@
}
},
{
"context": "vim_mode == helix_normal",
"context": "vim_mode == helix_normal && !menu",
"bindings": {
"escape": "editor::Cancel",
"ctrl-[": "editor::Cancel",
":": "command_palette::Toggle",
"shift-d": "vim::DeleteToEndOfLine",
"shift-j": "vim::JoinLines",
"y": "editor::Copy",
"shift-y": "vim::YankLine",
"i": "vim::InsertBefore",
"shift-i": "vim::InsertFirstNonWhitespace",
"a": "vim::InsertAfter",
"d": "vim::HelixDelete",
"w": "vim::NextWordStart",
"e": "vim::NextWordEnd",
"b": "vim::PreviousWordStart",
"shift-a": "vim::InsertEndOfLine",
"o": "vim::InsertLineBelow",
"shift-o": "vim::InsertLineAbove",
"~": "vim::ChangeCase",
"ctrl-a": "vim::Increment",
"ctrl-x": "vim::Decrement",
"p": "vim::Paste",
"shift-p": ["vim::Paste", { "before": true }],
"u": "vim::Undo",
"ctrl-r": "vim::Redo",
"r": "vim::PushReplace",
"s": "vim::Substitute",
"shift-s": "vim::SubstituteLine",
">": "vim::Indent",
"<": "vim::Outdent",
"=": "vim::AutoIndent",
"g u": "vim::PushLowercase",
"g shift-u": "vim::PushUppercase",
"g ~": "vim::PushOppositeCase",
"\"": "vim::PushRegister",
"g q": "vim::PushRewrap",
"g w": "vim::PushRewrap",
"ctrl-pagedown": "pane::ActivateNextItem",
"ctrl-pageup": "pane::ActivatePreviousItem",
"insert": "vim::InsertBefore",
// tree-sitter related commands
"[ x": "editor::SelectLargerSyntaxNode",
"] x": "editor::SelectSmallerSyntaxNode",
"] d": "editor::GoToDiagnostic",
"[ d": "editor::GoToPreviousDiagnostic",
"] c": "editor::GoToHunk",
"[ c": "editor::GoToPreviousHunk",
// Goto mode
"g n": "pane::ActivateNextItem",
"g p": "pane::ActivatePreviousItem",
// "tab": "pane::ActivateNextItem",
// "shift-tab": "pane::ActivatePrevItem",
"shift-h": "pane::ActivatePreviousItem",
"shift-l": "pane::ActivateNextItem",
"g l": "vim::EndOfLine",
"g h": "vim::StartOfLine",
"g s": "vim::FirstNonWhitespace", // "g s" default behavior is "space s"
"g e": "vim::EndOfDocument",
"g y": "editor::GoToTypeDefinition",
"g r": "editor::FindAllReferences", // zed specific
"g t": "vim::WindowTop",
"g c": "vim::WindowMiddle",
"g b": "vim::WindowBottom",
"h": "vim::Left",
"j": "vim::Down",
"k": "vim::Up",
"l": "vim::Right"
"x": "editor::SelectLine",
"shift-x": "editor::SelectLine",
// Window mode
"space w h": "workspace::ActivatePaneLeft",
"space w l": "workspace::ActivatePaneRight",
"space w k": "workspace::ActivatePaneUp",
"space w j": "workspace::ActivatePaneDown",
"space w q": "pane::CloseActiveItem",
"space w s": "pane::SplitRight",
"space w r": "pane::SplitRight",
"space w v": "pane::SplitDown",
"space w d": "pane::SplitDown",
// Space mode
"space f": "file_finder::Toggle",
"space k": "editor::Hover",
"space s": "outline::Toggle",
"space shift-s": "project_symbols::Toggle",
"space d": "editor::GoToDiagnostic",
"space r": "editor::Rename",
"space a": "editor::ToggleCodeActions",
"space h": "editor::SelectAllMatches",
"space c": "editor::ToggleComments",
"space y": "editor::Copy",
"space p": "editor::Paste",
// Match mode
"m m": "vim::Matching",
"m i w": ["workspace::SendKeystrokes", "v i w"],
"shift-u": "editor::Redo",
"ctrl-c": "editor::ToggleComments",
"d": "vim::HelixDelete",
"c": "vim::Substitute",
"shift-c": "editor::AddSelectionBelow"
}
},
{
"context": "vim_mode == insert && !(showing_code_actions || showing_completions)",
"bindings": {

View file

@ -48,6 +48,7 @@ actions!(
JoinLinesNoWhitespace,
DeleteLeft,
DeleteRight,
HelixDelete,
ChangeToEndOfLine,
DeleteToEndOfLine,
Yank,
@ -92,6 +93,21 @@ pub(crate) fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
let times = Vim::take_count(cx);
vim.delete_motion(Motion::Right, times, window, cx);
});
Vim::action(editor, cx, |vim, _: &HelixDelete, window, cx| {
vim.record_current_action(cx);
vim.update_editor(window, cx, |_, editor, window, cx| {
editor.change_selections(None, window, cx, |s| {
s.move_with(|map, selection| {
if selection.is_empty() {
selection.end = movement::right(map, selection.end)
}
})
})
});
vim.visual_delete(false, window, cx);
});
Vim::action(editor, cx, |vim, _: &ChangeToEndOfLine, window, cx| {
vim.start_recording(cx);
let times = Vim::take_count(cx);

View file

@ -438,7 +438,7 @@ impl Vim {
vim.update(cx, |_, cx| {
Vim::action(editor, cx, |vim, _: &SwitchToNormalMode, window, cx| {
vim.switch_mode(Mode::Normal, false, window, cx)
vim.switch_mode(vim.default_mode(cx), false, window, cx)
});
Vim::action(editor, cx, |vim, _: &SwitchToInsertMode, window, cx| {
@ -739,6 +739,10 @@ impl Vim {
cx.on_release(|_, _| drop(subscription)).detach();
}
pub fn default_mode(&self, cx: &App) -> Mode {
VimSettings::get_global(cx).default_mode
}
pub fn editor(&self) -> Option<Entity<Editor>> {
self.editor.upgrade()
}
@ -1105,7 +1109,7 @@ impl Vim {
}
}
if mode == "normal" || mode == "visual" || mode == "operator" {
if mode == "normal" || mode == "visual" || mode == "operator" || mode == "helix_normal" {
context.add("VimControl");
}
context.set("vim_mode", mode);