To get this blog started, I’m writing about some code I’ve put online. The most interesting are probably the two Code::Stats plugins I’ve created.
Code::Stats is a free service for collecting stats about writing code. It’s a for-fun side project of a colleague. Basically the server exposes an API that receives character counts per language along with a timestamp. The data is gathered by editor plugins.
I thought it would be fun to see how much I type in the terminal, so I created a Zsh plugin for that. It wraps some Zsh widgets to be able to capture keystrokes and sends them using a background curl process after any process completes or the shell exits, throttled down to at most once every ten seconds.
The plugin reports Code::Stats XP as language Terminal (Zsh).
After I realized it’s not too hard to write a plugin and knowing there was some demand for a Vim plugin, I asked the local Vim guru at work for some help to get started.
The Vim plugin was a bit difficult to get working realiably as I wanted to support all the platforms I humanly could:
- Both Vim and NeoVim
- As old Vim versions as possible (The limiting factor became support for the
InsertCharPreevent, needed for counting keystrokes: Vim 7.3.196)
- All operating systems that could conceivably work (looking at you, Windows)
- Both Python 2 and Python 3
Plain Vimscript couldn’t make HTTP requests so it was obvious a script language was needed, and probably Python has the broadest coverage of installations. I also wouldn’t rely on async support as that would rule Vim 7.x out, so I needed to handle asynchonous behaviour by creating a background worker process using Python
multiprocessing. Eventually I got the obvious glitches ironed out and made a release.
Afterwards I sprinkled some unit tests for the Python code and some end-to-end tests that run a mock server and a Vim instance. The end-to-end tests were surprisingly difficult to get working properly. I set up Gitlab CI for the tests and even added (Python) coverage reporting so I get nice icons like this:
Below is an animation I created for the Gitlab page. It’s not perfect by any means but it should convey the idea.
The plugins were a lot of fun to write, and I had to learn a lot of new stuff for both:
- Zsh specifics. I usually prefer POSIX-compatible shell scripts, but that wouldn’t be idiomatic or good for performance.
- Quality control for a shell script. Basically ShellCheck running in Gitlab CI—maybe I should consider unit testing.
- VimL (and Python integration).
multiprocessing. Distributed systems are difficult to get right.
- Releasing software for other people to use. That means prioritizing usability both at install and run time, avoiding all the corner-case glitches that won’t happen on my machine, writing good READMEs etc.
Both plugins are under the Code::Stats organization on Gitlab. Both have users beside myself (yay!).
I also worked a bit on the Code::Stats core before creating these plugins. I did like Elixir and Phoenix, but I currently prefer to spend my spare time outside web development.