Open Tweet Links in Tweetbot with LaunchBar

I really went off the rails with this one.

The morning started with experimenting in Keynote to see if it had the tools I needed to make some animations for a video project I’m putting together. Before too long I discovered a bug with the Magic Move feature when applied to two text slides. Looking for a solution led me to this old tweet from Jake Wharton. The tweet didn’t offer a solution, but it was nice to see that he ran into the exact same problem I had. After I came up with a hacky fix, I wanted to ask Jake if he ever found a good solution.

Finally, the meat of this post!

No way I was going to use the Twitter website to post my reply to Jake’s tweet. I’ll do it in Tweetbot for Mac, thank you very much. But how to open this specific tweet ID in Tweetbot? There doesn’t seem to be a way to punch a Tweet ID into Tweetbot. But there is a Tweetbot URL scheme that will accomplish the goal. All I had to do was replace the portion of the tweet’s URL with tweetbot:// and that tweet would open up in Tweetbot. Brilliant!

Enter LaunchBar

Rather than get back to what I was supposed to be doing this morning, I figured there had to be a way to use LaunchBar to make this task easier. In other words, how could I have LaunchBar do the following:

  1. Take in a URL for a specific tweet
  2. Confirm that it is a valid tweet URL
  3. Transform the URL to Tweetbot’s format
  4. Open the transformed URL in the default browser (which in turn would open the tweet in Tweetbot)

Turns out, once you dig into the LaunchBar Action docs a bit, it is pretty simple. So let’s walk through it.

Making a simple LaunchBar Action

  1. Open the LaunchBar Action Editor (Hint: use LaunchBar to open the Action Editor)
  2. Give it a name such as Open Tweet URL in Tweetbot (Bonus: set the Action Icon to com.tapbots.TweetbotMac)
  3. Create a new Action (the + button in the bottom left of the window)
  4. Set JavaScript as the language for the Default Script.
  5. Check the boxes for Requires argument and Accepts string argument
  6. Edit the default.js file (the Edit button in the upper right of the window)
  7. Replace the template code that LaunchBar gives you with the following:
