MultiMarkdown footnotes in TextMate

Earlier this week, there was a thread on the TextMate mailing list about creating footnotes in text files. It was suggested that MultiMarkdown had a good footnote implementation and that my reference link macro/command/snippet system could be modified to make MultiMarkdown footnotes. As I was going to be spending some downtime this week flying and sitting in airports, I told the list I’d work it out and get back to them. So, thanks to a couple-hour delay at O’Hare, here it is.

The MultiMarkdown way of making footnotes follows the method described in this Markdown mailing list thread. It is apparently the format favored by John Gruber when he writes his Daring Fireball posts even though it hasn’t made its way into his version of Markdown yet. Basically, you stick [^x] at the point you want the footnote marker to appear, and [^x]: footnote text at the bottom of the document. The “x” between the square brackets can be any string of characters. The format is basically the same as that for reference-style links, but with the addition of the caret character (^), which cleverly suggests the superscript commonly used for footnote markers.

As with the reference-style link system, the footnote-making system consists of a command that inserts a snippet and a macro that calls the command.

First, we create a new command called “Footnote” in the Markdown category of the Bundle editor and insert the following Perl code:

#!/usr/bin/perl
use List::Util qw(max);

$text = $ENV{'TM_SELECTED_TEXT'};
$text = $text . "\n" unless substr($text, -1) eq "\n";

# Get the highest-numbered footnote.
@nums = $text =~ /^\[\^fn(\d+)\]: /mg;
$n = max(@nums) + 1;

# Escape special characters.
$text =~ s/([\$\\`])/\\$1/g;

# Insert the snippet.
print '[^${1:fn' . $n . '}]$0'.
       $text . '[^$1]: ${2:footnote}' . "\n\n";

This command assumes that all the text is selected from the point at which the footnote marker is to appear to the end of the file (that’s the $ENV{'TM_SELECTED_TEXT} part). Your Bundle Editor window should look like this:

(Click on the screenshot to see it full-sized.)

We now create a macro that makes that selection and calls the command. Start with a file that has some text and a couple of blank lines at the end. Then:

  1. Put the caret somewhere in the text. (At this point it doesn’t really matter where, but to get a feel of how the macro will work, you’ll probably want to put it where you want the footnote marker to appear.)
  2. Choose Start Macro Recording from the Automation menu.
  3. Press Command-Shift-Downarrow to select all the text from the caret to the end of the document.
  4. Invoke the Footnote command by choosing it from the little gear-like popup menu along the bottom of the TextMate window.
  5. Choose Stop Macro Recording from the Automation menu.
  6. Click anywhere in the document to deselect the footnote marker and interrupt the snippet.
  7. Press Command-Z to undo the snippet.

At this point, it’s probably best to test out the macro a few times by choosing Replay Scratch Macro from the Automation menu. When you’re convinced it’s working, choose Save Scratch Macro… from the Automation menu and save it with the name “Footnote” in the Markdown section. Use whatever Tab Trigger or Key Equivalent you like (I chose a Key Equivalent of Control-F) and set the Scope Selector to “text.html.markdown.” Your Bundle Editor window should now look like this:

To use the macro, put the caret where you want the footnote marker to appear and invoke the macro. The footnote marker, [^fn1], will appear at the caret position with the “fn1” selected and [^fn1]: footnote will appear at the bottom of the document. You can now type a new marker or just hit the Tab key to change the selection to the “footnote” text. When you’re done changing the footnote text another press of the Tab key will move the caret back to the end of the footnote marker. If you left the footnote marker as “fn1,” the next time you invoke the macro, the marker will be “fn2,” and the time after that it will be “fn3,” and so on. Please note that, as with the leading number in ordered list items, the number in your marker may not be the number that shows up in the HTML output.

There are two oddities you may be wondering about:

  1. Why [^fn1] and [^fn2] instead of just [^1] and [^2]?
  2. Why is there a blank line after each footnote?

The simple answer to both these questions is that MultiMarkdown won’t work otherwise. I haven’t looked into the code to see why, but MultiMarkdown doesn’t recognize footnote markers with just a single digit after the caret. And it also gets confused by multiple footnotes unless they’re separated by a blank line. My first thought is that restrictions are bugs in the implementation, but maybe there’s a good reason for them.

One more thing. If you start using footnotes and processing them through MultiMarkdown, you’ll soon find you need to create a “footnote” class in your CSS stylesheet. Otherwise, the footnote numbers will not be superscripted. And you’ll have to create a “reversefootnote” class if you want the footnotes themselves to have a different style (e.g., a smaller font size) than the regular body text.

Happy footnoting!

Tags: