Dec
30
Pretty Markdown & HTML Links With TextExpander & Perl
Filed Under Computers & Tech, Software Development, Automation on December 30, 2015 at 4:08 pm
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
, andlc
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
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:
<a href="LINK_URL" target="_blank">LINK_TEXT</a>
So, the new line 17 is:
print q{<a href="}.$url->canonical().q{" target="_blank">}.$url->host().q{/...</a>};
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{<a href="}.$url->canonical().q{" target="_blank">}.$url->host().q{/...</a>};
Works a treat – thank you so much for sharing!
[…] html better he created a version for html as well. He walks us through his detailed tutorial here: http://www.bartbusschots.ie/…. Then he tries to convince me that Markdown is awesome and html is dreadful. Listen along to see if […]
[…] I’m pretty sure I won’t do a Chit Chat Across the Pond next week, but who knows, maybe I’ll find someone fun to interview for longer than a 3 minute spot in the NosillaCast. Last week we had Bart back on the show. It wasn’t a Programming By Stealth segment but it was still pretty nerdy. He taught me how to write a perl scrip that I could embed inside TextExpander so that I could create what he calls “pretty” Markdown or HTML links. Instead of long gloppy-looking links, now I can easily embed links in the shownotes that simply say the domain followed by a / and three dots showing you that there’s more to it than what it shows. Very cool lesson and of course Bart has a detailed tutorial on it on bartbusschots.ie/…. […]
With some effort (the clipboard handling is a pig) I have managed to produce a version of the Markdown snippet written in Swift. Why? Because I can. 🙂
#!/usr/bin/env swift
import AppKit
let thePasteboard = NSPasteboard.generalPasteboard()
let stringClass = NSClassFromString(“NSString”)
let pasteboardContents = thePasteboard.readObjectsForClasses([stringClass!], options: [:])
if let theContent = pasteboardContents {
let theText = theContent[0] as! String
if let theURL = NSURL(string: theText) {
print(“[\(theURL.host!)/…](\(theURL.standardizedURL!))”, terminator: “”)
}
}
For those of us benighted individuals living without TextExpander, I created a shell script that puts the HTML href line back into the clipboard, ready for pasting wherever. So I have 2 files: prettyURL.pl which has Bart’s Perl script from the lesson and a shell script file, called prettyURL.sh, with the following:
#!/bin/bash
perl prettyURL.pl | pbcopy
As Allister says, because I can.
@MacLurker – you could do it all in the Perl script by assigning the generated string to a variable before printing it, say $pretty_url, then sending that to the clipboard from within Perl with a line something like the following:
[…] For many years now I have been an avid user, and eager evangelist for, a Mac app called TextExpander. TextExpander allows you to create snippets that you can invoke with shortcuts, and those snippets can range from the simple to the very complex, as in the URL conversion snippet I blogged about recently. […]