function run(argument) {
  var regex = /^https?:\/\/(www.)?\//
  // make sure that we passed in something, ANYTHING, to the action
  if (argument == undefined) {
    LaunchBar.alert('No argument was passed to the action');
  // make sure we passed in a valid Twitter URL
  if (argument.match(regex) != null && argument.match(regex).index === 0) {
    // replace the `` with `tweetbot://`
    argument = argument.replace(regex, "tweetbot://")
    // now just tell LaunchBar to open the tweetbot URL
  } else {
    LaunchBar.alert('It appears that\n`' + argument + '`\nis not a valid Twitter URL')

That’s all there is to it. A little regular expression magic and knowing how to tell LaunchBar to show alerts and open URLs is all this takes. This is far from a robust script. If you pass it a valid URL to a specific tweet in Twitter, such as, it’ll work. But it’ll choke and silently fail with a lot of other types of URLs.

It’s on GitHub

So you can grab the .lbaction package from there instead of building it yourself.

A new discovery


If you have this Action installed, you can just send a tweet URL directly to Tweetbot itself and it will open. The magic is in the Runtime Behavior > Associated Application field. Because it’s set to com.tapbots.TweetbotMac, LaunchBar will pass the tweet URL on to this Action if you send the URL directly to Tweetbot. 🔥🔥🔥

Solarized Light EPH


I made a tweaked version of the Solarized Light .tmTheme and posted it to GitHub. You can think of it as Solarized Light, with a tasteful sprinkling of italics and a few enhancements when editing Markdown.

I always come back to using Solarized Light in my editor. When I use a darker theme, it’s usually Cobalt2 by Wes Bos. I really like how Wes uses italics in his theme and I wanted the same kind of thing in Solarized Light. This is my attempt at it. It’s working for me. Perhaps you’ll like it, too. Give it a shot.


It's almost like they dropped the same photo of Mike Mykytok into two different scenes.
It’s almost like they dropped the same photo of Mike Mykytok into two different scenes.

I went down the Google rabbit hole and ended up looking at the list of past U.S. 10,000m champions. The name Mike Mykytok jumped out at me. It’s a name I hadn’t heard or seen since 1997 yet it was instantly familiar. I’m not sure why. My best guess is that I was paying very close attention to the U.S. 10,000m scene in 1997. That’s the year I ran the race at the Junior National meet. Or maybe I saw him run a good 10K at Stanford around that time. Or because he was a former Junior National champ at 10,000m and for nearly two years of high school and college I was focused on doing the same thing.

Who knows. Point is, running forms are like finger prints, aren’t they?

Bad UX: T-Mobile Online Payment

The Problem

The NEXT button is in the wrong place. By being on the far left of the screen, it implies BACK while its label reads NEXT. Cognitive dissonance makes me sad.

The NEXT button is in the wrong place
The NEXT button is in the wrong place

The Fix

Move the NEXT button to the far right, and make the button a little bit bigger while we’re at it.

Buttons that move you forward in a process should be on the right, at least when dealing with languages that read left to right.
Buttons that move you forward within a process should be on the right, at least when dealing with languages that read left to right. Buttons that cancel the process or move you backwards should be on the left.

Running Swift from the command line

A few months back I wrote a fairly simple Swift command line app in Xcode. The app did some Core Graphics drawing and saved the results to a PDF in the user’s Documents directory. The project consisted of a single main.swift file. Running it from with Xcode worked great. The PDF was created and saved to disk.

Today, I tried running either the uncompiled main.swift file or the compiled command line app from the command line with the following results:

$ ./main.swift
./main.swift:102:27: error: 'init(CGContext:flipped:)' is only available on OS X 10.10 or newer
    let graphicsContext = NSGraphicsContext(CGContext: context!, flipped:false)
./main.swift:102:27: note: add 'if #available' version check
    let graphicsContext = NSGraphicsContext(CGContext: context!, flipped:false)
./main.swift:102:27: note: add @available attribute to enclosing global function
    let graphicsContext = NSGraphicsContext(CGContext: context!, flipped:false)

Even though I’m running this on OS X 10.11 and even though this runs just fine from within Xcode, it’s complaining that I’m trying to use a bit of API that might not be available.

Solution #1

The app kicks off by calling a function called drawPDF(). It’s within that function that the call to NSGraphicsContext(CGContext: context!, flipped:false) is made. So the first way to get this to work is to make sure the offending code isn’t executed on a pre-10.10 system. In this case, I’ll use a guard statement at the top of the function that will skip the entire function if the user isn’t on 10.10 or newer:

func drawPDF() {
    guard #available(OSX 10.10, *) else {return}
    // ... the rest of the function ...

This allows the file to be run from the command line, but then Xcode flags that line with a warning: Unnecessary check for 'OSX'; minimum deployment target ensures guard will always be true. Yes, my Xcode project requires at least OS X 10.11, so Xcode is pointing out that I don’t need this check because we are guaranteed to always be running at OS 10.11. That’s a little annoying and I’m sure there’s a project setting to silence this kind of warning. But I’m not a big fan of silencing warnings. So this is an imperfect solution.

Solution #2

Add a @available attribute on the function that makes the potentially problematic API:

@available (OSX 10.10, *)
func drawPDF() {
    // ... the rest of the function ...

This doesn’t quite work because running from the command line now complains that I’m calling drawPDF() and that function requires at least OS X 10.10. So I have to do an if #available check before calling it:

if #available(OSX 10.10, *) {

And with that, it works great at the command line, but I get another one of those warning from Xcode telling me that I’m doing an unnecessary #available check.


I’m not sure what the best/correct solution is. These both work but I don’t like the warnings in Xcode. ¯\_(ツ)_/¯

Safari can’t find the server `localhost`

The Problem

I’m running the latest version of MAMP (3.4) on my Mac running the latest version of OS X (10.11.3). When I nav to localhost:8888/, Safari gives me the following message:

Safari can’t find the server.

Safari can’t open the page “localhost:8888” because Safari can’t find the server “localhost”.

It works just fine in Chrome and Firefox. And I swear this worked a few months ago in Safari.

I can get Safari to connect to MAMP using or lapalapa.local:8888 (lapalapa is my Computer Name as set in System Preferences > Sharing). But that workaround isn’t ideal. I would really like localhost:8888 to just work as it should so that my local install of a WordPress site I’m working on loads in Safari.

The Solution

Are you f’ing kidding me? Restarting my Mac fixed it. I wonder if just killing Safari would have fixed it.


`sass –watch` Not Watching

Seems that sass --watch is not actually seeing changes made to .scss files. Running the command does the initial scss-to-css conversion just fine, but doesn’t seem to actually be watching for changes.

$ sass --watch scss:css
>>> Sass is watching for changes. Press Ctrl-C to stop.
      write css/main.css
      write css/

Also, I have to hit ⌃-C twice to stop, at which point it spits out a bunch of error messages:

$ sass --watch scss:css
>>> Sass is watching for changes. Press Ctrl-C to stop.
      write css/main.css
      write css/
^C^C/Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/celluloid-0.16.0/lib/celluloid/proxies/cell_proxy.rb:55:in `thread': Interrupt
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/celluloid-0.16.0/lib/celluloid/actor.rb:96:in `join'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/celluloid-0.16.0/lib/celluloid/actor_system.rb:79:in `block (2 levels) in shutdown'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/celluloid-0.16.0/lib/celluloid/actor_system.rb:77:in `each'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/celluloid-0.16.0/lib/celluloid/actor_system.rb:77:in `block in shutdown'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/2.2.0/timeout.rb:88:in `block in timeout'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/2.2.0/timeout.rb:32:in `block in catch'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/2.2.0/timeout.rb:32:in `catch'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/2.2.0/timeout.rb:32:in `catch'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/2.2.0/timeout.rb:103:in `timeout'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/celluloid-0.16.0/lib/celluloid/actor_system.rb:66:in `shutdown'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/celluloid-0.16.0/lib/celluloid.rb:156:in `shutdown'
    from /Users/erikhansen/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/celluloid-0.16.0/lib/celluloid.rb:145:in `block in register_shutdown'

So I installed Ruby 2.3.0 (I was using 2.2.3) just to get a fresh start.

$ rbenv install 2.3.0
$ rbenv global 2.3.0

Then I installed Sass again: $ gem install sass

Then, when running sass --watch I got some new output about a [Listen warning]::

$ sass --watch scss:css
>>> Sass is watching for changes. Press Ctrl-C to stop.
      write css/main.css
      write css/
[Listen warning]:
  Listen will be polling for changes. Learn more at

Made a change to my .scss file, and it worked!

>>> Change detected to: scss/main.scss
      write css/main.css
      write css/

Also, I only had to hit ⌃-C once to quit.

So I’m back in business, but I still want to figure out how to fix this while still using Ruby 2.2.3, just for kicks.

Another oddity: After installing Compass under my fresh Ruby 2.3.0 install, everything still worked, but when I ran the sass --watch command I no longer got the [Listen warning]: but everything worked like it should:

$ sass --watch scss:css
>>> Sass is watching for changes. Press Ctrl-C to stop.
>>> Change detected to: scss/main.scss
      write css/main.css
      write css/

So far this isn’t a great solution. “Just blow everything away and start fresh” is basically like giving up. But if all else fails, it might work for you.

TextMate-style selections in Atom or Sublime

One of the features I miss from TextMate is the ability to convert a multi-line selection into a column selection by simply tapping on the ⌥ (Option/Alt) key. 99% of the time I used this create multiple cursors without anything selected. The following animated GIF should explain what I mean. I’m using the keyboard to select multiple lines and then I tap ⌥ to convert my selection into a bunch of cursors stacked on top of each other.

TextMate - Toggle Column Selection

Both Atom and Sublime have a command to convert a selection into multiple lines “Selection > Split into Lines” and it’s mapped to ⇧⌘L by default. This almost does what I want. It gives me multiple selections, but it doesn’t give me a nice stack of cursors the way TextMate does.

To get the same thing TextMate gives me with a simple tap of the ⌥ key, I have to hit:

  1. ⇧⌘L
  2. ⌘→
  3. ⌘←

Yes, I could just hold ⇧⌃ and tap the up or down arrows to create a stack of cursors right where I want them. And there are still times when I do this in Atom or Sublime. I have two issues with creating the column of cursors this way: First, my muscle memory is wired to make a selection first and then convert to cursors or selections. Secondly, the ⇧⌃↓ method is less forgiving; if you overshoot, you have to start the process over over.

Okay, so let’s try to get that TextMate-style behavior working in Atom or Sublime.

First, grab a copy of Karabiner and install it. Karabiner will allow us to remap a single tap of the Option key to a sequence of keyboard commands while in Atom or Sublime. Karabiner has tons of other features that I’m not going to mention here. At the very least, you should look into using it to set up a Hyper Key on your Mac.

In Karabiner, do the following:

  1. In the Misc & Uninstall tab, hit the Open private.xml button.

  2. That will open a Finder window with the private.xml so you can easily open it in your text editor.

  3. If you’re using Atom, enter the following <item> node within the <root>:

      <name>Tap left Option to convert selection to multiple cursors in Atom</name>
        KeyCode::OPTION_L, ModifierFlag::OPTION_L,
        KeyCode::L, ModifierFlag::COMMAND_L | ModifierFlag::SHIFT_L,
        KeyCode::CURSOR_RIGHT, ModifierFlag::COMMAND_L,
        KeyCode::CURSOR_LEFT, ModifierFlag::COMMAND_L

    For Sublime, the important difference is the <only> node:

      <name>Tap left Option to convert selection to multiple cursors in Sublime</name>
      <only>SUBLIME TEXT</only>
        KeyCode::OPTION_L, ModifierFlag::OPTION_L,
        KeyCode::L, ModifierFlag::COMMAND_L | ModifierFlag::SHIFT_L,
        KeyCode::CURSOR_RIGHT, ModifierFlag::COMMAND_L,
        KeyCode::CURSOR_LEFT, ModifierFlag::COMMAND_L
  4. Save private.xml. Back in Karabiner, in the Change Key tab, hit the Reload XML button.

  5. Finally, in Karabiner, make sure your new option, either “Tap left Option to convert selection to multiple cursors in Atom” or “Tap left Option to convert selection to multiple cursors in Sublime”, is checked.

This works the way I want it to. Most of the time. There are times when I want to create a column of stacked cursors in the middle of lines of text. In that case, this hack doesn’t work because the column of cursors always ends up at the start of the lines. Totally copying the TextMate behavior might be possible with a custom Atom plugin.

Adding GPS Data to Maplets

I had really high hopes that Maplets would be great for hiking in Portland. Sadly a key component of the app is really half-baked.

My complaint is rooted in the fact that the maps I tried did not have GPS data baked in. Without GPS data, the maps are basically useless for hiking. I want to have the map on my phone and be able to fire up my phone’s GPS to show where I am on the trail. A common use-case, I think.

A map without GPS data is no big deal, though, because the Maplets website lets you add GPS data to any of their maps. This is where the problems start. Specifically, I wanted to edit the GPS data for the Portland Forest Park map. Before I visited the Maplet GPS Editor to see how it works, I assumed you could simply drop points on the map and set the GPS coordinates for those points. GPS data for all other points on the map could be interpolated from the data you gave it.

No such luck.

What you actually have to do is perfectly align the Maplet map layer over Google Maps. If you have to rotate the Maplet map layer for any reason, which I did for Forest Park because North does not point directly up, you need to turn on Google Earth mode. That’s problem number one because the Google Earth plugin is basically dead. 64-bit Chrome and Safari both don’t support the 32-bit Google Earth plugin. By the way, there are no warnings about this in Chrome or on the Google Earth plugin page. The plugin just doesn’t work. Safari gives you a fairly useless error message when you try to use the plugin. However, the plugin does still work in Firefox. Yipee.

So in Firefox I now have the unenviable task of aligning the Maplet map of Forest Park over the Google Earth view of Forest Park and its surrounding area. This is maddening. You can get it fairly close, but it’s impossible to get perfect. Why? For starters, the Google Earth plugin area is too small on the webpage to work with comfortably. Getting the alignment right is an endless cycle of:

  • zooming in to check alignment
  • then possibly zooming out and repositioning the map so you can adjust the Maplet layer position on Google Earth
  • if you want to scale the Maplet layer, you have to zoom out or reposition the map to find a Maplet layer handle to drag to adjust the scale

Repeat those three steps endlessly. And add in rotation adjustments from time to time.

Beyond that slow and painful workflow, I had to two other big issues. First, I really needed to use the Full Res version of the Maplet map, not the Thumbnail version. There isn’t enough visual info in the thumbnail to be sure it’s aligning properly. But the full res version is ~20MB and took forever to load from Maplet’s server. So I gave up on that. I suspect that trying to work with a 20MB layer overlay in the Google Earth plugin would prove difficult anyway. Second, the only way to scale the Maplet layer is by dragging the handles of the Maplet layer. In addition to forcing you to zoom out enough to see a handle, there is zero precision with this method. It’s impossible to adjust the size in small amounts. Once I discovered that, I gave up on setting the GPS data and gave up on Maplets entirely.

Animated GIFs in Twenty Sixteen

UPDATE Shortly after initially posting this, I discovered that Photon, part of Jetpack, was to blame for the animated GIF issues.

Embedding animated GIFs into Twenty Sixteen makes them look awful. (I just checked and the same issue happens with Twenty Fifteen and Twenty Fourteen.) I’m telling WordPress to embed the full size, original image. But that’s too large to fit in the template so they are scaled down with CSS. I’d guess that the CSS scaling was to blame, but you can totally scale the same animated GIFs with CSS in a simple HTML page and it works just fine. What am I doing wrong?

Native size is 1444x896, embedded at full size, looks awful
Native size is 1440×896, embedded at full size, looks awful
This animated GIF is 720x448 and also looks horrible
This animated GIF is 720×448 and also looks horrible