I finally got access to a Google Wave sandbox account, making it possible to start experimenting. The first thing I made was a Latex robot. By adding the robot, it’s possible to write Latex in Waves. Afterwards, simply by putting Latex between two $’s:
$$\lim_{n \to \infty} \frac{1}{n} = 0$$
Watexy then changes the Wave and inserts the Latex as an image instead of the text.
You can try it yourself by adding watexy [this-funny-curly-a] appspot.com to your Wave-conversations. You can download the source here.
There’s still a quite big bug: It’s only the first Latex-image that gets substituted correctly. The following gets inserted some positions wrong, and the deletion of the text isn’t correct neither. But the images itself are correct, only the substitution isn’t working properly. But I’m working on that!
The more technical part: the robot is written in Python, hence using the Google Wave Python API. It’s the first time I’ve tried that (thought it was a good possibility to learn it). The robot basically works by getting triggered when a new blip is submitted. Then it searches for Latex-code in that and substitutes it with pictures. Although the code is quite simple, it shows some very basic concepts on how to alter/change the contents of Waves on-the-fly (deleting text and inserting images, but it could be other things as well) with robots. The Latex-source-to-image is done by the http://www.forkosh.dreamhost.com/source_mathtex.html#webservice service.
The core Python comprising the robot is this:
# Python reference:
# http://wave-robot-python-client.googlecode.com/svn/trunk/pydocs/index.html
# Shortcut to the important OpBasedDocument
# http://wave-robot-python-client.googlecode.com/svn/trunk/pydocs/waveapi.ops.OpBasedDocument-class.html
"""
Known bugs:
- From (and including) the second Latex-fragment, the positioning gets wrong
> Probably the document needs some kind of updatering
> Even though it's a bit strange since the re matches all the Latex correctly
"""
__author__ = 'mikl@mikl.dk (Mikkel Meyer Andersen)'
import re
from waveapi import events
from waveapi import model
from waveapi import robot
from waveapi import document
def OnRobotAdded(properties, context):
"""Invoked when the robot has been added."""
root_wavelet = context.GetRootWavelet()
root_wavelet.CreateBlip().GetDocument().SetText("Hi. My name is Watexy and I'm here to help you presenting Latex in waves. Just put the latex between $$ and $$, e.g. $$2+2=5$$. This robot uses the http://www.forkosh.dreamhost.com/source_mathtex.html#webservice service.")
def OnBlipSubmitted(properties, context):
"""Invoked when a blip has been added."""
blip = context.GetBlipById(properties['blipId'])
blip_text_view = blip.GetDocument()
latex_regex = re.compile('\$\$(.+?)\$\$')
m = latex_regex.search(blip_text_view.GetText())
"""
Only replace one Latex-fragment at a time, because replaceing one fragment
changes the text positions in the rest. That's why re.finditer isn't used.
"""
while m != None:
"""
The +/- 2 is because of the length of the $$'s.
If not removed, the loop will run infintely!
"""
blip_text_view.DeleteRange(document.Range(m.start(1)-2, m.end(1)+2))
image = document.Image('http://www.forkosh.dreamhost.com/mathtex.cgi?' + m.group(1), caption=m.group(1))
blip_text_view.InsertElement(m.start(1)-2, image)
m = latex_regex.search(blip_text_view.GetText())
if __name__ == '__main__':
myRobot = robot.Robot('watexy',
image_url='http://watexy.appspot.com/assets/icon.png',
version='9',
profile_url='http://watexy.appspot.com/')
myRobot.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded)
myRobot.RegisterHandler(events.BLIP_SUBMITTED, OnBlipSubmitted)
myRobot.Run()