Skip to content

Instantly share code, notes, and snippets.

@nikolovlazar
Last active April 3, 2025 03:28
Show Gist options
  • Save nikolovlazar/1174876ab2769c52ac9fc1534c557d70 to your computer and use it in GitHub Desktop.
Save nikolovlazar/1174876ab2769c52ac9fc1534c557d70 to your computer and use it in GitHub Desktop.
VSCode key bindings to navigate like Neovim
[
// Navigation
{
"key": "ctrl-h",
"command": "workbench.action.navigateLeft"
},
{
"key": "ctrl-l",
"command": "workbench.action.navigateRight"
},
{
"key": "ctrl-k",
"command": "workbench.action.navigateUp"
},
{
"key": "ctrl-j",
"command": "workbench.action.navigateDown"
},
{
"key": "space ,",
"command": "workbench.action.showAllEditors",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus)"
},
{
"key": "space e",
"command": "runCommands",
"args": {
"commands": [
"workbench.action.toggleSidebarVisibility",
"workbench.files.action.focusFilesExplorer"
]
},
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus) && !sideBarFocus"
},
{
"key": "space e",
"command": "runCommands",
"args": {
"commands": [
"workbench.action.toggleSidebarVisibility",
"workbench.action.focusActiveEditorGroup"
]
},
"when": "sideBarFocus && !inputFocus"
},
{
"key": "space e",
"when": "vim.mode == 'Normal' && editorTextFocus && foldersViewVisible",
"command": "workbench.action.toggleSidebarVisibility"
},
{
"key": "s h",
"command": "workbench.action.splitEditor",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus)"
},
{
"key": "s v",
"command": "workbench.action.splitEditorDown",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus)"
},
// Coding
{
"key": "space c a",
"command": "editor.action.codeAction",
"when": "vim.mode == 'Normal' && editorTextFocus"
},
{
"key": "shift-k",
"command": "editor.action.moveLinesUpAction",
"when": "vim.mode == 'VisualLine' && editorTextFocus"
},
{
"key": "shift-j",
"command": "editor.action.moveLinesDownAction",
"when": "vim.mode == 'VisualLine' && editorTextFocus"
},
{
"key": "shift-k",
"command": "editor.action.showHover",
"when": "vim.mode == 'Normal' && editorTextFocus"
},
{
"key": "space c r",
"command": "editor.action.rename",
"when": "vim.mode == 'Normal' && editorTextFocus"
},
{
"key": "space c s",
"command": "workbench.action.gotoSymbol",
"when": "vim.mode == 'Normal' && editorTextFocus"
},
{
"key": "space b d",
"command": "workbench.action.closeActiveEditor",
"when": "(vim.mode == 'Normal' && editorTextFocus) || !inputFocus"
},
{
"key": "space b o",
"command": "workbench.action.closeOtherEditors",
"when": "(vim.mode == 'Normal' && editorTextFocus) || !inputFocus"
},
{
"key": "space space",
"command": "workbench.action.quickOpen",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus)"
},
{
"key": "space g d",
"command": "editor.action.revealDefinition",
"when": "vim.mode == 'Normal' && editorTextFocus"
},
{
"key": "space g r",
"command": "editor.action.goToReferences",
"when": "vim.mode == 'Normal' && editorTextFocus"
},
{
"key": "space g i",
"command": "editor.action.goToImplementation",
"when": "vim.mode == 'Normal' && editorTextFocus"
},
{
"key": "space s g",
"command": "workbench.action.findInFiles",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus)"
},
{
"key": "space g g",
"command": "runCommands",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus)",
"args": {
"commands": ["workbench.view.scm", "workbench.scm.focus"]
}
},
{
"key": "ctrl-n",
"command": "editor.action.addSelectionToNextFindMatch",
"when": "(vim.mode == 'Normal' || vim.mode == 'Visual') && (editorTextFocus || !inputFocus)"
},
// File Explorer
{
"key": "r",
"command": "renameFile",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
"key": "c",
"command": "filesExplorer.copy",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
"key": "p",
"command": "filesExplorer.paste",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
"key": "x",
"command": "filesExplorer.cut",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
"key": "d",
"command": "deleteFile",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
"key": "a",
"command": "explorer.newFile",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
"key": "s",
"command": "explorer.openToSide",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
"key": "shift-s",
"command": "runCommands",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus",
"args": {
"commands": [
"workbench.action.splitEditorDown",
"explorer.openAndPassFocus",
"workbench.action.closeOtherEditors"
]
}
},
{
"key": "enter",
"command": "explorer.openAndPassFocus",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceIsFolder && !inputFocus"
},
{
"key": "enter",
"command": "list.toggleExpand",
"when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && explorerResourceIsFolder && !inputFocus"
},
// Debug
{
"key": "space d a",
"command": "workbench.action.debug.selectandstart",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus) && debuggersAvailable"
},
{
"key": "space d t",
"command": "workbench.action.debug.stop",
"when": "vim.mode == 'Normal' && editorTextFocus && inDebugMode && !focusedSessionIsAttached"
},
{
"key": "space d o",
"command": "workbench.action.debug.stepOver",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus) && inDebugMode && debugState == 'stopped'"
},
{
"key": "space d b",
"command": "editor.debug.action.toggleBreakpoint",
"when": "vim.mode == 'Normal' && editorTextFocus"
},
{
"key": "space d e",
"command": "editor.debug.action.showDebugHover",
"when": "vim.mode == 'Normal' && editorTextFocus && inDebugMode && debugState == 'stopped'"
},
{
"key": "space d c",
"command": "workbench.action.debug.continue",
"when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus) && inDebugMode && debugState == 'stopped'"
}
]
@ivo-toby
Copy link

ivo-toby commented Oct 29, 2024

