Monday, July 2, 2018

My Tabhunter Decade


Inspiration can strike in strange places. Most of my ideas hit me in the usual spots, like during a 2-wheeled commute, in the shower, or suddenly in bed at 2 in the morning. But about ten years ago it happened at a suburb of Vancouver in an area that had been forest and farms when I was growing up, and was now gleaming towers and a brand new astroturf field.

See, I have a daughter who had taken up field hockey, and I happily ferried her and some team members to whichever field they were on that particular Saturday.

On weekdays I was working on a project where we were using Bugzilla to track everything -- bugs, features, chores: it was all in there. Bugzilla search was its usual taciturn self, saying "Zarro Boogs" regardless of what I put in the query box, so I adapted by simply never closing any tab that I had an interest in. I tried to group the tabs in particular windows based on some logical taxonomy, but too often when I was looking for something I'd end up listing all open bugs, and then searching by firefox search to find the bug I was looking for. I also tended to memorize issue numbers and would type them out in the address bar, to the amusement of one of my co-workers who is now a product manager on Firefox.

I wasn't really thinking about my tab management situation at that Coquitlam turf field, but at one point early in the game I watched one of the field-hockey fathers (a species not as well-known as soccer moms, but with better taste in beer), break away from our group and go mingle with the parents of the girls on the other team. How does this guy from Virginia know all these people from Coquitlam, I wondered? Oh right, he was the American consul to Vancouver at the time, and was doing what you'd expect a professional diplomat would be good at: mingle with pretty much anyone.  And then I was struck by a bolt on how to deal with my tab problem:

I would write a Firefox extension, and I would have to call it "Tabhunter".

Firefox extensions had been around for a few years, and I had been working on a product that was built on Mozilla, so I was familiar with the tech. Greasemonkey had been around for 4 years, launched in late 2004. AdBlock Plus was about 2 years old.  O'Reilly's "Firefox Hacks" came out in 2005. This wasn't exactly a new field, by industry standards. So that was my third bolt from the blue: it was about time I published my own extension as a side-project.

As for the name, I knew about the B-movie actor named Tab Hunter from the early 1960s because John Waters revived his career with three movies that came out some 25 years later: Polyester, Lust in the Dust, and the first Hairspray (the one with Divine, not John Travolta). I didn't know much about Tab, and back in those days there was no wikipedia to look things up, and I doubt there'd be much information on him in the Robarts library, U of Toronto's hulking brutualist peaon to book storage. But I knew he was a washed-up actor who Waters figured would be the perfect foil for Devine (an oversized cross-dressing actor (hard to use language when talking about him that isn't going to offend _someone_ -- hey, it was the '80s)).

Robarts Library, the concrete goose named after the Ontario premier John, not the actor Jason

Polyester was brilliant, especially with its use of "Odorama". We were each handed a card with 12 brightly colored circles. When a number flashed on the screen, that was the signal to scratch the appropriate number and sniff your fingers. Like when the florist shows up at Divine's door with a bouquet of flowers. We won't know how the movie holds up without Odorama until the internet of smells is completed.





The name also was highly appropriate in a personal way. My last big side project involved applying the Kevin Bacon game to Amazon.com's "people who bought X also bought these 10 items".  I called the site "The Amazing Baconizer", and killed it off when I was getting more traffic from hackers than users.  But I was always looking with half-open eyes for another fun project with a pop culture name.

Developing the extension didn't take that long -- I had been working with the classic DOM API and Mozilla specifics for almost a decade, and knew enough CSS to make sure the extension didn't look horrible. In those days you had to get a review from a core member of the Mozilla project before it was accepted in the add-ons site. I recall my reviewer said the code was surprisingly good for a first timer.  It could have been better, but it worked for me, helping me deal with 400 open tabs at a time instead of the previous limit of 200. Another extension, Bar Tab, kept most of my tabs unloaded. So I had access to the main details of each tab, but didn't have to have it loaded.

The field hockey season is short here - early April though early June, and I shipped in late June, so I can see I didn't procrastinate on this project.

