VSCode as a Vim editor
Tags: vscode, vim
Published: 2019-07-17 21:57:38

---
title: VSCode as a Vim editor
published: true
tags: vscode, vim
canonical_url: https://kewah.com/vscode-as-a-vim-editor/
cover_image: https://images.unsplash.com/photo-1545670723-196ed0954986?ixlib=rb-1.2.1&auto=format&fit=crop&w=1952&q=80
---

_Photo by [@goshua13](https://unsplash.com/@goshua13) on [Unsplash](https://unsplash.com)_

In 2013 I started to use [Vim as my primary editor](https://blog.kewah.com/2014/from-sublime-text-to-vim), the journey hasn’t been without frustration, but in general, I really enjoyed using it. It took me sometimes, but I found a setup that worked well for me from auto completion to code navigation. What I love the most is [Vim motions](https://blog.kewah.com/2014/from-sublime-text-to-vim/#magic-motions), I would not trade that feature for something else.

> So, if everything was fine why did you start using VSCode?

I got mainly interested by [VSCode](https://code.visualstudio.com/) for its debugging and refactoring features. I got used to debugging JavaScript or CSS in the browser’s dev tools, but I never found the right spot for debugging Node apps. With VSCode it is possible to debug directly in the editor, to add breakpoints or investigate the stack trace.

But, as usual, the first thing I do when I start to use a new code editor to install the Vim plugin.

## VSCode Vim plugin

In a nutshell, [VSCodeVim](https://github.com/VSCodeVim/Vim) is really good. It is by far the best Vim integration I have tried outside Vim (or NeoVim) itself. It’s fast, includes [plugins](https://github.com/VSCodeVim/Vim#-emulated-plugins) I love ([easymotion](https://github.com/easymotion/vim-easymotion), [sneak](https://github.com/justinmk/vim-sneak), [surround](https://github.com/tpope/vim-surround)), and supports all motions and most shortcuts I used to use.

To get there I had to tweak the settings to be able to remap commands, but the great thing with this plugin is that we can remap loads of it!

For instance, I use `jk` to switch between insert and normal mode.

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

_You need to define that in User Settings. (Search for`Preferences: Open User Settings.` in the command palette (`⇧⌘P`).)_

It is pretty straightforward, you define what mapping you want to use in`before` and what output you want to get into `after`.

I rely a lot on EasyMotion to move around (jump to a different line or a character) but I found the default setting quite annoying: I have a double press the leader key, instead of once in Vim, and then the action (for instance `j` to go to a line below). But, it is possible to remap it!

```
{
  "vim.normalModeKeyBindingsNonRecursive": [
    {
      "before": ["<leader>", "j"],
      "after": ["<leader>", "<leader>", "j"]
    }
  ]
}
```

You can remap not only key bindings but also execute commands. For instance to toggle a [bookmark](https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks) using `ma`:

```
{
  "vim.normalModeKeyBindingsNonRecursive": [
    {
      "before": ["m", "a"],
      "after": [],
      "commands": [
        {
          "command": "bookmarks.toggle",
          "args": []
        }
      ]
    }
  ]
}
```

I have been able to remap bindings to match my Vim memory muscles. I felt at home when starting to use VSCode.

You can find my VSCodeVim settings on this [Gist](https://gist.github.com/kewah/a5d8c1eff08db1623f98593727d99353).

## Refactoring

VSCode has made some refactoring tasks easier than what I used to in Vim. One of my favourites is renaming a variable by pressing `f2`. All occurence will be updated in the project. The same happens when you rename a file or move it to another folder, its path is updated where it is used.

We can also transform arrow function with implicit return using `cmd+.`:

```
const add = (a, b) => a + b;
```

Put the curson on `(`, then press `cmd+.` ->`add braces to arrow function`. It will convert it to:

```
const add = (a, b) => {
  return a + b;
};
```

Super convenient when you need to debug a function.
It can also be used for disabling a ESLint rules for the current line.

In general, I find it more comfortable to refactor in VSCode, the multiple cursors works better than on Vim, and I can still use visual block mode when I need it.

## Debugging

So far, I have only used the “attach to process” debug mode. When you run node (or nodemon) with the `—inspect` flag you can attach the process in VSCode to debug the application.

In `launch.json`

```
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "dev:server inspect",
      "port": 5858,
      "restart": true,
      "protocol": "inspector"
    }
  ]
}
```

It’s an excellent way of debugging Node.js apps, so you don’t need to open a Chrome dev tools to add breakpoints and put `debugger` statement in your code.

## Navigation

After some tuning, navigating in VSCode looks familiar to Vim:

- Search a file using the fuzzy finder à la [CtrlP](https://github.com/ctrlpvim/ctrlp.vim).
- Use the command palette to run commands when I don’t think it is necessary to memorise a key binding. 
- Jump between windows using `ctrl + hjkl`. (More about it in “What I miss from Vim” section.)
- Go to definition using `gf`. (In Vim I used Ternjs to have this feature, “60% of the time, it works every time”.)
- Use the code outline to jump between symbols in a file using `cmd+shift+o`. I’m in love with this feature.
- Switch between tabs using `gt` (next tab) or `gT` (previous tab). `ctrl + tab` comes handy when I have too many files open, which happen more often to me because of the poor window management support on VSCode.
- Jump to the next occurrence of the variable under the cursor using `*`.
- Jump to the [next change](https://gist.github.com/kewah/a5d8c1eff08db1623f98593727d99353#file-vimusersettings-js-L205-L223)using `<leader>n` (next change) or `<leader>p` (previous change).
- And of course, my beloved Vim motions.

## Language support

The VSCode community is active, so I haven’t encountered a language that wasn’t supported: JavaScript (+JSX), TypeScript, Sass, Elm, Elixir/Phoenix, or Haskell.

Auto completion is right most of the time, except for CSS or Sass files where it struggles to suggest class names defined in a template file. It also has some issues to autocomplete snippets. If I type too fast, I will need to close and reopen the suggestion box to be able to run a snippet.

## What I miss from Vim

Obviously, everything is not perfect. The main thing I miss from Vim is the window management, in VSCode the current support is really basic.

In Vim, it is possible to open several files under the same tab, so it is straight forward to create different spaces with related files and terminal open.For instance, you can open a tab containing all files related to a component.

```
| TAB A | TAB B
|       |-------------------------------------------------------------
Module.js     | Module.test.js     | Terminal that runs
              |                    | Module.test.js
              |--------------------|
              | Module.style.scss  |
              |                    |
```

In VSCode, tabs are all independent, so even if I can split the screen in two, I can’t switch tabs to change both files at the same time. So, I need to jump back and forth between the files to switch the tabs accordingly. Annoying.

```
| TAB Module.js | TAB Module.test.js | TAB Terminal
-------------------------------------------------------------------------
```

It creates some frustration when I try to jump quickly between files and terminals since I need to remember where are the related files are and keep things in sync manually.

## What’s next?

I will keep using VSCode and haven’t planned to go back to my previous setup iTerm + NeoVim. It has (almost) everything I’m looking for: it is fast, it has good language, and auto completion support, a built-in terminal, and I can still use Vim in it. A nice thing is that most of my colleagues use it as well, so we can share settings in a project or do remote pair programming in VSCode directly, which is fantastic.