This post should have been titled “What happens to my mornings.”

I get a lot of one-off requests for scripts and tips on how to handle tasks specific to people’s workflow or writing style. I generally keep myself pretty busy, so I usually reply with a quick idea or thought and leave it up to them to run with it. David Coleman emailed me this morning, though, with a request that struck me as an interesting enough idea to whip up a script before work.

What David wanted to do was take the idea behind my “Inline Links to References” command in the Markdown Service Tools and do something similar for footnotes, allowing him to write footnotes inline in a paragraph and have them converted before processing with MultiMarkdown. It’s not such a chore to skip a few lines and drop in the footnote syntax that this should be part of the spec, but it is something I would find handy in several situations. So…

The format I picked uses a syntax like this to denote a footnote:

This is the regular text(*This is the footnote*), and you can drop the footnote in at any point.

The Service can handle footnotes inside of lines, at the end of lines, spanning multiple lines with breaks (creates paragraphs) and does fine with Markdown within the footnote. One nice thing about this syntax is that–if you’re previewing as you write–it italicizes the output to differentiate it until you’ve used the service to move it out of the main text.

Multi-line footnotes need to begin at the end of a line of text, and just use double-newlines to separate paragraphs within the footnote, e.g.:

...the end of the paragraph. (*This is a footnote

which is going to span

more than one line*)

Here’s the script, also available as a Service download at the end of the post.

Update: I just added a fix (in code below and the Service download) for making sure that footnote reference titles aren’t duplicated if you have existing MultiMarkdown-formatted footnotes in the document.

#!/usr/bin/env ruby

def e_sh(str)
	str.to_s.gsub(/(?=[^a-zA-Z0-9_.\/\-\x7F-\xFF\n])/n, '\\')
end

input = STDIN.read

footnotes = input.scan(/\(\*(.*?)\*\)/m)
existing = input.scan(/^\[\^fn(\d+)\]: /i)
counter = existing.empty? ? 1 : existing.uniq.sort[-1].join.to_i + 1

output = []
footnotes.each {|note| 
	output << {'orig' => note[0], 'title' => "fn#{counter}", 'footnote' => note[0] }
	counter += 1
}

o = []
output.each_with_index { |x,i| 
	o.push("[^#{x['title']}]: #{x['footnote'].gsub(/\n\n(\s*.)/,"\n\n\t\\1")}")
	input.gsub!(/\(\*#{e_sh x['orig']}\*\)/m,"[^#{x['title']}]")
}
puts input.strip + "\n\n#{o.join("\n\n")}\n"

I’m in San Francisco for an AOL Tech code jam right now, so I don’t have a lot of time to thoroughly test this. Please let me know about any bugs that need fixing.

If you’re in San Francisco and like coffee or beer, hit me up on Twitter. If you’re here for Macworld, then you’d better be at my “40 Tips in 40 Minutes” talk with David Sparks and Merlin Mann on Thursday!

Convert Inline Footnotes Service v1.2

Convert inline footnotes in `(*Footnote to be created*)` format to MultiMarkdown footnotes.

Published 01/24/12.

Updated 01/24/12. Changelog

DonateMore info…