I was doing some writing and the power usage on my laptop was doing these funny spiky things. Without any evidence, I arbitrarily decided to blame VS Code and started looking for a replacement editor. Of course, those of you familiar with the creative process will recognize this for what it is: procrastination, but let me take you on my journey which ended up, as many such journeys do, with Vim.
I started off with searches like “Best text editor for Linux” and “Linux text editors” which returned moderately clickbaity pages, but through them I created a list of editors to try. I wasn’t entirely whimsical: I had a short list of fairly modest requirements (which, however, differ in some important aspects from what I need from a coding IDE):
- Hard word wrap
- Indicate lines changed since last commit
- Running word count
- Tabs
Also, it’s very trivial, but I got used to markdown mini-rendering (e.g. _italics_ and **bold**) so I wanted that too. Somewhere at the back of my mind, also, was this idea that I would like it if the editor were console (terminal) based, though this was not a hard requirement.
Geany | This looked kind of retro in a bad way. It’s the most trivial thing, but the icon ticked me off. In the editor itself, I didn’t see anything that would easily satisfy my need for indicating changed lines, word wrapping and word count. |
emacs | This installed 700 Mb of dependencies. I think there are operating systems half this size. I don’t know why I even thought about it – I’ve never had any kind of attraction to it. I can’t even open a file or exit out of it. Sorry. I don’t know why emacs ticks me off so much. It’s possibly because so many computer experts praise it and I feel stupid for not getting it. |
Gedit | This was yet another editor with the same kind of features of every other editor out there, which were not so important to me |
Kate | As was this: nothing stood out. |
Nano | This was terminal based which was the only thing that stood out. |
micro | This might have been suitable (looking at the run down here and the gorgeous screenshots) but sadly I had enough by then … |
And none of these, out of the box at least, applied those italic and bold styles I’d gotten used to.
You can see where I’m headed. Yup. I ended up with Vi(m). Sometimes the answer is right under your nose in every terminal you’ve ever logged into.
Not your hippie uncle’s Vi
Modern Vim has colored text, it has tabs, it responds to mouse inputs, it responds to touch inputs, you can customize the status bar with one line entries in a text config, it has plugins to show line change status from your version control.
Some random things I could use to very quickly get it to where I wanted it
git-gutter extension | https://github.com/airblade/vim-gitgutter Show changed lines in the editor gutter. |
highlight clear signcolumn | Improves how the gutter looks in dark themes |
“+y | Copy these lines into the system clipboard (like CTRL+C) |
“+p | Paste from the system clipboard (live CTRL-V) |
“*y | Copy to the primary clipboard |
“*p | Paste from the primary clipboard (paste text highlighted in some other application) |
:tabn, :tabp | Navigating tabs left/right (or use the mouse!!) |
:tabedit | Open new empty tab |
vim -p file1 file2 file3 … | Open files in multiple tabs |
CTRL+SHIFT+V | Paste. If you want the right click menu, you will need a vim version with clipboard support compiled in. You can check this by doing vim --version | grep clipboard |
:mks[ession][!] [file] | Write a Vim script that restores the current editing session. When [!] is included an existing file is overwritten. When [file] is omitted "Session.vim" is used. |
Clipboard
I’m running Vim in a terminal, so I assumed that the terminals copy/paste would just work. It would, except for one wrinkle: I have set mouse=a
and so Vim’s capturing all my mouse/touch inputs, which is nice, but is kicking out the terminal’s own mouse handling. So I can no longer select/copy and paste into Vim.
The solution to this was complicated by the fact that there are different flavors of Vim floating around with different compilation options. Doing vim --version
prints out this information. Mine, for example has -clipboard
and -xterm_clipboard
which means this one won’t do the required handling. You can also execute :echo has('clipboard')
and if this returns 0, vim hasn’t been compiled with clipboard support.
The X-display primary clipboard is an interesting oddity on *nix systems. You just highlight text and that gets copied into the primary clipboard (you don’t need to CTRL+C). You can then paste this into vim by using "*p
.
Hard wrapping
I like my prose lines hard wrapped at 80 columns. It helps with diffing and in general is more manageable than the default, which would be lines as long as the paragraph is. This is two lines in the .vimrc configuration file:
set tw=80
set wrap
To do this in VS Code you have to download and install a plugin from the market place.
Modifying the status line
I wanted to have the word count in the left of the status line, and a slightly modified column and line count.
set laststatus=2
set statusline=
set statusline+=\%{wordcount().words}\ words
set statusline+=%=
set statusline+=\[%c]
set statusline+=\ %l/
set statusline+=%L
It’s a little esoteric but well explained in the manual.
To do this in VS Code, you guessed, it you have to download a plugin from the marketplace, or more accurately, since my taste is so specific, you have to write your own plugin. I’ve written a VS Code plugin. It was enjoyable, and the plugin system is very powerful, but it would have been an awful lot of work just for this.
Edit: A little afterwards I got it into my head that I would like to display the word count up to my cursor. In VS Code you’d have to do some extra coding in your TS plugin to do this. Take about an afternoon of coding and fiddling. In vim? The solution is to change the wordcount part of the status line to
set statusline^=\%{wordcount().cursor_words}/%{wordcount().words}\ words
Yes, it’s just a field in the struct returned by wordcount()
.
File type plugins
I didn’t want my hard wrapping and word counting to mess up the odd Python or C++ or Go file I might open. The correct way to handle this is to create a filetype specific plugin.
I removed the relevant code from my .vimrc
file, which now is just
set mouse=a
set laststatus=2
set statusline=
set statusline+=%=
set statusline+=\[%c]
set statusline+=\ %l/
set statusline+=%L
filetype plugin on
And the filetype specific plugin is in ~/.vim/ftplugin/markdown.vim
setlocal tw=80
setlocal wrap
setlocal statusline^=\%{wordcount().words}\ words
Note the use of setlocal
to prevent messing up settings for other files, sorry buffers, open in other tabs.
I wanted the word count to appear on the left of the column/line display. Initially, I only knew of the += operator for the statusline and thrashed about wondering how I could get it to appear first. Turns out the ^= operator prepends to option strings.
An important part is that you have to have filetype plugin on
in your .vimrc
for these plugins to be loaded (see :h filetype-plugin-on
).
I even made a plugin for it in 5min
Plugins in other editors conjure up coding in typescript or lua or some thing. I wanted to display my laptop’s power consumption in the status bar.
All I had to do was add my custom function to the status bar string:
set statusline+=\%{PowerDraw()}\ W
And the function goes in any file under ~/.vim/plugin/
, say like ~/.vim/plugin/power.vim
function! PowerDraw()
return system("echo \"scale=2; $(cat /sys/class/power_supply/BAT0/power_now)/1000000.0\" | bc -l")
endfunction
As an aside, I wondered what happened if any of these functions took a little bit to complete, which this one surely does, since it’s waiting on a device file. Turns out that this plugin caused glitches when I typed too fast, like when I hit the left or right cursor, it would leave weird escape characters on the display, so make sure the called functions terminate quickly. I ended up turning this power status function into a Ubuntu task bar app notification, which is for another post …
The only problem now is …
That I keep hitting “ESC” everywhere when I’m done writing text. On the wordpress web editor this scrolls me all the way to the top of the article, which is friggin annoying.
Heh 🙂 The eternal fight between vi and emacs is not over — and will never be (to the benefit of both, I’m sure!).
I totally agree that installing 700 MBytes of dependencies and who knows what else just to have a simple text-based editor is totally overkill. It always was that way. Vim’s currently incarnation might include everything but the kitchen sink these days, but it still has a tiny footprint, when compared to Emacs.
You’re right about the existence of operating systems which are smaller than Emacs. When Stallman started to write what is today GNU Hurd, decades ago (allegedly around 1976 or so), as a “Unix-compatible open source replacement” (a decade before Linus even had learned how to type code), this was going to be such a monumental task, that, to start it, he needed a compiler (and wrote GCC) and a text editor which didn’t share any code with whatever was being used in Unix those days, and wrote Emacs instead.
As time passed, Stallman was writing less and less code for his Ultimate Open Source operating system, and bloating Emacs more and more, to the point that, yes, people in the early 1990s (before Linux appeared!) joked with Stallman, saying that others wrote operating systems in order to run text editors (such as vi), while Stallman wrote a text editor which would do everything that an operating system needed to do — and became gigantic in size as a consequence.
Even today, I need to search Wikipedia to refresh my memory about what Emacs stands for. I can only remember the two humorous ones — Esc-Meta-Alt-Ctrl-Shift, as a reminder of how many keys you need to type all its commands, and, of course, Eight Megabytes And Constantly Swapping. 8 MB might not sound terrible these days (when things like Fortnite take 100 Gigabytes to install…), but when that acronym was coined (about the time when half a Megabyte was the usual amount of RAM on a PC), it really felt that way. And even today, on a fast machine, vim and its many variants will load instantly (fractions of a second), while Emacs, by contrast, will take a very perceptible moment to launch. Even “just a second” is, I think, too long to wait for a text editor to launch, no matter how fast/slow it is. On a underpowered Raspberry Pi, vi continues to be as fast as it ever was. Emacs… well… no comments 🙂
(The actual acronym stands for “Editor MACroS”.)
Nevertheless, and perhaps surprisingly so, I have stuck with Emacs clones for ages, namely, jmacs, a clone designed by the elusive Joseph Allan, who, at some point in the very remote past, did ports of the most popular editors of the time. The default, joe (“Joe’s Own Editor“), emulates most of WordStar’s not-so-very-stupid key combinations (some of which still persist in contemporary word processors!) and adds a few borrowed/inspired by Emacs. But Joe has essentially built an editor’s editor, which comes with several flavours built in, namely, “jmacs” (emulates GNU-EMACS), “jstar” (emulates WordStar), “jpico” (emulates the Pine mailer editor PICO) and “rjoe”(a read-only variant of joe). In practice, they are all symlinks to the “main” joe — the different flavours come essentially from reasonably simple configuration files, one for each environment it emulates — but the executable binary is the same. joe features multi-screen splits and launching shells inside it (like Emacs), a comprehensive built-in help system, regexp search & replace, full mouse support, an internal a la Emacs clipboard, but also the ability to use the OS’s own clipboard, and, well, syntax highlighting (and formatting) for a whole bunch of programming languages, not only the “most popular” ones.
All that in just a 700K executable (Linux) or 620K on the Mac. That’s a reasonably small footprint (the basic version of vim on Ubuntu Linux 22.04 takes 3.7 MBytes — which is still half of what Emacs takes just to launch its core engine!). It’s written in very compact and highly portable C, with very few dependencies, so it usually compiles well in most environments, even obscure ones.
On the rarest of rarest occasions when joe failed to build for some reason (AFAIK it just happened once — the maintainer of the joe port for the Mac had a typo somewhere), I have toyed around with micro instead. The overall concept of micro is similar to joe, and I suppose you could replicate much of its functionality to keep them side by side, but… well, micro even has a plugin system (besides extensive support for all sorts of configuration files) and is developed in Go — which means that the binary on disk will be huge (larger than Emacs, in fact) due to Go’s love of statically linking all libraries in it — which, these days, you can (cross-)compile for anything (including web assembly!), and that means that, no matter what machine you have, if you know what kind of CPU it has, you can compile micro for it. Still, joe is much faster and (currently) does a better job at emulating Emacs for the die-hard fanatics just like myself 🙂 Also, joe is being leisurely updated; since its inception in 1988 (!), there have been relatively few versions (even minor ones). I’m currently running 4.6, which is the “big upgrade” that followed 4.5… back in 2018 🙂 (By contrast, micro, vim or Emacs itself are always being updated, all the time, often at an hourly basis).
Obviously everybody has their “favourite” text editor, and on Ubuntu Linux, if you want a small footprint, I believe you can’t beat nano with its 277K. It’s so small, indeed, that pico is just symlinked to nano (something I wasn’t even aware of!). nano is fast but does almost nothing except very basic and primitive plain text manipulation 🙂
The real issue I have with vi and its successors is merely because I don’t personally like the idea of having different “modes” to edit text, so to speak, and on the legacy versions, it wasn’t easy to know in which mode you were currently on. I remember when there was a vi version that came out which did bind the Insert key to, well, insert mode, and that was a blessing!… until contemporary laptop keyboards dropped that key. Arrgh! Back to whatever-was-it-now command to insert characters…
Granted, contemporary versions of vim are much more user-friendly regarding the mode they’re in, while still retaining all the command line goodies from sed/awk era. It’s just, well… you know, mechanical memory. I already use the Emacs set (well, a subset) of keys on the shell command line, and on every text-based application that uses the same set as well (which are many, and their number is increasing…). I do not wish to launch a text-based application — a text editor, that is — which has a completely different way of dealing with keystrokes. Even on my GUI-based code editor I have most of the Emacs-style commands active (which always surprises me when I instinctively press one of those combinations, without remembering that I’m not on the console, and it just happens to work there as well).
Then again, the way the “mode switching” works — either in vi or in Emacs — is, and always will be, a source of contention, and I’m pretty sure that it will never be “decided”. There will be fanatics on both sides, always, no matter what the tools of the future will look like. And both will frown at the third side, the minimalists who are happy with the pico/nano-style of just moving the cursor around the window with the cursor keys and have little else that they can do…
But in any case, one thing is for sure: no matter what machine or device you’re using, if it’s an Unix variant, you will have a variant of vi in there — even if it’s one of the “old school”, no-extra-frills variants. Which means that in an emergency you have to know at least the basics of how vi works. The reverse used not to be true — why should a vi user worry about Emacs keys? — until, well, as mentioned, shells such as bash started to use Emacs-style commands, which in turn meant that text-based applications all started to use the same kind of input line processing keys as well, so… these days, vi users will have no choice but to learn a few of those as well.
Anyway… :q! for now. Unless it’s Ctrl-X Ctrl-C of course 🙂