hardscrabble 🍫

Psst. Check out my RubyConf 2017 talk, There are no rules in Ruby.

An Alfred Workflow for adding the frontmost Firefox tab to OmniFocus with AppleScript

13 Jul 2014

Saw a link about using tools to take long-lasting tabs out of your browser and put them somewhere useful like Evernote or OmniFocus rather than let them tax your mind and memory. I wanted in.

Sadly, there was only support for Chrome and Safari, not Firefox, which I continue to stubbornly prefer. I assumed at first this was simply a reflection of Firefox not being particularly popular among Mac users1 and resolved to patch the gap.

In order to interact with your running Mac applications, people often use AppleScript, a kind of strange programming language that comes with Macs and lets you script or automate user tasks. So whenever I want to close a tab without forgetting that it might matter somehow, I have to do these steps manually:

Imagine having two dozen tabs open and kind of wanting to do that for each of them? Prime candidate for automation!

Given that this is my first AppleScript, I’m bizarrely confident that I can figure this out. I assume I can just ask Firefox for the list of currently open URLs, write some kind of loop, and then send OmniFocus a bunch of messages (in the background maybe) and have it all just work easily. Pretty quickly I learn that, unlike Safari and Chrome, Firefox exposes nothing to AppleScript. It’s scriptable insoafar as every app is scriptable – you can perform user actions like clicking and typing, but it doesn’t expose anything nicely, and Mozilla’s bugtracker has multiple tickets dating back several years of people saying they wish Firefox supported AppleScript without much movement as far as I can tell.

No worry! I’ll find some clever solution. I open AppleScript Editor and start trying to figure out how to even do any of this.

tell application "FirefoxNightly" # I'm using the nightly build, and I have to specifically say so
  activate # this opens or switches to the application
end tell

a digression about running AppleScripts

You can write small things like this in the AppleScript Editor app and run them from there. This is what I was doing while writing the thing and tinkering. But it’s not a great interface, really, as far as text editors go. Another option is to use the texteditor of your choice and run it from the terminal by writing osascript your_file.scpt. There’s something kind of trippy about running something like this, and seeing your operating system react:

[hardscrabble] [hardscrabble.net] [my-first-applescript branch]
⇥ osascript -e 'display alert "hello world"'
button returned:OK

Later on you can use tools like Alfred to run your scripts from anywhere at any time.

back to struggling with this code

So if Firefox doesn’t expose anything to us, how can we get the list of tabs open? I went down a few dead ends. I spent several minutes trying to make a bookmarks group of the currently opened tabs, then export the bookmarks, then parse the exported file before I realized I was definitely going the wrong way and I definitely didn’t know how to do parse JSON in AppleScript.

After a little more googling I came upon a comment on Bugzilla which provides a way to get the current page’s URL at least. Here’s how:


tell application "FirefoxNightly"
  activate
  delay 2 # sleeps 2 seconds because idk... it doesn't work otherwise
  tell application "System Events"
    tell process "firefox"
      keystroke "l" using {command down} # ⌘+l is the keyboard shortcut to focus on the address bar
      keystroke "c" using {command down} # ⌘+c copies the current URL to the clipboard
      set tabUrl to get the clipboard    # stores the clipboard in a variable
    end tell
  end tell
end tell

display alert tabUrl

Yikes… AppleScript is interesting because it’s an awkward, not fun language but also super powerful if you’re a kind of nerdy Mac power user, or maybe even developer who wants to harness the power of GUI applications in their project. Fortunately the next major version of OS X, Yosemite, has a JavaScript API for doing all the same stuff. This might be my last AppleScript too, because of that.

Now that I have the URL I want to do something better than display an alert. Some googling points me to a 2012 MacSparky blog post about AppleScripting with OmniFocus. The language is still awkward (set theProject to first flattened project where its name = "Finance"), but this is significantly better than Firefox because it exposes an API at all. Since then, there’s been a major 2.0 update to OmniFocus, but I guess they made an effort to maintain consistency because these examples still work. I don’t really blame Mozilla because they’re maintaining applications across every operating sytem that will support them and are very consistent. In fact I wish there existed OmniFocus for Linux but, like, lol. Everyone compromises!

OK so I can get the current URL and add a task to OmniFocus. A little more digging and this is what I came up with:

tell application "FirefoxNightly"
  activate
  set taskTitle to name of front window

  tell application "System Events"
    tell process "firefox"
      keystroke "l" using {command down}
      keystroke "c" using {command down}
      set taskNote to get the clipboard
    end tell
  end tell
end tell

tell application "OmniFocus"
  tell quick entry
    open
    make new inbox task with properties {name:taskTitle, note:taskNote}
  end tell
end tell

It’s kind of a dinky version of what I originally wanted to make. It’s only for the current tab, and when it’s done the quick entry panel is still open (by design: so I can still edit the details).

I packaged it as an Alfred Workflow here so I can invoke it from wherever by typing ⌘+space and then just writing tab.

I wonder if this is useful to other people!

  1. Recently on the Accidental Tech Podcast I was surprised to hear the hosts be super harsh to Firefox. This tweet makes the argument that Firefox isn’t relevant anymore and I don’t really know if that’s true, but I think it should be.