Publicly available in 1991, Vim is still a popular text editor today. Year after year it has hovered at around fourth place in Stack Overflow's editor/IDE survey. The other programming editors circling the top five spots all have plugins which provide Vim-style keyboard shortcuts and a facsimile of Vim's modal behavior. Given its thirty-year track history, it is a rare near-constant in an inconstant industry.

What gives Vim its legs? This post examines Vim through how I've used it:

  • For both low-end server environments and my local dev machine
  • For flexible text handling, such as formatting large data files and comparisons
  • For reusing shortcuts in other tools
  • For comfort during long periods of typing
  • For playing around with and customizing

None of this guarantees a "faster, more productive" developer or writer. Vim's initial time investment is expensive. Not everyone needs or wants yet another tool. Instead, this post goes over how Vim's philosophy contributes to its persistence in modern programming through the use cases I've described.

Vim's anatomy

Vim is frequently referred to in terms of its approach or philosophy to text handling (its modal behavior, shortcuts, and commands) and/or its interface. Vim plugins in other tools typically implement a subset of Vim's approach. It's clear that user demand exists for Vim's philosophy, which is born out of its anatomy.

Vim opens with little else but a column of tildes, a splash screen, and an easy-to-miss command line at the very bottom of the text editor. Whereas not all IDEs implement a command line out of the box, Vim's commands are a core feature of Vim, born out of the constraints of a text-only interface. That modern IDEs returned to this pattern (Ctrl+Shift+P on Sublime Text, VSCode, and Atom), upgrading it with a much more visible placement, is proof of the command line's enduring utility.

The famously disorienting command line is at the last row, which does not have a tilde, on the lower left.

Another side effect of the text-only interface is Vim's use of modes, which contributes to Vim's longevity as well. Modes differentiate functions based on what the user aims to do, whether it be to navigate around the text, insert text, or select text. Modes dictate how keystrokes are interpreted; most text editors insert text by default without any other modes, but in Vim, its corresponding Insert Mode is only one of six. Vim's most commonly used modes are: Normal, Insert, and Visual. Vim's use of modes contributes to its longevity, in that it is able to keep up with allegedly new or rediscovered features. For example, one of the key drivers of Sublime Text's adoption was Block insertion and selection — a feature Vim had already implemented in Visual Mode. By implementing modes, Vim created a space for all the needs of a human that is editing text, enabling future generations of coders and modders to build on the foundation as needed.