The launch was fun. My favorite memory is the write-up in Gina Trapani's Lifehacker blog. Half the comments were from people who couldn't imagine having more than 6 or 8 tabs up at a time, and the other half were from people who couldn't believe an extension like mine shipped with every copy of Firefox. Plus a few shoutouts from people who also remembered Tab "space" Hunter, and thought the name was great.

Once the inevitable post-release bugs were fixed, I did almost nothing with the code until I had to perform a major rewrite to be compliant with Mozilla's new "Electrolysis" framework for Firefox, around 2014. The old framework was single-process, and my extension had direct access to everything it needed. The main part of Electrolysis was that the scripts of all the loaded web pages would run in one process, and the internal part, called chrome (the source of Google Chrome's name) would run in another process. The two processes would communicate via message-passing.

Tabhunter had always been open-source, but it was a typical open-source project in the way that apart from a couple of trivial pull-requests, I was doing all the work. This took a few weekends, and it wasn't a fun API to work with.

And then last year Mozilla announced that it was going to stop supporting all extensions based on current frameworks and APIs, and support only extensions using the new WebExtensions API, which would be more-or-less compatible with Chrome's API. This also meant rewriting the UI in standard HTML; previously the extensions were written in an XML-based UI-description language called XUL, which I was actually more comfortable with than basic HTML. You want to build a tree-widget in XUL, there's a tag for that, with sub-elements. You want to do that in HTML, you need to research a bunch of widget frameworks. Fortunately, Tabhunter doesn't have any tree widgets.

Once again I found a spare weekend to rewrite the add-on, and found the new WebExtensions API was straightforward to use, well documented, and performed really well. I also decided to try the browser-polyfill JS library and got Tabhunter running in Chrome, after all these years.

Also I discovered that someone had shipped a similar extension with a similar name (theirs has a space) to the Chrome store. It looks like a one-time thing -- it's still on version 0.0.1, only searches titles, and is missing all kinds of other useful features.

Since the current API is like an industry-standard, and feels more stable than anything before it, I started tackling all the feature requests and bug-reports that had built up over the years. My attitude had been that Tabhunter is an open-source project and I have always welcomed pull request submitters and even collaborators.  But I knew many of my users weren't developers and would have no ability to scratch their own itches.

And almost everything went easily. Some of my favorite new features are highlighting duplicate tags (so if you see an orange line, you can delete it, as the first one will be in black text); selecting only the tabs that are blaring audio; and, on Firefox only, sorting tabs by what I call Neglect, which is the duration since a tab was last viewed. On my home machine I saw I had a few tabs that were 14 months old, from when I went to a talk on writing your own bot. If I hadn't looked at those tabs since then I wasn't going to write a bot anytime soon. Goodbye, natural-language-processing tabs.

Also, I worked out a decent build system to make it as easy as possible to target both Firefox and Chrome.  It's all driven from a Makefile, and the goal is that you should be able to download the source (from https://github.com/ericpromislow/tabhunter/), run make, and end up with two zipfiles, one for each browser.  About half the source files are .erb files, written in Ruby's preprocessor, and that lets me disable features in Chrome, like the aforementioned Neglect feature. Along those lines, there's no need to load browser-polyfill.min.js into the Firefox build, so it's loaded conditionally for the Chrome builds only.  Yes, the only use of Ruby is in the build system. I could have used EJs, but I'm not a purist, and welcomed this surreptitious introduction of Ruby into the build system.  I can run make after development, go to the Mozilla dashboard and load the firefox extension from the same directory, and then go do the Chrome dashboard and load a new version of a Chrome-compatible extension from the same directory as the previous version. I can upload both versions within 5 minutes after testing a new release.

As for Tabhunter's namesake, I hoped to get a testimonial from Tab Hunter himself for the launch. I found an 'info@tabhunter.com' address and wrote to it, but never heard anything. He's still around, and was even the subject of a 2015 documentary called "Tab Hunter Confidential". I proposed a meetup of the Vancouver Tabhunter Users Group in the lobby before or after the show, but was out of town the day it showed in town, and never heard if anyone attended.  That's how we tab horders are -- quietly trying to deal with our internal demons, and closing tabs whenever we can.

No comments: