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:
- Enable the Vim: Enable Neovim option (
vim.enableNeovim
) - Set the path to Neovim inside the Vim: Neovim Path setting (
vim.neovimPath
) - 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:
- Copy the content of your file inside Neovim.
- Execute the command in Neovim.
- 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:
- The
A;
to append a semicolon, in combination with, - 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 givenpattern
.
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 registera
(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:
:0,+3d a
delete first three lines into thea
register:$put a
paste the contents of registera
(the three lines we deleted earlier) at the end of the file
- 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.↩
- Well… They’re not there there, they are just around the corner in Neovim land.↩
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.