2010-04-03

Shaving cycles off your Firefox addon dev cycle

When developing Firefox extensions (like Greasemonkey), some of the best invested time you'll ever spend is on stuff making your change-restart-test cycle shorter, smoother and/or more convenient to you, whatever that looks like. Here are my own top suggestions:

  • As the Firefox extension model still requires a browser restart for many changes, make sure you at least don't have to repeat the messy part of packaging your xpi and installing it again over and over again (unless that is the part you are debugging at the moment).

    Reading the page on how extensions are installed on your operating system, replace the directory with your extension's guid with either a symlink to the directory where you develop your extension, or a file containing the path to it (if, say, you work on Windows with some file system that doesn't support symbolic links). Now you can edit your code, restart Firefox, and see the effect immediately without the extra steps of building an xpi and installing it every time you change something.

    (If your extension uses the more elaborate jar double zipping build procedure, my suggestion is "don't do that while developing", as doing more, invariable also takes more time and effort.)

  • Install the QuickRestart extension, as Firefox developers don't give you access to the crucial feature of restarting your session via keyboard hot key.

  • Check out the File menu and learn the hot key.

  • Some things can be updated without a browser restart, even in Firefox! (*) Set your development profile's about:config preference nglayout.debug.disable_xul_cache = true. <= this entire page is worth a read-through

  • Maybe you're poking around with things in an overlay in browser chrome and really just wish you could have a read-eval-print console into it, kind of like Firebug's. That's what MozRepl does. Install it, and now you can telnet or netcat into your browser session (from a terminal window, or maybe emacs), after focusing which window you want to have a prompt in.

  • If you are hacking on Greasemonkey specifically, and, say, poking with any of the stuff concerning gm_scripts and what is stored there, I suggest you cd into your gm_scripts directory, run git init, git add * and git commit -a -m 'Something descriptive' so you can revert to a prior state effortlessly with a git reset --hard before restarting, when your code changed something and you want to restart from a known earlier state.

That's all for today. Doubtlessly there are tons of other things that slim up the dev cycle. Feel free to post, or better still, link to other useful things to do. The docs at MDC are unfortunately too ill organized to easily strike gold there, so web pages that aggregate the nuggets are particularly valuable resources.

(*) Mozilla developers are hard at work making future extensions based on their (recently rebooted) Jetpack (SDK) project able to update without a browser restart, just like Greasemonkey scripts or Google Chrome extensions can. Any year now.

2010-01-13

$Revision$ keyword expansion with git-svn

I just ended up needing to do subversion keyword expansion on a bunch of files in a subversion repository I track with git, but git-svn doesn't do that kind of thing. So I hacked up a tiny shell script I called git-svn-keyword-expand, which looks like this:
#! /bin/zsh
typeset -A revs
files=($@)
for n in {1..$#files} ; do
f=$files[$n]
h=$(git log -n 1 --pretty=format:%H -- $f)
revs[$h]=${revs[$h]-$(git svn find-rev $h)}
perl -pi -e 's/\$Revision[ :\d]*\$/\$Revision: '${revs[$h]}' \$/gp' $f
done

Just feed it a list of files, and it'll update them in place to whatever current revision they are at. It's a rather dumb tool, which doesn't cross reference the file list with which of those files actually have an svn:keywords property including Revision in it, and it doesn't do any other keywords, but people that want that kind of thing might at least grab this as a starting point. Cheers!

2010-01-12

Current state of HTML5 storage events

In attempting to put HTML5 storage to use for cross-window configuration synchronization purposes, I just performed some tests on what works how in different browsers, and how it relates to the not-yet-frozen HTML5 specs, which at present declare that storage events should work like this:

On changing a value in localStorage (running localStorage.setItem(), localStorage.removeItem(), or localStorage.clear(), and presumably their javascript setter / deletion conveinence API:s, where supported), an e.type === "storage" event should be fired in all other windows open to the same domain (e here being the event object seen by the event listener). (No specific mention forbids firing the same event in the same window, too, but it seems to be the intent to avoid that, to me, and is also the behaviour I would prefer myself.)

When an assignment (localStorage.setItem()), the e.key property should be the name of the key, the e.oldValue its former value, and e.newValue its new value.

When a deletion (localStorage.removeItem()), e.newValue should instead be the null value.

When a clear all event (localStorage.clear()), e.key, e.oldValue and e.newValue should all be the null value.

No browser seems to do quite that yet, but Safari and Chrome are at least rather close. My tests have covered Firefox 3.5.7, Safari 4.0.4 (6531.21.10), WebKit 4.0.4 (6531.21.10, r53119), Google Chrome 4.0.249.49 (35163) beta, Chromium 4.0.267.0 (34084), all on MacOS X (10.6). They all ignore which window triggered the storage event (= fire the event in all applicable windows).

Firefox, sadly, never provides either of the three properties mentioned above.

Chrome, Chromium, Safari and WebKit all provide all three, but instead of setting the e.key to null for the clear event, it gets set to the empty string. The rest works beautifully, though.

Whether the clear event fires when clearing an already empty localStorage varies a little -- Firefox and Safari will, the others don't.

Neither browser fires events when deleting an already deleted value, but Firefox fires events when setting a property to the same value it already had (the others don't).

I spent a minimal amount of time peeking at what IE8 does and how, but didn't get it working. It supposedly supports at least the localStorage function-calling API, according to MSDN. The tests above may miss something subtle, maybe with how to use attachEvent instead of the W3C standard addEventListener (don't ask me why they still don't support that).