Advanced Projectionist Templates
This week I migrated some of the vim tooling I use for my blog from UltiSnips to projectionist. The result is a lighter weight and a more user friendly (for me) interface.
When I blogged about my vim plugins I mentioned that I use UltiSnips
solely for writing new blog posts. It always felt weird to use this incredibly
powerful snippit tool to generate the boilerplate for a single file by typing
fmatter<tab>
every time.
Projectionist
, which I also blogged about in my vim plugins post,
is generally useful for me in navigating well known parts of a project. One
feature of Projectionist that I’d never used before was its templating.
Basically with Projectionist you define a path and you can easily open files
based on it.
For this blog I have a file like this:
{
"content/posts/*.md": {
"type": "post"
}
}
I can run the command :Epost station
and it will open the file at
content/posts/station.md
. It supports tab completion out of the box and other
very handy features that make more sense when programming.
Back to templates; if you run the above command and the file does not exist, a template can fill in some boilerplate for you. You define the template in the JSON as follows:
{
"content/posts/*.md": {
"type": "post",
"template": [
"---",
"title: ",
"date: ~~CURDATE~~",
"tags: ",
"guid: ~~GUID~~",
"---"
]
}
}
It’s a little noisy, but the result is that when you first open a fresh post
with :Epost some-post
it will have the above filled in:
---
title:
date: ~~CURDATE~~
tags:
guid: ~~GUID~~
---
Of course there is one major setback. With UltiSnips
you can trivially insert
commands in the template. Their output is then seamlessly interpolated.
I proposed as much to Tim Pope and he didn’t seem to like the idea. After a few months of pondering on it I struck upon the idea of using an autocommand to postprocess the generated content. Here was my first version:
{
"content/posts/*.md": {
"type": "post",
"template": [
"TPLTPLTPL",
"---",
"title: ",
"date: ~~CURDATE~~",
"tags: ",
"guid: ~~GUID~~",
"---"
]
}
}
Note especially the use of TPLTPLTPL
as a signal that a template is to be
processed.
Then I wrote the following vimscript:
function! ExpandTemplate()
if getline(1) == 'TPLTPLTPL'
%s/\~\~CURDATE\~\~/\=systemlist("date +%FT%T")[0]/ge
%s/\~\~GUID\~\~/\=systemlist("uuidgen")[0]/ge
1g/TPLTPLTPL/d
endif
endfunction
au BufReadPost * call ExpandTemplate()
I figured out the autocommand to hook into by reading the source of
Projectionist
and the rest is just regular vimscript.
Finally, I decided I could make it slightly simpler with a patch to
Projectionist
. With the patch in place the code simply becomes:
function! ExpandTemplate()
%s/\~\~CURDATE\~\~/\=systemlist("date +%FT%T")[0]/ge
%s/\~\~GUID\~\~/\=systemlist("uuidgen")[0]/ge
endfunction
au User ProjectionistApplyTemplate call ExpandTemplate()
And the TPLTPLTPL
line can go away.
I felt good to finally be able to scratch this itch. The user interface is simpler and the code is lighter and I have one fewer plugin that I rarely use.
(The following includes affiliate links.)
If you’d like to learn more about vim, I can recommend a few excellent books. I first learned how to use vi from Learning the vi and Vim Editors. The new edition has a lot more information and spends more time on Vim specific features. It was helpful for me at the time, and the fundamental model of vi is still well supported in Vim and this book explores that well.
Second, if you really want to up your editing game, check out Practical Vim. It’s a very approachable book that unpacks some of the lesser used features in ways that will be clearly and immediately useful. I periodically review this book because it’s such a treasure trove of clear hints and tips.
Third and finally, if you want to really grok the guts of advanced vim, to write a plugin for example, you should really check out Learn Vimscript the Hard Way by Steve Losh. I expect to reread it two or three more times. I got the PDF version so I could read it while offline.
Posted Mon, Oct 16, 2017If you're interested in being notified when new posts are published, you can subscribe here; you'll get an email once a week at the most.