Thoughts on Vim, Neovim, and Modal Editing

You can’t spell Vim without ‘VM’

thoughts
tooling
Author

Vincent “VM” Mercator

Published

July 30, 2024

Modified

August 28, 2024

The logos of Vim (left) and Neovim (right) modified to spell the initials 'VM'.

If only Neovim started with an M, or my initials were ‘VN’.

For the past couple of months, I’ve been teaching myself how to use Vim and Neovim to be more productive when using weaker computers that struggle to run integrated development environments (IDEs) and also win imaginary internet points. Vim, written by the late Bram Moolenaar, and Neovim, its community-maintained fork, are keyboard-oriented text editors that use a text-based user interface instead of a graphical one. The way they work depends on their current mode, like inserting text or running a command; hence, they’re called “modal editors”. While their learning curves are steep, I find that they are rewarding to use because they change the way I think about manipulating and moving through text. The main issue I have, though, is that these editors’ extreme configurability is too distracting. I keep wasting time trying to configure my editors instead of actually working on the tasks I want to do.

For me, Vim and Neovim are similar enough for my use case to the point where it gets difficult to figure out which program is better. Which one I want to use mostly depends on what other CLI applications I want to run on my code and what nitpicks I have with the other editor. While I like Neovim for its first-party language server protocol support, I dislike how its plugins are inconsistently configured in Lua. While I like Vim for its stabler and simpler plugins, it can’t consistently map keybindings with Alt-keys across all terminals.

I keep constantly writing and re-writing my basic configuration from scratch since I’m split between configuring my text editor(s) in two different programming languages. Vim’s vimrc configuration file can only be written in its custom domain-specific language, Vimscript, while Neovim can be configured in either Vimscript or Lua using an init.vim or an init.lua file, respectively (but not both). While the addition of a much more popular embedded scripting language has led to a thriving Neovim plugin ecosystem, I think it introduced a Python-like two-language problem:1 using commands in Neovim requires knowing Vimscript, but configuring Neovim to its fullest extent requires knowing Lua.

Note

If you want to see how I configure Vim and Neovim to my liking, you can check out the various branches on my vim-configs repository on GitHub. Be warned, though: it’s not production-quality, and it’s rather volatile!

Between the two, I prefer using Vimscript over Lua since it’s the language of both Vim and Neovim’s command mode. I use that mode a lot in Vim / Neovim since I find command names easier to remember than keybindings. I like its terse syntax for describing editor configuration, it can skip over some simple syntax errors, and short one-line expressions like key remapping can be quickly tested. Even though Lua is orders of magnitude faster than Vimscript, I find it harder to use mostly because its documentation isn’t fully integrated into Neovim’s help pages as much as Vimscript is, and Lua scripting isn’t backwards-compatible with Vim.

Here’s some example key mappings that I have in my (Neo)Vim configuration that lets me move lines up and down in normal mode using Alt-j and Alt-k, like how Alt-Up and Alt-Down work in VS Code. Since Vimscript’s entire purpose is to configure Vim, its syntax is much cleaner than its counterpart in Lua.

" Vimscript key mapping for moving lines up and down
nmap <A-j> :m.+1<CR>==
nmap <A-k> :m.-2<CR>==
-- Lua for moving lines up and down
vim.keymap.set("n", "<A-j>", "<cmd>m.+1<cr>==")
vim.keymap.set("n", "<A-k>", "<cmd>m.-2<cr>==")

Despite being three times older than Neovim, Vim’s plugin ecosystem isn’t nearly as powerful. Lua ports or re-implementations of popular Vimscript plugins often expand upon their counterparts: NERDTree has fewer features than Neo-Tree, and gitgutter has fewer features than gitsigns.

One thing that’s nice about these editors is that their configurations are easily shareable and reproducible. Vim and Neovim distributions like LazyVim and reference configurations like Kickstart.nvim help start users off with a whole slew of preconfigured plugins and are great for helping new users learn their editor’s configuration fundamentals. In fact, my configuration’s keybindings are directly taken from LazyVim’s source code, and the official Neovim reference configuration was very helpful for understanding basic plugin management in Lua. However, I think that the sheer number of plugins these distributions include is overkill: plugins in both ecosystems re-implement things that Vim or Neovim can already do that I would consider “good enough”. For example:

While Neovim’s new features provide nice quality-of-life improvements, it can’t beat how Vim is installed by default on almost every UNIX machine I can think of. Since I do a lot of work disconnected from internet and without administrative access, I’m often stuck with whatever default applications the operating system I’m using has. If most of my editing tasks are doable with out-of-the-box Vim, and it’s impossible for me to install Neovim, then the choice of editor I should use is obvious.

I’ve heard some good things about other Vim-inspired modal editors like Helix and Kakoune, attempts to rebuild the text editor from the ground up. The keybindings that these newer editors use are not only different from Vim’s, but not nearly as universal. Vim’s ubiquity has inspired people to create plugins for popular or more specialized text editors and IDEs like Obsidian, VS Code, and Overleaf to enable Vim-like motions; but there are fewer plugins that would set up Kakoune-like or Helix-like keybindings.

Footnotes

  1. I’m referring to how common performance-efficient libraries for Python use lower-level languages like C/C++, Rust, and Fortran to get around its performance and single-threading issues.↩︎

Reuse

CC BY SA 4.0 International License(View License)