I have been using VSCode as my primary editor for a couple of months. However it has been a recurring pain point for me that we have to switch back and forth between the arrow keys and primary rows when editing code. This post outlines a somewhat non-conventional approach for this by abusing the when clause of vscode keybinding configuration.
Prior state of the art
The most popular solution for this seems to be the vscode vim plugin, and I tried adapting to it despite not being a vim user. While I got comfortable with the primary vim keybindings in a week or so of continued used, I continued getting the feeling that it was not really well integrated with VSCode.
Along with general performance issues and lagginess, the biggest problem for me was that often when navigating and editing rapidly the keystrokes would be applied out of order. This really breaks the flow when rapidly typing and after a month of usage I started looking out for an alternative.
Turns out a very simple alternative is to simulate modal editing through VSCode themes.
Theme specific keybindings
While I liked vim’s modal editing, not being a longtime vim user, I kept longing for a visual indication when switching modes. A trivial solution here is to just use different vscode themes along with the settings cycler extension.
With this extension enabled, we can have a single command to switch between two themes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// kebindings.json { "key": "ctrl+;", "command": "settings.cycle", "when": "editorTextFocus", "args": { "id": "colorTheme", // must be unique "overrideWorkspaceSettings": true, "values": [ { "workbench.colorTheme": "Default Dark+" }, { "workbench.colorTheme": "Monokai" } ] } }, |
Now, we can define keybindings that are active only in a specific theme using the when clause.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
{ "key": "k", "command": "cursorUp", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "j", "command": "cursorDown", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "h", "command": "cursorLeft", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "l", "command": "cursorRight", "when": "config.workbench.colorTheme == 'Monokai'" }, |
This is somewhat verbose because VSCode only allows json for configuration (which I think is a bad idea), but nevertheless it gets the job done.
Now, when we press ctrl+;
and switch to Monokai
theme, we can use h,j,k,l as our arrow keys.
We can of course extend this further and define more keybindings for selection, jumping to start/end etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
{ "key": "k", "command": "cursorUp", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "j", "command": "cursorDown", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "h", "command": "cursorLeft", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "l", "command": "cursorRight", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+k", "command": "cursorUpSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+j", "command": "cursorDownSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+h", "command": "cursorLeftSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+l", "command": "cursorRightSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "i", "command": "cursorPageUp", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "m", "command": "cursorPageDown", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "alt+h", "command": "cursorHome", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "alt+l", "command": "cursorEnd", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+i", "command": "cursorPageUpSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+k", "command": "cursorPageDownSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "alt+shift+h", "command": "cursorHomeSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "alt+shift+l", "command": "cursorEndSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "ctrl+i", "command": "cursorTop", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "ctrl+m", "command": "cursorBottom", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "ctrl+h", "command": "cursorWordLeft", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "ctrl+l", "command": "cursorWordRight", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "ctrl+shift+i", "command": "cursorTopSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "ctrl+shift+m", "command": "cursorBottomSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "ctrl+shift+h", "command": "cursorWordLeftSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "ctrl+shift+l", "command": "cursorWordRightSelect", "when": "config.workbench.colorTheme == 'Monokai'" }, |
Once arrow keys were no longer needed for primary navigation, I have been using them for switching focus across editors in different split panels and moving the editor around between split frames (a common but infrequent operation).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
{ "key": "shift+up", "command": "workbench.action.moveEditorToAboveGroup", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+down", "command": "workbench.action.moveEditorToBelowGroup", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+right", "command": "workbench.action.moveEditorToRightGroup", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "shift+left", "command": "workbench.action.moveEditorToLeftGroup", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "down", "command": "workbench.action.focusBelowGroup", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "up", "command": "workbench.action.focusAboveGroup", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "right", "command": "workbench.action.focusRightGroup", "when": "config.workbench.colorTheme == 'Monokai'" }, { "key": "left", "command": "workbench.action.focusLeftGroup", "when": "config.workbench.colorTheme == 'Monokai'" } |
This has worked out quite well for me so far.