Pretty Markdown & HTML Links With TextExpander & Perl

What’s the problem to be solved? When doing show notes for the various podcasts I contribute to, I generally have to include a lot of links. Particularly for Let’s Talk Apple and the Security Stuff segment on the Nosillacast, I want to clearly show where the news story came from. I also want to keep the link text short. To balance those two requirements, I decided to use the domain part of the URL with /... appended to it as the link text. Doing this manually would be a really big pain in the backside because there are often more than 50 links in the notes for a single episode! Clearly, this needed automation.

I do my show notes in Markdown, so my initial solution produced links in Markdown format. Allison asked me how I did my links, because she thought they looked good, and she assumed I would have automated the process in some way. I explained my solution, and she asked if I could build a variant for her that generates the same style of links in HTML format.

My solution is built using a number of building blocks, but the glue that holds it all together is TextExpander. TextExpander is a paid-for Mac-only app, but one I would argue is well worth the price of admission. TextExpander is one of the first things I install on every new Mac.

TextExpander’s raison d’Ãªtre is to monitor everything you type, looking for abbreviations you have defined, and replacing them with expansions you have defined as you type. Each of these abbreviations/expansion pairs are referred to as snippets within TextExpander.

Snippets can be very simple replacements like expanding *bb into Bart Busschots, but they can also be much more complex. The next level up would be to include special codes to inject data into the replacements, for example, I have a snippet that replaces *di with the current date and my initials, the content of that snippet is %d-%m-%Y BB – %d gets replaced with the day part of the current date, %m the month part of the current date etc.. The next level of complexity is that you can include special codes to make TextExpander popup a little form when ever you type the abbreviation into which you then fill in information that gets included in the replacement text.

However, the thing that really makes TextExpander powerful in my mind is it’s ability to execute a script to generate the replacement text. The scripts can be written in AppleScript, JavaScript, and any scripting language supported in the OS X terminal. This allows TextExpander to utilise the full power of the Terminal, as well as the full power of scripting languages like Perl, Python and Ruby.

Unsurprisingly, I like to use Perl in my snippets, and in this case, I use Perl to reach out to the pbpaste terminal command, and to harness the power of the URI perl module.

I use my solution as follows:

Copy the link to be included in the show notes to the clipboard

Cmd+tab to the show notes I am working on and type the abbreviation *mdlc into the place in the notes where I want the URL to be inserted (all my Markdown expansions start with *md, and lc stands for linkify clipboard).

The TextExpander snippet then executes – it fetches the URL from the clipboard, parses it with the URI perl module, and assuming that succeeds, generates the Markdown code for the link, and inserts it into the show notes in place of the *mdlc abbreviation.

Listen Along: Chit chat Across the Pond Episode 419
http://media.blubrry.com/nosillacast/traffic.libsyn.com/nosillacast/CCATP_2015_12_31.mp3

Prep Work

For this solution to work, you obviously need TextExpander installed on your Mac. You also need the URI perl module installed. You can check if the module is installed with the command:

perl -e 'use URI; print "OK\n";'

If the module is installed, the only output you’ll get is ‘OK’:

bart-iMac2013:~ bart$ perl -e 'use URI; print "OK\n";'
OK
bart-iMac2013:~ bart$

If the module is not installed, you’ll get a big messy error message.

To install the module simply run:

sudo cpan URI

The Markdown TextExpander Snippet

When creating a new snippet in TextExpander, you can choose the content type for the snippet with a dropdown menu at the top of the snippet content text area. The default value for this dropdown is Plain Text, but we need to change it to Shell Script:

This will auto-populate the content of the new snippet with some sample code. Replace this sample code with the following Perl code:

#!/usr/bin/perl

use strict;
use warnings;
use URI;

my $clipboard = `/usr/bin/pbpaste`;

my $url = URI->new($clipboard);

# if we didn't get a valid URL, just call it a day
unless($url->scheme() =~ m/^https?$/sx){
exit 1;
}

# assemble and print the markdown link
print q{[}.$url->host().q{/...](}.$url->canonical().q{)};

So, what is going on here?

The first line is the so-called shebang line, it tells TextExpander which interpreter to use to execute the script – in this case, Perl.

Lines 3 & 4 include standard best-practices Perl modules.

Line 5 includes the URI module which we’ll use to interpret our URL.

Line 7 shells out to the pbpaste command using Perl’s back-tick (reverse single quote) operator. The back-tick operator executes the terminal command enclosed between the back-ticks, and saves the output of that command into the variable $clipboard.

Line 9 creates a URI object called $url from the content of the clipboard.

Lines 12 through 14 check that the clipboard contained an absolute URL by checking that the URL scheme is either http or https by matching it against a regular expression.

Finally, line 17 prints out the link in Markdown format. $url->host() returns just the domain part of the URL, and $url->canonical() returns the full absolute URL.

A reminder that in Markdown, a URL is represented as follows:

[LINK_TEXT](LINK_URL)

So, Line 17 prints the character [, then the domain part of the URL, then the characters /...](, then the URL, and finally the character ). Note that in Perl, a string can be enclosed between q{ and }.

The HTML Variant

To convert this snippet to HTML, all we need to do is alter the line that does the printing, that is to say, line 17.

A reminder that in HTML, a link is coded as follows:

LINK_TEXT

So, the new line 17 is:

print q{canonical().q{" target="_blank">}.$url->host().q{/...};

For completeness, here is the full content for the HTML variant of the Snippet:

#!/usr/bin/perl

use strict;
use warnings;
use URI;

my $clipboard = `/usr/bin/pbpaste`;

my $url = URI->new($clipboard);

# if we didn't get a valid URL, just call it a day
unless($url->scheme() =~ m/^https?$/sx){
exit 1;
}

# assemble and print the HTML link
print q{canonical().q{" target="_blank">}.$url->host().q{/...};