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):

  1. Hard word wrap
  2. Indicate lines changed since last commit
  3. Running word count
  4. 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.

GeanyThis 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.
emacsThis 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.
GeditThis was yet another editor with the same kind of features of every other editor out there, which were not so important to me
KateAs was this: nothing stood out.
NanoThis was terminal based which was the only thing that stood out.
microThis 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 extensionhttps://github.com/airblade/vim-gitgutter Show changed lines in the editor gutter.
highlight clear signcolumnImproves how the gutter looks in dark themes
“+yCopy these lines into the system clipboard (like CTRL+C)
“+pPaste from the system clipboard (live CTRL-V)
“*y Copy to the primary clipboard
“*pPaste from the primary clipboard (paste text highlighted in some other application)
:tabn, :tabp Navigating tabs left/right (or use the mouse!!)
:tabeditOpen new empty tab
vim -p file1 file2 file3 …Open files in multiple tabs
CTRL+SHIFT+VPaste. 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.