From 46bfcf00c679f5a17b651b610e77614ae6e3c29f Mon Sep 17 00:00:00 2001 From: David Little Date: Sun, 12 Jan 2025 07:28:03 -0500 Subject: [PATCH] Larkin: Layout independent bindings --- README.md | 6 +- package.json | 2 +- presets/larkin.toml | 775 +++--- presets/larkin_layout.toml | 3543 ++++++++++++++++++++++++++ src/web/commands/palette.ts | 26 +- src/web/commands/visualKeyDoc.ts | 5 +- src/web/keybindings/docParsing.ts | 13 +- src/web/keybindings/index.ts | 16 +- src/web/keybindings/layout.ts | 61 + src/web/keybindings/parsing.ts | 24 + src/web/keybindings/processing.ts | 167 +- src/web/status/keyseq.ts | 4 +- test/specs/simpleMotionLayout.ux.mts | 212 ++ test/specs/utils.mts | 17 +- 14 files changed, 4337 insertions(+), 534 deletions(-) create mode 100644 presets/larkin_layout.toml create mode 100644 src/web/keybindings/layout.ts create mode 100644 test/specs/simpleMotionLayout.ux.mts diff --git a/README.md b/README.md index 594cca6..088ae6c 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,11 @@ Learn and review your bindings on a keyboard layout: ![example of visual docs](images/readme/visualdoc.jpg) -### Cheet sheet of keybindings +### Cheat sheet of keybindings -Review your bindings in a cheet sheet organized by theme: +Review your bindings in a cheat sheet organized by theme: -![example of cheet sheet](images/readme/cheatsheet.png) +![example of cheat sheet](images/readme/cheatsheet.png) ### Keybinding hints diff --git a/package.json b/package.json index 2d140e2..34dbff3 100644 --- a/package.json +++ b/package.json @@ -276,4 +276,4 @@ "zod": "^3.22.4", "zod-validation-error": "^2.1.0" } -} +} \ No newline at end of file diff --git a/presets/larkin.toml b/presets/larkin.toml index 242abc9..b224743 100644 --- a/presets/larkin.toml +++ b/presets/larkin.toml @@ -7,6 +7,9 @@ # Larkin is the default keybinding set that ships with Master Key. It follows in the footsteps of Vim, Kakoune and Helix. +# > ⚠️ **Warning**: These bindings use a layout independent keymap. This means the key names may not match those on your keyboard but will instead match those shown in the layout visible in the visual documentation. They follow the U.S. Keyboard Layout. Layout independent keys are surrounded with `[]` to make clear they are not layout dependent. If your needs require a layout dependent keymap consider using `Larkin (Layout Dependent)`. + +# # Some key features: # - Commands are modal: most actions are available in `normal` mode, while typing occurs in `insert` mode @@ -19,7 +22,7 @@ #- NOTE: this file is used to generate both keybindings and to generate a markdown file that documents the bindings. When comments are prefixed with a `-` they are ignored in the final markdown output. All other comments will become part of the markdown output. Any [[bind]] entries unbroken by normal, markdown-displayed comments will show up in a table in the markdown output. Make sure that the normal comments do not break up TOML data in a way that means it is invalid TOML. [header] -name = "Larkin Key Bindings" +name = "Larkin" version = "1.0" requiredExtensions = [ @@ -114,7 +117,7 @@ default.kind = "util" [[bind]] path = "util" -key = "shift+;" +key = "shift+[Semicolon]" name = "suggest" resetTransient = false hideInPalette = true @@ -126,7 +129,7 @@ show command suggestions within the context of the current mode and keybinding p command = "master-key.commandSuggestions" [[bind]] -key = "tab /" +key = "[Tab] [Slash]" name = "text docs" priority = -1 mode = "normal" @@ -134,7 +137,7 @@ description = "Show text documentation for keybindings" command = "master-key.showTextDoc" [[bind]] -key = "tab shift+/" +key = "[Tab] shift+[Slash]" name = "visual doc" priority = -1 mode = "normal" @@ -165,8 +168,8 @@ command = "master-key.showVisualDoc" path = "modes" name = "normal" description = "Enter normal mode" -foreach.key = ["escape", "ctrl+["] -combinedKey = "escape/ctrl+[" +foreach.key = ["[Escape]", "ctrl+[BracketLeft]"] +combinedKey = "[Escape]/ctrl+[BracketLeft]" combinedName = "normal" combinedDescription = "Enter normal mode" key = "{key}" @@ -180,7 +183,7 @@ prefixes = "" [[bind]] path = "modes" name = "normal" -foreach.key = ["escape", "ctrl+["] +foreach.key = ["[Escape]", "ctrl+[BracketLeft]"] key = "{key}" hideInPalette = true hideInDocs = true @@ -195,7 +198,7 @@ prefixes = "" path = "modes" name = "ignore" description = "this key does nothing" -foreach.key = ['{key: .}', 'shift+{key: .}'] #- all keys whose bindings are described by a single character +foreach.key = ['{key: \[[^]]\]}', 'shift+{key: \[[^]]\]}', '{key: .}', '{key: shift+.}'] key = "{key}" command = "master-key.ignore" prefixes = "" @@ -238,10 +241,10 @@ default.computedArgs.select = "editorHasSelection || select_on" [[bind]] path = "edit.motion.prim" -key = "h" +key = "[KeyH]" name = "←" combinedName = "←/→" -combinedKey = "h/l" +combinedKey = "[KeyH]/[KeyL]" combinedDescription = "move left/right" description = "move left" args.to = "left" @@ -249,7 +252,7 @@ mode = "normal" [[bind]] path = "edit.motion.prim" -key = "l" +key = "[KeyL]" combinedName = "←/→" name = "→" description = "move right" @@ -257,10 +260,10 @@ args.to = "right" [[bind]] path = "edit.motion.prim" -key = "j" +key = "[KeyJ]" name = "↓" combinedName = "↓/↑" -combinedKey = "j/k" +combinedKey = "[KeyJ]/[KeyK]" combinedDescription = "move down/up" description = "move down" args.to = "down" @@ -268,7 +271,7 @@ args.by = "wrappedLine" [[bind]] path = "edit.motion.prim" -key = "k" +key = "[KeyK]" name = "↑" description = "move up" combinedName = "↓/↑" @@ -277,17 +280,17 @@ args.by = "wrappedLine" [[bind]] path = "edit.motion.prim" -key = "shift+h" +key = "shift+[KeyH]" name = "start" description = "start of line (alternates between first non-white and first)" combinedName = "start/end" -combinedKey = "shift+h/shift+l" +combinedKey = "shift+[KeyH]/shift+[KeyL]" combinedDescription = "move to start/end of line" command = "cursorHomeSelect" -[[bind]] # we don't use prim because we don't want the defaults +[[bind]] #- we don't use prim because we don't want the defaults path = "edit.motion" -key = "shift+l" +key = "shift+[KeyL]" name = "end" combinedName = "start/end" description = "end of line" @@ -297,11 +300,11 @@ args.select = true [[bind]] path = "edit.motion.prim" -key = "shift+k" +key = "shift+[KeyK]" name = "sel ↑" combinedName = "sel ↑/↓" combinedDescription = "select lines up/down" -combinedKey = "shift+k/shift+j" +combinedKey = "shift+[KeyK]/shift+[KeyJ]" description = "select lines upwards" command = "runCommands" @@ -321,7 +324,7 @@ command = "selection-utilities.exchangeAnchorActive" [[bind]] path = "edit.motion.prim" -key = "shift+j" +key = "shift+[KeyJ]" name = "sel ↓" combinedName = "sel ↑/↓" description = "select lines downwards" @@ -340,11 +343,11 @@ command = "expandLineSelection" [[bind]] path = "edit.motion.prim" -key = "ctrl+d" +key = "ctrl+[KeyD]" mode = ["normal", "insert"] name = "pg ↓" combinedName = "pg ↓/↑" -combinedKey = "ctrl+d/ctrl+u" +combinedKey = "ctrl+[KeyD]/ctrl+[KeyU]" combinedDescription = "move down/up, relative to page size" description = "move down, relative to page size" command = "selection-utilities.activePageMove" @@ -354,7 +357,7 @@ computedArgs.select = "mode == 'normal'" [[bind]] path = "edit.motion.prim" -key = "ctrl+u" +key = "ctrl+[KeyU]" mode = ["normal", "insert"] name = "pg ↑" combinedName = "pg ↓/↑" @@ -366,7 +369,7 @@ computedArgs.select = "mode == 'normal'" [[bind]] path = "edit.motion.prim" -key = "shift+x" +key = "shift+[KeyX]" name = "exapand" description = "expand selections to full lines" command = "expandLineSelection" @@ -384,18 +387,18 @@ default.args.select = true [[bind]] path = "edit.motion.obj" -key = "w" +key = "[KeyW]" name = "subwrd →" description = "next subword (camel/snake case)" combinedName = "subwrd ←/→" combinedDescription = "next/prev subword (camel/snake case)" -combinedKey = "w/b" +combinedKey = "[KeyW]/[KeyB]" args.unit = "subword" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "b" +key = "[KeyB]" name = "subwrd ←" description = "previous subword (camel/snake case)" combinedName = "subwrd ←/→" @@ -404,18 +407,18 @@ computedArgs.value = "-count || -1" [[bind]] path = "edit.motion.obj" -key = "shift+w" +key = "shift+[KeyW]" name = "word →" description = "next word" combinedName = "word ←/→" combinedDescription = "next/prev word" -combinedKey = "shift+w/b" +combinedKey = "shift+[KeyW]/[KeyB]" args.unit = "word" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "shift+b" +key = "shift+[KeyB]" name = "word ←" combinedName = "word ←/→" description = "previous word" @@ -425,7 +428,7 @@ computedArgs.value = "-count || -1" [[bind]] path = "edit.motion.obj" -key = "e" +key = "[KeyE]" name = "subwrd end" description = "next subword (camel/snake case) end" args.unit = "subword" @@ -434,7 +437,7 @@ computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "shift+e" +key = "shift+[KeyE]" name = "word end" description = "next word end" args.unit = "word" @@ -443,18 +446,18 @@ computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "shift+]" +key = "shift+[BracketRight]" name = "parag. →" description = "next paragraph" combinedName = "paragraph →/←" combinedDescription = "next/previous paragraph" -combinedKey = "shift+]/[" +combinedKey = "shift+[BracketRight]/[BracketLeft]" args.unit = "paragraph" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "shift+[" +key = "shift+[BracketLeft]" name = "parag. ←" combinedName = "paragraph →/←" description = "previous paragraph" @@ -463,18 +466,18 @@ computedArgs.value = "-(count || 1)" [[bind]] path = "edit.motion.obj" -key = "shift+0" +key = "shift+[Digit0]" name = "subsec →" description = "next subsection" combinedName = "subsec →/←" combinedDescription = "next/previous subsection" -combinedKey = "shift+0/9" +combinedKey = "shift+[Digit0]/[Digit9]" args.unit = "subsection" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "shift+9" +key = "shift+[Digit9]" name = "subsec ←" description = "previous subsection" combinedName = "subsec →/←" @@ -483,7 +486,7 @@ computedArgs.value = "-(count || 1)" [[bind]] path = "edit.motion.prim" -key = "v" +key = "[KeyV]" name = "shrink selection" combinedName = "shrink/hold selection" combinedDescription = """ @@ -500,7 +503,7 @@ args.commands = [ [[bind]] path = "edit.motion.mod" -key = "shift+v" +key = "shift+[KeyV]" name = "hold selection" combinedName = "shrink/hold selection" description = """ @@ -514,9 +517,9 @@ args.value = true path = "edit.action.open_lines" name = "open, act →" description = "without selection: open a line below current line and enter insert, with selection: move cursor to start" -key = "o" +key = "[KeyO]" combinedName = "open below/above, act →/←" -combinedKey = "o/shift+o" +combinedKey = "[KeyO]/shift+[KeyO]" combinedDescription = """ without selection: open a line below/above current line and enter insert, with selection: move cursor to end/start of selection @@ -527,7 +530,7 @@ args.commands = ["editor.action.insertLineAfter", "master-key.enterInsert"] [[bind]] path = "edit.action.open_lines" -key = "o" +key = "[KeyO]" combinedName = "open below/above, act →/←" when = "editorHasSelection" command = "selection-utilities.activeAtEnd" @@ -537,7 +540,7 @@ path = "edit.action.open_lines" name = "open blw, act ←" combinedName = "open below/above, act →/←" description = "without selection: open a line above current line and enter insert, with selection: move cursor to end" -key = "shift+o" +key = "shift+[KeyO]" when = "!editorHasSelection" command = "runCommands" args.commands = [ "editor.action.insertLineBefore", "master-key.enterInsert" ] @@ -547,25 +550,25 @@ path = "edit.action.open_lines" name = "open blw, act ←" combinedName = "open below/above, act →/←" description = "without selection: open a line above current line and enter insert, with selection: move cursor to end" -key = "shift+o" +key = "shift+[KeyO]" when = "editorHasSelection" command = "selection-utilities.activeAtStart" [[bind]] path = "edit.motion" -key = "shift+5" +key = "shift+[Digit5]" name = "to bracket" description = "Move to matching bracket" command = "editor.action.jumpToBracket" [[bind]] path = "edit.motion.prim" -key = '\' +key = '[Backslash]' name = "→ sel" combinedName = "→/← sel" description = "select *just* the character to the right" combinedDescription = "select *just* the character to the right" -combinedKey = 'shift+\/\' +combinedKey = 'shift+[Backslash]/[Backslash]' mode = ["normal", "selectedit"] command = "runCommands" @@ -579,7 +582,7 @@ computedArgs = { value = "count" } [[bind]] path = "edit.motion.prim" -key = 'shift+\' +key = 'shift+[Backslash]' name = "← sel" combinedName = "→/← sel" description = "select *just* the character to the left" @@ -602,14 +605,14 @@ default.kind = "motion" [[bind]] path = "edit.motion.obj" -key = "shift+4" +key = "shift+[Digit4]" name = "all" description = "Select entire document" command = "editor.action.selectAll" [[bind]] path = "edit.motion" -key = "shift+r" +key = "shift+[KeyR]" name = "trim wht" description = "trim external whitespace" command = "selection-utilities.trimSelectionWhitespace" @@ -618,10 +621,10 @@ command = "selection-utilities.trimSelectionWhitespace" path = "edit.motion.obj" name = "→ num." description = "Move to next number" -key = "shift+3" +key = "shift+[Digit3]" combinedName = "→/← num." combinedDescription = "Move to next/prev number" -combinedKey = "shift+3/2" +combinedKey = "shift+[Digit3]/[Digit2]" args.unit = "number" args.selectWhole = true args.boundary = "both" @@ -631,7 +634,7 @@ computedArgs.value = "(count || 1)" path = "edit.motion.obj" name = "← num." description = "Move to next number" -key = "shift+2" +key = "shift+[Digit2]" combinedName = "→/← num." args.unit = "number" args.selectWhole = true @@ -642,7 +645,7 @@ computedArgs.value = "-(count || 1)" path = "edit.motion" name = 'narrow to subword' description = "Narrow current selection so it starts and stops at a subword (e.g. 'snake' in snake_case)" -key = "z" +key = "[KeyZ]" command = "selection-utilities.narrowTo" args.unit = "subident" args.boundary = "both" @@ -657,12 +660,12 @@ args.boundary = "both" path = "edit.count" foreach.num = ['{key: [0-9]}'] name = "count {num}" -key = "{num}" +key = "[Digit{num}]" command = "master-key.updateCount" description = "Add digit {num} to the count argument of a command" -combinedKey = "0-9" +combinedKey = "[Digit0]-[Digit9]" combinedName = "count 0-9" -combinedDescription = "Add digit 1-9 to count argument of a command" +combinedDescription = "Add digit 0-9 to count argument of a command" args.value = "{num}" resetTransient = false mode = ["!insert", "!capture"] @@ -677,7 +680,7 @@ description = "Commands that repeat some kind of motion" [[bind]] path = "edit.motion.history" -key = ";" +key = "[Semicolon]" name = "repeat motion" description = """ Repeat the last motion command. Motions usually move the cursor or change the selection. @@ -685,9 +688,9 @@ Repeat the last motion command. Motions usually move the cursor or change the se repeat = "count" command = "master-key.replayFromHistory" args.at = """ -commandHistory[i].path.startsWith('edit.motion') && -commandHistory[i].name != 'repeat motion' && -commandHistory[i].name != 'shrink selection' +commandHistory[KeyI].path.startsWith('edit.motion') && +commandHistory[KeyI].name != 'repeat motion' && +commandHistory[KeyI].name != 'shrink selection' """ [[bind]] @@ -698,10 +701,10 @@ Repeat the subject: a motion command that occurred right before an action. For instance `w` followed by `d` selects a word and deletes it. The `w` command would be the last subject until some new action is run after `d`. See also `.` which repeats the last action. """ -key = "," +key = "[Comma]" command = "master-key.replayFromHistory" args.at = """ -commandHistory[i].path.startsWith("edit.motion") && +commandHistory[KeyI].path.startsWith("edit.motion") && commandHistory[i+1].path.startsWith("edit.action") && !(commandHistory[i+1].name.startsWith("repeat ") && commandHistory[i+1].path.startsWith("edit.action.history")) @@ -710,16 +713,16 @@ commandHistory[i+1].path.startsWith("edit.action") && [[bind]] path = "edit.motion.history" name = "cursor undo" -key = "-" +key = "[Minus]" combinedName = "cursor undo/redo" -combinedKey = "-/shift+-" +combinedKey = "[Minus]/shift+[Minus]" command = "cursorUndo" [[bind]] path = "edit.motion.history" name = "cursor redo" combinedName = "cursor undo/redo" -key = "shift+-" +key = "shift+[Minus]" command = "cursorRedo" [[bind]] @@ -727,9 +730,9 @@ path = "edit.motion.history" name = "nav ←" description = "Go back in navigation history (e.g. goto definition)" combinedName = "nav ←/→" -combinedKey = "n/shift+n" +combinedKey = "[KeyN]/shift+[KeyN]" combinedDescription = "Go back/forward in navigation history" -key = "g n" +key = "[KeyG] [KeyN]" command = "workbench.action.navigateBackInNavigationLocations" [[bind]] @@ -737,16 +740,16 @@ path = "edit.motion.history" name = "nav →" combinedName = "nav ←/→" description = "Go forward in navigation history (e.g. goto definition)" -key = "g shift+n" +key = "[KeyG] shift+[KeyN]" command = "workbench.action.navigateForwardInNavigationLocations" [[bind]] path = "edit.motion.history" name = "edit hist ←" description = "Go back in edit history" -key = "g -" +key = "[KeyG] [Minus]" combinedName = "edit ←/→" -combinedKey = "-/shift+-" +combinedKey = "[Minus]/shift+[Minus]" combinedDescription = "Go back/forward in edit history" command = "workbench.action.navigateBackInEditLocations" @@ -754,7 +757,7 @@ command = "workbench.action.navigateBackInEditLocations" path = "edit.motion.history" name = "edit hist →" description = "Go forward in edit history)" -key = "g shift+-" +key = "[KeyG] shift+[Minus]" combinedName = "edit ←/→" command = "workbench.action.navigateForwardInEditLocations" @@ -776,18 +779,18 @@ default.args.wrapAround = true [[bind]] path = "edit.motion.search" -key = "/" +key = "[Slash]" name = "search →" description = "search forwards" combinedName = "search → (←)" combinedDescription = "search forwards (backwards)" -combinedKey = "/ (shift+/)" +combinedKey = "[Slash] (shift+[Slash])" args.offset = "start" args.register = "search" [[bind]] path = "edit.motion.search" -key = "shift+/" +key = "shift+[Slash]" name = "search ←" description = "search backwards" combinedName = "search → (←)" @@ -797,7 +800,7 @@ args.backwards = true [[bind]] path = "edit.motion.search" -key = "n" +key = "[KeyN]" name = "→ search" description = "Go to the next match of the search query" command = "master-key.nextMatch" @@ -806,7 +809,7 @@ computedArgs.repeat = "(count || 1)-1" [[bind]] path = "edit.motion.search" -key = "shift+n" +key = "shift+[KeyN]" name = "← search" description = "Go to the previous match of the search query" command = "master-key.previousMatch" @@ -815,19 +818,19 @@ computedArgs.repeat = "(count || 1)-1" [[bind]] path = "edit.motion.search" -key = "shift+8" +key = "shift+[Digit8]" name = "match →" description = "Next match to object under cursor" combinedName = "match →/←" combinedDescription = "Next/previous match to object under cursor" -combinedKey = "shift+8/7" +combinedKey = "shift+[Digit8]/[Digit7]" computedArgs.text = "firstSelectionOrWord" args.offset = "start" args.register = "search" [[bind]] path = "edit.motion.search" -key = "shift+7" +key = "shift+[Digit7]" name = "match ←" description = "Previous match to object under cursor" combinedName = "match →/←" @@ -838,19 +841,19 @@ args.backwards = true [[bind]] path = "edit.motion.search" -key = "f" +key = "[KeyF]" name = "find char" description = "Find the next char (include char in selection)" combinedName = "find char (back)" combinedDescription = "Find the next (previous) char (include char in selection)" -combinedKey = "f (shift+f)" +combinedKey = "[KeyF] (shift+[KeyF])" args.acceptAfter = 1 computedArgs.skip = "count-1" args.offset = "inclusive" [[bind]] path = "edit.motion.search" -key = "shift+f" +key = "shift+[KeyF]" name = "find char back" description = "Find the previous char (include char in selection)" combinedName = "find char (back)" @@ -861,11 +864,11 @@ computedArgs.skip = "count-1" [[bind]] path = "edit.motion.search" -key = "t" +key = "[KeyT]" name = "to char" description = "Find the next char (exclude char in selection)" combinedName = "to char (back)" -combinedKey = "t (shift+t)" +combinedKey = "[KeyT] (shift+[KeyT])" combinedDescription = "Find the next/previous char (exclude char in selection)" args.acceptAfter = 1 args.offset = "start" @@ -873,7 +876,7 @@ computedArgs.skip = "count-1" [[bind]] path = "edit.motion.search" -key = "shift+t" +key = "shift+[KeyT]" name = "to char back" description = "Find the previous char (exclude char in selection)" combinedName = "to char (back)" @@ -884,12 +887,12 @@ computedArgs.skip = "count-1" [[bind]] path = "edit.motion.search" -key = "s" +key = "[KeyS]" name = "find char pair" description = "To next character pair" combinedName = "char pair →/←" combinedDescription = "To next character pair" -combinedKey = "s/shift+s" +combinedKey = "[KeyS]/shift+[KeyS]" args.acceptAfter = 2 args.offset = "start" computedArgs.skip = "count-1" @@ -897,7 +900,7 @@ mode = "normal" [[bind]] path = "edit.motion.search" -key = "shift+s" +key = "shift+[KeyS]" name = "char pair back" description = "To previous character pair" combinedName = "char pair →/←" @@ -913,7 +916,7 @@ args.backwards = true [[bind]] path = "edit.motion" -key = "g" +key = "[KeyG]" priority = 1 name = "goto" command = "master-key.prefix" @@ -924,11 +927,11 @@ or backwards in some direction. [[bind]] path = "edit.motion.prim" -key = "g j" +key = "[KeyG] [KeyJ]" priority = 1 name = "unwrp ↓" combinedName = "unwrap ↓/↑" -combinedKey = "j/k" +combinedKey = "[KeyJ]/[KeyK]" combinedDescription = """ move cursor up/down unwrapped text line; if a single line is wrapped into multiple lines by the editor, this command skips all such wrapped lines @@ -942,7 +945,7 @@ args.by = "line" [[bind]] path = "edit.motion.prim" -key = "g k" +key = "[KeyG] [KeyK]" priority = 1 name = "unwrp ↑" combinedName = "unwrap ↓/↑" @@ -952,11 +955,11 @@ args.by = "line" [[bind]] path = "edit.motion.prim" -key = "g shift+k" +key = "[KeyG] shift+[KeyK]" priority = 1 combinedName = "unwrp sel ↑/↓" combinedDescription = "select unwrapped lines up/down" -combinedKey = "shift+k/j" +combinedKey = "shift+[KeyK]/[KeyJ]" name = "unwrp sel ↑" description = "select unwrapped lines upwards" command = "runCommands" @@ -974,7 +977,7 @@ command = "expandLineSelection" [[bind]] path = "edit.motion.prim" -key = "g shift+j" +key = "[KeyG] shift+[KeyJ]" priority = 1 name = "sel ↓" combinedName = "unwrp sel ↑/↓" @@ -994,18 +997,18 @@ command = "expandLineSelection" [[bind]] path = "edit.motion.prim" -key = "shift+g" +key = "shift+[KeyG]" priority = 1 name = "doc end" description = "select to end of document" combinedName = "doc top/bottom" combinedDescription = "select to top/bottom of document" -combinedKey = ",/." +combinedKey = "[Comma]/[Period]" command = "cursorBottomSelect" [[bind]] path = "edit.motion.prim" -key = "g g" +key = "[KeyG] [KeyG]" priority = 1 name = "doc start" description = "select to start (line) of document." @@ -1028,7 +1031,7 @@ computedArgs.lineNumber = "count" [[bind]] path = "edit.motion.prim" -key = "g g" +key = "[KeyG] [KeyG]" priority = 1 name = "doc start" description = "select to start of document" @@ -1037,21 +1040,21 @@ when = "master-key.count <= 1" [[bind]] path = "edit.motion.obj" -key = "g w" +key = "[KeyG] [KeyW]" priority = 1 name = "WORD →" combinedName = "WORD →/←" combinedDescription = """ next/prev WORD; e.g. contiguous non-whitespace region """ -combinedKey = "w/b" +combinedKey = "[KeyW]/[KeyB]" description = "next WORD; e.g. contiguous non-whitespace region" args.unit = "WORD" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "g b" +key = "[KeyG] [KeyB]" priority = 1 name = "WORD ←" combinedName = "WORD →/←" @@ -1061,7 +1064,7 @@ computedArgs.value = "-count || -1" [[bind]] path = "edit.motion.obj" -key = "g e" +key = "[KeyG] [KeyE]" priority = 1 name = "WORD end →" description = "next WORD end; e.g. contiguous non-whitespace region" @@ -1071,19 +1074,19 @@ computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "g 0" +key = "[KeyG] [Digit0]" priority = 1 name = "sec →" description = "next section" combinedName = "sec →/←" combinedDescription = "next/previous section" -combinedKey = "0/9" +combinedKey = "[Digit0]/[Digit9]" args.unit = "section" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.obj" -key = "g 9" +key = "[KeyG] [Digit9]" priority = 1 name = "sec ←" description = "previous section" @@ -1096,7 +1099,7 @@ path = "window" name = "goto line" priority = 1 description = "goto line command" -key = "g l" +key = "[KeyG] [KeyL]" command = "workbench.action.gotoLine" when = "editorTextFocus" @@ -1105,7 +1108,7 @@ path = "window" name = "to refs" priority = 1 description = "jump to a location where this symbol is referenced" -key = "g r" +key = "[KeyG] [KeyR]" command = "editor.action.goToReferences" when = "editorTextFocus" @@ -1114,9 +1117,9 @@ path = "window" name = "go to" priority = 1 description = "go to the definition of symbol under cursor" -key = "g d" +key = "[KeyG] [KeyD]" combinedName = "go to (aside)" -combinedKey = "(shift+)d" +combinedKey = "(shift+)[KeyD]" combinedDescription = "go to the definition of symbol (in an editor to the side)" command = "editor.action.revealDefinition" when = "editorTextFocus" @@ -1126,7 +1129,7 @@ path = "window" name = "go to, aside" priority = 1 description = "go to the definition of symbol under cursor in an editor to the side" -key = "g shift+d" +key = "[KeyG] shift+[KeyD]" combinedName = "go to (aside)" command = "editor.action.revealDefinitionAside" when = "editorTextFocus" @@ -1135,13 +1138,13 @@ when = "editorTextFocus" path = "window" name = "open" description = "open the file name under the cursor" -key = "g f" +key = "[KeyG] [KeyF]" command = "extension.openFileFromPath" when = "editorTextFocus" [[bind]] path = "edit.motion" -key = "g c" +key = "[KeyG] [KeyC]" name = "cell →" combinedName = "cell →/←" command = "runCommands" @@ -1150,7 +1153,7 @@ description = "previous jupyter notebook cell" [[bind]] path = "edit.motion" -key = "g shift+c" +key = "[KeyG] shift+[KeyC]" name = "cell ←" combinedName = "cell →/←" description = "previous jupyter notebook cell" @@ -1179,7 +1182,7 @@ default.args.boundary = "start" [[bind]] path = "edit.motion.match" -key = "m" +key = "[KeyM]" name = "match" description = """ Find the closest character range matching a specified object. @@ -1189,7 +1192,7 @@ command = "master-key.prefix" [[bind]] path = "edit.motion.match" -key = "m m" +key = "[KeyM] [KeyM]" prefixes = [""] name = "smart expand" description = "Use VSCode's built-in smart expansion command" @@ -1197,18 +1200,18 @@ command = "editor.action.smartSelect.expand" [[bind]] path = "edit.motion.match.obj" -key = "m w" +key = "[KeyM] [KeyW]" name = "around subwrd →" description = "(camel/snake case)" combinedName = "around subwrd ←/→" combinedDescription = "(camel/snake case)" -combinedKey = "w/b" +combinedKey = "[KeyW]/[KeyB]" args.unit = "subword" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m b" +key = "[KeyM] [KeyB]" name = "around subwrd ←" description = "(camel/snake case)" combinedName = "around subwrd ←/→" @@ -1217,16 +1220,16 @@ computedArgs.value = "-count || -1" [[bind]] path = "edit.motion.match.obj" -key = "m shift+w" +key = "[KeyM] shift+[KeyW]" name = "ard word →" combinedName = "around word →/←" -combinedKey = "shift+w/b" +combinedKey = "shift+[KeyW]/[KeyB]" args.unit = "word" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m shift+b" +key = "[KeyM] shift+[KeyB]" name = "ard word ←" combinedName = "around word →/←" prefixes = [""] @@ -1235,17 +1238,17 @@ computedArgs.value = "-count || -1" [[bind]] path = "edit.motion.match.obj" -key = "m e" +key = "[KeyM] [KeyE]" name = "in subwrd" combinedName = "in → subword/word" -combinedKey = "e/shift+e" +combinedKey = "[KeyE]/shift+[KeyE]" args.unit = "subident" args.boundary = "both" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m shift+e" +key = "[KeyM] shift+[KeyE]" name = "in word" combinedName = "in → subword/word" args.unit = "word" @@ -1254,17 +1257,17 @@ computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m p" +key = "[KeyM] [KeyP]" name = "in parag. →" combinedName = "in paragraph →/←" -combinedKey = "p/o" +combinedKey = "[KeyP]/[KeyO]" args.boundary = "both" args.unit = "paragraph" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m o" +key = "[KeyM] [KeyO]" name = "in parag. ←" combinedName = "in paragraph →/←" args.unit = "paragraph" @@ -1273,16 +1276,16 @@ computedArgs.value = "-(count || 1)" [[bind]] path = "edit.motion.match.obj" -key = "m shift+p" +key = "[KeyM] shift+[KeyP]" name = "arn parag. →" combinedName = "around paragraph →/←" -combinedKey = "shift+p/shift+o" +combinedKey = "shift+[KeyP]/shift+[KeyO]" args.unit = "paragraph" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m shift+o" +key = "[KeyM] shift+[KeyO]" name = "arn parag. ←" combinedName = "around paragraph →/←" args.unit = "paragraph" @@ -1290,16 +1293,16 @@ computedArgs.value = "-(count || 1)" [[bind]] path = "edit.motion.match.obj" -key = "m 0" +key = "[KeyM] [Digit0]" name = "arn subsec →" combinedName = "around subsection →/←" -combinedKey = "0/shift+0" +combinedKey = "[Digit0]/shift+[Digit0]" args.unit = "subsection" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m shift+0" +key = "[KeyM] shift+[Digit0]" name = "arn subsec ←" combinedName = "around subsection →/←" args.unit = "subsection" @@ -1307,16 +1310,16 @@ computedArgs.value = "-(count || 1)" [[bind]] path = "edit.motion.match.obj" -key = "m 9" +key = "[KeyM] [Digit9]" name = "in subsec →" combinedName = "in subsection →/←" -combinedKey = "9/shift+9" +combinedKey = "[Digit9]/shift+[Digit9]" args.unit = "subsection" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m shift+9" +key = "[KeyM] shift+[Digit9]" name = "in subsec ←" combinedName = "in subsection →/←" args.unit = "subsection" @@ -1324,23 +1327,23 @@ computedArgs.value = "-(count || 1)" [[bind]] path = "edit.motion.match" -key = "m g" +key = "[KeyM] [KeyG]" name = "other..." description = "additional objects to match..." command = "master-key.prefix" [[bind]] path = "edit.motion.match.obj" -key = "m g 0" +key = "[KeyM] [KeyG] [Digit0]" name = "section →" combinedName = "section →/←" -combinedKey = "0/9" +combinedKey = "[Digit0]/[Digit9]" args.unit = "section" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m g 9" +key = "[KeyM] [KeyG] [Digit9]" name = "section ←" combinedName = "section →/←" args.unit = "section" @@ -1348,16 +1351,16 @@ computedArgs.value = "-(count || 1)" [[bind]] path = "edit.motion.match.obj" -key = "m g w" +key = "m [KeyG] [KeyW]" name = "around WORD →" combinedName = "around WORD →/←" -combinedKey = "w/b" +combinedKey = "[KeyW]/[KeyB]" args.unit = "WORD" computedArgs.value = "count || 1" [[bind]] path = "edit.motion.match.obj" -key = "m g b" +key = "m [KeyG] [KeyB]" name = "around WORD ←" combinedName = "around WORD →/←" args.unit = "WORD" @@ -1365,7 +1368,7 @@ computedArgs.value = "-(count || 1)" [[bind]] path = "edit.motion.match.obj" -key = "m g e" +key = "m [KeyG] [KeyE]" name = "in WORD" args.unit = "WORD" args.boundary = "both" @@ -1380,10 +1383,10 @@ selection commands that move by a predefined syntactic object like brackets and [[bind]] path = "edit.motion.match.syntax" -key = "m [" +key = "[KeyM] [BracketLeft]" name = "in parens" combinedName = "in/arnd parens" -combinedKey = "[/shift+[" +combinedKey = "[BracketLeft]/shift+[BracketLeft]" combinedDescription = """ expand inside/around parens/brackets/braces and their contents; repeated calls to this command will seek out larger and larger scopes @@ -1396,7 +1399,7 @@ command = "selection-utilities.expandWithinBrackets" [[bind]] path = "edit.motion.match.syntax" -key = "m shift+[" +key = "[KeyM] shift+[BracketLeft]" name = "arnd parens" combinedName = "in/arnd parens" description = """ @@ -1407,14 +1410,14 @@ command = "selection-utilities.expandAroundBrackets" [[bind]] path = "edit.motion.match.syntax" -key = "m '" +key = "[KeyM] [Quote]" name = "in quotes" description = """ select within current quotes; repeated calls to this command will seek out larger and larger scopes """ combinedName = "in/arnd quotes" -combinedKey = "'/shift+'" +combinedKey = "[Quote]/shift+[Quote]" combinedDescription = """ select within/around current quotes; repeated calls to this command will seek out larger and larger scopes @@ -1423,7 +1426,7 @@ command = "bracketeer.selectQuotesContent" [[bind]] path = "edit.motion.match.syntax" -key = "m shift+'" +key = "[KeyM] shift+[Quote]" name = "around quotes" combinedName = "in/arnd quotes" description = """ @@ -1435,17 +1438,17 @@ args.commands = ["bracketeer.selectQuotesContent", "bracketeer.selectQuotesConte [[bind]] path = "edit.motion.match.syntax" -key = "m shift+." +key = "[KeyM] shift+[Period]" name = "in <>" description = "text inside angle brackets" combinedName = "in <> / in ><" -combinedKey = "shift+. / shift+," +combinedKey = "shift+[Period] / shift+[Comma]" combinedDescription = "text inside angle brackets / pairs (e.g. text in text)" command = "extension.selectAngleBrackets" [[bind]] path = "edit.motion.match.syntax" -key = "m shift+," +key = "[KeyM] shift+[Comma]" name = "in ><" combinedName = "in <> / in ><" description = "text inside tag pairs (e.g. text)" @@ -1453,11 +1456,11 @@ command = "extension.selectInTag" [[bind]] path = "edit.motion.match.syntax" -key = "m i" +key = "[KeyM] [KeyI]" name = "in indent" description = "all text at the same indentation level" combinedName = "in/arnd" -combinedKey = "space/shift+space" +combinedKey = "[space]/shift+[space]" combinedDescription = """ all text at the same indentation level / all indentation along with the line above and below this (ala c-like syntax) @@ -1466,7 +1469,7 @@ command = "vscode-select-by-indent.select-inner" [[bind]] path = "edit.motion.match.syntax" -key = "m shift+i" +key = "[KeyM] shift+[KeyI]" name = "arnd indent" description = """ all text at the same indentation level along with the line above and below @@ -1477,7 +1480,7 @@ command = "vscode-select-by-indent.select-outer" [[bind]] path = "edit.motion.match.syntax" -key = "m g i" +key = "m [KeyG] [KeyI]" name = "indent+top" description = """ all text at the same indentation level and the line just above it (ala python syntax) @@ -1494,7 +1497,7 @@ description = "Motions that match some range of characters by predefined regex" path = "edit.motion.match.cell" name = "in cell" description = "select text within a cell (ala jupyter)" -key = "m c" +key = "[KeyM] [KeyC]" command = "jupyter.selectCell" [[path]] @@ -1511,10 +1514,10 @@ characters (s), where N is the count. Examples: 2mt'' would search for a string between `''` and `''`. 2ms,,.. would search for a string between `,,` and `..`. """ -key = "m t" +key = "[KeyM] [KeyT]" command = "runCommands" combinedName = "between pair/two" -combinedKey = "t/s" +combinedKey = "[KeyT]/[KeyS]" description = """ Select between pairs of the same N characters, where N is the count. Example: 2mt'' would search for a string between '' and ''. @@ -1536,7 +1539,7 @@ description = """ Select between two different sets of N characters, where N is the count e.g. 2ms,,.. would search for a string between ,, and .. """ -key = "m s" +key = "[KeyM] [KeyS]" combinedName = "between pair/two" command = "runCommands" @@ -1570,7 +1573,7 @@ description = "Essential actions required to edit text" [[bind]] path = "edit.action.basic" #- TODO: add documentation to these basic editor keys -key = "i" +key = "[KeyI]" name = "insert" description = "Switch to insert mode (right before character)" command = "runCommands" @@ -1579,7 +1582,7 @@ mode = ["normal", "selectedit", "syminsert"] [[bind]] path = "edit.action.basic" -key = "a" +key = "[KeyA]" name = "append" description = "insert after cursor" mode = ["normal", "selectedit", "syminsert"] @@ -1592,7 +1595,7 @@ args.commands = [ [[bind]] path = "edit.action.basic" -key = "shift+i" +key = "shift+[KeyI]" name = "insert start" mode = ["normal", "selectedit", "syminsert"] command = "runCommands" @@ -1603,7 +1606,7 @@ args.commands = [ [[bind]] path = "edit.action.basic" -key = "shift+a" +key = "shift+[KeyA]" name = "insert end" mode = ["normal", "selectedit", "syminsert"] command = "runCommands" @@ -1614,7 +1617,7 @@ args.commands = [ [[bind]] path = "edit.action.basic" -key = "c" +key = "[KeyC]" name = "change" description = """ Without a count: change selected region of text. With a count: @@ -1626,14 +1629,14 @@ args.commands = ["deleteRight", "editor.action.insertLineBefore", "master-key.en [[bind]] path = "edit.action.basic" -key = "c" +key = "[KeyC]" when = "!editorHasMultilineSelection && editorHasSelection" command = "runCommands" args.commands = ["deleteRight", "master-key.enterInsert"] [[bind]] path = "edit.action.basic" -key = "c" +key = "[KeyC]" when = "!editorHasSelection && master-key.count <= 1" command = "runCommands" args.commands = [ @@ -1645,7 +1648,7 @@ args.commands = [ [[bind]] path = "edit.action.basic" -key = "c" +key = "[KeyC]" when = "!editorHasSelection && master-key.count > 1" command = "runCommands" args.commands = [ @@ -1657,7 +1660,7 @@ args.commands = [ [[bind]] path = "edit.action.basic" -key = "shift+c" +key = "shift+[KeyC]" name = "change to/back" description = """Without a count: change from current char to end of line. With a count: change the previous `count` lines. @@ -1673,7 +1676,7 @@ args.commands = [ [[bind]] path = "edit.action.basic" -key = "shift+c" +key = "shift+[KeyC]" mode = ["normal", "selectedit"] when = "master-key.count > 1" command = "runCommands" @@ -1686,7 +1689,7 @@ args.commands = [ [[bind]] path = "edit.action.basic" -key = "x" +key = "[KeyX]" mode = "normal" name = "delete char" command = "runCommands" @@ -1698,14 +1701,14 @@ args.commands = [ [[bind]] path = "edit.action.basic" -key = "r" +key = "[KeyR]" name = "replace char" description = "replace the character under the cursor" command = "master-key.replaceChar" [[bind]] path = "edit.action.basic" -key = "ctrl+i" +key = "ctrl+[KeyI]" name = "insert char" mode = ["normal", "selectedit"] description = "insert a character in front of the cursor" @@ -1718,19 +1721,19 @@ description = "Operations that manipulate the clipboard in some way." [[bind]] path = "edit.action.clipboard" -key = "p" +key = "[KeyP]" name = "paste after" description = "Paste clipboard after the cursor/selection" combinedName = "paste before/after/in" combinedDescription = "Paste clipboard before/after/at the cursor/selection" -combinedKey = "p/shift+p/ctrl+p" +combinedKey = "[KeyP]/shift+[KeyP]/ctrl+[KeyP]" when = "editorHasSelection" command = "runCommands" args.commands = ["selection-utilities.activeAtEnd", "selection-utilities.shrinkToActive", "editor.action.clipboardPasteAction"] [[bind]] path = "edit.action.clipboard" -key = "p" +key = "[KeyP]" name = "paste after" combinedName = "paste before/after/in" when = "!editorHasSelection" @@ -1739,7 +1742,7 @@ args.commands = ["cursorRight", "editor.action.clipboardPasteAction"] [[bind]] path = "edit.action.clipboard" -key = "ctrl+p" +key = "ctrl+[KeyP]" when = "!suggestWidgetVisible" mode = ["normal", "insert"] name = "paste in" @@ -1749,7 +1752,7 @@ command = "editor.action.clipboardPasteAction" [[bind]] path = "edit.action.clipboard" -key = "shift+p" +key = "shift+[KeyP]" name = "paste before" combinedName = "paste before/after" description = "Paste before the cursor/selection" @@ -1759,7 +1762,7 @@ args.commands = ["selection-utilities.activeAtStart", "selection-utilities.shrin [[bind]] path = "edit.action.clipboard" -key = "shift+p" +key = "shift+[KeyP]" combinedName = "paste before/after" when = "!editorHasSelection" command = "runCommands" @@ -1773,7 +1776,7 @@ Repeat the last action command. Actions usually modify the text of a document in another. (But, e.g. sending text to the REPL is also considered an editor action). See also `,` which repeats the last subject. """ -key = "." +key = "[Period]" command = "runCommands" repeat = "count" @@ -1781,9 +1784,9 @@ repeat = "count" command = "master-key.replayFromHistory" #- we can repeat any action but history-related actions; we make an exception for replaying macros, which can be repeated args.at = """ -commandHistory[i].path.startsWith('edit.action') && -(!commandHistory[i].path.startsWith('edit.action.history') || - commandHistory[i].name == 'replay') +commandHistory[KeyI].path.startsWith('edit.action') && +(!commandHistory[KeyI].path.startsWith('edit.action.history') || + commandHistory[KeyI].name == 'replay') """ [[bind.args.commands]] @@ -1792,14 +1795,14 @@ command = "master-key.enterNormal" [[bind]] path = "edit.action.history" name = "undo" -key = "u" +key = "[KeyU]" command = "runCommands" args.commands = [ "undo", "selection-utilities.shrinkToActive" ] [[bind]] path = "edit.action.history" name = "redo" -key = "shift+u" +key = "shift+[KeyU]" command = "runCommands" args.commands = [ "redo", "selection-utilities.shrinkToActive" ] @@ -1807,12 +1810,12 @@ args.commands = [ "redo", "selection-utilities.shrinkToActive" ] path = "edit.action.basic" name = 'toggle check' description = "Toggle a markdown checkbox" -key = "shift+6" +key = "shift+[Digit6]" command = "markdown-checkbox.markCheckbox" [[bind]] path = "edit.action.clipboard" -key = "d" +key = "[KeyD]" name = "delete" description = """ Without a count: delete selected text (and store to clipboard). With a @@ -1828,7 +1831,7 @@ args.commands = [ [[bind]] path = "edit.action.clipboard" -key = "d" +key = "[KeyD]" when = "editorHasSelection" command = "runCommands" args.commands = [ @@ -1838,7 +1841,7 @@ args.commands = [ [[bind]] path = "edit.action.clipboard" -key = "shift+d" +key = "shift+[KeyD]" mode = "normal" name = "without count: Delete from cursor to end of line; with count: Delete from current line up `count` number of keys." command = "runCommands" @@ -1850,7 +1853,7 @@ args.commands = [ [[bind]] path = "edit.action.clipboard" -key = "shift+d" +key = "shift+[KeyD]" mode = "normal" when = "master-key.count > 1" command = "runCommands" @@ -1858,7 +1861,7 @@ args.commands = [{ defined = "selectLinesUp" }, "deleteRight"] [[bind]] path = "edit.action.clipboard" -key = "y" +key = "[KeyY]" name = "copy" description = "copy selected text to clipboard" command = "runCommands" @@ -1866,7 +1869,7 @@ args.commands = ["editor.action.clipboardCopyAction", "selection-utilities.shrin [[bind]] path = "edit.action.clipboard" -key = "y" +key = "[KeyY]" when = "master-key.count > 1" command = "runCommands" args.commands = [ @@ -1877,7 +1880,7 @@ args.commands = [ [[bind]] path = "edit.action.clipboard" -key = "shift+y" +key = "shift+[KeyY]" name = "copy (eol/up)" description = "without a count: copy to end of line; with a count: copy this and the previous N lines" when = "master-key.count <= 1" @@ -1891,7 +1894,7 @@ args.commands = [ [[bind]] path = "edit.action.clipboard" -key = "shift+y" +key = "shift+[KeyY]" when = "master-key.count > 1" command = "runCommands" args.commands = [ @@ -1916,14 +1919,14 @@ Operations that affect line indentation [[bind]] path = "edit.action.indent" -key = "shift+." +key = "shift+[Period]" name = "indent" description = "Indent lines" command = "editor.action.indentLines" [[bind]] path = "edit.action.indent" -key = "shift+." +key = "shift+[Period]" name = "indent" description = "Indent lines" when = "master-key.count >= 1" @@ -1935,7 +1938,7 @@ args.commands = [ [[bind]] path = "edit.action.indent" -key = "shift+," +key = "shift+[Comma]" name = "deindent" when = "master-key.count < 1" description = "De-indent lines" @@ -1943,7 +1946,7 @@ command = "editor.action.outdentLines" [[bind]] path = "edit.action.indent" -key = "shift+," +key = "shift+[Comma]" name = "deindent" when = "master-key.count >= 1" description = "Deindent lines" @@ -1972,14 +1975,14 @@ description = "Commands that modify one or more numbers" path = "edit.action.numbers" name = 'inc #' description = "Increment a number by 1" -key = "=" +key = "[Equal]" command = "selection-utilities.incrementNumber" [[bind]] path = "edit.action.numbers" name = 'dec #' description = "Decrement a number by 1 " -key = "shift+=" +key = "shift+[Equal]" command = "selection-utilities.decrementNumber" # ## Captilization @@ -1996,98 +1999,98 @@ default.mode = ["normal", "selectedit"] path = "edit.action.capitals" name = 'camel' description = "Swap style to lower camel case (`camelCase`)" -key = "` c" +key = "` [KeyC]" command = "extension.changeCase.camel" [[bind]] path = "edit.action.capitals" name = 'constant' description = "Swap style to constant (`IS_CONSTANT`)" -key = "` shift+u" +key = "` shift+[KeyU]" command = "extension.changeCase.constant" [[bind]] path = "edit.action.capitals" name = 'dot' description = "Swap style to dot case (`dot.case`)" -key = "` ." +key = "` [Period]" command = "extension.changeCase.dot" [[bind]] path = "edit.action.capitals" name = 'kebab' description = "Swap style to kebab case (`kebab-case`)" -key = "` -" +key = "` [Minus]" command = "extension.changeCase.kebab" [[bind]] path = "edit.action.capitals" name = 'all lower' description = "Swap all to lower case" -key = "` shift+l" +key = "` shift+[KeyL]" command = "extension.changeCase.lower" [[bind]] path = "edit.action.capitals" name = 'first lower' description = "Swap first letter to lower case" -key = "` l" +key = "` [KeyL]" command = "extension.changeCase.lowerFirst" [[bind]] path = "edit.action.capitals" name = 'spaces' description = "Swap to spaces (`camelCase` -> `camel case`)" -key = "` space" +key = "` [Space]" command = "extension.changeCase.no" [[bind]] path = "edit.action.capitals" name = 'Camel' description = "Swap to upper camel case (`CamelCase`)" -key = "` shift+c" +key = "` shift+[KeyC]" command = "extension.changeCase.pascal" [[bind]] path = "edit.action.capitals" name = 'path' description = "Swap to 'path' case (`path/case`)" -key = "` /" +key = "` [Slash]" command = "extension.changeCase.path" [[bind]] path = "edit.action.capitals" name = 'snake' description = "Swap to snake case (`snake_case`)" -key = "` shift+-" +key = "` shift+[Minus]" command = "extension.changeCase.snake" [[bind]] path = "edit.action.capitals" name = 'swap' description = "Swap upper and lower case letters" -key = "` s" +key = "` [KeyS]" command = "extension.changeCase.swap" [[bind]] path = "edit.action.capitals" name = 'title' description = "Swap to title case (all words have first upper case letter)" -key = "` t" +key = "` [KeyT]" command = "extension.changeCase.title" [[bind]] path = "edit.action.capitals" name = 'all upper' description = "Swap to use all upper case letters" -key = "` shift+y" +key = "` shift+[KeyY]" command = "extension.changeCase.upper" [[bind]] path = "edit.action.capitals" name = 'first upper' description = "Swap first character to upper case" -key = "` u" +key = "` [KeyU]" command = "extension.changeCase.upperFirst" # ## "Do" Actions @@ -2103,7 +2106,7 @@ default.mode = "normal" [[bind]] path = "edit.action.do" name = "do" -key = "space" +key = "[Space]" description = "additional actions, mostly for modifying specific syntactic formats" command = "master-key.prefix" @@ -2111,10 +2114,10 @@ command = "master-key.prefix" path = "edit.action.do" name = "paste after line" combinedName = "paste after/before line" -combinedKey = "p/shift+p" +combinedKey = "[KeyP]/shift+[KeyP]" description = "Paste text after current line" priority = 2 -key = "space p" +key = "[Space] [KeyP]" command = "runCommands" args.commands = [ "expandLineSelection", @@ -2129,7 +2132,7 @@ priority = 2 name = "paste before line" combinedName = "paste after/before line" description = "Paste text before current line" -key = "space shift+p" +key = "[Space] shift+[KeyP]" command = "runCommands" args.commands = [ "expandLineSelection", @@ -2144,9 +2147,9 @@ priority = 2 name = "add line below" combinedName = "add line below/above" combinedDescription = "open a line below/above current line" -combinedKey = "o/shift+o" +combinedKey = "[KeyO]/shift+[KeyO]" description = "open a line below current line" -key = "space o" +key = "[Space] [KeyO]" command = "editor.action.insertLineAfter" [[bind]] @@ -2155,7 +2158,7 @@ name = "add line above" priority = 2 combinedName = "add line below/above" description = "open a line above current line" -key = "space shift+o" +key = "[Space] shift+[KeyO]" command = "editor.action.insertLineBefore" [[bind]] @@ -2163,10 +2166,10 @@ path = "edit.action.do" name = 'sym insert' description = "Insert a character pair around a character" priority = 1 -key = "space i" +key = "[Space] [KeyI]" combinedName = "sym insert (mode)" combinedDescription = "Insert characters around pair (switching to syminster mode until hitting again)" -combinedKey = "i/shift+i" +combinedKey = "[KeyI]/shift+[KeyI]" command = "runCommands" [[bind.args.commands]] @@ -2183,17 +2186,17 @@ args.followCursor = true path = "edit.action.do" name = 'trim white' description = "Delete all external whitespace (left and right edges)" -key = "space shift+-" +key = "[Space] shift+[Minus]" command = "selection-utilities.trimWhitespace" [[bind]] path = "edit.action.do" -key = "space w" +key = "[Space] [KeyW]" name = "wrap p" combinedName = "wrap/join lines" description = "wrap paragraph text, preserving commenting" combinedDescription = "wrap paragraph text, preserving commenting / join lines together" -combinedKey = "w/j" +combinedKey = "[KeyW]/[KeyJ]" command = "rewrap.rewrapComment" [[bind]] @@ -2201,7 +2204,7 @@ path = "edit.action.basic" name = 'join' combinedName = "wrap/join lines" description = "Remove newline between current and next line" -key = "space j" +key = "[Space] [KeyJ]" mode = ["normal", "selectedit"] when = "!editorHasSelection" command = "runCommands" @@ -2213,12 +2216,12 @@ combinedName = "wrap/join lines" name = 'join' description = "Remove newline between current and next line" mode = ["normal", "selectedit"] -key = "space j" +key = "[Space] [KeyJ]" command = "editor.action.joinLines" [[bind]] path = "edit.action.do" -key = "space f" +key = "[Space] [KeyF]" name = "format" combinedName = "format / format document" when = "master-key.count < 1" @@ -2226,9 +2229,9 @@ command = "editor.action.formatSelection" [[bind]] path = "edit.action.do" -key = "space f" +key = "[Space] [KeyF]" combinedName = "format / format document" -combinedKey = "f/shift+f" +combinedKey = "[KeyF]/shift+[KeyF]" combinedDescription = "Format selection / document" name = "format" description = "Format sel" @@ -2242,7 +2245,7 @@ args.commands = [ [[bind]] path = "edit.action.do" -key = "space shift+f" +key = "[Space] shift+[KeyF]" name = "format doc" combinedName = "format / format document" command = "editor.action.formatDocument" @@ -2256,42 +2259,42 @@ description = "Commands that edit two matching brackets or quotes." path = "edit.action.do" name = 'parens' description = "actions related to various brackets (`[`, `(`, `{`)" -key = "space [" +key = "[Space] [BracketLeft]" command = "master-key.prefix" [[bind]] path = "edit.action.do" name = 'remove' description = "Removes surrounding pairs" -key = "space [ d" +key = "[Space] [BracketLeft] [KeyD]" command = "bracketeer.removeBrackets" [[bind]] path = "edit.action.do" name = 'parens/brackets' description = "Swap between `[`, `(` and `{`" -key = "space [ s" +key = "[Space] [BracketLeft] [KeyS]" command = "bracketeer.swapBrackets" [[bind]] path = "edit.action.do" name = 'quotes' description = "Actions related to quotes" -key = "space '" +key = "[Space] [Quote]" command = "master-key.prefix" [[bind]] path = "edit.action.do" name = 'remove' description = "Removes quotes (', \" or `)" -key = "space ' d" +key = "[Space] [Quote] [KeyD]" command = "bracketeer.removeQuotes" [[bind]] path = "edit.action.do" name = 'swap' description = "Swap quotes (', \" or `)" -key = "space ' s" +key = "[Space] [Quote] [KeyS]" command = "bracketeer.swapQuotes" [[path]] @@ -2303,18 +2306,18 @@ Operations that modify comments [[bind]] path = "edit.action.do" -key = "space /" +key = "[Space] [Slash]" combinedName = "(block) comment" when = "master-key.count < 1" command = "editor.action.commentLine" [[bind]] path = "edit.action.do" -key = "space /" +key = "[Space] [Slash]" name = "comment lines" combinedName = "(block) comment" combinedDescription = "Toggle (block) comment" -combinedKey = "(shift+)/" +combinedKey = "(shift+)[Slash]" description = "select next comment" when = "master-key.count >= 1" command = "runCommands" @@ -2325,14 +2328,14 @@ args.commands = [ [[bind]] path = "edit.action.do" -key = "space shift+/" +key = "[Space] shift+[Slash]" when = "master-key.count < 1" combinedName = "(block) comment" command = "editor.action.blockComment" [[bind]] path = "edit.action.do" -key = "space shift+/" +key = "[Space] shift+[Slash]" name = "block comment lines" combinedName = "(block) comment" description = "select previous comment" @@ -2349,9 +2352,9 @@ path = "edit.action.do" name = 'inc all #' combinedName = "inc/dec all #" combinedDescription = "Increment/decrement selected numbers; increment/decrement increases per selection" -combinedKey = "=/shift+=" +combinedKey = "[Equal]/shift+[Equal]" description = "Increment selected numbers; increment increases per selection" -key = "space =" +key = "[Space] [Equal]" command = "selection-utilities.incrementNumberPerSelection" [[bind]] @@ -2359,19 +2362,19 @@ path = "edit.action.do" name = 'dec all #' combinedName = "inc/dec all #" description = "Decrement selected numbers; decrement increases per selection" -key = "space shift+=" +key = "[Space] shift+[Equal]" command = "selection-utilities.decrementNumberPerSelection" [[bind]] path = "edit.action.do" name = 'nb cell' description = "Actions related to notebook cells" -key = "space c" +key = "[Space] [KeyC]" command = "master-key.prefix" [[bind]] path = "edit.action.do" -key = "space c i" +key = "[Space] [KeyC] [KeyI]" when = "editorLangId == 'quarto'" command = "quarto.insertCodeCell" name = "insert cell" @@ -2379,13 +2382,13 @@ description = "insert a new cell in a notebook" [[bind]] path = "edit.action.do" -key = "space c s" +key = "[Space] [KeyC] [KeyS]" when = "editorLangId != 'quarto'" command = "jupyter.selectCell" [[bind]] path = "edit.action.basic" -key = "space ." +key = "[Space] [Period]" name = 'sent. lines' description = "Split paragraph into one line per sentence" mode = "normal" @@ -2425,7 +2428,7 @@ command = "selection-utilities.cancelSelection" path = "edit.action.history" name = "record" description = "Start/stop recording Master Key commands" -key = "shift+q" +key = "shift+[KeyQ]" when = "!master-key.record" command = "master-key.record" args.on = true @@ -2437,7 +2440,7 @@ description = """ Start/stop recording key presses defined by Master Key pushing it to the top of the `history` stack once recording finishes." """ -key = "shift+q" +key = "shift+[KeyQ]" when = "master-key.record" command = "runCommands" @@ -2457,7 +2460,7 @@ description = """ Replay the Master Key command sequence at the top of the `history` stack. Specifying a count requests the Nth most recent item on this stack. """ -key = "q q" +key = "[KeyQ] [KeyQ]" command = "master-key.replayFromStack" computedArgs.index = "count" @@ -2468,7 +2471,7 @@ description = """ Stores the top of the `history` stack into a named register. Specifying a count stores the Nth most recent item on this stack. """ -key = "q s" +key = "[KeyQ] [KeyS]" command = "master-key.storeNamed" args.description = "Save Macro" args.name = "macro" @@ -2481,7 +2484,7 @@ description = """ Replay a recorded Master Key command sequence from a named register, pushing it to the front of the history stack. """ -key = "q r" +key = "[KeyQ] [KeyR]" command = "runCommands" [[bind.args.commands]] @@ -2503,7 +2506,7 @@ name = "store last" description = """ Store the N most recently run commands as a macro, where N is the count (defaulting to 1). """ -key = "q l" +key = "[KeyQ] [KeyL]" command = "master-key.pushHistoryToStack" args.range.from = "i-(count || 0)" args.range.to = "i" @@ -2514,7 +2517,7 @@ args.range.to = "i" [[bind]] path = "window" -key = "shift+ctrl+;" +key = "shift+ctrl+[Semicolon]" name = "palette" resetTransient = false hideInPalette = true @@ -2524,13 +2527,13 @@ description = """ show command suggestions within the context of the current mode and keybinding prefix (if any keys have already been typed) """ -command = "master-key.commandPalette" +command = "master-key.commandSuggestions" [[bind]] path = "util" name = "git..." description = "git commands" -key = "tab g" +key = "[Tab] [KeyG]" command = "master-key.prefix" [[bind]] @@ -2539,15 +2542,15 @@ name = "pull" combinedName = "push/pull" description = "pull changes from remote" combinedDescription = "pull from/push to remote" -combinedKey = "p/shift+p" -key = "tab g p" +combinedKey = "[KeyP]/shift+[KeyP]" +key = "[Tab] [KeyG] [KeyP]" command = "git.pull" [[bind]] path = "util" name = "push" description = "push changes to remote" -key = "tab g shift+p" +key = "[Tab] [KeyG] shift+[KeyP]" command = "git.push" [[bind]] @@ -2556,8 +2559,8 @@ name = "checkout" combinedName = "commit/checkout" description = "commit changes" combinedDescription = "commit/checkout git changes" -combinedKey = "c/shift+c" -key = "tab g c" +combinedKey = "[KeyC]/shift+[KeyC]" +key = "[Tab] [KeyG] [KeyC]" command = "git.commit" [[bind]] @@ -2565,28 +2568,28 @@ path = "util" name = "checkout" combinedName = "commit/checkout" description = "checkout changes" -key = "tab g shift+c" +key = "[Tab] [KeyG] shift+[KeyC]" command = "git.checkout" [[bind]] path = "util" name = "revert range" description = "revert unstaged changes in selected range" -key = "tab g r" +key = "[Tab] [KeyG] [KeyR]" command = "git.revertSelectedRanges" [[bind]] path = "util" name = "revert range" description = "revert unstaged changes in selected range" -key = "tab g s" +key = "[Tab] [KeyG] [KeyS]" command = "git.stageSelectedRanges" [[bind]] path = "util" name = "commands..." description = "show GitLens command palette for git" -key = "tab g g" +key = "[Tab] [KeyG] [KeyG]" command = "gitlens.gitCommands" # ## Miscellaneous Commands @@ -2602,7 +2605,7 @@ when = "editorTextFocus && !findWidgetVisible" [[bind]] path = "util" name = "utility" -key = "tab" +key = "[Tab]" description = "utility related commands: file opening, window manipulation, debugging etc..." command = "master-key.prefix" @@ -2610,7 +2613,7 @@ command = "master-key.prefix" path = "util" name = "open recent" description = "Open recent file" -key = "tab r" +key = "[Tab] [KeyR]" command = "workbench.action.openRecent" [[bind]] @@ -2619,8 +2622,8 @@ name = "hover" description = "show the hover view" combinedName = "(debug) hover" combinedDescription = "show the (debug) hover view" -combinedKey = "(shift+)h" -key = "tab h" +combinedKey = "(shift+)[KeyH]" +key = "[Tab] [KeyH]" command = "editor.action.showHover" [[bind]] @@ -2628,7 +2631,7 @@ path = "util" name = "debug hover" combinedName = "(debug) hover" description = "show the debug hover view" -key = "tab shift+h" +key = "[Tab] shift+[KeyH]" command = "editor.debug.action.showDebugHover" [[bind]] @@ -2639,8 +2642,8 @@ description = "toggle bookmark at given line" combinedDescription = """ toggle bookmark at given line / bookmark related commands """ -key = "tab shift+m" -combinedKey = "shift+m / m" +key = "[Tab] shift+[KeyM]" +combinedKey = "shift+[KeyM] / [KeyM]" command = "vsc-labeled-bookmarks.toggleBookmark" [[bind]] @@ -2648,7 +2651,7 @@ path = "util" name = "mark" combinedName = "add mark / mark..." description = "bookmark related commands" -key = "tab m" +key = "[Tab] [KeyM]" command = "master-key.prefix" [[bind]] @@ -2657,15 +2660,15 @@ name = "mark ↓" description = "move to next bookmark" combinedName = "mark ↓/↑" combinedDescription = "move to next/previous bookmark" -combinedKey = "j/k" -key = "tab m j" +combinedKey = "[KeyJ]/[KeyK]" +key = "[Tab] [KeyM] [KeyJ]" when = "!master-key.select_on && !editorHasSelection" command = "vsc-labeled-bookmarks.navigateToNextBookmark" [[bind]] path = "util" combinedName = "mark ↓/↑" -key = "tab m j" +key = "[Tab] [KeyM] [KeyJ]" when = "master-key.select_on || editorHasSelection" command = "vsc-labeled-bookmarks.expandSelectionToNextBookmark" @@ -2674,7 +2677,7 @@ path = "util" name = "mark ↑" combinedName = "mark ↓/↑" description = "move to previous bookmark" -key = "tab m k" +key = "[Tab] [KeyM] [KeyK]" when = "!master-key.select_on && !editorHasSelection" command = "vsc-labeled-bookmarks.navigateToPreviousBookmark" @@ -2683,7 +2686,7 @@ path = "util" name = "mark ↑" combinedName = "mark ↓/↑" description = "move to previous bookmark" -key = "tab m k" +key = "[Tab] [KeyM] [KeyK]" when = "master-key.select_on || editorHasSelection" command = "runCommands" args.commands = ["vsc-labeled-bookmarks.expandSelectionToPreviousBookmark", @@ -2693,14 +2696,14 @@ args.commands = ["vsc-labeled-bookmarks.expandSelectionToPreviousBookmark", path = "util" name = "remove mark" description = "remove bookmark (use quick selection)" -key = "tab m d" +key = "[Tab] [KeyM] [KeyD]" command = "vsc-labeled-bookmarks.deleteBookmark" [[bind]] path = "util" name = "nav marks" description = "reveal quick selection to move to a bookmark" -key = "tab m t" +key = "[Tab] [KeyM] [KeyT]" command = "vsc-labeled-bookmarks.navigateToBookmark" [[bind]] @@ -2708,11 +2711,11 @@ path = "util" name = "error →" combinedName = "error →/←" combinedDescription = "move to next/previous error" -combinedKey = "e/shift+e" +combinedKey = "[KeyE]/shift+[KeyE]" description = """ move to next error """ -key = "tab e" +key = "[Tab] [KeyE]" command = "editor.action.marker.next" [[bind]] @@ -2722,7 +2725,7 @@ combinedName = "error →/←" description = """ move to previous error """ -key = "tab shift+e" +key = "[Tab] shift+[KeyE]" command = "editor.action.marker.prev" [[bind]] @@ -2730,11 +2733,11 @@ path = "edit.motion" name = "diff →" combinedName = "diff →/←" combinedDescription = "move to and show next/previous diff" -combinedKey = "c/shift+c" +combinedKey = "[KeyC]/shift+[KeyC]" description = """ move to and show next diff """ -key = "tab c" +key = "[Tab] [KeyC]" command = "editor.action.dirtydiff.next" [[bind]] @@ -2744,7 +2747,7 @@ combinedName = "diff →/←" description = """ move to and show previous diff """ -key = "tab shift+c" +key = "[Tab] shift+[KeyC]" command = "editor.action.dirtydiff.previous" [[bind]] @@ -2752,11 +2755,11 @@ path = "edit.motion" name = "change →" combinedName = "change →/←" combinedDescription = "move to next/previous file change" -combinedKey = "d/shift+d" +combinedKey = "[KeyD]/shift+[KeyD]" description = """ move to next file change """ -key = "tab d" +key = "[Tab] [KeyD]" command = "workbench.action.editor.nextChange" [[bind]] @@ -2766,7 +2769,7 @@ combinedName = "change →/←" description = """ move to previous change """ -key = "tab shift+d" +key = "[Tab] shift+[KeyD]" command = "workbench.action.editor.previousChange" # ## Window Manipulation @@ -2785,7 +2788,7 @@ when = "editorTextFocus && !findWidgetVisible" path = "window" name = "cntr win" description = "center window at primary cursor position" -key = "tab l" +key = "[Tab] [KeyL]" command = "selection-utilities.revealActive" args.at = "center" when = "editorTextFocus" @@ -2794,13 +2797,13 @@ when = "editorTextFocus" path = "window" name = "window" description = "window/editor pane manipulation-related commands" -key = "tab w" +key = "[Tab] [KeyW]" command = "master-key.prefix" [[bind]] path = "window" name = "vert/horz" -key = "tab w r" +key = "[Tab] [KeyW] [KeyR]" description = "Toggle between horizontal and vertical layouts" command = "workbench.action.toggleEditorGroupLayout" @@ -2810,8 +2813,8 @@ name = "next window" combinedName = "next/previous window" description = "move to next window" combinedDescription = "move to next/prev window" -key = "tab ]" -combinedKey = "]/[" +key = "[Tab] [BracketRight]" +combinedKey = "[BracketRight]/[BracketLeft]" command = "workbench.action.focusNextGroup" [[bind]] @@ -2819,7 +2822,7 @@ path = "window" name = "prev window" combinedName = "next/previous window" description = "move to previous window" -key = "tab [" +key = "[Tab] [BracketLeft]" command = "workbench.action.focusPreviousGroup" [[bind]] @@ -2827,9 +2830,9 @@ path = "window" name = "move →" combinedName = "move →/←" combinedDescription = "move editor to window left/right" -combinedKey = "l/h" +combinedKey = "[KeyL]/[KeyH]" description = "move editor to window to left" -key = "tab w l" +key = "[Tab] [KeyW] [KeyL]" command = "workbench.action.moveEditorToRightGroup" [[bind]] @@ -2837,7 +2840,7 @@ path = "window" name = "←" combinedName = "move →/←" description = "move editor to window to left" -key = "tab w h" +key = "[Tab] [KeyW] [KeyH]" command = "workbench.action.moveEditorToLeftGroup" [[bind]] @@ -2845,9 +2848,9 @@ path = "window" name = "↓" combinedName = "move ↓/↑" combinedDescription = "move editor to window above/below" -combinedKey = "j/k" +combinedKey = "[KeyJ]/[KeyK]" description = "move editor to window below" -key = "tab w j" +key = "[Tab] [KeyW] [KeyJ]" command = "workbench.action.moveEditorToBelowGroup" [[bind]] @@ -2855,14 +2858,14 @@ path = "window" name = "↑" combinedName = "move ↓/↑" description = "move editor to window above" -key = "tab w k" +key = "[Tab] [KeyW] [KeyK]" command = "workbench.action.moveEditorToAboveGroup" [[bind]] path = "window" name = "split editor..." description = "split editor to in a given direction" -key = "tab w s" +key = "[Tab] [KeyW] [KeyS]" command = "master-key.prefix" [[bind]] @@ -2870,9 +2873,9 @@ path = "window" name = "move →" combinedName = "split →/←" combinedDescription = "move editor to window left/right" -combinedKey = "l/h" +combinedKey = "[KeyL]/[KeyH]" description = "split editor to window to left" -key = "tab w s l" +key = "[Tab] w [KeyS] [KeyL]" command = "workbench.action.splitEditorRight" [[bind]] @@ -2880,7 +2883,7 @@ path = "window" name = "←" combinedName = "split →/←" description = "split editor to window to left" -key = "tab w s h" +key = "[Tab] w [KeyS] [KeyH]" command = "workbench.action.splitEditorLeft" [[bind]] @@ -2888,9 +2891,9 @@ path = "window" name = "↓" combinedName = "split ↓/↑" combinedDescription = "split editor to window above/below" -combinedKey = "j/k" +combinedKey = "[KeyJ]/[KeyK]" description = "split editor to window below" -key = "tab w s j" +key = "[Tab] w [KeyS] [KeyJ]" command = "workbench.action.splitEditorDown" [[bind]] @@ -2898,40 +2901,40 @@ path = "window" name = "↑" combinedName = "split ↓/↑" combinedDescription = "split editor to window above/below" -combinedKey = "j/k" +combinedKey = "[KeyJ]/[KeyK]" description = "split editor to window below" -key = "tab w s k" +key = "[Tab] w [KeyS] [KeyK]" command = "workbench.action.splitEditorUp" [[bind]] path = "window" name = "close pane" description = "close the given group of editors" -key = "tab w x" +key = "[Tab] [KeyW] [KeyX]" command = "workbench.action.closeEditorsInGroup" [[bind]] path = "window" name = "max" description = "minimize size of all other windows" -key = "tab w shift+m" +key = "[Tab] [KeyW] shift+[KeyM]" command = "workbench.action.minimizeOtherEditors" [[bind]] path = "window" name = "equal" description = "equalize size of all windows" -key = "tab w =" +key = "[Tab] [KeyW] [Equal]" command = "workbench.action.evenEditorWidths" [[bind]] path = "window" name = "curs. win top" description = "center window so that primary cursor is at the top" -key = "tab k" +key = "[Tab] [KeyK]" combinedName = "center window top/bottom" combinedDescription = "center window so that primary cursor is at the top/bottom" -combinedKey = "k/j" +combinedKey = "[KeyK]/[KeyJ]" command = "selection-utilities.revealActive" args.at = "top" @@ -2940,7 +2943,7 @@ path = "window" name = "curs. win bot" combinedName = "center window top/bottom" description = "center window so that primary cursor is at the bottom" -key = "tab j" +key = "[Tab] [KeyJ]" command = "selection-utilities.revealActive" args.at = "bottom" @@ -2952,10 +2955,10 @@ args.at = "bottom" path = "util" name = "breakpt." combinedName = "breakpt / debug..." -combinedKey = "shift+b/b" +combinedKey = "shift+[KeyB]/[KeyB]" description = "toggle debug breakpoint" combinedDescription = "toggle debug breakpoint / debug related commands..." -key = "tab shift+b" +key = "[Tab] shift+[KeyB]" command = "editor.debug.action.toggleBreakpoint" [[bind]] @@ -2963,14 +2966,14 @@ path = "util" name = "debug..." combinedName = "breakpt / debug..." description = "assorted debugging actions" -key = "tab b" +key = "[Tab] [KeyB]" command = "master-key.prefix" [[bind]] path = "util" name = "cond. break" description = "conditional breakpoint" -key = "tab b shift+c" +key = "[Tab] [KeyB] shift+[KeyC]" command = "editor.debug.action.conditionalBreakpoint" @@ -2978,35 +2981,35 @@ command = "editor.debug.action.conditionalBreakpoint" path = "util" name = "start" description = "start debugging" -key = "tab b r" +key = "[Tab] [KeyB] [KeyR]" command = "workbench.action.debug.start" [[bind]] path = "util" name = "continue" description = "continue debugging" -key = "tab b c" +key = "[Tab] [KeyB] [KeyC]" command = "workbench.action.debug.continue" [[bind]] path = "util" name = "next" description = "debug: step over next line" -key = "tab b j" +key = "[Tab] [KeyB] [KeyJ]" command = "workbench.action.debug.stepOver" [[bind]] path = "util" name = "into" description = "debug: step into next line" -key = "tab b i" +key = "[Tab] [KeyB] [KeyI]" command = "workbench.action.debug.stepInto" [[bind]] path = "util" name = "out" description = "debug: step out" -key = "tab b o" +key = "[Tab] [KeyB] [KeyO]" command = "workbench.action.debug.stepOut" # ## Select-edit Mode @@ -3031,16 +3034,16 @@ name = "select-edit" description = """ Enter a mode where you can edit and manipulate (possibly multiple) selections. """ -key = "'" +key = "[Quote]" command = "master-key.setMode" args.value = "selectedit" mode = "normal" [[bind]] path = "edit.select_edit" -key = "shift+'" +key = "shift+[Quote]" combinedName = "rm cursors" -combinedKey = "shift/ctrl+'" +combinedKey = "shift/ctrl+[Quote]" combinedDescription = "Delete all selections and return to normal (multiple key variants)" name = "del. cursors" description = "Delete all selections and return to normal" @@ -3050,7 +3053,7 @@ mode = ["selectedit", "normal"] [[bind]] path = "edit.select_edit" -key = "ctrl+'" +key = "ctrl+[Quote]" mode = ["insert", "selectedit", "normal"] name = "rm cursors" combinedName = "rm cursors" @@ -3062,7 +3065,7 @@ args.commands = ["selection-utilities.cancelSelection", "master-key.enterNormal" path = "edit.select_edit" name = 'normal' description = "return to normal mode" -key = "'" +key = "[Quote]" command = "master-key.enterNormal" [[bind]] @@ -3071,8 +3074,8 @@ name = "add →" combinedName = "add →/←" description = "add cursor at the next match to the primary cursor's text" combinedDescription = "add cursor at the next/previous match to the primary cursor's text" -key = "l" -combinedKey = "l/h" +key = "[KeyL]" +combinedKey = "[KeyL]/[KeyH]" repeat = "count" command = "selection-utilities.addNext" @@ -3081,7 +3084,7 @@ path = "edit.select_edit" name = "add ←" combinedName = "add →/←" description = "add cursor at the previous match to the primary cursor's text" -key = "h" +key = "[KeyH]" command = "selection-utilities.addPrev" repeat = 'count' @@ -3091,8 +3094,8 @@ name = "skip →" combinedName = "skip →/←" description = "move primary cursor to the next match of the primary cursor's text" combinedDescription = "move primary cursor to the next/previous match of the primary cursor's text" -key = "shift+l" -combinedKey = "shift+l/h" +key = "shift+[KeyL]" +combinedKey = "shift+[KeyL]/[KeyH]" command = "selection-utilities.skipNext" repeat = "count" @@ -3101,7 +3104,7 @@ path = "edit.select_edit" name = "skip ←" combinedName = "skip →/←" description = "move primary cursor to the previous match of the primary cursor's text" -key = "shift+h" +key = "shift+[KeyH]" command = "selection-utilities.skipPrev" repeat = 'count' @@ -3109,14 +3112,14 @@ repeat = 'count' path = "edit.select_edit" name = "align ←" description = "align selections left" -key = "=" +key = "[Equal]" command = "selection-utilities.alignSelectionsLeft" [[bind]] path = "edit.select_edit" name = "align →" description = "align selections right" -key = "shift+=" +key = "shift+[Equal]" command = "selection-utilities.alignSelectionsRight" [[bind]] @@ -3131,8 +3134,8 @@ combinedDescription = """ make the next/previous selection primary; primary selections determine from where you add cursors, what cursor you delete, and where the cursor goes when you clear or save selections """ -key = "j" -combinedKey = "j/l" +key = "[KeyJ]" +combinedKey = "[KeyJ]/[KeyL]" command = "selection-utilities.movePrimaryRight" repeat = 'count' @@ -3141,7 +3144,7 @@ path = "edit.select_edit" name = "← sel" combinedName = "→/← sel" description = "make the previous selection primary; primary selections determine from where you add cursors, what cursor you delete, and where the cursor goes when you clear or save selections" -key = "k" +key = "[KeyK]" command = "selection-utilities.movePrimaryLeft" repeat = 'count' @@ -3153,8 +3156,8 @@ description = """ insert cursor on line above """ combinedDescription = "insert cursor on line above/below" -key = "shift+k" -combinedKey = "shift+k/j" +key = "shift+[KeyK]" +combinedKey = "shift+[KeyK]/[KeyJ]" command = "editor.action.insertCursorAbove" repeat = "count" @@ -3165,7 +3168,7 @@ combinedName = "insert ↑/↓" description = """ insert cursor on line below """ -key = "shift+j" +key = "shift+[KeyJ]" command = "editor.action.insertCursorBelow" repeat = "count-1" @@ -3178,7 +3181,7 @@ combinedDescription = """ Remove either the primary selection or all selections. Return to normal mode if all selections are deleted. """ -key = "d" +key = "[KeyD]" command = "selection-utilities.deletePrimary" repeat = "count-1" @@ -3186,7 +3189,7 @@ repeat = "count-1" path = "edit.select_edit" name = 'del. others' description = "delete all other cursors but the primary selection" -key = "shift+d" +key = "shift+[KeyD]" command = "removeSecondaryCursors" [[bind]] @@ -3196,7 +3199,7 @@ description = """ save all selections to the default register. Use a count to specify an alternate register """ -key = "c" +key = "[KeyC]" command = "runCommands" args.commands = [ { command = "selection-utilities.appendToMemory", computedArgs = { register = "count || 'default'" } }, @@ -3210,7 +3213,7 @@ description = """ load previously saved selections in the default register. Use a count to specify an alternate register """ -key = "v" +key = "[KeyV]" command = "runCommands" args.commands = [ { command = "selection-utilities.restoreAndClear", computedArgs = { register = "count || 'default'" } }, @@ -3222,7 +3225,7 @@ name = "exchange sel" description = """ exchange selections: with no saved selection, saves the selection, with saved selections exchanges text of current selections with those of the saved selections (number of selections must match). Use a count to specify an alternate register. """ -key = "x" +key = "[KeyX]" command = "runCommands" args.commands = [ { command = "selection-utilities.swapWithMemory", computedArgs = {register = "count || 'default'"} }, @@ -3236,7 +3239,7 @@ description = """ remove the most recently saved selection from the list of saved selections """ command = "runCommands" -key = "n" +key = "[KeyN]" args.commands = [ { command = "selection-utilities.deleteLastSaved", computedArgs = {register = "count || 'default'"} }, "master-key.enterNormal" @@ -3244,7 +3247,7 @@ args.commands = [ [[bind]] path = "edit.select_edit" -key = "shift+enter" +key = "shift+[Enter]" name = "split sel" description = """ split selection into multiple selections by new line charactesr @@ -3257,14 +3260,14 @@ name = "sel all" description = """ create a selection for every match of the current word (or selection) """ -key = "shift+8" +key = "shift+[Digit8]" command = "editor.action.selectHighlights" [[bind]] path = "edit.select_edit" name = "character" description = "split by a given character" -key = "s" +key = "[KeyS]" command = "runCommands" [[bind.args.commands]] @@ -3279,7 +3282,7 @@ computedArgs.text = "captured" path = "edit.select_edit" name = "string" description = "split by a given string" -key = "shift+s" +key = "shift+[KeyS]" command = "selection-utilities.splitBy" [[bind]] @@ -3288,7 +3291,7 @@ name = "include" description = """ Include all selections that contain a given marker """ -key = "f" +key = "[KeyF]" command = "selection-utilities.includeBy" [[bind]] @@ -3297,56 +3300,56 @@ name = "exclude" description = """ Exclude all selections that contain a given marker """ -key = "shift+f" +key = "shift+[KeyF]" command = "selection-utilities.excludeBy" [[bind]] path = "edit.select_edit" name = "create" description = "create selections of given string scoped to the current selections" -key = "/" +key = "[Slash]" command = "selection-utilities.createBy" [[bind]] path = "edit.select_edit" name = "regex" description = "operations by regex rather than string" -key = "r" +key = "[KeyR]" command = "master-key.prefix" [[bind]] path = "edit.select_edit" name = "split" description = "split by a given regular expression" -key = "r shift+s" +key = "[KeyR] shift+[KeyS]" command = "selection-utilities.splitByRegex" [[bind]] path = "edit.select_edit" name = "create" description = "create selections of given regular expression scoped to the current selections" -key = "r /" +key = "[KeyR] [Slash]" command = "selection-utilities.createByRegex" [[bind]] path = "edit.select_edit" name = "include" description = "Include all selections that contain a given regular expression" -key = "r f" +key = "[KeyR] [KeyF]" command = "selection-utilities.includeByRegex" [[bind]] path = "edit.select_edit" name = "exclude" description = "Exclude all selections that contain a given regular expression" -key = "r shift+f" +key = "[KeyR] shift+[KeyF]" command = "selection-utilities.excludeByRegex" [[bind]] path = "edit.select_edit" -key = "o" +key = "[KeyO]" name = "active to front" -combinedKey = "o/shift+o" +combinedKey = "[KeyO]/shift+[KeyO]" combinedName = "active to start/end" combinedDescription = "move cursor to start/end of selection" description = "move cursor to start of selection" @@ -3357,7 +3360,7 @@ path = "edit.select_edit" name = "active to end" combinedName = "active to start/end" description = "move cursor to back of selection" -key = "shift+o" +key = "shift+[KeyO]" command = "selection-utilities.activeAtStart" # ## Symmetric Insert Mode @@ -3423,7 +3426,7 @@ In this mode all commands and character insertions happen at both ends of the selection """ mode = "normal" -key = "space shift+i" +key = "[Space] shift+[KeyI]" combinedName = "sym insert (mode)" command = "master-key.setMode" args.value = "syminsert" @@ -3432,23 +3435,25 @@ args.value = "syminsert" path = "edit.action.symmetric" name = "Normal" description = "Return to normal model" -key = "enter" +key = "[Enter]" command = "master-key.setMode" mode = "syminsert" [[bind]] path = "edit.action.symmetric" -foreach.key = ["{key: [a-z]}", "shift+{key: [a-z]}"] +foreach.key = ['{key: \[KeyA-Z]\]}', '{key: shift+\[KeyA-Z]\]}'] name = "" description = "this key is ignored and has no associated command in syminsert mode" key = "{key}" command = "master-key.ignore" mode = "syminsert" +hideInDocs = true +hideInPalette = true [[bind]] name = "esc. char" path = "edit.action.symmetric" -key = "\\" +key = "[Backslash]" description = "Insert escaped character" command = "runCommands" @@ -3465,7 +3470,7 @@ args.followCursor = true [[bind]] path = "edit.action.symmetric" name = "delete" -key = "x" +key = "[KeyX]" description = """ delete the first and last adjacent character when cursor is at end of selection and delete the first and last character *in* the selection when cursor is at the start of the @@ -3477,7 +3482,7 @@ args.followCursor = true [[bind]] path = "edit.motion.symmetric" -key = "l" +key = "[KeyL]" name = "sel →" description = "shrink/grow selections in direction that's rightwards from cursor" command = "selection-utilities.adjustSelections" @@ -3486,7 +3491,7 @@ computedArgs.count = "count" [[bind]] path = "edit.motion.symmetric" -key = "h" +key = "[KeyH]" name = "sel ←" description = "shrink/grow selections in direction that's leftwards from cursor" command = "selection-utilities.adjustSelections" @@ -3495,9 +3500,9 @@ computedArgs.count = "count" [[bind]] path = "edit.motion.symmetric" -key = "o" +key = "[KeyO]" name = "active to front" -combinedKey = "o/shift+o" +combinedKey = "[KeyO]/shift+[KeyO]" combinedName = "active to start/end" combinedDescription = "move cursor to start/end of selection" description = "move cursor to start of selection" @@ -3508,24 +3513,24 @@ path = "edit.motion.symmetric" name = "active to end" combinedName = "active to start/end" description = "move cursor to back of selection" -key = "shift+o" +key = "shift+[KeyO]" command = "selection-utilities.activeAtStart" [[bind]] path = "edit.action.symmetric" name = "undo" -key = "u" +key = "[KeyU]" command = "undo" [[bind]] path = "edit.action.symmetric" name = "redo" -key = "shift+u" +key = "shift+[KeyU]" command = "redo" [[bind]] path = "edit.motion.symmetric" -key = "v" +key = "[KeyV]" name = "shrink selection" description = """ reduce all selections to length zero and return to normal mode diff --git a/presets/larkin_layout.toml b/presets/larkin_layout.toml new file mode 100644 index 0000000..ee2a5a5 --- /dev/null +++ b/presets/larkin_layout.toml @@ -0,0 +1,3543 @@ +# --- +# author: David Little +# license: MIT https://github.com/haberdashPI/vscode-master-key/blob/main/LICENSE.md +# --- + +# # Master Keybindings: Larkin (Layout Dependent) + +# Larkin is the default keybinding set that ships with Master Key. It follows in the footsteps of Vim, Kakoune and Helix. This is the version of Larkin that uses a layout dependent keymap. + +# > ⚠️ **Warning**: These bindings use a layout dependent keymap. This means the key always match those on your keyboard. If your needs require a layout independent keymap consider using `Larkin` which selects key bindings based on the U.S. Keyboard Layout. + +# +# Some key features: + +# - Commands are modal: most actions are available in `normal` mode, while typing occurs in `insert` mode +# - Command are organized around noun-verb ordering: e.g. `w` selects a word, and `d` will then delete it. +# - Selection is sticky: once a selection is created, further commands tend to extend that selection until it is reset (using `v`). However a number of commands are defined to automatically reset the selection (e.g. `mw` creates a new selection around a word). + +# +# These bindings are named after the middle name of my first child (Larkin). + +#- NOTE: this file is used to generate both keybindings and to generate a markdown file that documents the bindings. When comments are prefixed with a `-` they are ignored in the final markdown output. All other comments will become part of the markdown output. Any [[bind]] entries unbroken by normal, markdown-displayed comments will show up in a table in the markdown output. Make sure that the normal comments do not break up TOML data in a way that means it is invalid TOML. + +[header] +name = "Larkin (Layout Dependent)" +version = "1.0" + +requiredExtensions = [ + "dbankier.vscode-quick-select", + "haberdashPI.vscode-select-by-indent", + "haberdashPI.selection-utilities", + "pustelto.bracketeer", + "wmaurer.change-case", + "pkief.markdown-checkbox", + "jack89ita.open-file-from-path", + "koalamer.labeled-bookmarks", + "stkb.rewrap", +] + +[[mode]] +name = "insert" +lineNumbers = "on" +recordEdits = true + +[[mode]] +name = "normal" +default = true +highlight = "Highlight" +cursorShape = "Block" +lineNumbers = "relative" + +[[mode]] +name = "selectedit" +highlight = "Highlight" +cursorShape = "BlockOutline" +lineNumbers = "relative" + +[define] +select_on = false +around_on = false + +[[kind]] +name = "motion" +description = "These commands move the cursor and/or selections." + +[[kind]] +name = "action" +description = """ +Actions do something with the selected text (e.g. delete it). Unless otherwise noted, in +the absence of a selection, an action will modify an entire line, and a count argument +indicates the number of lines (e.g. 3d deletes this line and the next 3 lines). +""" + +[[kind]] +name = "util" +description = """ +Assorted other commands that aren't motions or actions +""" + +[[define.selectLinesDown]] +command = "selection-utilities.shrinkToActive" + +[[define.selectLinesDown]] +if = "count" +command = "cursorMove" +args = { to = "down", by = "wrappedLine", select = true } +computedArgs = { value = "count" } + +[[define.selectLinesDown]] +command = "expandLineSelection" + +[[define.selectLinesUp]] +command = "selection-utilities.shrinkToActive" + +[[define.selectLinesUp]] +if = "count" +command = "cursorMove" +args = { to = "up", by = "wrappedLine", select = true } +computedArgs = { value = "count" } + +[[define.selectLinesUp]] +command = "expandLineSelection" + + +[[path]] +id = "modes" +name = "Modes" +default.kind = "util" + +# ## Getting Help + +# There are three kinds of help available in Master Key. + +# 1. The visual documentation shows up in the lower pane and shows the currently available bindings on-top of a keyboard layout. +# 2. The text documentation is what you are reading now. +# 3. The suggestion palette shows a list of the current bindings given the current key binding prefix. + +[[bind]] +path = "util" +key = "shift+;" +name = "suggest" +resetTransient = false +hideInPalette = true +prefixes = [] +mode = ["!capture", "!insert"] +description = """ +show command suggestions within the context of the current mode and keybinding prefix (if any). E.g. `TAB, ⇧;` in `normal` mode will show all `normal` command suggestions that start with `TAB`. +""" +command = "master-key.commandSuggestions" + +[[bind]] +key = "tab /" +name = "text docs" +priority = -1 +mode = "normal" +description = "Show text documentation for keybindings" +command = "master-key.showTextDoc" + +[[bind]] +key = "tab shift+/" +name = "visual doc" +priority = -1 +mode = "normal" +description = "Show visual documentation for keybindings" +command = "master-key.showVisualDoc" + +# The visual keybinding documentation is modified by three additional commands that can be used to determine which modifiers are shown. + +# - `Master Key: Toggle Visual Doc Modifier by frequency`: changes keybinding modifiers from most to least common modifiers across all modifiers defined by the current keybindings. +# +# - `Master Key: Toggle Visual Doc Modifier for Top of Key`: allows you to explicitly change the modifier shown on the top of a key. +# - `Master Key: Toggle Visual Doc Modifier for Bottom of Key`: allows you to explicitly change the modifier shown on the bottom of a key. +# +# There are no keybindings for these commands by default. + +# ## Normal Mode + +# The default mode in Larkin, is Normal. In this mode, instead of the keys entering text, all keys are commands that modify selections or perform actions on those selections. To exit normal mode you can use `i` to enter `insert` mode, which returns VSCode keybindings to their normal state (see [Simple actions](#simple-actions) for more ways to enter insert mode). + +# While in Normal model you will see a highlighted section with the text "normal" in the lower left hand corner of the status bar. + +# |mode|key|name|description| +# |---|----|----|-----------| +# |`-`|`ESC` or `^[`|normal|enter normal mode| +# + +[[bind]] +path = "modes" +name = "normal" +description = "Enter normal mode" +foreach.key = ["escape", "ctrl+["] +combinedKey = "escape/ctrl+[" +combinedName = "normal" +combinedDescription = "Enter normal mode" +key = "{key}" +mode = [] +hideInPalette = true +hideInDocs = false +command = "master-key.enterNormal" +when = "!findWidgetVisible" +prefixes = "" + +[[bind]] +path = "modes" +name = "normal" +foreach.key = ["escape", "ctrl+["] +key = "{key}" +hideInPalette = true +hideInDocs = true +when = "suggestWidgetVisible && editorTextFocus && !findWidgetVisible" +command = "runCommands" +args.commands = ["hideSuggestWidget", "master-key.enterNormal"] +mode = [] +prefixes = "" + +#- in "command" like modes (e.g. normal), typing keys without a command defined below should have no effect +[[bind]] +path = "modes" +name = "ignore" +description = "this key does nothing" +foreach.key = ['{key: .}', 'shift+{key: .}'] #- all keys whose bindings are described by a single character +key = "{key}" +command = "master-key.ignore" +prefixes = "" +mode = ["normal", "selectedit"] +when = "editorTextFocus" +hideInDocs = true +hideInPalette = true +priority = -10 + +[[path]] +id = "edit" +name = "Editor Commands" +when = "editorTextFocus && !findWidgetVisible" +default.mode = "normal" + +[[path]] +id = "edit.count" +name = "count" +default.kind = "count" + +# ## Basic motions + +# These are the most common, simple motions that can be performed in Larkin. + +# Selection behavior uses the following logic: motions that move more than one character generally select the text "under" the motion. If a selection already exists (e.g. from a previous motion) additional motions extend that selection. You can always reset the selection using `v`, and several commands (e.g. `x`) operate on the next character rather than the current selection. + +[[path]] +id = "edit.motion" +name = "Motions" +description = "Commands that move the cursors and/or selections" +default.kind = "motion" + +[[path]] +id = "edit.motion.prim" +name = "Primitive Motions" +description = "Motions fundamental to moving around in the editor." +default.command = "cursorMove" +default.computedArgs.value = "count" +default.computedArgs.select = "editorHasSelection || select_on" + +[[bind]] +path = "edit.motion.prim" +key = "h" +name = "←" +combinedName = "←/→" +combinedKey = "h/l" +combinedDescription = "move left/right" +description = "move left" +args.to = "left" +mode = "normal" + +[[bind]] +path = "edit.motion.prim" +key = "l" +combinedName = "←/→" +name = "→" +description = "move right" +args.to = "right" + +[[bind]] +path = "edit.motion.prim" +key = "j" +name = "↓" +combinedName = "↓/↑" +combinedKey = "j/k" +combinedDescription = "move down/up" +description = "move down" +args.to = "down" +args.by = "wrappedLine" + +[[bind]] +path = "edit.motion.prim" +key = "k" +name = "↑" +description = "move up" +combinedName = "↓/↑" +args.to = "up" +args.by = "wrappedLine" + +[[bind]] +path = "edit.motion.prim" +key = "shift+h" +name = "start" +description = "start of line (alternates between first non-white and first)" +combinedName = "start/end" +combinedKey = "shift+h/shift+l" +combinedDescription = "move to start/end of line" +command = "cursorHomeSelect" + +[[bind]] # we don't use prim because we don't want the defaults +path = "edit.motion" +key = "shift+l" +name = "end" +combinedName = "start/end" +description = "end of line" +command = "cursorMove" +args.to = "wrappedLineEnd" +args.select = true + +[[bind]] +path = "edit.motion.prim" +key = "shift+k" +name = "sel ↑" +combinedName = "sel ↑/↓" +combinedDescription = "select lines up/down" +combinedKey = "shift+k/shift+j" +description = "select lines upwards" +command = "runCommands" + +[[bind.args.commands]] +command = "selection-utilities.shrinkToActive" + +[[bind.args.commands]] +command = "cursorMove" +args = { to = "up", by = "wrappedLine", select = true } +computedArgs = { value = "count" } + +[[bind.args.commands]] +command = "expandLineSelection" + +[[bind.args.commands]] +command = "selection-utilities.exchangeAnchorActive" + +[[bind]] +path = "edit.motion.prim" +key = "shift+j" +name = "sel ↓" +combinedName = "sel ↑/↓" +description = "select lines downwards" +command = "runCommands" + +[[bind.args.commands]] +command = "selection-utilities.shrinkToActive" + +[[bind.args.commands]] +command = "cursorMove" +args = { to = "down", by = "wrappedLine", select = true } +computedArgs = { value = "count" } + +[[bind.args.commands]] +command = "expandLineSelection" + +[[bind]] +path = "edit.motion.prim" +key = "ctrl+d" +mode = ["normal", "insert"] +name = "pg ↓" +combinedName = "pg ↓/↑" +combinedKey = "ctrl+d/ctrl+u" +combinedDescription = "move down/up, relative to page size" +description = "move down, relative to page size" +command = "selection-utilities.activePageMove" +args.dir = "down" +computedArgs.count = "(count || 1)/3" +computedArgs.select = "mode == 'normal'" + +[[bind]] +path = "edit.motion.prim" +key = "ctrl+u" +mode = ["normal", "insert"] +name = "pg ↑" +combinedName = "pg ↓/↑" +description = "move up, relative to page size" +command = "selection-utilities.activePageMove" +args.dir = "up" +computedArgs.count = "(count || 1)/3" +computedArgs.select = "mode == 'normal'" + +[[bind]] +path = "edit.motion.prim" +key = "shift+x" +name = "exapand" +description = "expand selections to full lines" +command = "expandLineSelection" +repeat = "count" + +[[path]] +id = "edit.motion.obj" +name = "Motions defined by various regex and syntactical objects" +description = """ +motions that move by a predefined syntactic object (e.g. word, paragraph, etc...) +""" +default.command = "selection-utilities.moveBy" +default.args.boundary = "start" +default.args.select = true + +[[bind]] +path = "edit.motion.obj" +key = "w" +name = "subwrd →" +description = "next subword (camel/snake case)" +combinedName = "subwrd ←/→" +combinedDescription = "next/prev subword (camel/snake case)" +combinedKey = "w/b" +args.unit = "subword" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "b" +name = "subwrd ←" +description = "previous subword (camel/snake case)" +combinedName = "subwrd ←/→" +args.unit = "subword" +computedArgs.value = "-count || -1" + +[[bind]] +path = "edit.motion.obj" +key = "shift+w" +name = "word →" +description = "next word" +combinedName = "word ←/→" +combinedDescription = "next/prev word" +combinedKey = "shift+w/b" +args.unit = "word" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "shift+b" +name = "word ←" +combinedName = "word ←/→" +description = "previous word" +prefixes = [""] +args.unit = "word" +computedArgs.value = "-count || -1" + +[[bind]] +path = "edit.motion.obj" +key = "e" +name = "subwrd end" +description = "next subword (camel/snake case) end" +args.unit = "subword" +args.boundary = "end" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "shift+e" +name = "word end" +description = "next word end" +args.unit = "word" +args.boundary = "end" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "shift+]" +name = "parag. →" +description = "next paragraph" +combinedName = "paragraph →/←" +combinedDescription = "next/previous paragraph" +combinedKey = "shift+]/[" +args.unit = "paragraph" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "shift+[" +name = "parag. ←" +combinedName = "paragraph →/←" +description = "previous paragraph" +args.unit = "paragraph" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion.obj" +key = "shift+0" +name = "subsec →" +description = "next subsection" +combinedName = "subsec →/←" +combinedDescription = "next/previous subsection" +combinedKey = "shift+0/9" +args.unit = "subsection" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "shift+9" +name = "subsec ←" +description = "previous subsection" +combinedName = "subsec →/←" +args.unit = "subsection" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion.prim" +key = "v" +name = "shrink selection" +combinedName = "shrink/hold selection" +combinedDescription = """ +reduce selections to zero length / make all commands extend the selection +""" +description = """ +reduce all selections to length zero +""" +command = "runCommands" +args.commands = [ + "selection-utilities.shrinkToActive", + { command = "master-key.setFlag", args = { name = "select_on", value = false } }, +] + +[[bind]] +path = "edit.motion.mod" +key = "shift+v" +name = "hold selection" +combinedName = "shrink/hold selection" +description = """ +all motions extend the selection +""" +command = "master-key.setFlag" +args.name = "select_on" +args.value = true + +[[bind]] +path = "edit.action.open_lines" +name = "open, act →" +description = "without selection: open a line below current line and enter insert, with selection: move cursor to start" +key = "o" +combinedName = "open below/above, act →/←" +combinedKey = "o/shift+o" +combinedDescription = """ +without selection: open a line below/above current line and enter insert, with selection: move cursor to end/start +of selection +""" +when = "!editorHasSelection" +command = "runCommands" +args.commands = ["editor.action.insertLineAfter", "master-key.enterInsert"] + +[[bind]] +path = "edit.action.open_lines" +key = "o" +combinedName = "open below/above, act →/←" +when = "editorHasSelection" +command = "selection-utilities.activeAtEnd" + +[[bind]] +path = "edit.action.open_lines" +name = "open blw, act ←" +combinedName = "open below/above, act →/←" +description = "without selection: open a line above current line and enter insert, with selection: move cursor to end" +key = "shift+o" +when = "!editorHasSelection" +command = "runCommands" +args.commands = [ "editor.action.insertLineBefore", "master-key.enterInsert" ] + +[[bind]] +path = "edit.action.open_lines" +name = "open blw, act ←" +combinedName = "open below/above, act →/←" +description = "without selection: open a line above current line and enter insert, with selection: move cursor to end" +key = "shift+o" +when = "editorHasSelection" +command = "selection-utilities.activeAtStart" + +[[bind]] +path = "edit.motion" +key = "shift+5" +name = "to bracket" +description = "Move to matching bracket" +command = "editor.action.jumpToBracket" + +[[bind]] +path = "edit.motion.prim" +key = '\' +name = "→ sel" +combinedName = "→/← sel" +description = "select *just* the character to the right" +combinedDescription = "select *just* the character to the right" +combinedKey = 'shift+\/\' +mode = ["normal", "selectedit"] +command = "runCommands" + +[[bind.args.commands]] +command = "selection-utilities.shrinkToActive" + +[[bind.args.commands]] +command = "cursorMove" +args = { to = "right", select = true } +computedArgs = { value = "count" } + +[[bind]] +path = "edit.motion.prim" +key = 'shift+\' +name = "← sel" +combinedName = "→/← sel" +description = "select *just* the character to the left" +mode = ["normal", "selectedit"] +command = "runCommands" + +[[bind.args.commands]] +command = "selection-utilities.shrinkToActive" + +[[bind.args.commands]] +command = "cursorMove" +args = { to = "left", select = true } +computedArgs = { value = "count" } + +[[path]] +id = "edit.motion.mod" +name = "Modify Motion Effects" +description = "Keys that change how other motions work" +default.kind = "motion" + +[[bind]] +path = "edit.motion.obj" +key = "shift+4" +name = "all" +description = "Select entire document" +command = "editor.action.selectAll" + +[[bind]] +path = "edit.motion" +key = "shift+r" +name = "trim wht" +description = "trim external whitespace" +command = "selection-utilities.trimSelectionWhitespace" + +[[bind]] +path = "edit.motion.obj" +name = "→ num." +description = "Move to next number" +key = "shift+3" +combinedName = "→/← num." +combinedDescription = "Move to next/prev number" +combinedKey = "shift+3/2" +args.unit = "number" +args.selectWhole = true +args.boundary = "both" +computedArgs.value = "(count || 1)" + +[[bind]] +path = "edit.motion.obj" +name = "← num." +description = "Move to next number" +key = "shift+2" +combinedName = "→/← num." +args.unit = "number" +args.selectWhole = true +args.boundary = "both" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion" +name = 'narrow to subword' +description = "Narrow current selection so it starts and stops at a subword (e.g. 'snake' in snake_case)" +key = "z" +command = "selection-utilities.narrowTo" +args.unit = "subident" +args.boundary = "both" + +# ## Repeating Motions + +# Like VIM, the number keys (0-9) can be typed as a prefix to most commands and serve as a `count` +# argument to that command. In most cases this causes the command to be repeated `count` +# times e.g. 2w would select the next two words starting from the current cursor position. + +[[bind]] +path = "edit.count" +foreach.num = ['{key: [0-9]}'] +name = "count {num}" +key = "{num}" +command = "master-key.updateCount" +description = "Add digit {num} to the count argument of a command" +combinedKey = "0-9" +combinedName = "count 0-9" +combinedDescription = "Add digit 1-9 to count argument of a command" +args.value = "{num}" +resetTransient = false +mode = ["!insert", "!capture"] +hideInDocs = true + +# There are several ways to repeat or undo previously entered commands, both actions and motions + +[[path]] +id = "edit.motion.history" +name = "motion history" +description = "Commands that repeat some kind of motion" + +[[bind]] +path = "edit.motion.history" +key = ";" +name = "repeat motion" +description = """ +Repeat the last motion command. Motions usually move the cursor or change the selection. +""" +repeat = "count" +command = "master-key.replayFromHistory" +args.at = """ +commandHistory[i].path.startsWith('edit.motion') && +commandHistory[i].name != 'repeat motion' && +commandHistory[i].name != 'shrink selection' +""" + +[[bind]] +path = "edit.motion.history" +name = "repeat subject" +description = """ +Repeat the subject: a motion command that occurred right before an action. For +instance `w` followed by `d` selects a word and deletes it. The `w` command would be the +last subject until some new action is run after `d`. See also `.` which repeats the last action. +""" +key = "," +command = "master-key.replayFromHistory" +args.at = """ +commandHistory[i].path.startsWith("edit.motion") && +commandHistory[i+1].path.startsWith("edit.action") && +!(commandHistory[i+1].name.startsWith("repeat ") && + commandHistory[i+1].path.startsWith("edit.action.history")) +""" + +[[bind]] +path = "edit.motion.history" +name = "cursor undo" +key = "-" +combinedName = "cursor undo/redo" +combinedKey = "-/shift+-" +command = "cursorUndo" + +[[bind]] +path = "edit.motion.history" +name = "cursor redo" +combinedName = "cursor undo/redo" +key = "shift+-" +command = "cursorRedo" + +[[bind]] +path = "edit.motion.history" +name = "nav ←" +description = "Go back in navigation history (e.g. goto definition)" +combinedName = "nav ←/→" +combinedKey = "n/shift+n" +combinedDescription = "Go back/forward in navigation history" +key = "g n" +command = "workbench.action.navigateBackInNavigationLocations" + +[[bind]] +path = "edit.motion.history" +name = "nav →" +combinedName = "nav ←/→" +description = "Go forward in navigation history (e.g. goto definition)" +key = "g shift+n" +command = "workbench.action.navigateForwardInNavigationLocations" + +[[bind]] +path = "edit.motion.history" +name = "edit hist ←" +description = "Go back in edit history" +key = "g -" +combinedName = "edit ←/→" +combinedKey = "-/shift+-" +combinedDescription = "Go back/forward in edit history" +command = "workbench.action.navigateBackInEditLocations" + +[[bind]] +path = "edit.motion.history" +name = "edit hist →" +description = "Go forward in edit history)" +key = "g shift+-" +combinedName = "edit ←/→" +command = "workbench.action.navigateForwardInEditLocations" + +# ## Search Motions + +# Search motions accept one or more characters and select text up until the given character. Search commands are case insensitive by default. They can serve as very efficient ways to jump to a desired location. E.g. typing `sfod` in normal mode would delete the first three words of the following line of text +# +# > I want some food + +[[path]] +id = "edit.motion.search" +name = "Search Related Motions" +description = "Motions related to searching for text in a document" +default.command = "master-key.search" +default.args.caseSensitive = false +default.args.backwards = false +default.args.selectTillMatch = true +default.args.wrapAround = true + +[[bind]] +path = "edit.motion.search" +key = "/" +name = "search →" +description = "search forwards" +combinedName = "search → (←)" +combinedDescription = "search forwards (backwards)" +combinedKey = "/ (shift+/)" +args.offset = "start" +args.register = "search" + +[[bind]] +path = "edit.motion.search" +key = "shift+/" +name = "search ←" +description = "search backwards" +combinedName = "search → (←)" +args.offset = "start" +args.register = "search" +args.backwards = true + +[[bind]] +path = "edit.motion.search" +key = "n" +name = "→ search" +description = "Go to the next match of the search query" +command = "master-key.nextMatch" +args.register = "search" +computedArgs.repeat = "(count || 1)-1" + +[[bind]] +path = "edit.motion.search" +key = "shift+n" +name = "← search" +description = "Go to the previous match of the search query" +command = "master-key.previousMatch" +args.register = "search" +computedArgs.repeat = "(count || 1)-1" + +[[bind]] +path = "edit.motion.search" +key = "shift+8" +name = "match →" +description = "Next match to object under cursor" +combinedName = "match →/←" +combinedDescription = "Next/previous match to object under cursor" +combinedKey = "shift+8/7" +computedArgs.text = "firstSelectionOrWord" +args.offset = "start" +args.register = "search" + +[[bind]] +path = "edit.motion.search" +key = "shift+7" +name = "match ←" +description = "Previous match to object under cursor" +combinedName = "match →/←" +computedArgs.text = "firstSelectionOrWord" +args.offset = "start" +args.register = "search" +args.backwards = true + +[[bind]] +path = "edit.motion.search" +key = "f" +name = "find char" +description = "Find the next char (include char in selection)" +combinedName = "find char (back)" +combinedDescription = "Find the next (previous) char (include char in selection)" +combinedKey = "f (shift+f)" +args.acceptAfter = 1 +computedArgs.skip = "count-1" +args.offset = "inclusive" + +[[bind]] +path = "edit.motion.search" +key = "shift+f" +name = "find char back" +description = "Find the previous char (include char in selection)" +combinedName = "find char (back)" +args.acceptAfter = 1 +args.offset = "inclusive" +args.backwards = true +computedArgs.skip = "count-1" + +[[bind]] +path = "edit.motion.search" +key = "t" +name = "to char" +description = "Find the next char (exclude char in selection)" +combinedName = "to char (back)" +combinedKey = "t (shift+t)" +combinedDescription = "Find the next/previous char (exclude char in selection)" +args.acceptAfter = 1 +args.offset = "start" +computedArgs.skip = "count-1" + +[[bind]] +path = "edit.motion.search" +key = "shift+t" +name = "to char back" +description = "Find the previous char (exclude char in selection)" +combinedName = "to char (back)" +args.acceptAfter = 1 +args.offset = "end" +args.backwards = true +computedArgs.skip = "count-1" + +[[bind]] +path = "edit.motion.search" +key = "s" +name = "find char pair" +description = "To next character pair" +combinedName = "char pair →/←" +combinedDescription = "To next character pair" +combinedKey = "s/shift+s" +args.acceptAfter = 2 +args.offset = "start" +computedArgs.skip = "count-1" +mode = "normal" + +[[bind]] +path = "edit.motion.search" +key = "shift+s" +name = "char pair back" +description = "To previous character pair" +combinedName = "char pair →/←" +args.acceptAfter = 2 +args.offset = "start" +computedArgs.skip = "count-1" +args.backwards = true + +# ## Goto Commands + +# Goto commands all begin with the mnemonic prefix key `g`. They are additional +# motion commands that compliment the basic motions listed in the previous section. + +[[bind]] +path = "edit.motion" +key = "g" +priority = 1 +name = "goto" +command = "master-key.prefix" +description = """ +Goto commands move the location of the cursor (or the active selection position) forward +or backwards in some direction. +""" + +[[bind]] +path = "edit.motion.prim" +key = "g j" +priority = 1 +name = "unwrp ↓" +combinedName = "unwrap ↓/↑" +combinedKey = "j/k" +combinedDescription = """ +move cursor up/down unwrapped text line; if a single line is wrapped into multiple lines by +the editor, this command skips all such wrapped lines +""" +description = """ +down unwrapped line; if a single line is wrapped into multiple lines by the editor, this +command skips all such wrapped lines +""" +args.to = "down" +args.by = "line" + +[[bind]] +path = "edit.motion.prim" +key = "g k" +priority = 1 +name = "unwrp ↑" +combinedName = "unwrap ↓/↑" +description = "up unwrapped line" +args.to = "up" +args.by = "line" + +[[bind]] +path = "edit.motion.prim" +key = "g shift+k" +priority = 1 +combinedName = "unwrp sel ↑/↓" +combinedDescription = "select unwrapped lines up/down" +combinedKey = "shift+k/j" +name = "unwrp sel ↑" +description = "select unwrapped lines upwards" +command = "runCommands" + +[[bind.args.commands]] +command = "selection-utilities.shrinkToActive" + +[[bind.args.commands]] +command = "cursorMove" +args = { to = "up", by = "line", select = true } +computedArgs = { value = "count" } + +[[bind.args.commands]] +command = "expandLineSelection" + +[[bind]] +path = "edit.motion.prim" +key = "g shift+j" +priority = 1 +name = "sel ↓" +combinedName = "unwrp sel ↑/↓" +description = "select unwrapped lines downwards" +command = "runCommands" + +[[bind.args.commands]] +command = "selection-utilities.shrinkToActive" + +[[bind.args.commands]] +command = "cursorMove" +args = { to = "down", by = "line", select = true } +computedArgs = { value = "count" } + +[[bind.args.commands]] +command = "expandLineSelection" + +[[bind]] +path = "edit.motion.prim" +key = "shift+g" +priority = 1 +name = "doc end" +description = "select to end of document" +combinedName = "doc top/bottom" +combinedDescription = "select to top/bottom of document" +combinedKey = ",/." +command = "cursorBottomSelect" + +[[bind]] +path = "edit.motion.prim" +key = "g g" +priority = 1 +name = "doc start" +description = "select to start (line) of document." +command = "runCommands" +when = "master-key.count > 1" + +[[bind.args.commands]] +command = "cursorTop" + +[[bind.args.commands]] +command = "cursorMove" +args.to = "down" +args.by = "wrappedLine" +computedArgs.value = "count-1" + +[[bind.args.commands]] +command = "revealLine" +args.at = "center" +computedArgs.lineNumber = "count" + +[[bind]] +path = "edit.motion.prim" +key = "g g" +priority = 1 +name = "doc start" +description = "select to start of document" +command = "cursorTopSelect" +when = "master-key.count <= 1" + +[[bind]] +path = "edit.motion.obj" +key = "g w" +priority = 1 +name = "WORD →" +combinedName = "WORD →/←" +combinedDescription = """ +next/prev WORD; e.g. contiguous non-whitespace region +""" +combinedKey = "w/b" +description = "next WORD; e.g. contiguous non-whitespace region" +args.unit = "WORD" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "g b" +priority = 1 +name = "WORD ←" +combinedName = "WORD →/←" +description = "previous WORD; e.g. contiguous non-whitespace region" +args.unit = "WORD" +computedArgs.value = "-count || -1" + +[[bind]] +path = "edit.motion.obj" +key = "g e" +priority = 1 +name = "WORD end →" +description = "next WORD end; e.g. contiguous non-whitespace region" +args.unit = "WORD" +computedArgs.boundary = "around_on ? 'both' : 'end'" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "g 0" +priority = 1 +name = "sec →" +description = "next section" +combinedName = "sec →/←" +combinedDescription = "next/previous section" +combinedKey = "0/9" +args.unit = "section" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.obj" +key = "g 9" +priority = 1 +name = "sec ←" +description = "previous section" +combinedName = "sec →/←" +args.unit = "section" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "window" +name = "goto line" +priority = 1 +description = "goto line command" +key = "g l" +command = "workbench.action.gotoLine" +when = "editorTextFocus" + +[[bind]] +path = "window" +name = "to refs" +priority = 1 +description = "jump to a location where this symbol is referenced" +key = "g r" +command = "editor.action.goToReferences" +when = "editorTextFocus" + +[[bind]] +path = "window" +name = "go to" +priority = 1 +description = "go to the definition of symbol under cursor" +key = "g d" +combinedName = "go to (aside)" +combinedKey = "(shift+)d" +combinedDescription = "go to the definition of symbol (in an editor to the side)" +command = "editor.action.revealDefinition" +when = "editorTextFocus" + +[[bind]] +path = "window" +name = "go to, aside" +priority = 1 +description = "go to the definition of symbol under cursor in an editor to the side" +key = "g shift+d" +combinedName = "go to (aside)" +command = "editor.action.revealDefinitionAside" +when = "editorTextFocus" + +[[bind]] +path = "window" +name = "open" +description = "open the file name under the cursor" +key = "g f" +command = "extension.openFileFromPath" +when = "editorTextFocus" + +[[bind]] +path = "edit.motion" +key = "g c" +name = "cell →" +combinedName = "cell →/←" +command = "runCommands" +args.commands = [ "jupyter.gotoNextCellInFile", "jupyter.selectCell" ] +description = "previous jupyter notebook cell" + +[[bind]] +path = "edit.motion" +key = "g shift+c" +name = "cell ←" +combinedName = "cell →/←" +description = "previous jupyter notebook cell" +command = "runCommands" +args.commands = ["jupyter.gotoPrevCellInFile", "jupyter.selectCell"] + +# ## Match Commands + +# Match commands select some syntactical region of text, e.g. in or around parenthesis, brackets, indent level etc... Where the `g` prefixed commands move forward or backward, these commands move both the start and the end of the selection away from the active cursor position. Repeating the command moves to the next (or previous) match, depending on the command. + +# If you accidentally select `around` instead of `in`, you can revise your selection using `R` to narrow to non-white space or `z` to narrow to a subword (e.g. excludes `_`) + +[[path]] +id = "edit.motion.match" +name = "Matching Motions" +description = "Motions that match some range of characters" + +[[path]] +id = "edit.motion.match.obj" +name = "Matching Object Motions" +description = "Motions that match some range of characters by predefined regex" +default.command = "selection-utilities.moveBy" +default.kind = "motion" +default.args.selectWhole = true +default.args.boundary = "start" + +[[bind]] +path = "edit.motion.match" +key = "m" +name = "match" +description = """ +Find the closest character range matching a specified object. +""" +kind = "motion" +command = "master-key.prefix" + +[[bind]] +path = "edit.motion.match" +key = "m m" +prefixes = [""] +name = "smart expand" +description = "Use VSCode's built-in smart expansion command" +command = "editor.action.smartSelect.expand" + +[[bind]] +path = "edit.motion.match.obj" +key = "m w" +name = "around subwrd →" +description = "(camel/snake case)" +combinedName = "around subwrd ←/→" +combinedDescription = "(camel/snake case)" +combinedKey = "w/b" +args.unit = "subword" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m b" +name = "around subwrd ←" +description = "(camel/snake case)" +combinedName = "around subwrd ←/→" +args.unit = "subword" +computedArgs.value = "-count || -1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m shift+w" +name = "ard word →" +combinedName = "around word →/←" +combinedKey = "shift+w/b" +args.unit = "word" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m shift+b" +name = "ard word ←" +combinedName = "around word →/←" +prefixes = [""] +args.unit = "word" +computedArgs.value = "-count || -1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m e" +name = "in subwrd" +combinedName = "in → subword/word" +combinedKey = "e/shift+e" +args.unit = "subident" +args.boundary = "both" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m shift+e" +name = "in word" +combinedName = "in → subword/word" +args.unit = "word" +args.boundary = "both" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m p" +name = "in parag. →" +combinedName = "in paragraph →/←" +combinedKey = "p/o" +args.boundary = "both" +args.unit = "paragraph" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m o" +name = "in parag. ←" +combinedName = "in paragraph →/←" +args.unit = "paragraph" +args.boundary = "both" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion.match.obj" +key = "m shift+p" +name = "arn parag. →" +combinedName = "around paragraph →/←" +combinedKey = "shift+p/shift+o" +args.unit = "paragraph" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m shift+o" +name = "arn parag. ←" +combinedName = "around paragraph →/←" +args.unit = "paragraph" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion.match.obj" +key = "m 0" +name = "arn subsec →" +combinedName = "around subsection →/←" +combinedKey = "0/shift+0" +args.unit = "subsection" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m shift+0" +name = "arn subsec ←" +combinedName = "around subsection →/←" +args.unit = "subsection" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion.match.obj" +key = "m 9" +name = "in subsec →" +combinedName = "in subsection →/←" +combinedKey = "9/shift+9" +args.unit = "subsection" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m shift+9" +name = "in subsec ←" +combinedName = "in subsection →/←" +args.unit = "subsection" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion.match" +key = "m g" +name = "other..." +description = "additional objects to match..." +command = "master-key.prefix" + +[[bind]] +path = "edit.motion.match.obj" +key = "m g 0" +name = "section →" +combinedName = "section →/←" +combinedKey = "0/9" +args.unit = "section" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m g 9" +name = "section ←" +combinedName = "section →/←" +args.unit = "section" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion.match.obj" +key = "m g w" +name = "around WORD →" +combinedName = "around WORD →/←" +combinedKey = "w/b" +args.unit = "WORD" +computedArgs.value = "count || 1" + +[[bind]] +path = "edit.motion.match.obj" +key = "m g b" +name = "around WORD ←" +combinedName = "around WORD →/←" +args.unit = "WORD" +computedArgs.value = "-(count || 1)" + +[[bind]] +path = "edit.motion.match.obj" +key = "m g e" +name = "in WORD" +args.unit = "WORD" +args.boundary = "both" +computedArgs.value = "count || 1" + +[[path]] +id = "edit.motion.match.syntax" +name = "Motions around syntactic objects (e.g. parentheses and quotes)" +description = """ +selection commands that move by a predefined syntactic object like brackets and quotes +""" + +[[bind]] +path = "edit.motion.match.syntax" +key = "m [" +name = "in parens" +combinedName = "in/arnd parens" +combinedKey = "[/shift+[" +combinedDescription = """ +expand inside/around parens/brackets/braces and their contents; repeated calls to this command +will seek out larger and larger scopes +""" +description = """ +expand inside parens/brackets/braces and their contents; repeated calls to this command +will seek out larger and larger scopes +""" +command = "selection-utilities.expandWithinBrackets" + +[[bind]] +path = "edit.motion.match.syntax" +key = "m shift+[" +name = "arnd parens" +combinedName = "in/arnd parens" +description = """ +expand inside parens/brackets/braces and their contents; repeated calls to this command +will seek out larger and larger scopes +""" +command = "selection-utilities.expandAroundBrackets" + +[[bind]] +path = "edit.motion.match.syntax" +key = "m '" +name = "in quotes" +description = """ +select within current quotes; repeated calls to this command +will seek out larger and larger scopes +""" +combinedName = "in/arnd quotes" +combinedKey = "'/shift+'" +combinedDescription = """ +select within/around current quotes; repeated calls to this command +will seek out larger and larger scopes +""" +command = "bracketeer.selectQuotesContent" + +[[bind]] +path = "edit.motion.match.syntax" +key = "m shift+'" +name = "around quotes" +combinedName = "in/arnd quotes" +description = """ +select around current quotes; repeated calls to this command +will seek out larger and larger scopes +""" +command = "runCommands" +args.commands = ["bracketeer.selectQuotesContent", "bracketeer.selectQuotesContent"] + +[[bind]] +path = "edit.motion.match.syntax" +key = "m shift+." +name = "in <>" +description = "text inside angle brackets" +combinedName = "in <> / in ><" +combinedKey = "shift+. / shift+," +combinedDescription = "text inside angle brackets / pairs (e.g. text in text)" +command = "extension.selectAngleBrackets" + +[[bind]] +path = "edit.motion.match.syntax" +key = "m shift+," +name = "in ><" +combinedName = "in <> / in ><" +description = "text inside tag pairs (e.g. text)" +command = "extension.selectInTag" + +[[bind]] +path = "edit.motion.match.syntax" +key = "m i" +name = "in indent" +description = "all text at the same indentation level" +combinedName = "in/arnd" +combinedKey = "space/shift+space" +combinedDescription = """ +all text at the same indentation level / all indentation along with the line above and +below this (ala c-like syntax) +""" +command = "vscode-select-by-indent.select-inner" + +[[bind]] +path = "edit.motion.match.syntax" +key = "m shift+i" +name = "arnd indent" +description = """ +all text at the same indentation level along with the line above and below +this (ala c-like syntax) +""" +combinedName = "in/arnd" +command = "vscode-select-by-indent.select-outer" + +[[bind]] +path = "edit.motion.match.syntax" +key = "m g i" +name = "indent+top" +description = """ +all text at the same indentation level and the line just above it (ala python syntax) +""" +combinedName = "in/arnd" +command = "vscode-select-by-indent.select-outer-top-only" + +[[path]] +id = "edit.motion.match.cell" +name = "Matching Object Motions" +description = "Motions that match some range of characters by predefined regex" + +[[bind]] +path = "edit.motion.match.cell" +name = "in cell" +description = "select text within a cell (ala jupyter)" +key = "m c" +command = "jupyter.selectCell" + +[[path]] +id = "edit.motion.searchpair" +name = "Search pairs" +description = "Find text that falls between pairs of characters" + +[[bind]] +path = "edit.motion.searchpair" +name = "between pair" +combinedDescription = """ +Select between pairs of the same N characters (t) or distinct sets of N +characters (s), where N is the count. Examples: +2mt'' would search for a string between `''` and `''`. +2ms,,.. would search for a string between `,,` and `..`. +""" +key = "m t" +command = "runCommands" +combinedName = "between pair/two" +combinedKey = "t/s" +description = """ +Select between pairs of the same N characters, where N is the count. +Example: 2mt'' would search for a string between '' and ''. +""" + +[[bind.args.commands]] +command = "master-key.captureKeys" +computedArgs.acceptAfter = "count || 1" + +[[bind.args.commands]] +command = "selection-utilities.selectBetween" +computedArgs.str = "captured" +args.inclusive = false + +[[bind]] +path = "edit.motion.searchpair" +name = "between two" +description = """ +Select between two different sets of N characters, where N is the count e.g. +2ms,,.. would search for a string between ,, and .. +""" +key = "m s" +combinedName = "between pair/two" +command = "runCommands" + +[[bind.args.commands]] +command = "master-key.captureKeys" +computedArgs.acceptAfter = "2*(count || 1)" + +[[bind.args.commands]] +command = "selection-utilities.selectBetween" +computedArgs.between.from = "captured.slice(0, captured.length/2)" +computedArgs.between.to = "captured.slice(captured.length/2)" +args.inclusive = false + +# ## Simple Actions + +# These are the most common, basic actions available in Larkin that can be used +# to edit text in relation to the current selection. + +[[path]] +id = "edit.action" +name = "Actions" +description = "Commands that modify the document or UI" +default.kind = "action" +default.mode = "normal" + +[[path]] +id = "edit.action.basic" +name = "Basic Actions" +description = "Essential actions required to edit text" + +[[bind]] +path = "edit.action.basic" +#- TODO: add documentation to these basic editor keys +key = "i" +name = "insert" +description = "Switch to insert mode (right before character)" +command = "runCommands" +args.commands = ["selection-utilities.shrinkToActive", "master-key.enterInsert"] +mode = ["normal", "selectedit", "syminsert"] + +[[bind]] +path = "edit.action.basic" +key = "a" +name = "append" +description = "insert after cursor" +mode = ["normal", "selectedit", "syminsert"] +command = "runCommands" +args.commands = [ + "selection-utilities.shrinkToActive", + "cursorRight", + "master-key.enterInsert", +] + +[[bind]] +path = "edit.action.basic" +key = "shift+i" +name = "insert start" +mode = ["normal", "selectedit", "syminsert"] +command = "runCommands" +args.commands = [ + { command = "cursorMove", args = { to = "wrappedLineFirstNonWhitespaceCharacter", select = false } }, + "master-key.enterInsert", +] + +[[bind]] +path = "edit.action.basic" +key = "shift+a" +name = "insert end" +mode = ["normal", "selectedit", "syminsert"] +command = "runCommands" +args.commands = [ + { command = "cursorMove", args = { to = "wrappedLineEnd", select = false } }, + "master-key.enterInsert", +] + +[[bind]] +path = "edit.action.basic" +key = "c" +name = "change" +description = """ +Without a count: change selected region of text. With a count: +change up to `count` lines. +""" +when = "editorHasMultilineSelection" +command = "runCommands" +args.commands = ["deleteRight", "editor.action.insertLineBefore", "master-key.enterInsert"] + +[[bind]] +path = "edit.action.basic" +key = "c" +when = "!editorHasMultilineSelection && editorHasSelection" +command = "runCommands" +args.commands = ["deleteRight", "master-key.enterInsert"] + +[[bind]] +path = "edit.action.basic" +key = "c" +when = "!editorHasSelection && master-key.count <= 1" +command = "runCommands" +args.commands = [ + "expandLineSelection", + "deleteRight", + "editor.action.insertLineBefore", + "master-key.enterInsert", +] + +[[bind]] +path = "edit.action.basic" +key = "c" +when = "!editorHasSelection && master-key.count > 1" +command = "runCommands" +args.commands = [ + { defined = "selectLinesDown" }, + "deleteRight", + "editor.action.insertLineBefore", + "master-key.enterInsert", +] + +[[bind]] +path = "edit.action.basic" +key = "shift+c" +name = "change to/back" +description = """Without a count: change from current char to end of line. With a count: +change the previous `count` lines. +""" +mode = "normal" +when = "master-key.count <= 1" +command = "runCommands" +args.commands = [ + "selection-utilities.shrinkToActive", + "deleteAllRight", + "master-key.enterInsert", +] + +[[bind]] +path = "edit.action.basic" +key = "shift+c" +mode = ["normal", "selectedit"] +when = "master-key.count > 1" +command = "runCommands" +args.commands = [ + { defined = "selectLinesUp" }, + "deleteRight", + "editor.action.insertLineBefore", + "master-key.enterInsert", +] + +[[bind]] +path = "edit.action.basic" +key = "x" +mode = "normal" +name = "delete char" +command = "runCommands" +args.commands = [ + "selection-utilities.shrinkToActive", + { command = "cursorMove", args = { to = "right", select = true }, computedArgs = { value = "count" } }, + "editor.action.clipboardCutAction" +] + +[[bind]] +path = "edit.action.basic" +key = "r" +name = "replace char" +description = "replace the character under the cursor" +command = "master-key.replaceChar" + +[[bind]] +path = "edit.action.basic" +key = "ctrl+i" +name = "insert char" +mode = ["normal", "selectedit"] +description = "insert a character in front of the cursor" +command = "master-key.insertChar" + +[[path]] +id = "edit.action.clipboard" +name = "Clipboard Operations" +description = "Operations that manipulate the clipboard in some way." + +[[bind]] +path = "edit.action.clipboard" +key = "p" +name = "paste after" +description = "Paste clipboard after the cursor/selection" +combinedName = "paste before/after/in" +combinedDescription = "Paste clipboard before/after/at the cursor/selection" +combinedKey = "p/shift+p/ctrl+p" +when = "editorHasSelection" +command = "runCommands" +args.commands = ["selection-utilities.activeAtEnd", "selection-utilities.shrinkToActive", "editor.action.clipboardPasteAction"] + +[[bind]] +path = "edit.action.clipboard" +key = "p" +name = "paste after" +combinedName = "paste before/after/in" +when = "!editorHasSelection" +command = "runCommands" +args.commands = ["cursorRight", "editor.action.clipboardPasteAction"] + +[[bind]] +path = "edit.action.clipboard" +key = "ctrl+p" +when = "!suggestWidgetVisible" +mode = ["normal", "insert"] +name = "paste in" +combinedName = "paste before/after/in" +description = "Paste clipboard at location" +command = "editor.action.clipboardPasteAction" + +[[bind]] +path = "edit.action.clipboard" +key = "shift+p" +name = "paste before" +combinedName = "paste before/after" +description = "Paste before the cursor/selection" +when = "editorHasSelection" +command = "runCommands" +args.commands = ["selection-utilities.activeAtStart", "selection-utilities.shrinkToActive", "editor.action.clipboardPasteAction"] + +[[bind]] +path = "edit.action.clipboard" +key = "shift+p" +combinedName = "paste before/after" +when = "!editorHasSelection" +command = "runCommands" +args.commands = ["cursorRight", "editor.action.clipboardPasteAction"] + +[[bind]] +path = "edit.action.history" +name = "repeat action" +description = """ +Repeat the last action command. Actions usually modify the text of a document in one way or +another. (But, e.g. sending text to the REPL is also considered an editor action). +See also `,` which repeats the last subject. +""" +key = "." +command = "runCommands" +repeat = "count" + +[[bind.args.commands]] +command = "master-key.replayFromHistory" +#- we can repeat any action but history-related actions; we make an exception for replaying macros, which can be repeated +args.at = """ +commandHistory[i].path.startsWith('edit.action') && +(!commandHistory[i].path.startsWith('edit.action.history') || + commandHistory[i].name == 'replay') +""" + +[[bind.args.commands]] +command = "master-key.enterNormal" + +[[bind]] +path = "edit.action.history" +name = "undo" +key = "u" +command = "runCommands" +args.commands = [ "undo", "selection-utilities.shrinkToActive" ] + +[[bind]] +path = "edit.action.history" +name = "redo" +key = "shift+u" +command = "runCommands" +args.commands = [ "redo", "selection-utilities.shrinkToActive" ] + +[[bind]] +path = "edit.action.basic" +name = 'toggle check' +description = "Toggle a markdown checkbox" +key = "shift+6" +command = "markdown-checkbox.markCheckbox" + +[[bind]] +path = "edit.action.clipboard" +key = "d" +name = "delete" +description = """ +Without a count: delete selected text (and store to clipboard). With a +count, delete up to the next `count` lines and store to clipboard. +""" +when = "!editorHasSelection" +command = "runCommands" +args.commands = [ + { defined = "selectLinesDown" }, + "editor.action.clipboardCutAction", + { command = "master-key.setMode", args = { value = "normal" } }, +] + +[[bind]] +path = "edit.action.clipboard" +key = "d" +when = "editorHasSelection" +command = "runCommands" +args.commands = [ + "editor.action.clipboardCutAction", + { command = "master-key.setMode", args = { value = "normal" } }, +] + +[[bind]] +path = "edit.action.clipboard" +key = "shift+d" +mode = "normal" +name = "without count: Delete from cursor to end of line; with count: Delete from current line up `count` number of keys." +command = "runCommands" +args.commands = [ + "selection-utilities.shrinkToActive", + { command = "cursorMove", args = { to = "wrappedLineEnd", select = true} }, + "editor.action.clipboardCutAction" +] + +[[bind]] +path = "edit.action.clipboard" +key = "shift+d" +mode = "normal" +when = "master-key.count > 1" +command = "runCommands" +args.commands = [{ defined = "selectLinesUp" }, "deleteRight"] + +[[bind]] +path = "edit.action.clipboard" +key = "y" +name = "copy" +description = "copy selected text to clipboard" +command = "runCommands" +args.commands = ["editor.action.clipboardCopyAction", "selection-utilities.shrinkToActive"] + +[[bind]] +path = "edit.action.clipboard" +key = "y" +when = "master-key.count > 1" +command = "runCommands" +args.commands = [ + { defined = "selectLinesDown" }, + "editor.action.clipboardCopyAction", + "selection-utilities.shrinkToActive" +] + +[[bind]] +path = "edit.action.clipboard" +key = "shift+y" +name = "copy (eol/up)" +description = "without a count: copy to end of line; with a count: copy this and the previous N lines" +when = "master-key.count <= 1" +command = "runCommands" +args.commands = [ + "selection-utilities.shrinkToActive", + { command = "cursorMove", args = { to = "wrappedLineEnd", select = true} }, + "editor.action.clipboardCopyAction", + "selection-utilities.shrinkToActive" +] + +[[bind]] +path = "edit.action.clipboard" +key = "shift+y" +when = "master-key.count > 1" +command = "runCommands" +args.commands = [ + { defined = "selectLinesUp" }, + "editor.action.clipboardCopyAction", + "selection-utilities.shrinkToActive" +] + +[[path]] +id = "edit.action.open_lines" +name = "Line opening actions" +description = """ +These commands provides several ways of adding lines above or below the current line +""" + +[[path]] +id = "edit.action.indent" +name = "Indentation" +description = """ +Operations that affect line indentation +""" + +[[bind]] +path = "edit.action.indent" +key = "shift+." +name = "indent" +description = "Indent lines" +command = "editor.action.indentLines" + +[[bind]] +path = "edit.action.indent" +key = "shift+." +name = "indent" +description = "Indent lines" +when = "master-key.count >= 1" +command = "runCommands" +args.commands = [ + { defined = "selectLinesDown" }, + "editor.action.indentLines" +] + +[[bind]] +path = "edit.action.indent" +key = "shift+," +name = "deindent" +when = "master-key.count < 1" +description = "De-indent lines" +command = "editor.action.outdentLines" + +[[bind]] +path = "edit.action.indent" +key = "shift+," +name = "deindent" +when = "master-key.count >= 1" +description = "Deindent lines" +command = "runCommands" +args.commands = [ + { defined = "selectLinesDown" }, + "editor.action.outdentLines", + "selection-utilities.shrinkToActive" +] + +[[path]] +id = "edit.action.history" +name = "History Commands" +description = "Commands that interact with edit or cursor history." + +# ## Number actions + +# These commands modify or enter numbers in some way. + +[[path]] +id = "edit.action.numbers" +name = "Number Editing" +description = "Commands that modify one or more numbers" + +[[bind]] +path = "edit.action.numbers" +name = 'inc #' +description = "Increment a number by 1" +key = "=" +command = "selection-utilities.incrementNumber" + +[[bind]] +path = "edit.action.numbers" +name = 'dec #' +description = "Decrement a number by 1 " +key = "shift+=" +command = "selection-utilities.decrementNumber" + +# ## Captilization + +# These modify the capitalization of letters in some way. + +[[path]] +id = "edit.action.capitals" +name = "Capitlization Actions" +description = "Actions that change how words are capitalized" +default.mode = ["normal", "selectedit"] + +[[bind]] +path = "edit.action.capitals" +name = 'camel' +description = "Swap style to lower camel case (`camelCase`)" +key = "` c" +command = "extension.changeCase.camel" + +[[bind]] +path = "edit.action.capitals" +name = 'constant' +description = "Swap style to constant (`IS_CONSTANT`)" +key = "` shift+u" +command = "extension.changeCase.constant" + +[[bind]] +path = "edit.action.capitals" +name = 'dot' +description = "Swap style to dot case (`dot.case`)" +key = "` ." +command = "extension.changeCase.dot" + +[[bind]] +path = "edit.action.capitals" +name = 'kebab' +description = "Swap style to kebab case (`kebab-case`)" +key = "` -" +command = "extension.changeCase.kebab" + +[[bind]] +path = "edit.action.capitals" +name = 'all lower' +description = "Swap all to lower case" +key = "` shift+l" +command = "extension.changeCase.lower" + +[[bind]] +path = "edit.action.capitals" +name = 'first lower' +description = "Swap first letter to lower case" +key = "` l" +command = "extension.changeCase.lowerFirst" + +[[bind]] +path = "edit.action.capitals" +name = 'spaces' +description = "Swap to spaces (`camelCase` -> `camel case`)" +key = "` space" +command = "extension.changeCase.no" + +[[bind]] +path = "edit.action.capitals" +name = 'Camel' +description = "Swap to upper camel case (`CamelCase`)" +key = "` shift+c" +command = "extension.changeCase.pascal" + +[[bind]] +path = "edit.action.capitals" +name = 'path' +description = "Swap to 'path' case (`path/case`)" +key = "` /" +command = "extension.changeCase.path" + +[[bind]] +path = "edit.action.capitals" +name = 'snake' +description = "Swap to snake case (`snake_case`)" +key = "` shift+-" +command = "extension.changeCase.snake" + +[[bind]] +path = "edit.action.capitals" +name = 'swap' +description = "Swap upper and lower case letters" +key = "` s" +command = "extension.changeCase.swap" + +[[bind]] +path = "edit.action.capitals" +name = 'title' +description = "Swap to title case (all words have first upper case letter)" +key = "` t" +command = "extension.changeCase.title" + +[[bind]] +path = "edit.action.capitals" +name = 'all upper' +description = "Swap to use all upper case letters" +key = "` shift+y" +command = "extension.changeCase.upper" + +[[bind]] +path = "edit.action.capitals" +name = 'first upper' +description = "Swap first character to upper case" +key = "` u" +command = "extension.changeCase.upperFirst" + +# ## "Do" Actions + +# These keys are all organized under the `space` key and they "do" something. These are generally more elaborate editing operations in the current editor pane. + +[[path]] +id = "edit.action.do" +name = "'Do' actions" +description = "Additional actions organized under the `'` (or 'do') prefix." +default.mode = "normal" + +[[bind]] +path = "edit.action.do" +name = "do" +key = "space" +description = "additional actions, mostly for modifying specific syntactic formats" +command = "master-key.prefix" + +[[bind]] +path = "edit.action.do" +name = "paste after line" +combinedName = "paste after/before line" +combinedKey = "p/shift+p" +description = "Paste text after current line" +priority = 2 +key = "space p" +command = "runCommands" +args.commands = [ + "expandLineSelection", + "selection-utilities.activeAtEnd", + "selection-utilities.shrinkToActive", + "editor.action.clipboardPasteAction", +] + +[[bind]] +path = "edit.action.do" +priority = 2 +name = "paste before line" +combinedName = "paste after/before line" +description = "Paste text before current line" +key = "space shift+p" +command = "runCommands" +args.commands = [ + "expandLineSelection", + "selection-utilities.activeAtStart", + "selection-utilities.shrinkToActive", + "editor.action.clipboardPasteAction", +] + +[[bind]] +path = "edit.action.do" +priority = 2 +name = "add line below" +combinedName = "add line below/above" +combinedDescription = "open a line below/above current line" +combinedKey = "o/shift+o" +description = "open a line below current line" +key = "space o" +command = "editor.action.insertLineAfter" + +[[bind]] +path = "edit.action.do" +name = "add line above" +priority = 2 +combinedName = "add line below/above" +description = "open a line above current line" +key = "space shift+o" +command = "editor.action.insertLineBefore" + +[[bind]] +path = "edit.action.do" +name = 'sym insert' +description = "Insert a character pair around a character" +priority = 1 +key = "space i" +combinedName = "sym insert (mode)" +combinedDescription = "Insert characters around pair (switching to syminster mode until hitting again)" +combinedKey = "i/shift+i" +command = "runCommands" + +[[bind.args.commands]] +command = "master-key.captureKeys" +args.acceptAfter = 1 + +[[bind.args.commands]] +command = "selection-utilities.insertAround" +computedArgs.before = "braces[captured].before || captured" +computedArgs.after = "braces[captured].after || captured" +args.followCursor = true + +[[bind]] +path = "edit.action.do" +name = 'trim white' +description = "Delete all external whitespace (left and right edges)" +key = "space shift+-" +command = "selection-utilities.trimWhitespace" + +[[bind]] +path = "edit.action.do" +key = "space w" +name = "wrap p" +combinedName = "wrap/join lines" +description = "wrap paragraph text, preserving commenting" +combinedDescription = "wrap paragraph text, preserving commenting / join lines together" +combinedKey = "w/j" +command = "rewrap.rewrapComment" + +[[bind]] +path = "edit.action.basic" +name = 'join' +combinedName = "wrap/join lines" +description = "Remove newline between current and next line" +key = "space j" +mode = ["normal", "selectedit"] +when = "!editorHasSelection" +command = "runCommands" +args.commands = [ { defined = "selectLinesDown" }, 'editor.action.joinLines' ] + +[[bind]] +path = "edit.action.basic" +combinedName = "wrap/join lines" +name = 'join' +description = "Remove newline between current and next line" +mode = ["normal", "selectedit"] +key = "space j" +command = "editor.action.joinLines" + +[[bind]] +path = "edit.action.do" +key = "space f" +name = "format" +combinedName = "format / format document" +when = "master-key.count < 1" +command = "editor.action.formatSelection" + +[[bind]] +path = "edit.action.do" +key = "space f" +combinedName = "format / format document" +combinedKey = "f/shift+f" +combinedDescription = "Format selection / document" +name = "format" +description = "Format sel" +when = "master-key.count >= 1" +command = "runCommands" +args.commands = [ + { defined = "selectLinesDown" }, + "editor.action.formatSelection", + "selection-utilities.shrinkToActive" +] + +[[bind]] +path = "edit.action.do" +key = "space shift+f" +name = "format doc" +combinedName = "format / format document" +command = "editor.action.formatDocument" + +[[path]] +id = "edit.action.brackets" +name = 'Bracket/Quote Editing' +description = "Commands that edit two matching brackets or quotes." + +[[bind]] +path = "edit.action.do" +name = 'parens' +description = "actions related to various brackets (`[`, `(`, `{`)" +key = "space [" +command = "master-key.prefix" + +[[bind]] +path = "edit.action.do" +name = 'remove' +description = "Removes surrounding pairs" +key = "space [ d" +command = "bracketeer.removeBrackets" + +[[bind]] +path = "edit.action.do" +name = 'parens/brackets' +description = "Swap between `[`, `(` and `{`" +key = "space [ s" +command = "bracketeer.swapBrackets" + +[[bind]] +path = "edit.action.do" +name = 'quotes' +description = "Actions related to quotes" +key = "space '" +command = "master-key.prefix" + +[[bind]] +path = "edit.action.do" +name = 'remove' +description = "Removes quotes (', \" or `)" +key = "space ' d" +command = "bracketeer.removeQuotes" + +[[bind]] +path = "edit.action.do" +name = 'swap' +description = "Swap quotes (', \" or `)" +key = "space ' s" +command = "bracketeer.swapQuotes" + +[[path]] +id = "edit.action.comment" +name = "Comments" +description = """ +Operations that modify comments +""" + +[[bind]] +path = "edit.action.do" +key = "space /" +combinedName = "(block) comment" +when = "master-key.count < 1" +command = "editor.action.commentLine" + +[[bind]] +path = "edit.action.do" +key = "space /" +name = "comment lines" +combinedName = "(block) comment" +combinedDescription = "Toggle (block) comment" +combinedKey = "(shift+)/" +description = "select next comment" +when = "master-key.count >= 1" +command = "runCommands" +args.commands = [ + { defined = "selectLinesDown" }, + "editor.action.commentLine", +] + +[[bind]] +path = "edit.action.do" +key = "space shift+/" +when = "master-key.count < 1" +combinedName = "(block) comment" +command = "editor.action.blockComment" + +[[bind]] +path = "edit.action.do" +key = "space shift+/" +name = "block comment lines" +combinedName = "(block) comment" +description = "select previous comment" +when = "master-key.count >= 1" +command = "runCommands" +args.commands = [ + { defined = "selectLinesDown" }, + "editor.action.blockComment", + "selection-utilities.shrinkToActive", +] + +[[bind]] +path = "edit.action.do" +name = 'inc all #' +combinedName = "inc/dec all #" +combinedDescription = "Increment/decrement selected numbers; increment/decrement increases per selection" +combinedKey = "=/shift+=" +description = "Increment selected numbers; increment increases per selection" +key = "space =" +command = "selection-utilities.incrementNumberPerSelection" + +[[bind]] +path = "edit.action.do" +name = 'dec all #' +combinedName = "inc/dec all #" +description = "Decrement selected numbers; decrement increases per selection" +key = "space shift+=" +command = "selection-utilities.decrementNumberPerSelection" + +[[bind]] +path = "edit.action.do" +name = 'nb cell' +description = "Actions related to notebook cells" +key = "space c" +command = "master-key.prefix" + +[[bind]] +path = "edit.action.do" +key = "space c i" +when = "editorLangId == 'quarto'" +command = "quarto.insertCodeCell" +name = "insert cell" +description = "insert a new cell in a notebook" + +[[bind]] +path = "edit.action.do" +key = "space c s" +when = "editorLangId != 'quarto'" +command = "jupyter.selectCell" + +[[bind]] +path = "edit.action.basic" +key = "space ." +name = 'sent. lines' +description = "Split paragraph into one line per sentence" +mode = "normal" +command = "runCommands" + +[[bind.args.commands]] +command = "selection-utilities.moveBy" +args.unit = "paragraph" +args.boundary = "both" +args.selectWhole = true + +[[bind.args.commands]] +command = "editor.action.joinLines" + +[[bind.args.commands]] +command = "selection-utilities.createBy" +args.text = "." + +[[bind.args.commands]] +command = "selection-utilities.shrinkToActive" + +[[bind.args.commands]] +command = "cursorRight" + +[[bind.args.commands]] +command = "type" +args.text = "\n" + +[[bind.args.commands]] +command = "selection-utilities.cancelSelection" + +# ## Repeat actions + +# These commands interact with the history of previously typed commands to repeat some sequence of commands. They can record any edits, and any commands that are issued through master key bindings. Commands that are not part of this binding file (e.g. a standard call to Cmd/Ctrl+V to paste) will not be recorded. You can copy your non-master-key bindings over to master key (so that they will be recorded) by [customizing your bindings](#customized-bindings) and using `Import Default Bindings` and `Import User Bindings` to allow all of the default and user bindings stored in VSCOde's normal keybinding files to be recorded by master key. (You will have to remove your original user bindings from the VSCOde `keybinding.json` file manually) + +[[bind]] +path = "edit.action.history" +name = "record" +description = "Start/stop recording Master Key commands" +key = "shift+q" +when = "!master-key.record" +command = "master-key.record" +args.on = true + +[[bind]] +path = "edit.action.history" +name = "record" +description = """ +Start/stop recording key presses defined by Master Key pushing it to the +top of the `history` stack once recording finishes." +""" +key = "shift+q" +when = "master-key.record" +command = "runCommands" + +[[bind.args.commands]] +command = "master-key.record" +args.on = false + +[[bind.args.commands]] +command = "master-key.pushHistoryToStack" +args.range.from = 'commandHistory[i-1].name === "record"' +args.range.to = "i" + +[[bind]] +path = "edit.action.history" +name = "replay" +description = """ +Replay the Master Key command sequence at the top of the `history` stack. Specifying +a count requests the Nth most recent item on this stack. +""" +key = "q q" +command = "master-key.replayFromStack" +computedArgs.index = "count" + +[[bind]] +path = "edit.action.history" +name = "store macro" +description = """ +Stores the top of the `history` stack into a named register. Specifying a count stores the +Nth most recent item on this stack. +""" +key = "q s" +command = "master-key.storeNamed" +args.description = "Save Macro" +args.name = "macro" +args.contents = "macro[macro.length-(count || 0)-1]" + +[[bind]] +path = "edit.action.history" +name = "replay stored" +description = """ +Replay a recorded Master Key command sequence from a named register, pushing +it to the front of the history stack. +""" +key = "q r" +command = "runCommands" + +[[bind.args.commands]] +command = "master-key.restoreNamed" +args.description = "Macro" +args.name = "macro" + +[[bind.args.commands]] +command = "master-key.pushHistoryToStack" +computedArgs.value = "captured" + +[[bind.args.commands]] +command = "master-key.replayFromStack" +args.index = 0 + +[[bind]] +path = "edit.action.history" +name = "store last" +description = """ +Store the N most recently run commands as a macro, where N is the count (defaulting to 1). +""" +key = "q l" +command = "master-key.pushHistoryToStack" +args.range.from = "i-(count || 0)" +args.range.to = "i" + +# ## Utility Commands + +# These actions include miscellaneous utilities. + +[[bind]] +path = "window" +key = "shift+ctrl+;" +name = "palette" +resetTransient = false +hideInPalette = true +mode = [] +prefixes = "" +description = """ +show command suggestions within the context of the current mode and keybinding prefix +(if any keys have already been typed) +""" +command = "master-key.commandPalette" + +[[bind]] +path = "util" +name = "git..." +description = "git commands" +key = "tab g" +command = "master-key.prefix" + +[[bind]] +path = "util" +name = "pull" +combinedName = "push/pull" +description = "pull changes from remote" +combinedDescription = "pull from/push to remote" +combinedKey = "p/shift+p" +key = "tab g p" +command = "git.pull" + +[[bind]] +path = "util" +name = "push" +description = "push changes to remote" +key = "tab g shift+p" +command = "git.push" + +[[bind]] +path = "util" +name = "checkout" +combinedName = "commit/checkout" +description = "commit changes" +combinedDescription = "commit/checkout git changes" +combinedKey = "c/shift+c" +key = "tab g c" +command = "git.commit" + +[[bind]] +path = "util" +name = "checkout" +combinedName = "commit/checkout" +description = "checkout changes" +key = "tab g shift+c" +command = "git.checkout" + +[[bind]] +path = "util" +name = "revert range" +description = "revert unstaged changes in selected range" +key = "tab g r" +command = "git.revertSelectedRanges" + +[[bind]] +path = "util" +name = "revert range" +description = "revert unstaged changes in selected range" +key = "tab g s" +command = "git.stageSelectedRanges" + +[[bind]] +path = "util" +name = "commands..." +description = "show GitLens command palette for git" +key = "tab g g" +command = "gitlens.gitCommands" + +# ## Miscellaneous Commands + +# These miscellaneous utility commands are all organized uner the prefix `tab`. + +[[path]] +id = "util" +name = "assorted misecellaneous commands" +default.kind = "util" +when = "editorTextFocus && !findWidgetVisible" + +[[bind]] +path = "util" +name = "utility" +key = "tab" +description = "utility related commands: file opening, window manipulation, debugging etc..." +command = "master-key.prefix" + +[[bind]] +path = "util" +name = "open recent" +description = "Open recent file" +key = "tab r" +command = "workbench.action.openRecent" + +[[bind]] +path = "util" +name = "hover" +description = "show the hover view" +combinedName = "(debug) hover" +combinedDescription = "show the (debug) hover view" +combinedKey = "(shift+)h" +key = "tab h" +command = "editor.action.showHover" + +[[bind]] +path = "util" +name = "debug hover" +combinedName = "(debug) hover" +description = "show the debug hover view" +key = "tab shift+h" +command = "editor.debug.action.showDebugHover" + +[[bind]] +path = "util" +name = "add mark" +combinedName = "add mark / mark..." +description = "toggle bookmark at given line" +combinedDescription = """ +toggle bookmark at given line / bookmark related commands +""" +key = "tab shift+m" +combinedKey = "shift+m / m" +command = "vsc-labeled-bookmarks.toggleBookmark" + +[[bind]] +path = "util" +name = "mark" +combinedName = "add mark / mark..." +description = "bookmark related commands" +key = "tab m" +command = "master-key.prefix" + +[[bind]] +path = "util" +name = "mark ↓" +description = "move to next bookmark" +combinedName = "mark ↓/↑" +combinedDescription = "move to next/previous bookmark" +combinedKey = "j/k" +key = "tab m j" +when = "!master-key.select_on && !editorHasSelection" +command = "vsc-labeled-bookmarks.navigateToNextBookmark" + +[[bind]] +path = "util" +combinedName = "mark ↓/↑" +key = "tab m j" +when = "master-key.select_on || editorHasSelection" +command = "vsc-labeled-bookmarks.expandSelectionToNextBookmark" + +[[bind]] +path = "util" +name = "mark ↑" +combinedName = "mark ↓/↑" +description = "move to previous bookmark" +key = "tab m k" +when = "!master-key.select_on && !editorHasSelection" +command = "vsc-labeled-bookmarks.navigateToPreviousBookmark" + +[[bind]] +path = "util" +name = "mark ↑" +combinedName = "mark ↓/↑" +description = "move to previous bookmark" +key = "tab m k" +when = "master-key.select_on || editorHasSelection" +command = "runCommands" +args.commands = ["vsc-labeled-bookmarks.expandSelectionToPreviousBookmark", + "selection-utilities.activeAtStart"] + +[[bind]] +path = "util" +name = "remove mark" +description = "remove bookmark (use quick selection)" +key = "tab m d" +command = "vsc-labeled-bookmarks.deleteBookmark" + +[[bind]] +path = "util" +name = "nav marks" +description = "reveal quick selection to move to a bookmark" +key = "tab m t" +command = "vsc-labeled-bookmarks.navigateToBookmark" + +[[bind]] +path = "util" +name = "error →" +combinedName = "error →/←" +combinedDescription = "move to next/previous error" +combinedKey = "e/shift+e" +description = """ +move to next error +""" +key = "tab e" +command = "editor.action.marker.next" + +[[bind]] +path = "edit.motion" +name = "error ←" +combinedName = "error →/←" +description = """ +move to previous error +""" +key = "tab shift+e" +command = "editor.action.marker.prev" + +[[bind]] +path = "edit.motion" +name = "diff →" +combinedName = "diff →/←" +combinedDescription = "move to and show next/previous diff" +combinedKey = "c/shift+c" +description = """ +move to and show next diff +""" +key = "tab c" +command = "editor.action.dirtydiff.next" + +[[bind]] +path = "edit.motion" +name = "diff ←" +combinedName = "diff →/←" +description = """ +move to and show previous diff +""" +key = "tab shift+c" +command = "editor.action.dirtydiff.previous" + +[[bind]] +path = "edit.motion" +name = "change →" +combinedName = "change →/←" +combinedDescription = "move to next/previous file change" +combinedKey = "d/shift+d" +description = """ +move to next file change +""" +key = "tab d" +command = "workbench.action.editor.nextChange" + +[[bind]] +path = "edit.motion" +name = "change ←" +combinedName = "change →/←" +description = """ +move to previous change +""" +key = "tab shift+d" +command = "workbench.action.editor.previousChange" + +# ## Window Manipulation + +# These are commands that interact with VSCode's user-interface in some way, rather than editing or moving around in the editor pane. + +[[path]] +id = "window" +name = "Window Manipulation" +description = "Commands for navigating and manipulating the window/editor panes in some way" +default.kind = "util" +default.mode = "normal" +when = "editorTextFocus && !findWidgetVisible" + +[[bind]] +path = "window" +name = "cntr win" +description = "center window at primary cursor position" +key = "tab l" +command = "selection-utilities.revealActive" +args.at = "center" +when = "editorTextFocus" + +[[bind]] +path = "window" +name = "window" +description = "window/editor pane manipulation-related commands" +key = "tab w" +command = "master-key.prefix" + +[[bind]] +path = "window" +name = "vert/horz" +key = "tab w r" +description = "Toggle between horizontal and vertical layouts" +command = "workbench.action.toggleEditorGroupLayout" + +[[bind]] +path = "window" +name = "next window" +combinedName = "next/previous window" +description = "move to next window" +combinedDescription = "move to next/prev window" +key = "tab ]" +combinedKey = "]/[" +command = "workbench.action.focusNextGroup" + +[[bind]] +path = "window" +name = "prev window" +combinedName = "next/previous window" +description = "move to previous window" +key = "tab [" +command = "workbench.action.focusPreviousGroup" + +[[bind]] +path = "window" +name = "move →" +combinedName = "move →/←" +combinedDescription = "move editor to window left/right" +combinedKey = "l/h" +description = "move editor to window to left" +key = "tab w l" +command = "workbench.action.moveEditorToRightGroup" + +[[bind]] +path = "window" +name = "←" +combinedName = "move →/←" +description = "move editor to window to left" +key = "tab w h" +command = "workbench.action.moveEditorToLeftGroup" + +[[bind]] +path = "window" +name = "↓" +combinedName = "move ↓/↑" +combinedDescription = "move editor to window above/below" +combinedKey = "j/k" +description = "move editor to window below" +key = "tab w j" +command = "workbench.action.moveEditorToBelowGroup" + +[[bind]] +path = "window" +name = "↑" +combinedName = "move ↓/↑" +description = "move editor to window above" +key = "tab w k" +command = "workbench.action.moveEditorToAboveGroup" + +[[bind]] +path = "window" +name = "split editor..." +description = "split editor to in a given direction" +key = "tab w s" +command = "master-key.prefix" + +[[bind]] +path = "window" +name = "move →" +combinedName = "split →/←" +combinedDescription = "move editor to window left/right" +combinedKey = "l/h" +description = "split editor to window to left" +key = "tab w s l" +command = "workbench.action.splitEditorRight" + +[[bind]] +path = "window" +name = "←" +combinedName = "split →/←" +description = "split editor to window to left" +key = "tab w s h" +command = "workbench.action.splitEditorLeft" + +[[bind]] +path = "window" +name = "↓" +combinedName = "split ↓/↑" +combinedDescription = "split editor to window above/below" +combinedKey = "j/k" +description = "split editor to window below" +key = "tab w s j" +command = "workbench.action.splitEditorDown" + +[[bind]] +path = "window" +name = "↑" +combinedName = "split ↓/↑" +combinedDescription = "split editor to window above/below" +combinedKey = "j/k" +description = "split editor to window below" +key = "tab w s k" +command = "workbench.action.splitEditorUp" + +[[bind]] +path = "window" +name = "close pane" +description = "close the given group of editors" +key = "tab w x" +command = "workbench.action.closeEditorsInGroup" + +[[bind]] +path = "window" +name = "max" +description = "minimize size of all other windows" +key = "tab w shift+m" +command = "workbench.action.minimizeOtherEditors" + +[[bind]] +path = "window" +name = "equal" +description = "equalize size of all windows" +key = "tab w =" +command = "workbench.action.evenEditorWidths" + +[[bind]] +path = "window" +name = "curs. win top" +description = "center window so that primary cursor is at the top" +key = "tab k" +combinedName = "center window top/bottom" +combinedDescription = "center window so that primary cursor is at the top/bottom" +combinedKey = "k/j" +command = "selection-utilities.revealActive" +args.at = "top" + +[[bind]] +path = "window" +name = "curs. win bot" +combinedName = "center window top/bottom" +description = "center window so that primary cursor is at the bottom" +key = "tab j" +command = "selection-utilities.revealActive" +args.at = "bottom" + +# ## Debugging Commands + +# Commands for interacting with VSCode's debugger UI. + +[[bind]] +path = "util" +name = "breakpt." +combinedName = "breakpt / debug..." +combinedKey = "shift+b/b" +description = "toggle debug breakpoint" +combinedDescription = "toggle debug breakpoint / debug related commands..." +key = "tab shift+b" +command = "editor.debug.action.toggleBreakpoint" + +[[bind]] +path = "util" +name = "debug..." +combinedName = "breakpt / debug..." +description = "assorted debugging actions" +key = "tab b" +command = "master-key.prefix" + +[[bind]] +path = "util" +name = "cond. break" +description = "conditional breakpoint" +key = "tab b shift+c" +command = "editor.debug.action.conditionalBreakpoint" + + +[[bind]] +path = "util" +name = "start" +description = "start debugging" +key = "tab b r" +command = "workbench.action.debug.start" + +[[bind]] +path = "util" +name = "continue" +description = "continue debugging" +key = "tab b c" +command = "workbench.action.debug.continue" + +[[bind]] +path = "util" +name = "next" +description = "debug: step over next line" +key = "tab b j" +command = "workbench.action.debug.stepOver" + +[[bind]] +path = "util" +name = "into" +description = "debug: step into next line" +key = "tab b i" +command = "workbench.action.debug.stepInto" + +[[bind]] +path = "util" +name = "out" +description = "debug: step out" +key = "tab b o" +command = "workbench.action.debug.stepOut" + +# ## Select-edit Mode + +# Select-edit mode allows you make a variety of kakoune-like modifications of one or more cursors. This lends itself to work flows such as: +# +# - select every line of text as a separate cursor, then filter out the lines you don't want +# - split an array by comma delimiters and edit each element of the array. +# - save a single selection to a list of selections to use for later and +# then move the cursor to the next selection you wish to add + +[[path]] +id = "edit.select_edit" +name = "Selection Editing" +description = "Various kakaune inspired commands for editing multiple selections" +default.mode = "selectedit" +default.kind = "motion" + +[[bind]] +path = "edit.select_edit" +name = "select-edit" +description = """ +Enter a mode where you can edit and manipulate (possibly multiple) selections. +""" +key = "'" +command = "master-key.setMode" +args.value = "selectedit" +mode = "normal" + +[[bind]] +path = "edit.select_edit" +key = "shift+'" +combinedName = "rm cursors" +combinedKey = "shift/ctrl+'" +combinedDescription = "Delete all selections and return to normal (multiple key variants)" +name = "del. cursors" +description = "Delete all selections and return to normal" +command = "runCommands" +args.commands = ["selection-utilities.cancelSelection", "master-key.enterNormal"] +mode = ["selectedit", "normal"] + +[[bind]] +path = "edit.select_edit" +key = "ctrl+'" +mode = ["insert", "selectedit", "normal"] +name = "rm cursors" +combinedName = "rm cursors" +description = "Delete all selections and return to normal" +command = "runCommands" +args.commands = ["selection-utilities.cancelSelection", "master-key.enterNormal"] + +[[bind]] +path = "edit.select_edit" +name = 'normal' +description = "return to normal mode" +key = "'" +command = "master-key.enterNormal" + +[[bind]] +path = "edit.select_edit" +name = "add →" +combinedName = "add →/←" +description = "add cursor at the next match to the primary cursor's text" +combinedDescription = "add cursor at the next/previous match to the primary cursor's text" +key = "l" +combinedKey = "l/h" +repeat = "count" +command = "selection-utilities.addNext" + +[[bind]] +path = "edit.select_edit" +name = "add ←" +combinedName = "add →/←" +description = "add cursor at the previous match to the primary cursor's text" +key = "h" +command = "selection-utilities.addPrev" +repeat = 'count' + +[[bind]] +path = "edit.select_edit" +name = "skip →" +combinedName = "skip →/←" +description = "move primary cursor to the next match of the primary cursor's text" +combinedDescription = "move primary cursor to the next/previous match of the primary cursor's text" +key = "shift+l" +combinedKey = "shift+l/h" +command = "selection-utilities.skipNext" +repeat = "count" + +[[bind]] +path = "edit.select_edit" +name = "skip ←" +combinedName = "skip →/←" +description = "move primary cursor to the previous match of the primary cursor's text" +key = "shift+h" +command = "selection-utilities.skipPrev" +repeat = 'count' + +[[bind]] +path = "edit.select_edit" +name = "align ←" +description = "align selections left" +key = "=" +command = "selection-utilities.alignSelectionsLeft" + +[[bind]] +path = "edit.select_edit" +name = "align →" +description = "align selections right" +key = "shift+=" +command = "selection-utilities.alignSelectionsRight" + +[[bind]] +path = "edit.select_edit" +name = "→ sel" +combinedName = "→/← sel" +description = """ +make the next selection primary; primary selections determine from where you add cursors, +what cursor you delete, and where the cursor goes when you clear or save selections +""" +combinedDescription = """ +make the next/previous selection primary; primary selections determine from where you add cursors, +what cursor you delete, and where the cursor goes when you clear or save selections +""" +key = "j" +combinedKey = "j/l" +command = "selection-utilities.movePrimaryRight" +repeat = 'count' + +[[bind]] +path = "edit.select_edit" +name = "← sel" +combinedName = "→/← sel" +description = "make the previous selection primary; primary selections determine from where you add cursors, what cursor you delete, and where the cursor goes when you clear or save selections" +key = "k" +command = "selection-utilities.movePrimaryLeft" +repeat = 'count' + +[[bind]] +path = "edit.select_edit" +name = "insert ↑" +combinedName = "insert ↑/↓" +description = """ +insert cursor on line above +""" +combinedDescription = "insert cursor on line above/below" +key = "shift+k" +combinedKey = "shift+k/j" +command = "editor.action.insertCursorAbove" +repeat = "count" + +[[bind]] +path = "edit.select_edit" +name = "insert sel ↓" +combinedName = "insert ↑/↓" +description = """ +insert cursor on line below +""" +key = "shift+j" +command = "editor.action.insertCursorBelow" +repeat = "count-1" + +[[bind]] +path = "edit.select_edit" +name = "del. primary" +combinedName = "del. primary/others" +description = "remove the primary selection" +combinedDescription = """ +Remove either the primary selection or all selections. Return to normal +mode if all selections are deleted. +""" +key = "d" +command = "selection-utilities.deletePrimary" +repeat = "count-1" + +[[bind]] +path = "edit.select_edit" +name = 'del. others' +description = "delete all other cursors but the primary selection" +key = "shift+d" +command = "removeSecondaryCursors" + +[[bind]] +path = "edit.select_edit" +name = "save sel" +description = """ +save all selections to the default register. +Use a count to specify an alternate register +""" +key = "c" +command = "runCommands" +args.commands = [ + { command = "selection-utilities.appendToMemory", computedArgs = { register = "count || 'default'" } }, + "selection-utilities.shrinkToActive", "master-key.enterNormal" +] + +[[bind]] +path = "edit.select_edit" +name = "load sel" +description = """ +load previously saved selections in the default register. +Use a count to specify an alternate register +""" +key = "v" +command = "runCommands" +args.commands = [ + { command = "selection-utilities.restoreAndClear", computedArgs = { register = "count || 'default'" } }, +] + +[[bind]] +path = "edit.select_edit" +name = "exchange sel" +description = """ +exchange selections: with no saved selection, saves the selection, with saved selections exchanges text of current selections with those of the saved selections (number of selections must match). Use a count to specify an alternate register. +""" +key = "x" +command = "runCommands" +args.commands = [ + { command = "selection-utilities.swapWithMemory", computedArgs = {register = "count || 'default'"} }, + "master-key.enterNormal" +] + +[[bind]] +path = "edit.select_edit" +name = "rem saved sel" +description = """ +remove the most recently saved selection from the list of saved selections +""" +command = "runCommands" +key = "n" +args.commands = [ + { command = "selection-utilities.deleteLastSaved", computedArgs = {register = "count || 'default'"} }, + "master-key.enterNormal" +] + +[[bind]] +path = "edit.select_edit" +key = "shift+enter" +name = "split sel" +description = """ +split selection into multiple selections by new line charactesr +""" +command = "selection-utilities.splitByNewline" + +[[bind]] +path = "edit.select_edit" +name = "sel all" +description = """ +create a selection for every match of the current word (or selection) +""" +key = "shift+8" +command = "editor.action.selectHighlights" + +[[bind]] +path = "edit.select_edit" +name = "character" +description = "split by a given character" +key = "s" +command = "runCommands" + +[[bind.args.commands]] +command = "master-key.captureKeys" +args.acceptAfter = 1 + +[[bind.args.commands]] +command = "selection-utilities.splitBy" +computedArgs.text = "captured" + +[[bind]] +path = "edit.select_edit" +name = "string" +description = "split by a given string" +key = "shift+s" +command = "selection-utilities.splitBy" + +[[bind]] +path = "edit.select_edit" +name = "include" +description = """ +Include all selections that contain a given marker +""" +key = "f" +command = "selection-utilities.includeBy" + +[[bind]] +path = "edit.select_edit" +name = "exclude" +description = """ +Exclude all selections that contain a given marker +""" +key = "shift+f" +command = "selection-utilities.excludeBy" + +[[bind]] +path = "edit.select_edit" +name = "create" +description = "create selections of given string scoped to the current selections" +key = "/" +command = "selection-utilities.createBy" + +[[bind]] +path = "edit.select_edit" +name = "regex" +description = "operations by regex rather than string" +key = "r" +command = "master-key.prefix" + +[[bind]] +path = "edit.select_edit" +name = "split" +description = "split by a given regular expression" +key = "r shift+s" +command = "selection-utilities.splitByRegex" + +[[bind]] +path = "edit.select_edit" +name = "create" +description = "create selections of given regular expression scoped to the current selections" +key = "r /" +command = "selection-utilities.createByRegex" + +[[bind]] +path = "edit.select_edit" +name = "include" +description = "Include all selections that contain a given regular expression" +key = "r f" +command = "selection-utilities.includeByRegex" + +[[bind]] +path = "edit.select_edit" +name = "exclude" +description = "Exclude all selections that contain a given regular expression" +key = "r shift+f" +command = "selection-utilities.excludeByRegex" + +[[bind]] +path = "edit.select_edit" +key = "o" +name = "active to front" +combinedKey = "o/shift+o" +combinedName = "active to start/end" +combinedDescription = "move cursor to start/end of selection" +description = "move cursor to start of selection" +command = "selection-utilities.activeAtEnd" + +[[bind]] +path = "edit.select_edit" +name = "active to end" +combinedName = "active to start/end" +description = "move cursor to back of selection" +key = "shift+o" +command = "selection-utilities.activeAtStart" + +# ## Symmetric Insert Mode + +# Symmetric insert mode allows you to edit text at both the start and the beginning of a selection. When entering a character with a complimentary pair (e.g. `(` to `)`) entry is handled in the expected way. For example if you type `(` at the start of a selection while in symmetric insert mode, `)` will apepar at the end of the selection. + +# As a general rule, the letter keys issue commands of various sorts, and the other keys can be used to enter text (since we rarley want to surround a selection with an `a` but might want to surround it with `*` or `/`. + +[define.braces] + +"{".before = "{" +"{".after = "}" +"}".before = "{" +"}".after = "}" + +"[".before = "[" +"[".after = "]" +"]".before = "[" +"]".after = "]" + +"(".before = "(" +"(".after = ")" +")".before = "(" +")".after = ")" + +"<".before = "<" +"<".after = ">" +">".before = "<" +">".after = ">" + +[[mode]] +name = "syminsert" +highlight = "Highlight" +cursorShape = "BlockOutline" +lineNumbers = "relative" + +[[mode.onType]] +command = "selection-utilities.insertAround" +computedArgs.before = "braces[captured].before || captured" +computedArgs.after = "braces[captured].after || captured" +args.followCursor = true + +[[path]] +id = "edit.action.symmetric" +name = "Symmetric Operations" +description = "Operations that occur at both ends of a selection" +default.kind = "action" +default.mode = "syminsert" + +[[path]] +id = "edit.motion.symmetric" +name = "Symmetric Motions" +description = "Motions that occur at both ends of a selection" +default.kind = "motion" +default.mode = "syminsert" + +[[bind]] +path = "edit.action.symmetric" +name = "sym insert mode" +priority = 1 +description = """ +In this mode all commands and character insertions happen at both ends of +the selection +""" +mode = "normal" +key = "space shift+i" +combinedName = "sym insert (mode)" +command = "master-key.setMode" +args.value = "syminsert" + +[[bind]] +path = "edit.action.symmetric" +name = "Normal" +description = "Return to normal model" +key = "enter" +command = "master-key.setMode" +mode = "syminsert" + +[[bind]] +path = "edit.action.symmetric" +foreach.key = ["{key: [a-z]}", "shift+{key: [a-z]}"] +name = "" +description = "this key is ignored and has no associated command in syminsert mode" +key = "{key}" +command = "master-key.ignore" +mode = "syminsert" +hideInDocs = true +hideInPalette = true + +[[bind]] +name = "esc. char" +path = "edit.action.symmetric" +key = "\\" +description = "Insert escaped character" +command = "runCommands" + +[[bind.args.commands]] +command = "master-key.captureKeys" +args.acceptAfter = 1 + +[[bind.args.commands]] +command = "selection-utilities.insertAround" +computedArgs.before = "'\\\\' + (braces[captured].before || captured)" +computedArgs.after = "'\\\\' + (braces[captured].after || captured)" +args.followCursor = true + +[[bind]] +path = "edit.action.symmetric" +name = "delete" +key = "x" +description = """ +delete the first and last adjacent character when cursor is at end of selection and +delete the first and last character *in* the selection when cursor is at the start of the +selection +""" +command = "selection-utilities.deleteAround" +computedArgs.count = "count" +args.followCursor = true + +[[bind]] +path = "edit.motion.symmetric" +key = "l" +name = "sel →" +description = "shrink/grow selections in direction that's rightwards from cursor" +command = "selection-utilities.adjustSelections" +args.dir = "forward" +computedArgs.count = "count" + +[[bind]] +path = "edit.motion.symmetric" +key = "h" +name = "sel ←" +description = "shrink/grow selections in direction that's leftwards from cursor" +command = "selection-utilities.adjustSelections" +args.dir = "backward" +computedArgs.count = "count" + +[[bind]] +path = "edit.motion.symmetric" +key = "o" +name = "active to front" +combinedKey = "o/shift+o" +combinedName = "active to start/end" +combinedDescription = "move cursor to start/end of selection" +description = "move cursor to start of selection" +command = "selection-utilities.activeAtEnd" + +[[bind]] +path = "edit.motion.symmetric" +name = "active to end" +combinedName = "active to start/end" +description = "move cursor to back of selection" +key = "shift+o" +command = "selection-utilities.activeAtStart" + +[[bind]] +path = "edit.action.symmetric" +name = "undo" +key = "u" +command = "undo" + +[[bind]] +path = "edit.action.symmetric" +name = "redo" +key = "shift+u" +command = "redo" + +[[bind]] +path = "edit.motion.symmetric" +key = "v" +name = "shrink selection" +description = """ +reduce all selections to length zero and return to normal mode +""" +command = "runCommands" +args.commands = [ + "selection-utilities.shrinkToActive", + { command = "master-key.setFlag", args = { name = "select_on", value = false } }, + "master-key.enterNormal" +] diff --git a/src/web/commands/palette.ts b/src/web/commands/palette.ts index e601011..7af617f 100644 --- a/src/web/commands/palette.ts +++ b/src/web/commands/palette.ts @@ -5,7 +5,11 @@ import {filterBindingFn} from '../keybindings'; import {bindings} from '../keybindings/config'; import {PREFIX_CODE} from './prefix'; import {MODE, defaultMode} from './mode'; -import {IConfigKeyBinding} from '../keybindings/processing'; +import {IConfigKeyBinding} from '../keybindings/parsing'; +import { + normalizeLayoutIndependentBindings, + normalizeLayoutIndependentString, +} from '../keybindings/layout'; import {COMMAND_HISTORY, RunCommandsArgs, doCommandsCmd} from './do'; import {reverse, uniqBy, sortBy} from 'lodash'; import replaceAll from 'string.prototype.replaceall'; @@ -41,6 +45,8 @@ function togglePaletteMode() { setPickerText(); } +const LAYOUT_MARKER = ' (U.S. layout)'; + export async function commandPalette(_args: unknown, opt: {useKey?: boolean} = {}) { const useKey = opt.useKey || false; @@ -58,17 +64,20 @@ export async function commandPalette(_args: unknown, opt: {useKey?: boolean} = { availableBindings = ( (bindings?.bind || []).filter(filterBindingFn(mode, prefixCode)) ); + const originalKeys = availableBindings.map(b => b.args.key); + availableBindings = normalizeLayoutIndependentBindings(availableBindings); availableBindings = reverse( uniqBy(reverse(availableBindings), b => (b.args.key || '') + b.args.prefixCode) ); - let picks = availableBindings.map(binding => { + let picks = availableBindings.map((binding, i) => { let key = binding.args.key; key = prettifyPrefix(key); return { label: key, - description: binding.args.name, + description: + binding.args.name + (originalKeys[i] !== key ? LAYOUT_MARKER : ''), detail: replaceAll(binding.args.description || '', /\n/g, ' '), args: binding.args, }; @@ -86,13 +95,20 @@ export async function commandPalette(_args: unknown, opt: {useKey?: boolean} = { let lastPick = picks[0]; filteredPicks.push(lastPick); + let i = 0; for (const pick of picks.slice(1)) { + i++; if ( lastPick.args.combinedName && lastPick.args.combinedName === pick.args.combinedName ) { - lastPick.label = prettifyPrefix(lastPick.args.combinedKey); - lastPick.description = lastPick.args.combinedName; + const combinedKey = normalizeLayoutIndependentString( + lastPick.args.combinedKey + ); + lastPick.label = prettifyPrefix(combinedKey); + lastPick.description = + lastPick.args.combinedName + + (originalKeys[i] !== pick.label ? LAYOUT_MARKER : ''); lastPick.detail = lastPick.args.combinedDescription || ''; } else { filteredPicks.push(pick); diff --git a/src/web/commands/visualKeyDoc.ts b/src/web/commands/visualKeyDoc.ts index 76397e5..f93a665 100644 --- a/src/web/commands/visualKeyDoc.ts +++ b/src/web/commands/visualKeyDoc.ts @@ -2,7 +2,9 @@ import {CommandState} from '../state'; import {withState} from '../state'; import * as vscode from 'vscode'; import {MODE} from './mode'; -import {Bindings, IConfigKeyBinding} from '../keybindings/processing'; +import {IConfigKeyBinding} from '../keybindings/parsing'; +import {Bindings} from '../keybindings/processing'; +import {normalizeLayoutIndependentBindings} from '../keybindings/layout'; import {filterBindingFn} from '../keybindings'; import {bindings, onChangeBindings} from '../keybindings/config'; import {PREFIX_CODE} from './prefix'; @@ -267,6 +269,7 @@ export class DocViewProvider implements vscode.WebviewViewProvider { let curBindings = allBindings.filter( filterBindingFn(values.get(MODE), values.get(PREFIX_CODE), true) ); + curBindings = normalizeLayoutIndependentBindings(curBindings, {noBrackets: true}); curBindings = reverse(uniqBy(reverse(curBindings), b => b.args.key)); this._bindingMap = {}; for (const binding of curBindings) { diff --git a/src/web/keybindings/docParsing.ts b/src/web/keybindings/docParsing.ts index 6ad441a..e933287 100644 --- a/src/web/keybindings/docParsing.ts +++ b/src/web/keybindings/docParsing.ts @@ -6,6 +6,7 @@ import {uniqBy, sortBy} from 'lodash'; import replaceAll from 'string.prototype.replaceall'; import {cloneDeep} from 'lodash'; import {IIndexed} from '../utils'; +import {normalizeLayoutIndependentString} from './layout'; const TOML = require('smol-toml'); @@ -53,8 +54,6 @@ function addIndexField(xs: T[], i = -1): [(T & IIndexed)[], number] { return [<(T & IIndexed)[]>xs, i]; } -// TODO: we need to grab the previously computed complete parse we should be able to -// uniquely match items to the full parse and use that to grab an default expansions export function parseBindingDocs(str: string) { let doc: IParsedBindingDoc = {str: '', items: []}; const result: IParsedBindingDoc[] = []; @@ -138,7 +137,10 @@ export function asBindingTable(parsed: BindingItem[]) { ) { const prefixMatch = item.key.match(/(.*)\s\S+$/); const prefix = prefixMatch ? prefixMatch[1] + ' ' : ''; - lastItem.key = prettifyPrefix(prefix + lastItem.args.combinedKey); + const keyseq = normalizeLayoutIndependentString( + prefix + lastItem.args.combinedKey + ); + lastItem.key = prettifyPrefix(keyseq); lastItem.args.name = lastItem.args.combinedName; lastItem.args.description = lastItem.args.combinedDescription || ''; } else { @@ -150,9 +152,10 @@ export function asBindingTable(parsed: BindingItem[]) { result += '\n\n|mode|key|name|description|\n'; result += '|---|----|----|-----------|\n'; for (const item of combinedToShow) { - const key = prettifyPrefix(item.key || ''); + const keyseq = normalizeLayoutIndependentString(item.key || ''); + const key = prettifyPrefix(keyseq); const mode = asArray(item.mode) - .map(m => '`' + m + '`') + .map(m => (m === undefined ? '' : '`' + m + '`')) .join(', '); result += `|${mode}|${key}|${item.args.name}|${stripNewlines(item.args.description || '')}|\n`; } diff --git a/src/web/keybindings/index.ts b/src/web/keybindings/index.ts index cbe2624..50ffd33 100644 --- a/src/web/keybindings/index.ts +++ b/src/web/keybindings/index.ts @@ -7,8 +7,9 @@ import { FullBindingSpec, ParsedResult, ErrorResult, + IConfigKeyBinding, } from './parsing'; -import {processBindings, IConfigKeyBinding, Bindings} from './processing'; +import {processBindings, Bindings} from './processing'; import {isSingleCommand} from '../utils'; import {uniq, pick} from 'lodash'; import replaceAll from 'string.prototype.replaceall'; @@ -296,6 +297,17 @@ async function insertKeybindingsIntoConfig(bindings: Bindings) { } return undefined; }); + if (bindings.bind.some(b => /\[[^\]]+\]/.test(b.key))) { + vscode.window.showInformationMessage( + replaceAll( + `The assigned bindings include layout independent bindings. When you + see keys surrounded by "[" and "]", they refer to the U.S. Layout + location of these characters.`, + /\s+/g, + ' ' + ) + ); + } } } } @@ -609,7 +621,7 @@ export async function updatePresets(event?: vscode.ConfigurationChangeEvent) { } } -const presetFiles = ['larkin.toml']; +const presetFiles = ['larkin.toml', 'larkin_layout.toml']; async function loadPreset(presets: Preset[], uri: vscode.Uri) { const fileData = await vscode.workspace.fs.readFile(uri); diff --git a/src/web/keybindings/layout.ts b/src/web/keybindings/layout.ts new file mode 100644 index 0000000..1a00dbc --- /dev/null +++ b/src/web/keybindings/layout.ts @@ -0,0 +1,61 @@ +import replaceAll from 'string.prototype.replaceall'; +import {IConfigKeyBinding} from '../keybindings/parsing'; + +// linting disabled for legibility of an unusual constant +/* eslint-disable */ +export const LI_KEY_TO_KEY = { + "\\[F1\\]": "f1", "\\[F2\\]": "f2", "\\[F3\\]": "f3", "\\[F4\\]": "f4", "\\[F5\\]": "f5", "\\[F6\\]": "f6", + "\\[F7\\]": "f7", "\\[F8\\]": "f8", "\\[F9\\]": "f9", "\\[F10\\]": "f10", "\\[F11\\]": "f11", + "\\[F12\\]": "f12", "\\[F13\\]": "f13", "\\[F14\\]": "f14", "\\[F15\\]": "f15", "\\[F16\\]": "f16", + "\\[F17\\]": "f17", "\\[F18\\]": "f18", "\\[F19\\]": "f19", + "\\[KeyA\\]": "a", "\\[KeyB\\]": "b", "\\[KeyC\\]": "c", "\\[KeyD\\]": "d", "\\[KeyE\\]": "e", + "\\[KeyF\\]": "f", "\\[KeyG\\]": "g", "\\[KeyH\\]": "h", "\\[KeyI\\]": "i", "\\[KeyJ\\]": "j", + "\\[KeyK\\]": "k", "\\[KeyL\\]": "l", "\\[KeyM\\]": "m", "\\[KeyN\\]": "n", "\\[KeyO\\]": "o", + "\\[KeyP\\]": "p", "\\[KeyQ\\]": "q", "\\[KeyR\\]": "r", "\\[KeyS\\]": "s", "\\[KeyT\\]": "t", + "\\[KeyU\\]": "u", "\\[KeyV\\]": "v", "\\[KeyW\\]": "w", "\\[KeyX\\]": "x", "\\[KeyY\\]": "y", + "\\[KeyZ\\]": "z", + "\\[Digit0\\]": "0", "\\[Digit1\\]": "1", "\\[Digit2\\]": "2", "\\[Digit3\\]": "3", + "\\[Digit4\\]": "4", "\\[Digit5\\]": "5", "\\[Digit6\\]": "6", "\\[Digit7\\]": "7", + "\\[Digit8\\]": "8", "\\[Digit9\\]": "9", + "\\[Backquote\\]": "`", "\\[Minus\\]": "-", "\\[Equal\\]": "=", "\\[BracketLeft\\]": "\[", + "\\[BracketRight\\]": "]", "\\[Backslash\\]": "\\", "\\[Semicolon\\]": ";", "\\[Quote\\]": "'", + "\\[Comma\\]": ",", "\\[Period\\]": ".", "\\[Slash\\]": "/", + "\\[ArrowLeft\\]": "left", "\\[ArrowUp\\]": "up", "\\[ArrowRight\\]": "right", + "\\[ArrowDown\\]": "down", + "\\[PageUp\\]": "pageup", "\\[PageDown\\]": "pagedown", "\\[End\\]": "end", "\\[Home\\]": "home", + "\\[Tab\\]": "tab", "\\[Enter\\]": "enter", "\\[Escape\\]": "escape", "\\[Space\\]": "space", + "\\[Backspace\\]": "backspace", "\\[Delete\\]": "delete", "\\[Pause\\]": "pause", + "\\[CapsLock\\]": "capslock", "\\[Insert\\]": "insert", + "\\[Numpad0\\]": "numpad0", "\\[Numpad1\\]": "numpad1", "\\[Numpad2\\]": "numpad2", + "\\[Numpad3\\]": "numpad3", "\\[Numpad4\\]": "numpad4", "\\[Numpad5\\]": "numpad5", + "\\[Numpad6\\]": "numpad6", "\\[Numpad7\\]": "numpad7", "\\[Numpad8\\]": "numpad8", + "\\[Numpad9\\]": "numpad9", + "\\[NumpadMultiply\\]": "numpad_multiply", "\\[NumpadAdd\\]": "numpad_add", + "\\[NumpadComma\\]": "numpad_separator", "\\[NumpadSubtract\\]": "numpad_subtract", + "\\[NumpadDecimal\\]": "numpad_decimal", "\\[NumpadDivide\\]": "numpad_divide", +} +/* eslint-enable */ + +export function normalizeLayoutIndependentBindings( + curBindings: IConfigKeyBinding[], + opts: {noBrackets: boolean} = {noBrackets: false} +): IConfigKeyBinding[] { + return curBindings.map(b => { + const key = normalizeLayoutIndependentString(b.args.key, opts); + return {...b, args: {...b.args, key}}; + }); +} + +export function normalizeLayoutIndependentString( + key: string, + opts: {noBrackets: boolean} = {noBrackets: false} +) { + for (const [liKey, toKey] of Object.entries(LI_KEY_TO_KEY)) { + if (opts.noBrackets) { + key = replaceAll(key, RegExp(liKey, 'ig'), toKey); + } else { + key = replaceAll(key, RegExp(liKey, 'ig'), '[' + toKey + ']'); + } + } + return key; +} diff --git a/src/web/keybindings/parsing.ts b/src/web/keybindings/parsing.ts index 87d29c2..dce7a47 100644 --- a/src/web/keybindings/parsing.ts +++ b/src/web/keybindings/parsing.ts @@ -434,3 +434,27 @@ export async function parseBindingFile(file: vscode.Uri) { const fileText = new TextDecoder().decode(fileData); return parseBindings(fileText); } + +export interface IConfigKeyBinding { + key: string; + command: 'master-key.do'; + prefixDescriptions: string[]; + when: string; + args: { + do: DoArgs; + key: string; // repeated here so that commands can display the key pressed + name?: string; + description?: string; + resetTransient?: boolean; + hideInPalette?: boolean; + hideInDocs?: boolean; + priority: number; + combinedName: string; + combinedKey: string; + combinedDescription: string; + kind: string; + path: string; + mode: string | undefined; + prefixCode: number | undefined; + }; +} diff --git a/src/web/keybindings/processing.ts b/src/web/keybindings/processing.ts index 47b62c3..9a9ae67 100644 --- a/src/web/keybindings/processing.ts +++ b/src/web/keybindings/processing.ts @@ -2,7 +2,6 @@ import hash from 'object-hash'; import { parseWhen, bindingItem, - DoArgs, DefinedCommand, BindingItem, BindingSpec, @@ -13,6 +12,7 @@ import { doArgs, KindItem, FullBindingSpec, + IConfigKeyBinding, } from './parsing'; import z from 'zod'; import { @@ -263,13 +263,17 @@ function resolveDocItems( let resolvedItems: BindingItem[] = []; for (const item of section.items) { if (byIndex[item.index] === undefined) { - problems.push( - `Master Key, unexpected internal inconsistency: could not find item - index ${item.index} in parsed keybindings. This is a bug!!`.replace( - /\s+/, - ' ' - ) - ); + if (item.command !== 'master-key.ignore') { + problems.push( + `Master Key, unexpected internal inconsistency: could not find item + index ${item.index} in parsed keybindings. This is a bug!! Item + was supposed to have name '${item.name}' with command + '${item.command}'.`.replace(/\s+/, ' ') + ); + console.log('Internal inconsistency, could not find following item.'); + console.dir(item); + console.dir(byIndex); + } } else { resolvedItems = resolvedItems.concat(byIndex[item.index]); } @@ -327,101 +331,38 @@ function expandForVars( return expandForVars(omit(vars, aKey), item, context, newDefs); } +// linting disabled for legibility of an unusual constant +/* eslint-disable */ const ALL_KEYS = [ - 'f0', - 'f1', - 'f2', - 'f3', - 'f4', - 'f5', - 'f6', - 'f7', - 'f8', - 'f9', - 'f10', - 'f11', - 'f12', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'a', - 'b', - 'c', - 'd', - 'e', - 'f', - 'g', - 'h', - 'i', - 'j', - 'k', - 'l', - 'm', - 'n', - 'o', - 'p', - 'q', - 'r', - 's', - 't', - 'u', - 'v', - 'w', - 'x', - 'y', - 'z', - '`', - '-', - '=', - '[', - ']', - '\\', - ';', - "'", - ',', - '.', - '/', - 'left', - 'up', - 'right', - 'down', - 'pageup', - 'pagedown', - 'end', - 'home', - 'tab', - 'enter', - 'escape', - 'space', - 'backspace', - 'delete', - 'pausebreak', - 'capslock', - 'insert', - 'numpad0', - 'numpad1', - 'numpad2', - 'numpad3', - 'numpad4', - 'numpad5', - 'numpad6', - 'numpad7', - 'numpad8', - 'numpad9', - 'numpad_multiply', - 'numpad_add', - 'numpad_separator', - 'numpad_subtract', - 'numpad_decimal', - 'numpad_divide', + 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '`', '-', '=', '[', ']', '\\', ';', "'", ',', '.', '/', + 'left', 'up', 'right', 'down', 'pageup', 'pagedown', 'end', 'home', 'tab', 'enter', + 'escape', 'space', 'backspace', 'delete', 'pausebreak', 'capslock', 'insert', + 'numpad0', 'numpad1', 'numpad2', 'numpad3', 'numpad4', 'numpad5', 'numpad6', 'numpad7', + 'numpad8', 'numpad9', 'numpad_multiply', 'numpad_add', 'numpad_separator', + 'numpad_subtract', 'numpad_decimal', 'numpad_divide', + "[F1]", "[F2]", "[F3]", "[F4]", "[F5]", "[F6]", "[F7]", "[F8]", "[F9]", + "[F10]", "[F11]", "[F12]", "[F13]", "[F14]", "[F15]", "[F16]", "[F17]", "[F18]", "[F19]", + "[KeyA]", "[KeyB]", "[KeyC]", "[KeyD]", "[KeyE]", "[KeyF]", "[KeyG]", "[KeyH]", "[KeyI]", + "[KeyJ]", "[KeyK]", "[KeyL]", "[KeyM]", "[KeyN]", "[KeyO]", "[KeyP]", "[KeyQ]", "[KeyR]", + "[KeyS]", "[KeyT]", "[KeyU]", "[KeyV]", "[KeyW]", "[KeyX]", "[KeyY]", "[KeyZ]", + "[Digit0]", "[Digit1]", "[Digit2]", "[Digit3]", "[Digit4]", "[Digit5]", "[Digit6]", + "[Digit7]", "[Digit8]", "[Digit9]", + "[Backquote]", "[Minus]", "[Equal]", "[BracketLeft]", "[BracketRight]", "[Backslash]", + "[Semicolon]", "[Quote]", "[Comma]", "[Period]", "[Slash]", + "[ArrowLeft]", "[ArrowUp]", "[ArrowRight]", "[ArrowDown]", "[PageUp]", "[PageDown]", + "[End]", "[Home]", "[Tab]", "[Enter]", "[Escape]", "[Space]", "[Backspace]", + "[Delete]", "[Pause]", "[CapsLock]", "[Insert]", + "[Numpad0]", "[Numpad1]", "[Numpad2]", "[Numpad3]", "[Numpad4]", "[Numpad5]", + "[Numpad6]", "[Numpad7]", "[Numpad8]", "[Numpad9]", + "[NumpadMultiply]", "[NumpadAdd]", "[NumpadComma]", "[NumpadSubtract]", + "[NumpadDecimal]", "[NumpadDivide]", ]; +/* eslint-enable */ + const REGEX_KEY_REGEX = /\{key(:\s*(.*))?\}/; function expandPattern(pattern: string): string[] { @@ -555,30 +496,6 @@ function expandDocsToDuplicates(items: BindingItem[]) { return items; } -export interface IConfigKeyBinding { - key: string; - command: 'master-key.do'; - prefixDescriptions: string[]; - when: string; - args: { - do: DoArgs; - key: string; // repeated here so that commands can display the key pressed - name?: string; - description?: string; - resetTransient?: boolean; - hideInPalette?: boolean; - hideInDocs?: boolean; - priority: number; - combinedName: string; - combinedKey: string; - combinedDescription: string; - kind: string; - path: string; - mode: string | undefined; - prefixCode: number | undefined; - }; -} - function makeModesExplicit(binding: BindingItem) { return { ...binding, diff --git a/src/web/status/keyseq.ts b/src/web/status/keyseq.ts index 4cc2657..6810158 100644 --- a/src/web/status/keyseq.ts +++ b/src/web/status/keyseq.ts @@ -4,6 +4,7 @@ import {PREFIX} from '../commands/prefix'; import {COUNT} from '../commands/count'; import {Map} from 'immutable'; import {prettifyPrefix} from '../utils'; +import {normalizeLayoutIndependentString} from '../keybindings/layout'; let keyStatusBar: vscode.StatusBarItem | undefined = undefined; @@ -15,7 +16,8 @@ function updateKeyStatus(values: Map) { if (keyStatusBar !== undefined && keyDisplayDelay > 0) { const count = values.get(COUNT, 0); let plannedUpdate = count ? count + '× ' : ''; - plannedUpdate += prettifyPrefix(values.get(PREFIX, '')); + const keyseq = normalizeLayoutIndependentString(values.get(PREFIX, '')); + plannedUpdate += prettifyPrefix(keyseq); if (plannedUpdate.length > 0) { keyStatusBar.text = plannedUpdate; keyStatusBar.accessibilityInformation = {label: 'Keys Typed: ' + plannedUpdate}; diff --git a/test/specs/simpleMotionLayout.ux.mts b/test/specs/simpleMotionLayout.ux.mts new file mode 100644 index 0000000..16a9c15 --- /dev/null +++ b/test/specs/simpleMotionLayout.ux.mts @@ -0,0 +1,212 @@ +// start with just some basic tests to verify all is well + +import '@wdio/globals'; +import 'wdio-vscode-service'; +import { + enterModalKeys, + setBindings, + setupEditor, + movesCursorInEditor, + storeCoverageStats, + clearNotifications, +} from './utils.mts'; +import {TextEditor} from 'wdio-vscode-service'; +import {Key} from 'webdriverio'; + +// NOTE: this differs from simpleMmotion.ux.mts only in the use of layout independent +// bindings; the tests are identical +describe('Simple Motions', () => { + let editor: TextEditor; + before(async () => { + await setBindings(` + [header] + version = "1.0" + + [[mode]] + name = "insert" + default = true + + [[mode]] + name = "normal" + + [[bind]] + name = "normal mode" + key = "escape" + command = "master-key.enterNormal" + prefixes = "" + + [[path]] + id = "motion" + name = "basic motions" + default.command = "cursorMove" + default.mode = "normal" + default.when = "editorTextFocus" + default.computedArgs.value = "count" + + [[bind]] + path = "motion" + name = "left" + key = "[KeyH]" + args.to = "left" + + [[bind]] + path = "motion" + name = "right" + key = "[KeyL]" + args.to = "right" + + [[bind]] + path = "motion" + name = "down" + key = "[KeyJ]" + args.to = "down" + + [[bind]] + path = "motion" + name = "up" + key = "[KeyK]" + args.to = "up" + + [[bind]] + name = "double right" + key = "shift+[KeyL]" + mode = "normal" + command = "cursorMove" + args.to = "right" + repeat = 1 + + # TODO: write a test for these + [[bind]] + mode = "normal" + name = "down (repeat)" + key = "shift+[KeyJ]" + command = "cursorMove" + args.to = "down" + repeat = "1+2" + + [[bind]] + mode = "normal" + name = "down (bad repeat)" + key = "ctrl+[KeyJ]" + command = "cursorMove" + args.to = "down" + repeat = "'a'+'b'" + + [[bind]] + name = "insert mode" + key = "[KeyI]" + command = "master-key.enterInsert" + mode = "normal" + + [[bind]] + #- NOTE: because of how vscode-extension-tester is implemented + #- numeric values get typed, so we use other keybindings here + #- to avoid picking up these typed keys + #- TODO: how do we deal with the stupid number of escapes required? + foreach.num = ["{key: \\\\[Digit[0-3]\\\\]}"] + key = "shift+{num}" + mode = "normal" + name = "count {num}" + command = "master-key.updateCount" + #- NOTE: it would be better to just use a digit in 'foreach' + #- in practice, but here we're trying to test a code path that + #- uses the new layout independent keys in the '{key: regex}' + #- field + args.value = "{num.slice(6,7)}" + resetTransient = false + `); + editor = + await setupEditor(`Anim reprehenderit voluptate magna excepteur dolore aliqua minim labore est +consectetur ullamco ullamco aliqua ex. Pariatur officia nostrud pariatur ex +dolor magna. Consequat cupidatat amet nostrud proident occaecat ex. +Ex cillum duis anim dolor cupidatat non nostrud non et sint ullamco. Consectetur consequat +ipsum ex labore enim. Amet do commodo et occaecat proident ex cupidatat in. Quis id magna +laborum ad. Dolore exercitation cillum eiusmod culpa minim duis`); + }); + + it('Can move cursor', async () => { + await browser.keys(Key.Escape); + await editor.moveCursor(1, 1); + + await movesCursorInEditor(() => enterModalKeys('[j]'), [1, 0], editor); + await movesCursorInEditor(() => enterModalKeys('[l]'), [0, 1], editor); + await movesCursorInEditor(() => enterModalKeys('[h]'), [0, -1], editor); + await movesCursorInEditor(() => enterModalKeys('[k]'), [-1, 0], editor); + }); + + it('Can use `repeat`', async () => { + await editor.moveCursor(1, 1); + await browser.keys([Key.Escape]); + + await movesCursorInEditor(() => enterModalKeys(['shift', '[l]']), [0, 2], editor); + await movesCursorInEditor(() => enterModalKeys(['shift', '[j]']), [4, 0], editor); + + const workbench = await browser.getWorkbench(); + clearNotifications(workbench); + enterModalKeys({key: ['ctrl', '[j]'], updatesStatus: false}); + const matches = await browser.waitUntil(async () => { + const notifs = await workbench.getNotifications(); + const messages = await Promise.all(notifs.map(n => n.getMessage())); + const matches = messages.filter(x => + x.match(/The expression.*did not.*number/) + ); + if (matches.length > 0) { + return matches; + } else { + return false; + } + }); + expect(matches).toHaveLength(1); + }); + + it('Can use `count`', async () => { + await editor.moveCursor(1, 1); + await browser.keys([Key.Escape]); + + for (let c = 1; c <= 3; c++) { + await movesCursorInEditor( + async () => { + await enterModalKeys({count: c, key: ['shift', String(c)]}, '[j]'); + }, + [1 * c, 0], + editor + ); + await movesCursorInEditor( + async () => { + await enterModalKeys({count: c, key: ['shift', String(c)]}, '[l]'); + }, + [0, 1 * c], + editor + ); + await movesCursorInEditor( + async () => { + await enterModalKeys({count: c, key: ['shift', String(c)]}, '[h]'); + }, + [0, -1 * c], + editor + ); + await movesCursorInEditor( + async () => { + await enterModalKeys({count: c, key: ['shift', String(c)]}, '[k]'); + }, + [-1 * c, 0], + editor + ); + } + await movesCursorInEditor( + async () => { + await enterModalKeys( + {count: 1, key: ['shift', '1']}, + {count: 0, key: ['shift', '0']}, + '[l]' + ); + }, + [0, 10], + editor + ); + }); + + after(async () => { + await storeCoverageStats('simpleMotion'); + }); +}); diff --git a/test/specs/utils.mts b/test/specs/utils.mts index 8be6f56..0e0ba65 100644 --- a/test/specs/utils.mts +++ b/test/specs/utils.mts @@ -32,10 +32,11 @@ export async function setBindings(str: string) { await input.confirm(); console.log('[DEBUG]: activate bindings'); - await workbench.executeCommand('Clear Command History'); await sleep(200); - await workbench.executeCommand('Master key: Activate Keybindings'); - await sleep(500); + await browser.executeWorkbench(async vscode => { + vscode.commands.executeCommand('master-key.activateBindings'); + }); + await sleep(200); input = await new InputBox(workbench.locatorMap).wait(); await input.setText('Current File'); await input.confirm(); @@ -247,9 +248,13 @@ export async function enterModalKeys(...keySeq: ModalKey[]) { ) { throw Error("Keys must all be lower case (use 'shift')"); } - const keyCodes = keys.map(k => - MODAL_KEY_MAP[k] !== undefined ? MODAL_KEY_MAP[k] : k - ); + const keyCodes = keys.map(k => { + if (MODAL_KEY_MAP[k] !== undefined) { + return MODAL_KEY_MAP[k]; + } else { + return k.replace(/\[(.*?)\]/, '$1'); + } + }); const keyCount = modalKeyCount(keys_); if (keyCount === undefined) { const keyString = keys.map(prettifyPrefix).join('');