VS Code Setup with Vim Motions

Published in VS Code, Vim, Neovim, Development on Aug 8, 2025

I recently started using Neovim more and more, but I feel like I still miss/need some of the functionality I get in VS Code, so I decided to try to setup VS Code to work as similar as I can to Neovim.

First of all lets list extensions that I think are must have for a nice dev experience:

  • Color Highlight
  • Code Spell Checker
  • Css Peek (peek inside CSS class definition)
  • Error Lens (display errors inline)
  • Git Blame (display inline git blame messages)
  • Goto Symbols (cleaner way to navigate methods)
  • Laravel (since I mostly work with Laravel)
  • Live Server
  • PHP Intelephense (all things PHP)
  • Prettier
  • Project Manager (I like to switch projects fast)
  • TODO Highlight
  • Vim (off course, we're talking about Vim motions)
  • Vue

Most of the Vim motions work without problems inside VS Code, but there are some things that IMO could use some improvement.

If you plan on learning Vim I would suggest first getting used to using the basics like moving around with h/j/k/l, switching modes and also learn how to exit vim :)

I'm gonna skip explaining most of the motions but I did save some for the end of article where you may find some you didn't know about.

If you just wanna skip to the and see my config and keymap for VS Code simply go here: [https://github.com/bstrahija/dotfiles/tree/main/vscode](VS Code Config).

Keybindings

Some keymaps are setup inside the settings.json file, and some in the keybindings.json. This is because the Vim plugin has a leader key which I mapped to Space.

So let's start with some simple binds. You know you can exit insert mode with ESC, but what I got used to is pressing jj (or jk), so the bind I have setup is this (settings.json).

"vim.insertModeKeyBindings": [
  { "before": ["j", "j"], "after": ["<Esc>"] },
  { "before": ["j", "k"], "after": ["<Esc>"] }
],

Next I prefer to use the leader key to open the command palette and fuzzy find files, so this is a must;

"vim.normalModeKeyBindingsNonRecursive": [
  { "before": ["leader", "space"], "commands": ["workbench.action.quickOpen"], "when": ["(vim.mode == 'Normal' || vim.mode == 'Visual') && (editorTextFocus || !inputFocus)"] },
  { "before": ["leader", "p"], "commands": ["workbench.action.showCommands"], "when": ["(vim.mode == 'Normal' || vim.mode == 'Visual') && (editorTextFocus || !inputFocus)"] },
  { "before": ["leader", "r"], "commands": ["tettekete.list-functions"], "when": ["(vim.mode == 'Normal' || vim.mode == 'Visual') && (editorTextFocus || !inputFocus)"] },
  { "before": ["leader", "t"], "commands": ["workbench.action.selectTheme"], "when": ["mode == 'Normal' || vim.mode == 'Visual') && (editorTextFocus || !inputFocus)"] },
  { "before": ["leader", "x"], "commands": ["workbench.view.extensions"], "when": ["mode == 'Normal' || vim.mode == 'Visual') && (editorTextFocus || !inputFocus)"] },
  { "before": ["leader", "o"], "commands": ["workbench.action.closeOtherEditors"], "when": ["mode == 'Normal' || vim.mode == 'Visual') && (editorTextFocus || !inputFocus)"] },

]

This means that if you press the leader key, and immediately after that a key defined here, you will run the command. Meaning pressing space twice will open the file search.

Next, one that I use all the time, switching between tabs/buffers:

"vim.normalModeKeyBindingsNonRecursive": [
  { "before": ["<S-h>"], "commands": [":bprevious"] },
  { "before": ["<S-l>"], "commands": [":bnext"] },
  { "before": ["<Tab>"], "commands": [":bnext"] },
  { "before": ["<S-Tab>"], "commands": [":bprevious"] },
]

This is setup so that you can switch tabs when in normal mode with the TAB key, but also using SHIFT+h/l.

The file tree was a bit harder to setup in a way that I want since it needed configs in 2 two places. I you know a better way let me know.
Basically I wanted to use leader e to toggle the file tree and focus into it.

Opening the file tree simple:

"vim.normalModeKeyBindingsNonRecursive": [
  { "before": ["leader", "e"], "commands": ["workbench.action.toggleSidebarVisibility", "workbench.files.action.focusFilesExplorer"] },
]

To toggle it back, and to add some funcionality to the file tree, I have the following setup (keybindings.json):

{
    "key": "space e",
    "command": "runCommands",
    "args": {
        "commands": [
            "workbench.action.toggleSidebarVisibility",
            "workbench.action.focusActiveEditorGroup"
        ]
    },
    "when": "sideBarFocus && !inputFocus"
},
{
    "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": "shift-a",
    "command": "explorer.newFolder",
    "when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
    "key": "s",
    "command": "explorer.openToSide",
    "when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
},
{
    "key": "enter",
    "command": "explorer.openAndPassFocus",
    "when": "filesExplorerFocus && foldersViewVisible && !explorerResourceIsRoot && !explorerResourceIsFolder && !inputFocus"
}

So as you can see you can manipulate files when focused in the file tree fairly easy with single keystrokes, like a to add a new file, r to rename, d to delete, or one of my favorites s to open a file in a split view.

Extras

One thing that bothered me when opening the command palette or quick find, you needed to use arrows to cycle through the results. To avoid this, I wanted to use TAB so I have it setup like this:

{
  "key": "tab",
  "command": "quickInput.next",
  "when": "inQuickInput && quickInputType == 'quickPick'"
},

For some reason SHIFT+TAB doesnt work to cycle backwards, so I gave up on that.

I you have multiple splits open, or just wanna navigate between the editor and the sidebars, you can use this setup:

{
    "key": "ctrl-h",
    "command": "workbench.action.navigateLeft"
},
{
    "key": "ctrl-j",
    "command": "workbench.action.navigateDown"
},
{
    "key": "ctrl-k",
    "command": "workbench.action.navigateUp"
},
{
    "key": "ctrl-l",
    "command": "workbench.action.navigateRight"
}

Usefull tips

Sometimes I need to quickly clean out a file, and the quickest way to do this for me is the following motion:

die

So gg goes to the file beginning, d is for delete, and G deletes ontil the end of file (SHIFT+g goes to the end of file).

© 2025 Creo
> >