Helix: Fix visual/textual line up/down (#42676)

Kasper created

Release Notes:

- Make Helix keybinds use visual line movement for `j`, `Down`, `k` and `Up`, and textual line movement for `g j`, `g Down`, `g k` and `g Up`.

Change summary

assets/keymaps/vim.json | 222 ++++++++++++++++++++++--------------------
1 file changed, 115 insertions(+), 107 deletions(-)

Detailed changes

assets/keymaps/vim.json 🔗

@@ -181,8 +181,8 @@
       "ctrl-w space": "editor::OpenExcerptsSplit",
       "ctrl-w g space": "editor::OpenExcerptsSplit",
       "ctrl-^": "pane::AlternateFile",
-      ".": "vim::Repeat"
-    }
+      ".": "vim::Repeat",
+    },
   },
   {
     "context": "vim_mode == normal || vim_mode == visual || vim_mode == operator",
@@ -223,8 +223,8 @@
       "] r": "vim::GoToNextReference",
       // tree-sitter related commands
       "[ x": "vim::SelectLargerSyntaxNode",
-      "] x": "vim::SelectSmallerSyntaxNode"
-    }
+      "] x": "vim::SelectSmallerSyntaxNode",
+    },
   },
   {
     "context": "vim_mode == normal",
@@ -261,16 +261,16 @@
       "[ d": "editor::GoToPreviousDiagnostic",
       "] c": "editor::GoToHunk",
       "[ c": "editor::GoToPreviousHunk",
-      "g c": "vim::PushToggleComments"
-    }
+      "g c": "vim::PushToggleComments",
+    },
   },
   {
     "context": "VimControl && VimCount",
     "bindings": {
       "0": ["vim::Number", 0],
       ":": "vim::CountCommand",
-      "%": "vim::GoToPercentage"
-    }
+      "%": "vim::GoToPercentage",
+    },
   },
   {
     "context": "vim_mode == visual",
@@ -322,8 +322,8 @@
       "g w": "vim::Rewrap",
       "g ?": "vim::ConvertToRot13",
       // "g ?": "vim::ConvertToRot47",
-      "\"": "vim::PushRegister"
-    }
+      "\"": "vim::PushRegister",
+    },
   },
   {
     "context": "vim_mode == helix_select",
@@ -343,8 +343,8 @@
       "ctrl-pageup": "pane::ActivatePreviousItem",
       "ctrl-pagedown": "pane::ActivateNextItem",
       ".": "vim::Repeat",
-      "alt-.": "vim::RepeatFind"
-    }
+      "alt-.": "vim::RepeatFind",
+    },
   },
   {
     "context": "vim_mode == insert",
@@ -374,8 +374,8 @@
       "ctrl-r": "vim::PushRegister",
       "insert": "vim::ToggleReplace",
       "ctrl-o": "vim::TemporaryNormal",
-      "ctrl-s": "editor::ShowSignatureHelp"
-    }
+      "ctrl-s": "editor::ShowSignatureHelp",
+    },
   },
   {
     "context": "showing_completions",
@@ -383,8 +383,8 @@
       "ctrl-d": "vim::ScrollDown",
       "ctrl-u": "vim::ScrollUp",
       "ctrl-e": "vim::LineDown",
-      "ctrl-y": "vim::LineUp"
-    }
+      "ctrl-y": "vim::LineUp",
+    },
   },
   {
     "context": "(vim_mode == normal || vim_mode == helix_normal) && !menu",
@@ -409,23 +409,31 @@
       "shift-s": "vim::SubstituteLine",
       "\"": "vim::PushRegister",
       "ctrl-pagedown": "pane::ActivateNextItem",
-      "ctrl-pageup": "pane::ActivatePreviousItem"
-    }
+      "ctrl-pageup": "pane::ActivatePreviousItem",
+    },
   },
   {
     "context": "VimControl && vim_mode == helix_normal && !menu",
     "bindings": {
+      "j": ["vim::Down", { "display_lines": true }],
+      "down": ["vim::Down", { "display_lines": true }],
+      "k": ["vim::Up", { "display_lines": true }],
+      "up": ["vim::Up", { "display_lines": true }],
+      "g j": "vim::Down",
+      "g down": "vim::Down",
+      "g k": "vim::Up",
+      "g up": "vim::Up",
       "escape": "vim::SwitchToHelixNormalMode",
       "i": "vim::HelixInsert",
       "a": "vim::HelixAppend",
-      "ctrl-[": "editor::Cancel"
-    }
+      "ctrl-[": "editor::Cancel",
+    },
   },
   {
     "context": "vim_mode == helix_select && !menu",
     "bindings": {
-      "escape": "vim::SwitchToHelixNormalMode"
-    }
+      "escape": "vim::SwitchToHelixNormalMode",
+    },
   },
   {
     "context": "(vim_mode == helix_normal || vim_mode == helix_select) && !menu",
@@ -526,22 +534,22 @@
       "]": ["vim::PushHelixNext", { "around": true }],
       "[": ["vim::PushHelixPrevious", { "around": true }],
       "g q": "vim::PushRewrap",
-      "g w": "vim::PushRewrap"  // not a helix default & clashes with helix `goto_word`
-    }
+      "g w": "vim::PushRewrap", // not a helix default & clashes with helix `goto_word`
+    },
   },
   {
     "context": "vim_mode == insert && !(showing_code_actions || showing_completions)",
     "bindings": {
       "ctrl-p": "editor::ShowWordCompletions",
-      "ctrl-n": "editor::ShowWordCompletions"
-    }
+      "ctrl-n": "editor::ShowWordCompletions",
+    },
   },
   {
     "context": "(vim_mode == insert || vim_mode == normal) && showing_signature_help && !showing_completions",
     "bindings": {
       "ctrl-p": "editor::SignatureHelpPrevious",
-      "ctrl-n": "editor::SignatureHelpNext"
-    }
+      "ctrl-n": "editor::SignatureHelpNext",
+    },
   },
   {
     "context": "vim_mode == replace",
@@ -557,8 +565,8 @@
       "backspace": "vim::UndoReplace",
       "tab": "vim::Tab",
       "enter": "vim::Enter",
-      "insert": "vim::InsertBefore"
-    }
+      "insert": "vim::InsertBefore",
+    },
   },
   {
     "context": "vim_mode == waiting",
@@ -570,14 +578,14 @@
       "escape": "vim::ClearOperators",
       "ctrl-k": ["vim::PushDigraph", {}],
       "ctrl-v": ["vim::PushLiteral", {}],
-      "ctrl-q": ["vim::PushLiteral", {}]
-    }
+      "ctrl-q": ["vim::PushLiteral", {}],
+    },
   },
   {
     "context": "Editor && vim_mode == waiting && (vim_operator == ys || vim_operator == cs)",
     "bindings": {
-      "escape": "vim::SwitchToNormalMode"
-    }
+      "escape": "vim::SwitchToNormalMode",
+    },
   },
   {
     "context": "vim_mode == operator",
@@ -585,8 +593,8 @@
       "ctrl-c": "vim::ClearOperators",
       "ctrl-[": "vim::ClearOperators",
       "escape": "vim::ClearOperators",
-      "g c": "vim::Comment"
-    }
+      "g c": "vim::Comment",
+    },
   },
   {
     "context": "vim_operator == a || vim_operator == i || vim_operator == cs || vim_operator == helix_next || vim_operator == helix_previous",
@@ -623,14 +631,14 @@
       "shift-i": ["vim::IndentObj", { "include_below": true }],
       "f": "vim::Method",
       "c": "vim::Class",
-      "e": "vim::EntireFile"
-    }
+      "e": "vim::EntireFile",
+    },
   },
   {
     "context": "vim_operator == helix_m",
     "bindings": {
-      "m": "vim::Matching"
-    }
+      "m": "vim::Matching",
+    },
   },
   {
     "context": "vim_operator == helix_next",
@@ -647,8 +655,8 @@
       "x": "editor::SelectSmallerSyntaxNode",
       "d": "editor::GoToDiagnostic",
       "c": "editor::GoToHunk",
-      "space": "vim::InsertEmptyLineBelow"
-    }
+      "space": "vim::InsertEmptyLineBelow",
+    },
   },
   {
     "context": "vim_operator == helix_previous",
@@ -665,8 +673,8 @@
       "x": "editor::SelectLargerSyntaxNode",
       "d": "editor::GoToPreviousDiagnostic",
       "c": "editor::GoToPreviousHunk",
-      "space": "vim::InsertEmptyLineAbove"
-    }
+      "space": "vim::InsertEmptyLineAbove",
+    },
   },
   {
     "context": "vim_operator == c",
@@ -674,8 +682,8 @@
       "c": "vim::CurrentLine",
       "x": "vim::Exchange",
       "d": "editor::Rename", // zed specific
-      "s": ["vim::PushChangeSurrounds", {}]
-    }
+      "s": ["vim::PushChangeSurrounds", {}],
+    },
   },
   {
     "context": "vim_operator == d",
@@ -687,36 +695,36 @@
       "shift-o": "git::ToggleStaged",
       "p": "git::Restore", // "d p"
       "u": "git::StageAndNext", // "d u"
-      "shift-u": "git::UnstageAndNext" // "d shift-u"
-    }
+      "shift-u": "git::UnstageAndNext", // "d shift-u"
+    },
   },
   {
     "context": "vim_operator == gu",
     "bindings": {
       "g u": "vim::CurrentLine",
-      "u": "vim::CurrentLine"
-    }
+      "u": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == gU",
     "bindings": {
       "g shift-u": "vim::CurrentLine",
-      "shift-u": "vim::CurrentLine"
-    }
+      "shift-u": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == g~",
     "bindings": {
       "g ~": "vim::CurrentLine",
-      "~": "vim::CurrentLine"
-    }
+      "~": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == g?",
     "bindings": {
       "g ?": "vim::CurrentLine",
-      "?": "vim::CurrentLine"
-    }
+      "?": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == gq",
@@ -724,66 +732,66 @@
       "g q": "vim::CurrentLine",
       "q": "vim::CurrentLine",
       "g w": "vim::CurrentLine",
-      "w": "vim::CurrentLine"
-    }
+      "w": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == y",
     "bindings": {
       "y": "vim::CurrentLine",
       "v": "vim::PushForcedMotion",
-      "s": ["vim::PushAddSurrounds", {}]
-    }
+      "s": ["vim::PushAddSurrounds", {}],
+    },
   },
   {
     "context": "vim_operator == ys",
     "bindings": {
-      "s": "vim::CurrentLine"
-    }
+      "s": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == >",
     "bindings": {
-      ">": "vim::CurrentLine"
-    }
+      ">": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == <",
     "bindings": {
-      "<": "vim::CurrentLine"
-    }
+      "<": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == eq",
     "bindings": {
-      "=": "vim::CurrentLine"
-    }
+      "=": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == sh",
     "bindings": {
-      "!": "vim::CurrentLine"
-    }
+      "!": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == gc",
     "bindings": {
-      "c": "vim::CurrentLine"
-    }
+      "c": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == gR",
     "bindings": {
       "r": "vim::CurrentLine",
-      "shift-r": "vim::CurrentLine"
-    }
+      "shift-r": "vim::CurrentLine",
+    },
   },
   {
     "context": "vim_operator == cx",
     "bindings": {
       "x": "vim::CurrentLine",
-      "c": "vim::ClearExchange"
-    }
+      "c": "vim::ClearExchange",
+    },
   },
   {
     "context": "vim_mode == literal",
@@ -825,15 +833,15 @@
       "tab": ["vim::Literal", ["tab", "\u0009"]],
       // zed extensions:
       "backspace": ["vim::Literal", ["backspace", "\u0008"]],
-      "delete": ["vim::Literal", ["delete", "\u007F"]]
-    }
+      "delete": ["vim::Literal", ["delete", "\u007F"]],
+    },
   },
   {
     "context": "BufferSearchBar && !in_replace",
     "bindings": {
       "enter": "vim::SearchSubmit",
-      "escape": "buffer_search::Dismiss"
-    }
+      "escape": "buffer_search::Dismiss",
+    },
   },
   {
     "context": "VimControl && !menu || !Editor && !Terminal",
@@ -894,8 +902,8 @@
       "ctrl-w ctrl-n": "workspace::NewFileSplitHorizontal",
       "ctrl-w n": "workspace::NewFileSplitHorizontal",
       "g t": "vim::GoToTab",
-      "g shift-t": "vim::GoToPreviousTab"
-    }
+      "g shift-t": "vim::GoToPreviousTab",
+    },
   },
   {
     "context": "!Editor && !Terminal",
@@ -905,8 +913,8 @@
       "] b": "pane::ActivateNextItem",
       "[ b": "pane::ActivatePreviousItem",
       "] shift-b": "pane::ActivateLastItem",
-      "[ shift-b": ["pane::ActivateItem", 0]
-    }
+      "[ shift-b": ["pane::ActivateItem", 0],
+    },
   },
   {
     // netrw compatibility
@@ -956,8 +964,8 @@
       "6": ["vim::Number", 6],
       "7": ["vim::Number", 7],
       "8": ["vim::Number", 8],
-      "9": ["vim::Number", 9]
-    }
+      "9": ["vim::Number", 9],
+    },
   },
   {
     "context": "OutlinePanel && not_editing",
@@ -965,8 +973,8 @@
       "j": "menu::SelectNext",
       "k": "menu::SelectPrevious",
       "shift-g": "menu::SelectLast",
-      "g g": "menu::SelectFirst"
-    }
+      "g g": "menu::SelectFirst",
+    },
   },
   {
     "context": "GitPanel && ChangesList",
@@ -981,8 +989,8 @@
       "x": "git::ToggleStaged",
       "shift-x": "git::StageAll",
       "g x": "git::StageRange",
-      "shift-u": "git::UnstageAll"
-    }
+      "shift-u": "git::UnstageAll",
+    },
   },
   {
     "context": "Editor && mode == auto_height && VimControl",
@@ -993,8 +1001,8 @@
       "#": null,
       "*": null,
       "n": null,
-      "shift-n": null
-    }
+      "shift-n": null,
+    },
   },
   {
     "context": "Picker > Editor",
@@ -1003,29 +1011,29 @@
       "ctrl-u": "editor::DeleteToBeginningOfLine",
       "ctrl-w": "editor::DeleteToPreviousWordStart",
       "ctrl-p": "menu::SelectPrevious",
-      "ctrl-n": "menu::SelectNext"
-    }
+      "ctrl-n": "menu::SelectNext",
+    },
   },
   {
     "context": "GitCommit > Editor && VimControl && vim_mode == normal",
     "bindings": {
       "ctrl-c": "menu::Cancel",
-      "escape": "menu::Cancel"
-    }
+      "escape": "menu::Cancel",
+    },
   },
   {
     "context": "Editor && edit_prediction",
     "bindings": {
       // This is identical to the binding in the base keymap, but the vim bindings above to
       // "vim::Tab" shadow it, so it needs to be bound again.
-      "tab": "editor::AcceptEditPrediction"
-    }
+      "tab": "editor::AcceptEditPrediction",
+    },
   },
   {
     "context": "MessageEditor > Editor && VimControl",
     "bindings": {
-      "enter": "agent::Chat"
-    }
+      "enter": "agent::Chat",
+    },
   },
   {
     "context": "os != macos && Editor && edit_prediction_conflict",
@@ -1033,8 +1041,8 @@
       // alt-l is provided as an alternative to tab/alt-tab. and will be displayed in the UI. This
       // is because alt-tab may not be available, as it is often used for window switching on Linux
       // and Windows.
-      "alt-l": "editor::AcceptEditPrediction"
-    }
+      "alt-l": "editor::AcceptEditPrediction",
+    },
   },
   {
     "context": "SettingsWindow > NavigationMenu && !search",
@@ -1044,8 +1052,8 @@
       "k": "settings_editor::FocusPreviousNavEntry",
       "j": "settings_editor::FocusNextNavEntry",
       "g g": "settings_editor::FocusFirstNavEntry",
-      "shift-g": "settings_editor::FocusLastNavEntry"
-    }
+      "shift-g": "settings_editor::FocusLastNavEntry",
+    },
   },
   {
     "context": "MarkdownPreview",
@@ -1053,7 +1061,7 @@
       "ctrl-u": "markdown::ScrollPageUp",
       "ctrl-d": "markdown::ScrollPageDown",
       "ctrl-y": "markdown::ScrollUp",
-      "ctrl-e": "markdown::ScrollDown"
-    }
-  }
+      "ctrl-e": "markdown::ScrollDown",
+    },
+  },
 ]