home, home on the web
where the links and the hypertexts play

Getting stuck on an approach

Published 2020-10-09

Once I start trying to solve a problem in a particular way, I find it very difficult to give up and look for an alternative approach—even though the alternative approach often ends up being much simpler.

I have an html file containing the lyrics to Radiohead’s Fitter Happier:

Fitter, happier, more productive
Comfortable (not drinking too much)
Regular exercise at the gym (3 days a week)
Getting on better with your associate employee contemporaries
At ease
Eating well (no more microwave dinners and saturated fats)
A patient, better driver
A safer car (baby smiling in back seat)
Sleeping well (no bad dreams)

And I wanted to transform it such that each word/phrase is a link to a Google search for that same word/phrase, as such:

<a href="https://google.com/search?q=Fitter&btnI">Fitter</a>, <a href="https://google.com/search?q=happier&btnI">happier</a>, <a href="https://google.com/search?q=more productive&btnI">more productive</a>
<a href="https://google.com/search?q=Comfortable&btnI">Comfortable</a> (<a href="https://google.com/search?q=not drinking too much&btnI">not drinking too much</a>)
<a href="https://google.com/search?q=Regular exercise at the gym&btnI">Regular exercise at the gym</a> (<a href="https://google.com/search?q=3 days a week&btnI">3 days a week</a>)

…and so on (let’s not worry about why right now). Of course this would be a pain in the ass to do manually, but I knew Vim would help me out.

It was clear upfront that a one-size-fits-all RegEx wouldn’t do the trick here, since some of the links need to be a single word, while some are a phrase, and there’s no obvious pattern—I need to decide for each one what I want the link to consist of.

My first approach, and the one that I got stuck on, was trying to use a visual selection in a search & replace expression. I figured that I could select a word or phrase, and then run a search & replace within that visual selection, replacing the selection with the appropriate HTML for a link to the selection. In Regular Expression terms, I’d be looking for (.*) within the selection (in other words, the entire selection), and replacing it with <a href="https://google.com/search\?q=$1&btnI">$1</a>

I tried to make this work for almost two hours—the issue was that I couldn’t get Vim to save the entire visual selection to a single capture group, no matter what I tried. There’s probably a way to do it, but I don’t know it. Finally, it occured to me that macros would probably provide a solution. Macros allow you to record and reply a set of keystrokes. By this point I was frustrated and ready for a break, so I took Tawny for a walk, and while walking the (easy) solution came to me:

v2e " Make any visual selection---in this case, we're selecting the next two words
qa " Begin recording a macro to register A
"zc " Yank the selection to the Z register, delete it, and switch to Insert mode
<a href="https://google.com/search?q= " Start typing our replacement string
^rz " Paste the contents of the Z buffer without leaving Insert mode
&btnI"> " Continue typing our replacement string
^rz " Again paste the contents of the Z buffer
</a> " Finish typing our replacement string
<esc> " Leave Insert mode
q " Stop recording our buffer

Now that we have our macro built, all we have to do to make the rest of the changes is select a word or phrase we want to “linkify”, and execute our macro with @a

Here’s the magic in action:

And the final result.