My Org Elisp webservice

org going mobile

originally published in September 2014

During the last months I spent a lot of time using Emacs, growing more and more fond of it. The main responsible for that is certainly org-mode, one of Emacs' killer applications. I progressively switched to org-mode for almost everything: taking notes, todo lists and agenda, keeping a journal, and so on.

One missing part of my setup, compared to what I've been using earlier, is the capability to take notes with my mobile phone. There's MobileOrg, but so far my attempts to obtain a working setup have failed. I eventually decided to write my own very simple version.

I have basic needs: just a form that allows me to enter the description of a task I need to perform. I want this scrap of text to be appended in a special org file that I can later manage when I'm at my desk, moving it in the org file where it belongs.

My initial intention was to write (probably in Perl) a very simple web app showing an input box to the user, then just appends what the user wrote to a particular file (let's say mobile-notes.org). This particular file would then be synced with other machines using Dropbox, which is already running -as Emacs does- on my remote servers.

It could certainly work, but I wanted something more, for example being able to apply tags or todo keywords directly, using the configuration I wrote for org-mode. I need a way to make Emacs talk to the outer world, precisely a way to pass informations to a web application. Being Emacs, the question is not "Can I do it?", but "How can I do it?".

It turns out, as I expected, that Emacs has a web server package that I can exploit for my needs: Elnode.

I started for a personal need, but I'm sharing it in case someone can actually find it useful. Moreover, as it's my first Emacs Lisp project (I knew that point was bound to happen) I can't rule out the possibility I'm violating some best practices: comments and critiques are most welcome!

First, a little bit of configuration:

(defvar moew:org-dir "/home/larsen/Dropbox/org")
(defvar moew:org-filename "mobile-notes.org")
(defvar moew:port 8002)

And a utility function to return the absolute filename for the Org file where the app saves the new items.

(defun moew:org-complete-filename ()
  (format "%s/%s" moew:org-dir moew:org-filename))

Here comes the interesting part, the definition for the dispatch table that maps URIs to function names. httpcon is the name of a variable containing a data structure with the HTTP connection details. Here is used so that elnode-hostpath-dispatcher can read the path.

(defun moew:main-handler (httpcon)
  (elnode-hostpath-dispatcher
     httpcon
     `(("^.*//form"     . moew:form)
       ("^.*//keywords" . moew:keywords)
       ("^.*//save"     . moew:save))))

moew:form simply serve a static html file (you can find the complete source in the github project for moew).

(defun moew:form (httpcon)
  (elnode-http-start httpcon 200 '("Content-type" . "text/html"))
  (elnode-send-file httpcon "form.html"))

moew:keywords is slightly more interesting. It serves (in JSON, thanks to json-encode, a function in the json package) a representation of the particular org-todo-keywords sequence.

(defun moew:keywords (httpcon)
  (elnode-send-json httpcon
                    (json-encode (cdr (car org-todo-keywords)))))

And the most important function. I use elnode-http-param on httpcon to fetch the params coming from the form, then I pass them to the function that produces the actual line that is appended (append-to-file) to the org file configured before. Eventually, a respose message is sent to the client.

(defun moew:save (httpcon)
  (let ((todo-item-body (elnode-http-param httpcon "text"))
        (todo-item-keyword (elnode-http-param httpcon "keyword")))
    (append-to-file 
     (moew:todo-item-complete-text todo-item-keyword todo-item-body)
     nil (moew:org-complete-filename))
    (elnode-send-json httpcon (json-encode "ok"))))

Other tools

My solution is admittedly very simple, perhaps too simple (and the example described here certainly lacks basic safety checks and error handling). Other tools you might consider are

  • MobileOrg, a /"open source iPhone and iPod Touch application for storing, searching, viewing and editing your Org-mode files"/;
  • There's also a MobileOrg implementation for Android;

Further thoughts

One might object I'm bending too much the infamous versatility of Emacs. I would have certainly said the same a few weeks ago, but I think Nic Ferrier -author of Elnode- eloquently illustrated a different and interesting point of view here.

The right reason to use Emacs is that it's a tool for building editing tools. VIM is a superior editor out of the box for nearly every conceivable editing task. But Emacs, with only a little customization, is soon just as good. And just as good specifically for you. And with a little more customization it's absolutely specifically your tool, crafted to your hands. Just like any master craftsmen the best programmers make their own tools. VIM users tend to make those tools out of the Unix shell. But in Emacs we think we have a better solution, a more flexible solution. Sometimes we can use the Unix way, sometimes we can use other methods.

Even with my limited experience, I subscribe it.

Author: Stefano Rodighiero

Created: 2019-12-31 Tue 12:15

Validate