Creating a Vim plugin.
Published 27 September 2020 at Yours, Kewbish. 1,335 words. Subscribe via RSS.
Introduction
This week, we had our first proper English class, and our teacher happened to [re]introduce a series of issues and common phrases that should be replaced for better, more concise writing. This checklist is called Dr. Blank’s Quirk List, apparently. If you go through the PDF, it’s a huge list of things like ‘delete aforementioned’ and ‘change economically deprived to poor’. The thing is, we’re going to be graded on how well we conform and utilize this list, so I"m going to have to pay a lot of attention to this list.
But with all my problems, I decided to overengineer and automate a solution to a problem that didn’t really exist.
Usually, I write my assignments in Markdown in Vim, and later use Pandoc to convert to a Word file if needed for the assignment. Therefore, I thought it’d be nice to have a Vim plugin that could highlight and remind me of all the rules, so I wouldn’t have to remember each of them. I also kind of just wanted to learn a bit of VimScript (or VimL. I still haven’t figured out what it’s supposed to be named.), and I thought that a simple highlighting plugin might be a nice, relatively easy introduction to the language1.
Eventually, it expanded to a linting function as well, which essentially copies the original file, replaces any Blank quirks found, and saves the file again. In the interest of making it easier to compare files, I also implemented a Blank diffing command, which lints files and then opens them in Vim’s vimdiff mode.
Learning
By the way, if you’d like to go through the source of the plugin at any point (it’s maybe only 20 lines or so, and it’s pretty self-explanatory), it’s up on my GitHub at kewbish/blank.vim. Maybe go take a look - or don’t (it’s quite messy).
I wrote the plugin in pure VimScript: I didn’t feel like attempting to figure out Lua or trying to use a wrapper in some other language. I found the syntax pretty fun - it kind of reminded me of Hugo’s templating syntax, which I’ve always kind of liked. I found two resources that were extremely helpful throughout this attempt - Steve Losh’s tutorial on learning Vimscrip the hard way and, surprisingly, the VimTips Wiki. Once I realized that the VimScript I wrote was essentially just the commands I’d normally run in the editor, I mostly trawled through the Vim Wiki for any new features or challenges that I faced.
Getting Started
I started by just putting a huge list (all on one line, by the way. Vim’s highlighting stopped halfway, which speaks to the amount of quirks I would have had to manually go through.) in my vimrc. I figured out that I was supposed to let
it to something, and from there, figured out how to run custom commands.
At first, these commands just printed to the screen, but I needed them to properly do something, so I attached function calls to them. These functions were also empty, so it was time to properly learn VimScript.
With my past attempts at making a Vim colourscheme, I was somewhat familiar with making a highlight group, so I decided to start figuring out how to highlight all the quirks. The syntax goes something like:
highlight Blank ctermfg=95 cterm=underline
syntax match Blank /find this/
syntax match Blank /also this/
syntax match Blank /this too/
Obviously, I wasn’t going to type out each of the matches, so I looked into Vim’s for loops. I managed to come up with something like:
for quirk in s:quirks
let quirkLen = len(split(quirk, " "))
if quirkLen > 1 || quirk == "ing"
execute "syntax match Blank /". quirk. "/"
else
execute "syntax keyword Blank ". quirk
endif
endfor
to check if the quirk was supposed to be highlighted as a keyword or just with regex matching.
With that, syntax highlighting was pretty much done, but I’d realized it’d be pretty nice to have a mode that could automatically remove and show the difference between quirks and a quirk-free file (even if that file wouldn’t be grammatically correct with lots of missing words, for example). So, I decided to write another function that would copy the file, open it in a split, and then use global find and replace to remove them all.
for quirk in s:quirks
if !(quirk == "ing")
execute "%s/\<". quirk. "\>//ge"
endif
endfor
This above for loop replaces all the quirks, and coupled with statements to construct an unique filename, copy the file to that filename, and splitting it, I managed to get a file that had all the quirks out. I could then open the two in a split view to see where they differed.
But then I realized - I could probably also automate that splitting, and after some digging, I found diffthis
, which was absolutely great. With another function that called the first replacing function, I got a view where every section that had quirks taken out were shown. This definitely helped for me personally, because I was pretty concerned that one day I’d miss a spot.
With these three functions, I figured I may as well try my hand at packaging this into a Vim plugin - maybe it’ll be a little useful for someone out there.2
Plugin Structure
The first thing I had to figure out after deciding to make the plugin a proper plugin was how to structure the project files, and where Vim-Plug and Vim would be expecting what. Eventually, I realized it had to go something like:
├── autoload
│ └── blank.vim
├── doc
│ ├── blank.txt
│ └── tags
├── ftplugin
│ └── markdown.vim
├── LICENSE
└── README.md
I’m going to go in reverse order:
- README and LICENSE are pretty self explanatory.
- the
ftplugin
folder contains amarkdown.vim
file, which will be loaded upon any markdown file being opened in Vim. Because I only write markdown in Vim, that’s all I need, though I suppose you could rename this totext.vim
.3 This contains three commands that call the main logic functions. More on that later. - the
doc
folder (not docs, as I had initially thought - another five minutes of Googling gone) contains the help file,blank.txt
, which has some help tags, which are intags
. - And finally, the
autoload
folder. That’s the slightly more complicated folder - it contains the main chunk of Blank-quirk-finding logic™. Those functions aren’t autoloaded, like the ftplugin folder is, and I have to call them from the commands inmarkdown.vim
.
Conclusion
Usually, I don’t like short projects, but this was merely a low-pressure weekend fling, and hopefully, it’ll keep my grades up. Also, an opportunity to pretend that I’m not procrastinating on work with more work / programming, so that was fun. VimScript is also pretty intuitive, I find - I like the endif
and endfor
syntax, and the scoping with colons is also fun.
I find that I’ve been writing a lot about Vim recently. Funny - I was just about to say that it’d be back to regularly scheduled programming, but I really don’t have any specific topics that I even write about. I might post a bit about some other school/tech related things that I’ve been doing, or maybe I won’t post at all. We’ll have to see how busy school gets.
If I can find time, I’ll be doing some cool things with diveintoht.ml, so maybe check that in a couple months or so. We’ll see.
-
Most of my open-ended projects and assignments end up being programming and learning a new framework or scripting language and passing that off as academic work. It’s a good system. ↩︎
-
Though I highly doubt that anyone whose grade semi-depends on the Blank list also uses Vim. I’m pretty sure those are two very small sections that do not have an overlap larger than 1 (myself). ↩︎
-
Also, as an aside, it’s not
md.vim
, it’smarkdown.vim
. Save yourself the hour it took me to realize. ↩︎