Over the years my brain has become wired to think in Vim when it comes to editing text. For example, when I want to change an if guard, I don’t want to click, <Del><Del><Del><Del><Del><Del>. Instead I simply change (c) inside (i) parentheses (.

The Vim Way™ of doing things has become so completely ingrained into me that I find myself reaching for Vim when it comes to any and every task involving editing text.

I’ve even incorporated Vim into my writing workflow. Check out how I use Vim scripts to format markdown and Git logs into the articles on this site.

Formatting Markdown

I do the majority of my writing in Ulysses. While it’s a fantastic writing application, but it’s very stubborn about its Markdown formatting. Combined with my even more stubborn Jekyll setup, I usually have to extensively massage every article before it’s formatted well enough to post.

This usually means doing things like decorating inline code blocks with language declarations, wrapping paragraph-style code blocks in <pre><code> tags, and other general formatting changes.

Originally, I did all of this work manually. Needless to say, that was a very time consuming and error-prone process.

While researching ways of automating the process, I had a recurring thought:

I know how to make all of these changes in Vim. Can’t I just script them?

It turns out I could! A Vim “script” can be written by writing Vim commands directly into a file, and running that script file against the file you want to modify. Armed with the global and normal Vim commands, anything is possible.


As a quick introduction to this idea, imagine we have a script file called script.vim:

:%s/cat/dog/g

And now imagine we have a file we want to modify:

I love cats!
Don't you love cats?

Our script will replace all instances of cat with dog. We can run this script against our file by executing the following command and saving the resulting Vim buffer:

vim -s script.vim text

Now that we have the basics under our belt, let’s take things up a notch. Here’s the Vim script I use to transform the markdown produced by Ulysses into a format accepted by Jekyll:

:%s/\t/    /g
:%s/’/'/g
:%s/“/"/g
:%s/”/"/g
:g/^\n    /exe "normal! o<pre class='language-vim'><code class='language-vim'>\<Esc>"
:g/pre class/exe "normal! }O</code></pre>"
:g/pre class/exe "normal! V}2<"
:%s/`.\{-}`{:.language-vim}/\0{:.language-vim}/g

The first line replaces all tab characters with spaces. The next three lines replace unicode quotes with their standard ascii equivalents.

The fifth line is especially interesting. It matches on all lines who’s next line starts with four spaces. It goes into normal mode, opens a line below the matched line and inserts my <pre ...><code ...> tags.

The next line in the script finds where each code block ends and closes those tags.

If this script is saved in a file called clean-post.vim, I can run it on a markdown file with the following command:

vim -s ./clean-post.vim ./_posts/post.markdown

As an added benefit, I can review the results of the transformation in Vim before saving the changes.

Formatting Git Logs

Similarly, I have a script dedicated to formatting my literate commit posts. This script is different.

Instead of formatting Markdown generated by Ulysses, it formats an entire git log (specifically git log --reverse --full-diff --unified=1 -p .), into a human readable article:

Go
g/^Author:/d
:g/^Date:/d
:g/^commit/exe "normal! dwdwjjwwi[\<Esc>A](/commit/\<Esc>pA)\<Esc>"
:g/^---/d
:g/^index/d
:g/^diff/d
:g/^new file/d
:g/^\\ No newline/d
:g/^@@.*@@$/d
:g/^@@/exe "normal! dt@..dwc$ ...\<Esc>"
:g/^+++/exe "normal! dwd2li\<CR><pre class='language-vimDiff'><p class='information'>\<Esc>"
:g/pre class/exe "normal! A</p><code class='language-vimDiff'>\<Esc>"
:g/^    /normal! 0d4l
:g/^ # \[/normal! dl
:g/^\n    /exe "normal! o<pre class='language-vim'><code class='language-vim'>\<Esc>V}2<"
:g/pre class/exe "normal! }O</code></pre>"
gg:%s/`.\{-}`{:.language-vim}/\0{:.language-vim}/g

While this script seems intimidating, the majority of the work its doing is simple string replacements. Combined with some fancy work done in normal mode, it transforms the output of a full Git log into a beautifully formatted markdown article.

Talk about power!

Final Thoughts

Vim scripts are not pretty by any means, but they get the job done. I continually find myself amazed by the power and utility of Vim when it comes to nearly every aspect of text editing.

If you use Vim and you find yourself repeatedly making similar edits to files, I encourage you to consider scripting those edits. We should always be striving to improve our process, and writing Vim scripts is an incredibly powerful tool that we often overlook.