If you haven’t seen Google Wave yet, you may want to watch this 10-minute demo or take a look at the official Wave site. Otherwise, this code won’t make a lot of sense. :-)

Figure: Real-time text annotation with Google Wave.

I received my developer sandbox account last week, and spent some time experimenting with Wave. So far, it seems like a really sweet tool—it’s fast (if you stay away from waves with 200+ messages), convenient, and fun to use. Wave isn’t yet ready for prime time, but it could be fairly solid in six months and widely deployed by this time next year.

After using Wave for less than a week, I really wish my friends and coworkers had accounts. This is a good sign.

Google has already released about 40,000 lines of Wave code as open source, and there’s apparently quite a bit more in the pipeline.

Extending wave with gadgets and robots

Wave supports two major kinds of extensions:

  1. Gadgets are interactive content that users can embed in a wave. In the demo, Google shows off a map gadget, a chess game, a handy “Yes/No/Maybe” poll, and many others.
  2. Robots are essentially a cross between IRC bots, text editor extensions, and web form processors. They can do anything another human could do, in real-time, as you type. They can also create and respond to HTML-style form elements.

So far, I’ve tried writing a robot in Java. (Why Java? Wave is built using Google Web Toolkit, which compiles Java to JavaScript. So right now, the Java libraries are slightly more mature than the Python libraries.)

buglinky reads your text as you type, and automatically links strings of the form “bug #123” to a bug tracker of your choice. It can also detect raw bug tracker URLs and replace them with the corresponding text.

Internally, buglinky is built around a custom BlipProcessor class that does all the heavy lifting. All I need to do is hook up my individual processors and run them:

ArrayList<BlipProcessor> processors =
  new ArrayList<BlipProcessor>();
processors.add(new BugUrlReplacer(BUG_URL));
processors.add(new BugNumberLinker(BUG_URL));
BlipProcessor.applyProcessorsToChangedBlips(
  processors, bundle, BOT_ADDRESS);

Here’s the code which links “bug #123” to the bug tracker:

class BugNumberLinker extends BlipProcessor {
  // ...constructor sets up bugUrl...

  protected String getPattern() {
    return "(?:[Bb]ug|[Ii]ssue|[Tt]icket|[Cc]ase) \#?(\\d+)";
  }
	
  protected void processMatch(
      TextView doc, Range range, Matcher match) {
    annotate(doc, range, "link/manual",
      bugUrl.concat(match.group(1)));
  }
}

Replacing URLs with plain text is similarly easy:

class BugUrlReplacer extends BlipProcessor {
  // ...constructor sets up bugUrl...

  protected String getPattern() {
    return Pattern.quote(bugUrl) + "(\\d+)";
  }

  protected void processMatch(
      TextView doc, Range range, Matcher match) {
    replace(doc, range, "issue #" + match.group(1));
  }
}

If you have a sandbox account, you can experiment with buglinky. You can also download the source code for buglinky from github.

Future directions

Obviously, this will look much better once somebody has the time to port it to JRuby. How about something like this?

match /#{Regexp.escape(bugUrl)}(\\d+)/ do
  replace "issue ###{$1}"
end

match /(?:[Bb]ug|[Ii]ssue|[Tt]icket|[Cc]ase) \#?(\\d+)/ do
  link(bug_url + $1)
end

Additionally, the current robot API relies on a JSON-RPC-based proxy between the Wave server and a robot. This is fine for processing entire waves in a single pass, but it uses too much bandwidth for real-time text processing. So I would love to be able to run this code inside a real wave server. But that will have to wait until the federation protocol is turned on.