Blogging with TextMate and Chromium/Chrome

September 28, 2010

Early this year I wrote a long piece titled Blogging with TextMate, and using AppleScript and JavaScript to ease the pain, which described a way to kind of automate the generation of linkblog-type posts using TextMate. That post was written with Safari/WebKit in mind, and this post provides a similar solution for Chromium/Chrome. (For the specifics of how to actually run all of this stuff using FastScripts, etc., please see the previous post; the only difference between the Safari and Chrome methods is the below AppleScript.)

Let's start with the final code, and then I'll explain how I got there.

tell application "System Events"
    set prevClip to (the clipboard as text)
end tell

tell application "Chromium"
    copy selection of (active tab) of window 1
    set pageURI to (get URL of (active tab) of window 1)
    set pageTitle to (get title of (active tab) of window 1)
end tell

tell application "System Events"
    set selectedText to (the clipboard as text)
end tell

property LF : ASCII character 10 -- Unix  \n

tell application "TextMate"
    activate
    open "/path/to/file" & (random number from 1 to 1000000) & ".txt"
    set post to "Title: " & pageTitle & LF
    set post to post & "Slug: " & LF
    set post to post & "Pings: Off" & LF
    set post to post & "Comments: Off" & LF
    set post to post & "Category: posts" & LF & LF
    set post to post & "[" & pageTitle & "]"
    set post to post & "(" & pageURI & ")." & LF & LF
    if prevClip is not equal to selectedText then
        set post to post & "> " & selectedText & LF & LF
    end if
    insert post
end tell

(Obviously if you're using Chrome, you'll want to replace "Chromium" in the above script with "Google Chrome.")

First of all, I had a hell of a time figuring out how to reference the active tab (i.e., the one to which you're trying to link; see the longer post referenced above). Turns out that Chromium's active tab property can't be used without identifying what window it's in (even though, obviously, only a single tab can be active at any given time), and window IDs are based on overlay order, not the order in which they were created. It took me a while to figure all of this out, but once I did the rest was fairly simple. Unfortunately, it took me even longer to determine how to get selected text from Chromium into TextMate via AppleScript.

For the Safari solution I used a combination of do JavaScript and AppleScript objects/commands provided by Safari. Turns out that Chromium now has a class similar to do JavaScript called execute, but I couldn't get it working to save my life, and part of me is convinced that it actually isn't fully functional just yet. (I can't tell you for sure because there's next to nothing on the web about using AppleScript with Chromium/Chrome.) Thus, I had to find another solution.

I noticed that Chromium had a copy selection class and started working through it. After some trial and error I realized that copy selection didn't return anything (unlike getSelection() via Safari's do JavaScript) — it just copied the selection (in this particular case, from the current tab) and placed it on the system clipboard.

At this point I knew I could use AppleScript to pull the selected text from the clipboard and into TextMate. Great! But, what about when I don't want to quote any part of the article and thus don't select any text? Because copy selection always grabs the last thing placed on the clipboard (no matter its origin), you'll end up getting whatever was last put there even if you aren't selecting text when it's invoked (and obviously will have to spend some time deleting this irrelevant content from your draft post). Given that copy selection doesn't return anything, there's no simple way to check whether anything actually was copied, and thus no way to determine if the text currently on the system clipboard should be incorporated into your post.

To get around this I grab the text on the system clipboard before and after running copy selection, and then compare the two strings. If they aren't equal, then some text definitely was selected and so the clipboard content is added to the post. If they are equal, then no text was selected and the clipboard content is ignored.

You should follow me on Twitter here