org-contribute.org: Add Alan D. Salewski to TINYCHANGE committers
[worg.git] / org-tutorials / org-protocol-custom-handler.org
blob729ff30b9d1f78800529072e3b9a4e5a676cd485
1 #+TITLE:      Defining custom handlers for use with org-protocol
2 #+AUTHOR:     Sebastian Rose
3 #+EMAIL:      sebastian_rose gmx de
4 #+OPTIONS:    H:3 num:nil toc:t \n:nil ::t |:t ^:t -:t f:t *:t tex:t d:(HIDE) tags:not-in-toc
5 #+STARTUP:    align fold nodlcheck hidestars oddeven lognotestate
6 #+SEQ_TODO:   TODO(t) INPROGRESS(i) WAITING(w@) | DONE(d) CANCELED(c@)
7 #+TAGS:       Write(w) Update(u) Fix(f) Check(c)
8 #+LANGUAGE:   en
9 #+PRIORITIES: A C B
10 #+CATEGORY:   worg-tutorial
12 # This file is released by its authors and contributors under the GNU
13 # Free Documentation license v1.3 or later, code examples are released
14 # under the GNU General Public License v3 or later.
16 [[file:index.org][{Back to Worg's tutorial index}]]
18 org-protocol intercepts calls from emacsclient to trigger custom actions without
19 external dependencies. Please refer to [[file:../org-contrib/org-protocol.org][this file]] for the basic setup required.
21 You might want to watch the [[http://www.youtube.com/watch?v=h7Z2PiAcgh8][screencast]] on youTube.
24 * Defining custom handlers
26   =org-protocol= scans the list of filenames passed to the emacs-server for
27   "=org-protocol:/sub-protocol:/=" and triggers actions associated with
28   =sub-protocol= through the custom variable =org-protocol-protocol-alist=.
30   To defun a custom org-protocol handler basically means to define two basic
31   elements:
33   1. a sub-protocol that triggers the action
34   2. a function that consumes the data (i.e. the part of an URL that follows
35      "=org-protocol://sub-protocol://=")
37   To install the custom handler's protocol, we add an entry to
38   =org-protocol-protocol-alist=:
40 #+begin_src emacs-lisp
41 (add-to-list 'org-protocol-protocol-alist
42              '("Hello World"
43                :protocol "hello-world"
44                :function my-hello-world))
45 #+end_src
47   The =:protocol= property is the sub-protocol, that triggers the action. Note,
48   that names of protocols (or URL schemes) are only allowed to consist of a
49   restricted set of characters. See [[http://www.ietf.org/rfc/rfc1738.txt][rfc1738]], section 2.1.
51   The =:function= is an arbitrary function that takes exactly one argument: the
52   string that follows our protocol, found in a filename passed to emacs through
53   emacsclient. All the three standard handlers split and decode that string
54   using a helper function in =org-protocol.el=:
56 #+begin_src emacs-lisp
57  org-protocol-split-data (data &optional unhexify separator)
58 #+end_src
60   You may use different separators for your custom handlers and pass them to
61   =org-protocol-split-data=.
65   Here is a simple definition:
67 #+begin_src emacs-lisp
68 (defun hello-world (data)
69   "Say hello to the world."
70   (message data)
71 nil)
72 #+end_src
74   Now the URL =org-protocol://hello-world://encoded-data= will call our function
75   with the string "=encoded-data=". Hence an
77   : emacsclient org-protocol://hello-world://encoded-data
79   will put "=encoded-data=" into the minibuffer.
82 * Killing the client
84   If your handler uses interactive functions that could be canceled by the user
85   by typing '=C-g=', consider to supply the '=:kill-client=' property when you
86   define the protocol.
88   This is what we did for the capture handler:
90   #+begin_src emacs-lisp
91     (defconst org-protocol-protocol-alist-default
92       '(("org-capture" :protocol "capture"
93          :function org-protocol-capture
94          :kill-client t)
95         ;; ...
96         ))
97   #+end_src
99   Otherwise, if the user has an interactive property defined in her capture
100   template, discarding it through '=C-g=' would lead to emacsclient waiting for
101   ever, thus to the appropriate questions when exiting emacs.
103   All filenames passing from emacsclient to the emacs will be ignored if you
104   set =:kill-client= to a non-nil value.
107 * Return values
109   Note, that our =hello-world= handler explicitly returns =nil=. This tells
110   =org-protocol= to remove the filename from the list of files passed to the
111   emacs-server. If more than one filename was supplied, all those filenames are
112   searched for protocols. Only filenames without protocols are passed to the
113   emacs-server as usual.
115   Another possible return value is a string. If the string is a valid filename,
116   and if that file can be read, =org-protocol= replaces the original filename with
117   the one returned from the handler.
120 * Using more than one value
122   Passing one argument to our custom handler is nice, but sometimes more
123   parameters are needed. We would have to encode the the data and split it into
124   parts using a separator.
126   This is where =org-protocol-split-data= comes into play. It takes a string as
127   its first argument, an optional parameter to tell if the string should be
128   considered URL-encoded UTF-8 text and finally an optional separator. By
129   default, no URL-encoding is assumed and '=/=' is used as the separator.
131   The return value is a list of strings. If a non-nil value is supplied as the
132   second argument, each elements of the returned list will be URL-decoded using
133   =org-protocol-unhex-string=. If the second argument is a function, that function
134   is used to decode each element of the list. The function should take a string
135   as its only parameter, and return the decoded value [fn:1].
137   This is a rewrite of our handler:
139 #+begin_src emacs-lisp
140 (defun hello-world (data)
141   "Say hello to the world."
142   (let* ((parts (org-protocol-split-data data nil '::my-separator::'))
143          (one (car parts))
144          (two (cadr parts))
145          (three (caddr parts)))
146     ;; ... do something with one, two and three
147     )
148   nil)
149 #+end_src
152 * Using more than one value /the greedy way/
154   Finally, it is possible to define a /greedy/ handler. Basically it will discard
155   _all_ the filenames from the servers list of files that follow the filename that
156   triggered the handler.
158   A handler is greedy, if you add the =:greedy= property to
159   =org-protocol-protocol-alist=, regardless of its return value:
161 #+begin_src emacs-lisp
162 (add-to-list 'org-protocol-protocol-alist
163              '("Greedy"
164                :protocol "greedy"
165                :function my-greedy-handler
166                :greedy t))
167 #+end_src
169   The one argument to greedy handlers is the rest of the list of filenames, the
170   one that triggered the handler included. But read on, please.
173 ** The list of filenames
175    Here I have to admit, that I was lying all the time. emacsclient does not
176    pass a list of filenames to the emacs-server. It's a list of lists. And the
177    list is the list of emacsclient's arguments reversed.
179    As an example, the following commandline:
181    : emacsclient org-protocol:/greedy:/one two three +15:42
183    is passed as
185    : ((/dir/three (15 . 42)) (/dir/two) (/dir/org-protocol:/greedy:/one))
187    to the emacs-server, where =org-protocol= grabs it and reverses it to make it
188    look like this:
190    : ((/dir/org-protocol:/greedy:/one) (/dir/two) (/dir/three  (15 . 42)))
192    This is now, what our greedy handler will receive as its only parameter.
194    The "=/dir/=" prefix is added by emacsclient. It's the absolute path to its
195    working directory.
197    You may set =org-protocol-reverse-list-of-files= to =nil= to inhibit the
198    reversion. But that leads to unexpected results. In this example, the only
199    filename left would be the one that triggered the actions. That seems not
200    very greedy, and reversing the arguments on the commandline seems
201    unnatural. Note though, that the sequence is not changed for the server.
204 ** Flatten the list of arguments
206    =org-protocol.el= provides a function to flatten the list of arguments for
207    greedy handlers:
209    : org-protocol-flatten-greedy (param-list &optional strip-path replacement)
211    This function takes the list of lists your greedy handler gets as its only
212    parameter, and turns it into a flat list. Also, all prefixes and protocols
213    are stripped from the element that triggered your handler.
215    This is, what the first parameter might look like:
217    : (("/dir/org-protocol:/greedy:/one") ("/dir/two") ("/dir/three" (15 . 42)))
219    If only the first parameter is supplied, =org-protocol-flatten-greedy= will
220    return this list:
222    : ("/dir/one" "/dir/two" "/dir/three" 15 42)
224    If you supply a non-nil value as the second parameter for the function:
226    : ("one" "two" "three" 15 42)
228    And, last not least, if you supply a replacement "=REPL-=" (must be a string):
230    : ("REPL-one" "REPL-two" "REPL-three" 15 42)
232    Note, that this works exactly this way regardless of your setting of
233    "=org-protocol-reverse-list-of-files=". The sequence of the returned list will
234    always reflect the sequence of arguments on the command line.
236 * General remarks
238   emacsclient compresses double and tripple slashes to one. That's why it
239   doesn't really matter how many slashes succeed the scheme part of the URL,
240   also known as /protocol/.
242   This behavior is the main reasons, why the slash was chosen as the
243   default separator for data fields. Keeping the slashes is insecure, since some
244   of the data fields could contain double or triple slashes themselves.
248 * Footnotes
250 [fn:1]  The function feature was added with the Org-mode 6.26 release (commit
251         6a9acfa9a3ec4ad889951d02c9809f55ac7491fb).