Just wanted to say BIG BIG thanks for this. I usually work in NeoVim, but lately I've been working in Python notebooks, which is cumbersome using the default Jupyter web-interface. Working with VSCode for notebooks made life a bit easier, but these mappings make a big difference.. No more painful wrists! πŸ™‡πŸΌβ€β™‚οΈ

Somehow g g was not working from the getgo, so I added

  {
    "key": "g g",
    "command": "cursorTop",
    "when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus)"
  },

@imsakg
Copy link

imsakg commented Nov 28, 2024

You should use "vim.normalModeKeyBindingsNonRecursive" for writing shortcuts. Check this out.

@sumanth-lingappa
Copy link

sumanth-lingappa commented Dec 23, 2024

@nikolovlazar , what's the difference between goToImplementaiton and revealDefinition?

because, in my case, the revealDefinition is showing all the implementations of the interface.

@leviFrosty
Copy link

leviFrosty commented Jan 22, 2025

You should use "vim.normalModeKeyBindingsNonRecursive" for writing shortcuts. Check this out.

Although it's true that the VIM extension has this feature, using the settings.json/vim.normalModeKeyBindingsNonRecursive setting has a few drawback. keybinds.json file is preferred for almost all situations.

  1. Keybinds within settings.json/vim.normalModeKeyBindingsNonRecursive only register when within normal mode in an editor. There are many situations where we want to use keybinds outside an editor, like space e. That simply isn't possible through the VIM extension.
  2. Using this abstraction is inherently slower than the built-in VSCode keybinds.json and relies on the VIM extension to be loaded before keybinds can be pressed.

keybinds.json is the correct choice even if it's not as concise to write your configs

@dgleitao
Copy link

Just wanted to say BIG BIG thanks for this. I usually work in NeoVim, but lately I've been working in Python notebooks, which is cumbersome using the default Jupyter web-interface. Working with VSCode for notebooks made life a bit easier, but these mappings make a big difference.. No more painful wrists! πŸ™‡πŸΌβ€β™‚οΈ

Somehow g g was not working from the getgo, so I added

  {
    "key": "g g",
    "command": "cursorTop",
    "when": "vim.mode == 'Normal' && (editorTextFocus || !inputFocus)"
  },

+1

@nikolovlazar
Copy link
Author

nikolovlazar commented Feb 24, 2025

woah I've missed a lot of comments πŸ˜… glad you find this useful!

@sumanth-lingappa the difference between goToImplementation and revealDefinition is most obvious when you're triggering it on interfaces or interface methods. revealDefinition will take you to the interface, while goToImplementation will show you all the classes that implement that interface.

@imsakg I knew about that feature, but @leviFrosty's message is the reason I modified keybindings.json instead. The whole "Navigation" section wouldn't be possible with just the vim.normalModeKeyBindingsNonRecursive because we'll be out of the editor and in the file explorer or terminal.

Also, I've just added Debugging keybindings (bottom of file), so feel free to copy-paste them in your configs if you're doing breakpoint debugging.

@qingzhoufeihu
Copy link

If the space key is set, EasyMotion will become ineffective.

@nikolovlazar
Copy link
Author

nikolovlazar commented Feb 26, 2025

If the space key is set, EasyMotion will become ineffective.

@qingzhoufeihu I don't use EasyMotion, so I didn't know about that. How would you get around this? Space is oftentimes set as the leaderkeys in vim/neovim, so I'd look into changing EasyMotion's trigger instead (if it's possible).

@qingzhoufeihu
Copy link

If the space key is set, EasyMotion will become ineffective.

@qingzhoufeihu I don't use EasyMotion, so I didn't know about that. How would you get around this? Space is oftentimes set as the leaderkeys in vim/neovim, so I'd look into changing EasyMotion's trigger instead (if it's possible).

Thank you for your reply. I changed the leader to < , and it perfectly solved the problem.

@Mcmikey39
Copy link

Navigation
ctrl + h : move to left window
ctrl + j : move down window
ctrl + k : move up window
ctrl + l : move to right window

space + , : show all editors
space + e : open sidebar
space s g : find in files
space g g : go to git

tab : next tab in group
shift + tab : prevoius tab in group

s h : split editor
s v : split editor down

Coding
shift + j : move line down ( editor mode)
shift + k : move line up ( editor mode)
shift + k : show hover

space c a : show code action
space c r : rename veriable
space c s : show symbol
space b d : close active editor
space b o : close other editor
space space : quick open
space g d : go to definition
space g r : go to reference
space g i : go to implementation
space s g : find in files

ctrl + n : add slection next find match (normal mode & visual mode)

File Explorer
r : rename file
c : copy file
p : paste file
x : cut file
d : delete file
enter: open file

s : open to side
shift + s : split editor down

a : add new file
shift + a : add new folder

Maybe usefull for some people that need a cheatsheet

@hvenry
Copy link

hvenry commented Mar 27, 2025

AMAZING

This was so helpful, I tried doing this on my own but was having issues with the sidebar.

Much love!

@ravicorreia
Copy link

Thank ... You... So... F... Much!!!
Absolutely Amazing keybindings, much love and appreciation πŸ™πŸ½

@nikolovlazar
Copy link
Author

Glad you found this useful @hvenry @ravicorreia πŸ™Œ

@cognitiveRobot
Copy link

@nikolovlazar thanks a lot. This is what I need - good from both worlds - VimVS.

@vsokolovskii
Copy link

If you have a problem with space+e try this:

 "key": "space e",
 "when": "vim.mode == 'Normal' && editorTextFocus && foldersViewVisible",
 "command": "workbench.action.toggleSidebarVisibility"
},
{
  "key": "space e",
  "when": "vim.mode == 'Normal'  && sideBarVisible",
  "command": "workbench.action.toggleSidebarVisibility"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment