Barbarian Meets Coding

presents

Boost Your Coding Fu With VSCode and Vim
Chapter 21.Table of ContentsCheatsheet

Integrating VSCode With Neovim

One final way to enhance your VSCodeVim experience is by integrating it with Neovim, the modern fork of Vim. When you integrate both editors, VSCodeVim will use Neovim to execute all Command-line mode commands. This will result in faster command execution and the addition of a slew of useful commands to your VSCodeVim arsenal.

Installing Neovim

Neovim, just like Vim, is supported in many operative systems. To install Neovim use the favorite package manager of your operative system of choice. For instance:

Installing Neovim on Mac OSX

The simplest way to get Neovim in OSX is to use Homebrew:

$ brew install neovim

Installing Neovim on Windows

The simplest way to install Neovim on Windows is to use the Chocolatey package manager. Type:

PS> choco install neovim -y

Installing Neovim on Ubuntu or Debian

To install the latest version of Neovim in Ubuntu or Debian use the following:

$ sudo apt-get update
$ sudo apt-get install software-properties-common -y
$ sudo add-apt-repository ppa:neovim-ppa/stable
$ sudo apt-get update
$ sudo apt-get install neovim -y

Install Neovim on Other Operative Systems

The Neovim Wiki has thorough instructions on how to install Neovim in lots and lots of operative systems, using a package manager or building from source. If your operative system is not one of the above, then please teleport to Neovim’s Wiki and follow the instructions.

Enabling Neovim Inside VSCode

Once you have installed Neovim in your operative system, you can enable it within VSCode inside the Preferences: User Settings window:

  1. Enable the Vim: Enable Neovim option (vim.enableNeovim)
  2. Set the path to Neovim inside the Vim: Neovim Path setting (vim.neovimPath)
  3. Restart VSCode

For instance, if you’re using MacOS and have installed Neovim using brew, your settings would look like this:

{
  "vim.neovimPath": "/usr/local/bin/nvim",
  "vim.enableNeovim": true
}

Using Neovim From VSCode

Once the integration is enabled, anytime you execute an Ex command it will be run within Neovim and then its effects will be reflected inside Visual Studio Code. In essence, executing an Ex command will follow these steps:

  1. Copy the content of your file inside Neovim.
  2. Execute the command in Neovim.
  3. Sync the results back to Visual Studio Code.

This means that interactive commands like :change (or substitute with the c flag) will not work with the current experimental state of this integration but others like :move, :normal, :global, and most use cases of :substitute will work fine.

Copying and Moving Lines Around

Using the :copy or :move commands you can quickly copy or move a range of lines from one part of the document to another. You use either of these commands as follows:

:[range]copy {address}
:[range]move {address}

Where:

  • range defines the range we want to copy or move.
  • address defines the target line destination of whatever we copy or move.

For instance:

  • :,+3c $ copy the current line and 3 lines below to the end of the file.
  • :,+3m $ like above but move the lines instead.

Both of these commands support shorthands:

  • :t or :co are equivalent to :copy.
  • :m is equivalent to :move.

The Normal Command

The :normal command (shorthand :norm) lets you run an arbitrary collection of Normal mode commands on multiple lines at once. It is defined like this:

:[range]normal {commands}

Imagine that you find a JavaScript file whose lines have no semicolons. Oh no! Damn JavaScript hipsters!joke You can remedy this travesty by using the :normal command like this:

:%norm A;

Which appends semicolons to all lines within a file. This is, without the shadow of a doubt, a faster way to add semicolons than using:

  1. The A; to append a semicolon, in combination with,
  2. the j. commands to go down a line and repeat the last change.

Let’s look at a slightly more involved example. Imagine that you have a list of magic weapons that looks like this:

<ul>
  <li>Sword of Truth</li>
  <li>Fire Lance</li>
  <li>Shardblade</li>
  <li>Poisoned Dagger of Despair</li>
</ul>

But now we want to improve the usefulness of this list and add some links to places of the Wizardsphere where someone could acquire some of these items.

Let’s simplify the problem by adding a link to a single li element:

  <li>Sword of Truth</li>
^

We could w to move the cursor on top of the element and cit to change its contents. Now type <a href=""><ESC>:

  <li><a href=""></li>
                ^

Then p to paste the previous contents of the li:

  <li><a href="">Sword of Truth</li>
                              ^

And finally a</a><ESC>:

  <li><a href="">Sword of Truth</a></li>
                                  ^

Tada! The complete series of commands was:

wcit<a href=""><ESC>pa</a><ESC

So now that we’ve solve this problem for a single line, we should be able to apply the same command to all the li elements within our list by taking advantage of the :normal command:

:%normal wcit<a href=""><ESC>pa</a><ESC

Try it yourself. What happened? Not what you expected, that’s for sure. This should be results of running the command above:

<ul>
  <li><a href=""><ESC>pa</a><ESC></li>
  <li><a href=""><ESC>pa</a><ESC></li>
  <li><a href=""><ESC>pa</a><ESC></li>
  <li><a href=""><ESC>pa</a><ESC></li>
</ul>

Can you see the problem? Exactly! All the characters have been taken literally. <ESC> didn’t work and therefore we never exited Insert mode which explains the results above.

This shows one of the limitations of the :normal command: it doesn’t understand special keys like <ENTER> or <C-> chords. Fortunately there’s a way to resolve these use cases with the aid of the execute command.

The :execute command (shorthand :exe) allows you to evaluate a string expression as an ex-command. It is like the eval of Vim. Using :execute we can use the :normal command in conjunction with special keys as follows:

:execute "%normal wcit<a href=\"\">\<ESC>pa</a>\<ESC>"

Notice how the execute commands allows us to use special keys like <ESC> by escaping them with a backslash. Notice also how, because the whole expression is a string, we need to escape any double quotes that may appear.

In summary:

  • The :normal command lets you apply arbitrary Normal mode commands on multiple lines at once. However, on its own, in doesn’t support special keys which limits its use.
  • Use :normal in combination with the :execute command when your sequence of normal mode commands includes special keys

The Global Command

The :global command (shorthand :g) allows you to execute any Ex command on lines that match a given pattern. It is like a generic version of :s that, instead of just substituting a pattern for something else, allows you to do pretty much anything.

The form of the :global command should be familiar to you at this point:

:[range]g[lobal]/{pattern}/[cmd]

So:

  • You define a range where to apply the :g command, and then,
  • within that range, the command cmd will be applied only to those lines that much the given pattern.

The default range for the :g command is the entire document so :g is the equivalent to :1,$g or :%g. This is fitting since the command isn’t called global for nothing.

Using the :global command we can now delete or copy lines that match a specific pattern. For instance, we can create an outline of a markdown document by copying (yanking) all titles and storing them in a register like so:

:g/^#/y A

Which means:

  • For every line that matches this pattern ^# (a title in markdown).
  • Run the :y A command, which means: Copy the current line and append it to register a (remember? A register in uppercase means using it to append instead of replacing its contents).

Now you can paste the outline in another file by typing :put a (or just "ap in Normal mode).

The :global command is specially useful when you combine it with the :normal command because it let’s you run an arbitrary number of Normal mode commands only when a certain condition is fulfilled.

So we could refine our previous semicolon adding contraption to only add a semicolon when it doesn’t find one at the end of a line like so:

:g!/;$/norm A;

Or we could define a command that decreases the depth of markdown chapters like this:

:g/^#/norm 0x

Using the :global and :normal commands together, the only limit of what you can achieve is determined by your own imagination.

A Delete Caveat To Take Into Account

When you enable the Neovim integration the :delete command will be executed within Neovim and use its registers. These registers aren’t shared with VSCodeVim and therefore you won’t be able to inspect them via the :reg command. Nonetheless, you can rely in the fact that they are still therethere. So the following sequence will work as expected:

  1. :0,+3d a delete first three lines into the a register
  2. :$put a paste the contents of register a (the three lines we deleted earlier) at the end of the file

[


  1. This is a joke. It is perfectly fine to be a JavaScript hipster and prefer no semicolons. Just be consistent and make sure to have all the team follow the same conventions. Even better, automate it with a code formatter like prettier.


Jaime González García

Written by Jaime González García , Dad, Husband, Front-end software engineer, UX designer, amateur pixel artist, tinkerer and master of the arcane arts. You should follow him on Twitter where he shares useful stuff! (and is funny too).Jaime González García