Things You Can Do With Neovim and Vscode That You Can't Do With Neovim Alone

This is the third time I’ve tried in earnest to switch to VSCode from Vim (or Neovim in my case) for reasons not all of which are relevant to this post. But I love Vim style modal editing and I’ve grown accustomed to some features that aren’t present or not well emulated in VSCodeVim.

Enter VSCode Neovim. I was intrigued by their claim to integrate Neovim instead of trying to emulate Vim. After going through the code a bit I thought this extension alone warranted a new attempt at switching to VSCode. So far it’s going great.

How VSCode Neovim Works

Here’s the gist of how this extension works. Feel free to skip to the good stuff below but this section is good background information for understanding why it works the way it does.

  1. Invokes an embedded Neovim instance.

    Code for this is in the main_controller.ts (linky) if you are curious about how exactly it’s implemented and the commandline options that are passed in.

    You’ll also notice that the code invokes --cmd source ${neovimSupportScriptPath} which runs vim/vscode-neovim.vim (linky) before running your init.vim file. This script is what sets up the g:vscode flag and sources all the other vscode-*.vim scripts except vscode-options.vim. The latter runs after your init.vim in order to force some settings that would otherwise break the extension or cause Neovim to be confused.

So far this is pretty standard fare for how Neovim would be embedded for a custom UI. But things get a bit interesting from the next step.

  1. Creates a new Neovim buffer and window corresponding to a VSCode editor.

    The buffer thus created is a plain text buffer without any bells or whistles. Contents of the buffer comes from VSCode1. VSCodeNeovim synchronizes the content between the Neovim buffer and the VSCode editor. Thus the relationship between the contents and the corresponding file on disk is mediated through VSCode. This is a key difference between other custom UIs and this one and one that opens many possibilities.

    VSCodeNeovim defers to VSCode for handling insert mode. VSCode handles autocompletion and other assistive features. You’ll have to get used to your insert mode customizations not working, or replicating that with VSCode keyboard mapping customizations. When exiting insert mode the extension asynchronously synchronizes the buffer contents – which at this point would include the changes that were introduced – with Neovim. The code for synchronizing the VSCode editor contents and the Neovim buffer is in buffer_manager.ts (linky) which is also a good place to look if you want to know the details about buffer options that are being set.

Of course I’m eliding lots of detail here including integrations for other areas of UI. But I think this captures the pertinent details. The extension is a pretty impressive piece of work which is well worth a gander. Now on to the good stuff.

Responsive Neovim Experience Over A laggy SSH Connection

This gets to the reason why I’m trying to move to VSCode in the first place. I work on a project consisting of thousands of C++ source files. My home-office doesn’t have enough hardware to do regular builds, or in fact any build at all. The beefy machines are in a remote location accessible via SSH.

I’ve been using Neovim over SSH for a while, but the latency really bothers me. And no, neither SCP nor SSHFS scratches this itch because I won’t have access to language smarts like clangd which require access to all the source files and some build tooling.

VSCode Remote Development was a nearly perfect answer with the exception that VSCodeVim didn’t quite have all the functionality I needed. VSCodeNeovim addresses that last piece of the puzzle.

VSCode + Remote SSH + VSCodeNeovim + Neovim gives me:

Since the embedded Neovim instance is local the editors are super responsive. Completions via clangd is still laggy as one might expect. But that’s something I’m willing to live with.

Proportional Fonts With Neovim

Okay, so why would anyone actually want this? Turns out I’m not the only one. In my case I prefer monospace for regular code, but I’d much much rather read comments and prose in proportional font. Also, I now spend a lot of my time writing Markdown with LatexMath. Staring at monospaced prose all day is not my cup of tea.

This is what it looks like when I’m editing this post in VSCode (in Markdown).

Screenshot of VSCode editing Markdown in proportional font

The best part is that I can use my familiar Vim/Neovim keybindings and modal editing. I had to make a couple of customizations and I only have this set up for Markdown. But it works fairly well. One gotcha is that the cursor jumps horizontally when moving the cursor up or down since the columns are no longer neatly aligned.

Monospace Code With Proportional Comments?

What I really want isn’t proportional fonts everywhere. Rather I only want proportional fonts for prose. In code, this would take the form of comments.

Unfortunately, VSCode doesn’t support changing the font for specific syntactic tokens or scopes. That would’ve been ideal because it would let me configure things so that comments are in proportional font while the rest is in monospace. Also in the case of Markdown, I’d be able to make everything proportional except for inline code and fenced code blocks. Alas we are not quite there yet. Several feature requests already exist2, but hasn’t seen much activity.

Takeaways

  1. VSCodeNeovim is a functional replacement for the avid Neovim or perhaps Vim user who wants it both ways. Lots of caveats exist including the fact that Neovim mode only really works inside editor windows.
  2. VSCodeNeovim + “Remote SSH” is an awesome combination for editing remote files using Neovim with the latency of a local Neovim instance.
  3. You can use proportional fonts with VSCodeNeovim for super double awesomeness.

  1. Not quite the whole story because it’s possible a buffer be created inside the Neovim instance and have it be mirrored in a VSCode editor. But that’s probably not what you’ll be using on a regular basis.↩︎

  2. A quick search in the VSCode repository with this query yields several issues that request for pretty much the same thing: Allow setting fontName in tokenColorCustomizations. There’s also this curious experiment which patches in a different font for italics so that you can use the existing fontStyle: "italic" option in tokenColorCustomizations to switch fonts.↩︎

Comment