Saturday, 11 October 2014 00:00

Vim Macros or: How I Learned to Stop Worrying and Save Time

Written by Albert "White Hat" Sharkis
Rate this item
(0 votes)
I once had the task of prepping an HTML newsletter every week. We had a general template, and the weekly content was prepped by a designer in Fireworks, with links and everything already sorted. My task was to insert the generated HTML table into the template and update all the links to append Google tracking code. This used to take me "half of forever" every week, especially since lots of times there would be errors in the newsletter that necessitated starting my whole process from scratch every time. I think it was Fridays.
Anyway, I got good at this after a while - it would only take me about an hour to receive an image and have the newsletter updated, uploaded, and ready to fire off to our 10,000 subscribers. But this was still way too much time, and ruined any other projects I had at the end of the week, which happens to coincide with how deadlines naturally appear. So I tried to research another way of tackling this problem. My thoughts turned to regular expressions, and, as they say, I now had two problems.

Here is how the links always appeared in the newsletter:
<a href="http://sharkis.org?foo=bar"><img src="images/image1.png"/></a>
<a href="http://sharkis.org?foo=bar"><img src="images/image1.png"/></a>
<a href="http://sharkis.org?foo=bar"><img src="images/image1.png"/></a>
<a href="http://sharkis.org?foo=bar"><img src="images/image1.png"/></a>
<a href="http://sharkis.org?foo=bar"><img src="images/image1.png"/></a>

So there were two issues with this, really: the missing tracking code, and the image path was relative when it should be absolute (this is an email newsletter, so we need to link to the images).

A moment of honesty, here: I lost the plugin code that I originally wrote, and I have no idea how I made that work. I tried recreating it using a vim plugin and the 'execute' command, along with the ':substitute' command and what appeared to be a crapload of backslashes ( \ ). The good news is I got it to work another way. A better way:
function! Newsreplace(issue,start,end)
	let a = 0
	execute '%s/'.(a:issue-1).'/'.a:issue.'/g'
	let i = a:start
	while i <= a:end
		let line = getline(i)
		let line = substitute(line,'\(href=".*\)"','\1\&utm-campaign=newsletter-'.a:issue.'\&utm-medium=link-'.a.'"','g')
		call setline(i,line)
		let a+=1
		let i+=1
	endw
	execute '%s/link-0/banner-top/g'
	execute '%s/link-'.(a-1).'/banner-bottom/g'
endfunction

This code highlighting plugin might not work too well, but hopefully well enough. The function takes as arguments the issue number, the starting line for the link/image table, and the last line as well. Ok, so I have some vestigial code that I DO remember at the top on line 3. This finds any reference to the newsletter in the template and increments the number to match the current issue number. After that, it's a simple loop to match the regex and replace it appropriately.
\(href=".*\)"

This regular expression matches the href, equals sign, opening quote, and any characters before the closing quote, as well as the closing quote. The parenthesis group everything but the last quotation mark together for backreference purposes.
\1\&utm-campaign=newsletter-'.a:issue.'\&utm-medium=link-'.a.'"

\1 indicates the backreference I just mentioned, so it spits out the href, equals, first quote, and the entire original link. The ampersand ( & ) is escaped because in vimscript land, the ampersand will expand to the entire matched pattern we searched for. The ampersand also extends the GET parameters of the link, allowing me to add utm-campaign (equal to the newsletter number) and utm-medium (equal to the ordinal position of the link within the document) before I finally close the href with the final quotation mark.

At the bottom of the document, I change link-0 and the last link to banner-top and banner-bottom because those were common elements we had that we wished to independently track. This closes the function.

So, you would start with something like this:



And end with this instantly after executing the command:



I left this out of my example today, but fixing the images would be one more simple search and replace. Search for 'src="' and use the backreference again to prepend "http://sharkis.org/images" or wherever the images can be found.
Read 3040 times Last modified on Sunday, 19 October 2014 19:48