(I must point out though, that Sublime Text's multi-caret/cursor editing — making multiple insertion points with Ctrl+Left Mouse Button — was another killer feature unique to it, which drove its adoption.)

Returning to Vim, by combining modes and commands with a scripting language, developers are able to customize it to its minutest behavior. This is further encouraged because of Vim's open-source status. This distributed effort has kept Vim going whereas other tools have eventually run into issues with maintenance due to limited licensing.

These anatomical features are the blueprint for Vim's long legs in the industry. The execution of this blueprint is what keeps those legs running.

Block insertion in Vim: Enter Visual Mode followed by Shift+I, <insert text>, Escape. Block selection is similarly handled, through the use of Visual Mode.

Learn once, run anywhere

IDE preferences ebb and flow for a number of reasons — Atom was bought by Microsoft, VSCode can be a resource hog because it's built on Electron, and sometimes people switch to experiment with other editors. Throughout all of the changes in operating systems, the transition from CLI to GUI, and from the desktop to the cloud, Vim's extensibility has enabled it for use on both low-end servers and high-end development machines. It comes pre-installed on many Linux distributions and on Mac OS and is easy to install on Windows. Given the question, "Does Vim run on X?" the short answer is likely yes.

Every day, some hapless developer is dropped into a pre-installed Vim environment. (Source: Stack Overflow blog)

While installing Vim is trivial, setting it up is not. However, it is possible to set up Vim for entirely different use cases, which I'll refer to as Vim instances. Over the years, I've refined two instances: Vim-as-TextEditor for editing server conf files, and Vim-as-IDE, which is my lightweight programming IDE.

Ubiquity and a scaling resource footprint

Vim's base install size for the past five years has hovered at about 30-42MB on modern Linux distros and Windows, similar to Notepad++. My additional plugins for HTML, Markdown, VueJS, Python, and text manipulation add about 20MB for a total of about 62MB. However, common Vim-as-IDE use cases realistically include plugins which push the total size to about 100MB, which is closer to Sublime Text's install size.

For all the setup work that Vim requires, the payoff is its extensibility. This allows it to be scaled up or down depending on what you're using it for. This means that instead of using, for example, nano on your server and VSCode on your dev machine, you can use Vim for both.

The lowest-specced box I've run Vim on is 1.3GHz + 512MB RAM, but it could be laggy and unsuitable for programming work. Instead I've used this low-end Vim instance for editing Nginx confs, where moving blocks of text is more configurable on Vim than nano.

The advantages of using the same program on different environments include comfort and knowledge reuse. Comfort matters in programming when you've just been dropped into an entirely new environment for intermittent tasks. Knowledge reuse means that instead of having to remember two sets of shortcuts, there is only one set to learn. Nor will these keyboard gestures be forgotten — they're reinforced by using Vim everywhere.

Vim for programming: A monospace font patched font, drawer (Fern plugin) and start screen (Startify plugin). Did it take a while to set all this up? Yes. Am I suffering from Stockholm Syndrome or sunk cost fallacy? I do not know.

Scaling any program up or down still requires configuration. A case can be made for using two programs that are tailored to their specific environment. In Vim's case, there is no way around it: Vim needs configuration. After my initial set up, I've been taking my bag of tricks anywhere.

Vim configuration boils down to plugins, custom commands or scripts, and a single .vimrc file. This prevents the scaling process from being onerous. Having spent time setting Vim up, I have found it easier down the line to use it everywhere.

Configuration portability: plugins and vimrc

Vim's confs do two things:

  • Ensure a consistent Vim experience across OSes — a wonderful boon when you're away from your dev machine for a few onsite tasks or when traveling
  • Easily scale down a Vim instance to fit a constrained use case

Throughout my writing life, creating a stripped-down Vim has gone something like this:

  1. I copied the "full Vim" .vimrc file.
  2. Commented out the unnecessary plugins or commands, but kept the plugin handler. From the very start, I'd used junegunn's.
  3. Installed a base Vim.
  4. In my case, I'd always installed Vim with access to the internet, so I could run my plugin handler to install everything for me.

With that, I'd recreated my home away from home. Or a camper van version of my home.

See, it's just like any other text editor.

Text manipulation across many use cases

Text manipulation comes in many forms. I've found myself wanting to invoke the right function out of a library of thousands, fill in the right number of ordered arguments, save a library of snippets, bracket code blocks for readability, enforce coherent team standards, fold large swathes of text to stay focused, and so on. I've ask myself, "Is this variable already defined somewhere?" and "Where is this file found?" Formatting, selecting, and moving blocks of text affect whether or not a program will compile or spit out errors: I do more than a simple copy-paste and know that many programmers have more complicated text handling operations than I do.

Movement commands and implications for scripting

In Vim, the cursor moves per-character by pressing hjkl bindings (left, down, up, right, respectively). Moving in Vim is meant to be precise: if you have to move to the nth word in a list of arguments, Vim has a command for that. If you need to move down an awkward and arbitrary number of lines to scan for something(with no anchoring bracket, Vim has a command for that too. Of course, I still spam movement commands when I don't feel like thinking too much about it, like b for when I want to move back a few words, or w to move forward a few words.

Because all these movements and commands have a corresponding code in VimScript, it's possible to write scripts to automate whatever text operations you need to do, or make macros. Making macros has never been an intuitive skill to me, but it has occasionally come in handy when editing large data files.

Programming on Vim: A sliding scale from text editor to IDE

There are various reasons for preferring to drive stick over automatic or vice-versa. Programming is similar: drop-down autocomplete may be one developer's ambrosia but another developer's bane. Are auto-closing tags a necessity when writing HTML, or annoying? How about folding behavior?

Not for all developers: A plugin (Tabular) which aligns a block of text based on some operator or symbol.

While programmers may not immediately have opinions about their editor's behaviors, over time, preferences accrue with exposure to more workflows. My path was no different. Eventually I asked myself, "How much of this IDE do I actually use?" or "What features from X editor do I wish Y editor had?"

This interest in making my programming environment fit like a glove is where Vim excels. Vim's VimL (or VimScript) allows users to write commands or plugins that call external programs such as linters, version control systems, and scripts. And users have been writing plugins and sharing their confs for decades, so I can go shopping for scripts and confs for ideas. By customizing Vim from the ground up, I have as much help as I want, and no more than that and I'm guaranteed to know how my editor works.

At the minimum, Vim is able to configure to minute detail all of the examples I've mentioned previously:

  • Autocomplete with user-defined functions, variables, and the like
  • Creating a library of snippets
  • Linters for coding standards compliance, including bracketing
  • Folding text based on criteria
  • Project and file drawers
  • Visual modes for selecting and operating on text blocks, lines, and so on
  • Syntax highlighting themes for programming and template languages, font and font-size selection (dependent on terminal or window)
  • Auto-closing HTML tags

Apart from Tabular, shown above, here's what folding looks like on my setup:

Folding in action with the help of Vim Anyfold. Handy for viewing functions at a certain nesting level and for outlines

General purpose writing on Vim through Markdown

General purpose writing presents different challenges. Writers have preferences and needs for specific formatting, text wrapping, easy-access headings at a sidebar or drawer, proportional fonts, table rendering, and the like. Support for these varies based on the environment Vim is run on.

Non-monospaced editor fonts, for example, are supported on mlterm, but mlterm may not be your terminal of choice — copy-pasting from mlterm on a Linux on Windows subsystem into the greater Windows OS can be tricky.

The gods flip a coin when someone pushes Vim to "run anywhere." mlterm -V on Windows Subsystem for Linux.

When writing on Vim for Markdown, my present preference is to view the Markdown when the cursor is in the paragraph. Upon moving away from the paragraph, the formatting (such as bold/strong or italics/emphasis) is applied. This lets me "preview" the work while writing. This is achieved through a plugin called Pencil.

The gif below works as follows:

  1. I use a distraction-free plugin, :Goyo, to remove line numbers and other elements. By default, text is not word wrapped, so the text disappears beyond a hidden margin.
  2. At the start of the gif, invoking :Pencil wraps the text.
  3. The cursor moves upwards to show that the line, "A note on coding..." has markdown formatting applied to it, which appears only when the cursor is on that paragraph.
Invoking the plugin by entering `:Pencil`.

Plugins for instant Markdown previews do exist for Vim, but I've found that checking the render in my local server is preferable to using these, as additional server processing affects the rendering for Markdown.

Manipulating data files (JSON, protobufs, lua)

Comparing and splicing are common operations when working with large data files, such as JSON, protobufs or lua. When I first worked with game data, it was unheard of to manually edit data files — they're supposed to be generated from an exporter tool that sanitizes the data. We used MS Excel and version controlled it through SVN's locking mechanism (Google Sheets didn't have export-to-JSON functionality yet).

A few years later, at a new company and in an online git-only environment, I was pulling data from different servers, and we needed a way to compare them. At this point, the server's output was uglified, not at all like the freshly exported files from my exporter, so it was necessary to arrange the fields uniformly before comparing them. This is also the case for many fixture files.

I use this command to format JSON back to its human-readable state:

:%!python -m json.tool

And I diff two files by opening them through vimdiff:

vimdiff file1.json file2.json

Here's an example of it in action to verify two files are exactly the same, save the minification on the right:

Vim bindings in other tools

ncdu, a common command for checking disk usage, and less, which displays the contents of a file, both make use of classic hjkl Vim navigation bindings. CLI file managers such as  ranger and vifm are based around Vim's philosophy as well.

Ranger's options after selecting a file for copying.

It is always a delight to instinctively use hjkl to navigate around a CLI tool and find that it works – it may not always happen, but when it does, it's like finding common ground with a new friend.

Does Vim persist or do I persist in learning Vim?

Learning Vim is a path with many road signs pointing hither and thither. One person's dead end is another person's enlightenment. Personally, there are plenty of features within Vim I've never used, such as buffers, Vimscript, and macros. I've also used Vim differently throughout the years, deleting heavier IDE-type plugins that provide autocomplete when not working with large codebases.

On my dev machine, Vim has never been my exclusive text editor – I still use VSCode for some languages, because the amount of time to customize Vim per language can be costly, not to mention that sometimes it's nice to have all the bells and whistles viewable from a menu rather than memorized as part of a configuration only you know. But Vim has exclusively been my in-server text editor for the past five years. Ubiquity and scalability are Vim's secrets. Vim persists because the environment in which it was birthed is the environment we return to, at some point in our careers — a single blinking cursor.

By building around that single blinking cursor, and focusing on the keyboard as its primary input first, Vim has continued to appeal to programmers in search of their zone. In particular, what Vim has done for me is allow me to exploit existing knowledge in many places while also exploring new ways of doing things — I'm happier as a writer with Vim, occasionally being able to tinker with stuff but also be secure in the fact that my editor has been receiving community support and continuity in its thirty or so years of existing. What else is software development but a structure built from the bricks of those who came before us?