Rephrase the link to MobileOrg for Android
[Worg.git] / org-tutorials / org-protocol-custom-handler.org
blob65cbe32b101701ac3f2fcec17bb3a3d8f7bad40f
1 #+OPTIONS:    H:3 num:nil toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t TeX:t LaTeX:t skip:nil d:(HIDE) tags:not-in-toc
2 #+STARTUP:    align fold nodlcheck hidestars oddeven lognotestate
3 #+SEQ_TODO:   TODO(t) INPROGRESS(i) WAITING(w@) | DONE(d) CANCELED(c@)
4 #+TAGS:       Write(w) Update(u) Fix(f) Check(c)
5 #+TITLE:      Defining custom handlers for use with org-protocol
6 #+AUTHOR:     Sebastian Rose
7 #+EMAIL:      sebastian_rose gmx de
8 #+LANGUAGE:   en
9 #+PRIORITIES: A C B
10 #+CATEGORY:   worg-tutorial
12 [[file:index.org][{Back to Worg's tutorial index}]]
14 org-protocol intercepts calls from emacsclient to trigger custom actions without
15 external dependencies. Please refer to [[file:../org-contrib/org-protocol.org][this file]] for the basic setup required.
17 You might want to watch the [[http://www.youtube.com/watch?v=h7Z2PiAcgh8][screencast]] on youTube.
20 * Defining custom handlers
22   =org-protocol= scanns the list of filenames passed to the emacs-server for
23   "=org-protocol:/sub-protocol:/=" and triggers actions assossiated with
24   =sub-protocol= through the custom variable =org-protocol-protocol-alist=.
26   To defun a custom org-protocol handler basically means to define two basic
27   elements:
29   1. a sub-protocol that triggers the action
30   2. a function that consumes the data (i.e. the part of an URL that follows
31      "=org-protocol://sub-protocol://=")
33   To install the custom handler's protocol, we add an entry to
34   =org-protocol-protocol-alist=:
36 #+begin_src emacs-lisp
37 (add-to-list 'org-protocol-protocol-alist
38              '("Hello World"
39                :protocol "hello-world"
40                :function my-hello-world))
41 #+end_src
43   The =:protocol= property is the sub-protocol, that triggers the action. Note,
44   that names of protcols (or URL schemas) are only allowed to consist of a
45   restricted set of characters. See [[http://www.ietf.org/rfc/rfc1738.txt][rfc1738]], section 2.1.
47   The =:function= is an arbitrary function that takes exactly one argument: the
48   string that follows our protocol, found in a filename passed to emacs through
49   emacsclient. All the three standard handlers split and decode that string
50   using a helper function in =org-protocol.el=:
52 #+begin_src emacs-lisp
53  org-protocol-split-data (data &optional unhexify separator)
54 #+end_src
56   You may use different separators for your custom handlers and pass them to
57   =org-protocol-split-data=.
61   Here is a simple definition:
63 #+begin_src emacs-lisp
64 (defun hello-world (data)
65   "Say hello to the world."
66   (message data)
67 nil)
68 #+end_src
70   Now the URL =org-protocol://hello-world://encoded-data= will call our fuction
71   with the string "=encoded-data=". Hence an
73   : emacsclient org-protocol://hello-world://encoded-data
75   will put "=encoded-data=" into the minibuffer.
78 * Killing the client
80   If your handler uses interactive functions that could be canceld by the user
81   by typing '=C-g=', consider to supply the '=:kill-client=' property when you
82   define the protocol.
84   This is what we did for the capture handler:
86   #+begin_src emacs-lisp
87     (defconst org-protocol-protocol-alist-default
88       '(("org-capture" :protocol "capture"
89          :function org-protocol-capture
90          :kill-client t)
91         ;; ...
92         ))
93   #+end_src
95   Otherwise, if the user has an interactive property defined in her capture
96   template, discarding it through '=C-g=' would leed to emacsclient waiting for
97   ever, thus to the appropriate questions when exiting emacs.
99   All filenames passing from emacsclient to the emacs will be ignored if you
100   set =:kill-client= to a non-nil value.
103 * Return values
105   Note, that our =hello-world= handler explicitly returns =nil=. This tells
106   =org-protocol= to remove the filename from the list of files passed to the
107   emacs-server. If more than one filename was supplied, all those filenames are
108   searched for protocols. Only filenames without protocolls are passed to the
109   emacs-server as usual.
111   Another possible return value is a string. If the string is a valid filename,
112   and if that file can be read, =org-protocol= replaces the original filename with
113   the one returned from the handler.
116 * Using more than one value
118   Passing one argument to our custom handler is nice, but sometimes more
119   parameters are needed. We would have to encode the the data and split it into
120   parts using a separator.
122   This is where =org-protocol-split-data= comes into play. It takes a string as
123   its first argument, an optional parameter to tell if the string should be
124   considered URL-encoded UTF-8 text and finally an optional separator. By
125   default, no URL-encoding is assumed and '=/=' is used as the separator.
127   The return value is a list of strings. If a non-nil value is supplied as the
128   second argument, each elements of the returned list will be URL-decoded using
129   =org-protocol-unhex-string=. If the second argument is a function, that function
130   is used to decode each element of the list. The function should take a string
131   as it's only parameter, and return the decoded value [fn:1].
133   This is a rewrite of our handler:
135 #+begin_src emacs-lisp
136 (defun hello-world (data)
137   "Say hello to the world."
138   (let* ((parts (org-protocol-split-data data nil '::my-separator::'))
139          (one (car parts))
140          (two (cadr parts))
141          (three (caddr parts)))
142     ;; ... do something with one, two and three
143     )
144   nil)
145 #+end_src
148 * Using more than one value /the greedy way/
150   Finally, it is possible to define a /greedy/ handler. Basically it will discard
151   _all_ the filenames from the servers list of files that follow the filename that
152   triggered the handler.
154   A handler is greedy, if you add the =:greedy= property to
155   =org-protocol-protocol-alist=, regardless of it's return value:
157 #+begin_src emacs-lisp
158 (add-to-list 'org-protocol-protocol-alist
159              '("Greedy"
160                :protocol "greedy"
161                :function my-greedy-handler
162                :greedy t))
163 #+end_src
165   The one argument to greedy handlers is the rest of the list of filenames, the
166   one that triggered the handler included. But read on, please.
169 ** The list of filenames
171    Here I have to admit, that I was lying all the time. emacsclient does not
172    pass a list of filenames to the emacs-server. It's a list of lists. And the
173    list is the list of emacsclient's arguments reversed.
175    As an example, the following commandline:
177    : emacsclient org-protocol:/greedy:/one two three +15:42
179    is passed as
181    : ((/dir/three (15 . 42)) (/dir/two) (/dir/org-protocol:/greedy:/one))
183    to the emacs-server, where =org-protocol= grabs it and reverses it to make it
184    look like this:
186    : ((/dir/org-protocol:/greedy:/one) (/dir/two) (/dir/three  (15 . 42)))
188    This is now, what our greedy handler will receive as it's only parameter.
190    The "=/dir/=" prefix is added by emacsclient. It's the absolute path to its
191    working directory.
193    You may set =org-protocol-reverse-list-of-files= to =nil= to inhibit the
194    reversion. But that leads to unexpected results. In this example, the only
195    filename left would be the one that triggered the actions. That seems not
196    very greedy, and reversing the arguments on the commandline seems
197    unnatural. Note though, that the sequence is not changed for the server.
200 ** Flatten the list of arguments
202    =org-protocol.el= provides a function to flatten the list of arguments for
203    greedy handlers:
205    : org-protocol-flatten-greedy (param-list &optional strip-path replacement)
207    This function takes the list of lists your greedy handler gets as its only
208    parameter, and turns it into a flat list. Also, all prefixes and protocols
209    are stripped from the element that triggered your handler.
211    This is, what the first parameter might look like:
213    : (("/dir/org-protocol:/greedy:/one") ("/dir/two") ("/dir/three" (15 . 42)))
215    If only the first parameter is supplied, =org-protocol-flatten-greedy= will
216    return this list:
218    : ("/dir/one" "/dir/two" "/dir/three" 15 42)
220    If you supply a non-nil value as the second parameter for the function:
222    : ("one" "two" "three" 15 42)
224    And, last not least, if you supply a replacement "=REPL-=" (must be a string):
226    : ("REPL-one" "REPL-two" "REPL-three" 15 42)
228    Note, that this works exactly this way regardless of your setting of
229    "=org-protocol-reverse-list-of-files=". The sequence of the returned list will
230    always reflect the sequence of arguments on the command line.
232 * General remarks
234   emacsclient compresses double and tripple slashes to one. That's why it
235   doesn't really matter how many slashes succeed the scheme part of the URL,
236   also known as /protocol/.
238   This behaviour is the main reasons, why the slash was choosen as the
239   default separator for data fields. Keeping the slashes is insecure, since some
240   of the data fields could contain double or tripple slashes themselves.
244 * Footnotes
246 [fn:1]  The function feature was added with the Org-mode 6.26 release (commit
247         6a9acfa9a3ec4ad889951d02c9809f55ac7491fb).