Let me begin by saying that I endeavored initially to get this working with Google Chrome (my main browser these days), but because Chrome’s AppleScript support currently is very minimal, it just wasn’t possible. In light of that I chose to at least proof-of-concept the idea with Safari/WebKit so that I can later use this post to inform my solution for Chrome (and so others can take advantage of this now if they happen to use Safari). (Update: I’ve come up with a solution for Chrome.)
A few weeks ago I decided I had to have support for Markdown syntax highlighting in my blogging client, which at the time (and for many years prior) was MarsEdit. After coming to terms with the fact that such highlighting just wasn’t going to happen in MarsEdit (any time soon), I set out to find another solution, and quickly remembered that TextMate (which may be my favorite application of all time) came out with a blogging bundle many years ago. After watching the screencast, running some tests and creating a couple of blogging templates, I very quickly was using TextMate to write and publish.
Doing all of my blogging with TextMate these past few weeks has been great, except for one terribly annoying thing, namely the inability to quickly conjure up a linked-list-type post. I was having to manually — gasp — create these (usually) quick, simple posts. I don’t necessarily need speed when starting long-form blog posts like the one you’re currently reading, but for the more frequent linked-list posts I definitely do. I need/want something that amounts to little more than a keyboard shortcut. MarsEdit has spoiled me over the years with its simple bookmarklet that grabs the data I need (i.e., page title, page URI and any currently-selected text), drops it into a new post (see my MarsEdit template below, formatted for Markdown) and populates the
Title field with the title of the page.
[pageTitle](pageURI). > selectedText (Via ().)
Obviously then I wanted an equal or less amount of friction when doing similar operations via TextMate. (For long-form stuff I created a new blogging template that has all the fields I need for a non-linked-list post, so I can just go to
File > New From Template > Blogging > Blog when I want to start writing a longer piece). While I was able to get some of the aforementioned bookmarklet’s functionality in Chrome via a combination of (a service using) Automator and AppleScript (i.e.,
Service receives selected text in Google Chrome together with some AppleScript to act on the selected text), it was limited to just the highlighted text (i.e., no page title, URI, etc.), which made the process only slightly better (if not worse) than just doing everything manually. It was at this point I resigned trying to get this to work with Chrome and moved on to Safari/WebKit.
(Note: if you use Safari you’ll want to change WebKit to Safari.)
Once I had the critical information, I needed to figure out how to get all of it into a new post within TextMate. If you watched the blogging bundle screencast or previously have blogged with TextMate, you know that various post-specific elements are set in a header at the top of each file (where each file corresponds to a particular post). For my linked-list posts, this header looks like the following:
Title: Slug: Pings: Off Comments: Off Category: bits
To automate the inclusion of these headers in a new file (to be created when the script is set in motion), I had to create a new template for the blogging bundle (
Bundles > Bundle Editor > Show Bundle Editor). (You can use the blogging templates that exist already as guides to creating your own.) After setting that up, I whipped up the following code to click on the correct menu item within TextMate so that a new file gets created using the new template.
tell application TextMate activate tell application System Events tell process TextMate tell menu bar 1 tell menu bar item File tell menu File tell menu item New From Template tell menu New From Template tell menu item Blogging tell menu Blogging click menu item Template end tell end tell end tell end tell end tell end tell end tell end tell end tell end tell
(Template in the above code is whatever you named the template you created.) It’s ugly, I know, but it gets the job done (and besides, I ended up not using it; keep reading). Now, each time I invoke the script I get a new file with proper headers and set to the desired bundle type (in my case, Markdown). However, I ran into a slight problem when attempting to insert the title, URI and selected text at their correct positions within the file (e.g.,
pageTitle should be inserted as so: Title:
pageTitle). I tried using AppleScript to move around within the document (using variations on the code below, which was to move the cursor to the right by seven spaces), but no dice. I struggled for a while with this and ultimately just had to convince myself that a solution probably wasn’t worth the time (though I’m certain it’s possible).
repeat 7 times keystroke (ASCII character 129) using command down end repeat
In light of my unsuccessful cursor positioning, I attempted to tackle the problem from another angle, and decided I could just create the headers with AppleScript instead of relying on the template from the blogging bundle. At this point there were three ways to move forward: 1) create a blank template and use it as described above (minus headers); 2) use TextMate’s built-in URL scheme that allows you to open local files with TextMate from within other applications (e.g., Safari via AppleScript); or 3) use AppleScript to cause TextMate to open a local file directly.
Option 1 should be fairly self-explanatory given the discussion so far. For option 2 you’ll want to tell Safari to run the following command within your script.
open location txmt://open/?url=file://~/path/to/local/file
The local file referenced above is one you will have created and saved, and to which you will have assigned the desired bundle type so that the syntax highlighting is correct. You’ll want to keep this file empty, because each time you invoke your script the proper headers and other relevant information will be auto-inserted. In my case, I never need to save this file (i.e., when creating a new post) because I’m only using this setup for my linked-list posts, which I publish almost as soon as I create; given this, the file always is blank, and therefore ready to receive the stuff I want to insert.
Option 3 is the route I chose for my implementation, because it’s the most straightforward (and because option 2 creates a new blank tab that I didn’t feel like figuring out how to kill). With option 3 you simply tell TextMate to open the local file.
open file path).
(LF corresponds to the Unix linefeed character.)
I launch the script using FastScripts (specifically, I use
option-b), but obviously you can just access the Script menu in the menu bar if you’re OK with being a little less efficient. 😉
As I noted at the beginning of this piece, this solution works beautifully in Safari/WebKit, but I currently use Chrome. Hopefully Chrome’s AppleScript support soon will be as robust as Safari’s, but something tells me that that probably is the last thing on the team’s mind right now. If and when sufficient support is there, I’ll be sure to update this code and this post.