I used Vim for several years, albeit at a rather shallow level of skill. I stopped about ten years ago, for one reason or another. Still, I kept a candle burning for Vim. There was just something about it. And so it wasn’t hard to be tempted when I was told that it had improved a lot in the time I’d been away.
And, oh my, it has. There’s everything I loved, still there. The weird but lovely modal editing. The speed, oh goodness the speed. But also Vim now has the things I left Vim to search for. Smart completion and navigation. Code refactorings. Pop up documentation. Clever highlighting. A scripting language I can understand.
For me, seeing these two walls of beautifully rendered text was like returning home. I like the way that the window shows nothing else until a function is called into being. Jetbrains Mono certainly helps too, it’s a lovely font. Just finding a nice theme and a nice font stoked my desire to figure out how to make this setup work.
So, what’s all this new shiny stuff I mentioned? What happened to Vim to tempt me back?
Basically Neovim happened. It forked from Vim in 2014, with the goal of modernising the codebase and editor while remaining true to what made Vim so gosh-darn-it lovely. Since the fork, it’s added native support for three key technologies:
- Language Server Protocol, originally created for VS Code and widely adopted.
- tree-sitter, built originally by some of the creators of the Atom editor.
- The Lua scripting language, a fast, embeddable programming language.
Already, after just two weeks, I think I have a better setup than I ever got to in my previous years of using Vim.
In addition to new functionality in Neovim, this is because, over the time I’d been away, I’d internalised how valuable it is to really learn your tools. And so I’ve dug deeper into learning how to navigate files and manipulate text in Vim’s modal style. I’ve also spent time really understanding how to configure the editor, rather than taking my previous copy/paste approach. I’ve added a few plugins, mostly around LSP, tree-sitter and effective project navigation. But I want to hold short for now, preferring writing my own Lua code over plugins where I want a specific behaviour. Essentially, I want to learn to work Vim’s way, rather than contorting it into the shape of another editor.
Let’s dive a bit deeper into my favourite new things.
Language Server Protocol
The Language Server Protocol emerged from Microsoft via the VS Code editor. In essence, the protocol describes a way that a language-agnostic editor can communicate with a language-specific server to enable the editor to provide an editing experience previously reserved for IDEs. Things like variable renaming, smart code completion and documentation overlays.
Plumbing support for LSP into the core of Neovim enables the editor to take advantage of the capabilities of LSP more effectively than a plugin-based approach, such as Sublime Text takes. The Neovim “LSP plugin” ecosystem is primarily around canned configurations (each LSP works slightly differently), alongside frameworks to manage language server binaries. While it’s a little overwhelming to start with — particularly compared to VS Code’s extensions — I really like the way the system is set up and what it allows.
One of the novel things making use of Neovim’s LSP support is the null-ls plugin. This rather cleverly hijacks the LSP support to wire in a wide variety of non-LSP tooling, by façading that tooling into an LSP shape for the editor. This means that all the editor’s features, like showing errors in the gutter, are easily wired into a wider ecosystem of tooling.
Overall, the inclusion of LSP closes one of the major gaps between editors like
Vim and editors like VS Code. Being able to access IDE-like functionality
natively integrated into the editing experience of Vim works really well for me.
It’s a big improvement over
ctags and the like that I used in my previous Vim
Showing documentation for Go’s
time.Date() function using LSP.
Another development in the last few years has been tree-sitter:
Tree-sitter is a parser generator tool and an incremental parsing library. It can build a concrete syntax tree for a source file and efficiently update the syntax tree as the source file is edited. (src)
Tree-sitter is a from-scratch library developed to, amongst other things, enable better highlighting in editors. Within Neovim, again with the help of configuration plugins, it’s used to dramatically improve the sophistication of syntax highlighting on offer. Apparently it also offers dramatic performance improvements too over the previous highlighting.
Other features make use of the syntax tree, such as Neovim’s built in spell-checking, which uses it to enable spell-checking comments and strings, but not other code. This is pleasing.
No screenshot here, as it’s somewhat hard to capture the smartness. Imagine a screenshot with more coloured words and you’ll get the gist, but it’s really during editing that the extra cleverness makes itself felt.
Beyond LSP and tree-sitter, I think my favourite plugin is Telescope. It’s a “highly extendable fuzzy finder over lists”. In practice this means that it’s the equivalent of VS Code’s cmd-p, and more. I primarily use this to quickly open files, one of Telescope’s “builtins” which cover quite a few pieces of functionality. I suspect that, over time, I’ll extend my use of Telescope quite a bit. But for now, I’m keeping it simple.
Narrowing down files to open using Telescope.
I particularly like a plugin called which-key. It makes remembering key
mappings easier by displaying a window at the bottom of the screen to help. When
Normal mode, one types chains of characters to carry out
actions, anything from deleting a line of text, to invoking Telescope to move to
a different file.
Here, I’ve typed
da and the plugin is showing what I can type next to execute
commands. The text at the bottom of the window tells me the mnemonic that I’ve
typed, “delete around”. We can see some of the smarts of a modal editor coming
out here: I can carry out this action on words, sentences, code blocks and
several other constructs.
Just what can I “delete around” again?
Overall, I’ve been really excited by my return to (Neo)vim. Neovim has injected
a lot of life into the ecosystem. The inclusion of Lua has jump-started the
creation of sophisticated plugins like Telescope. And the native support of both
LSP and Tree-sitter has enabled the code editing experience to advance leaps and
bounds beyond what
ctags and its ilk are able to offer.
While a lot has changed, the jokes about how hard it is to quit Vim will remain. The brutalist exterior is still there. But while I’ve been gone it has somehow been augmented with all mod-cons, and everything feels all fancy. I’m smitten.