Use a function, Luke

Volume 3, Issue 31; 05 Nov 2019

Sometimes I’m reminded how nice Emacs lisp is, mosty because it’s lisp.

I’ve been playing with org-brain. I wanted notes to use in the experiment, so I converted some data that I’d been storing elsewhere into Org mode. Some of those notes are about places, with geospatial coordinates like this: 37.506805,-122.24738.

I wanted to make those into OpenStreetMap links. I spent a few minutes trying to work out whether it would be easier to do this in Emacs by writing some elisp or just doing it with a script. (Well, there’s no question it’d be easier for me with a script, but I like to keep my hand in elisp programming.)

Org Mode has a handy syntax for links. This markup:

Check out [[][my homepage]].

Is rendered in my emacs buffer as:

Check out my homepage.

And a quick C-c C-l on that link will open it up in a browser.

What’s even better is that I can configure shortcuts. For example, I can configure it so that [[bug:12345]] renders as “bug:12345” and links to bug 12345 without me having to type the whole URI. Here’s a configuration that makes [[dd:docbook]] a shortcut for

("dd" . "")

The OpenStreetMap syntax I want to generate is:{LAT}&mlon={LNG}&zoom={ZOOM}

which isn’t just the coordinates stuck on the end or injected in the middle. It’s going to be necessary to parse the coordinates to generate the link.

That’s when it struck me, in lisp, code and data are delightfully intertwingly. In many cases, where you can put a string can also put a function. And this is one of those places! This configuration:

("geo" . geo-to-openstreetmap)

And this function:

(defun geo-to-openstreetmap (coords &optional zoom)
  "Parse COORDS into an OpenStreetMap link. The format of COORDS
is lat,long[/znum]. If ZOOM is specified, it overrides znum."
  (let* ((geo (split-string coords "/" t "[\s]+"))
         (latlong (split-string (car geo) ",[\s\t]*" t "[\s]+")))
    (concat ""
            (car latlong)
            (car (cdr latlong))
            (if zoom
              (if (cdr geo)
                  (car (cdr geo))

Does the trick. Now [[geo:37.506805,-122.24738][OpenStreetMap]] is a link: OpenStreetMap.