1 #+TITLE: org-protocol.el -- Intercept calls from emacsclient to trigger custom actions
2 #+OPTIONS: H:3 num:nil toc:t \n:nil @:t ::t |:t -:t f:t *:t TeX:t LaTeX:t skip:nil d:(HIDE) tags:not-in-toc ^:{} author:nil
4 #+SETUPFILE: ../macros.setupfile
5 #+STYLE: <script type="text/javascript">
6 #+STYLE: <!--/*--><![CDATA[/*><!--*/
7 #+STYLE: function makeUrl() {
8 #+STYLE: return encodeURIComponent(location.href)+
9 #+STYLE: '/'+encodeURIComponent(document.title)+
10 #+STYLE: '/'+encodeURIComponent(window.getSelection());
12 #+STYLE: function storeLink() {
13 #+STYLE: document.location.href='org-protocol://store-link://'+makeUrl();
15 #+STYLE: function remember() {
16 #+STYLE: document.location.href='org-protocol://remember://'+makeUrl();
18 #+STYLE: function capture() {
19 #+STYLE: document.location.href='org-protocol://capture://'+makeUrl();
24 [[file:index.org][{Back to Worg's contibutions index}]]
26 org-protocol intercepts calls from emacsclient to trigger custom actions without
27 external dependencies. Only one protocol has to be configured with your external
28 applications or the operating system, to trigger an arbitrary number of custom
29 actions. Just register your custom sub-protocol and handler with the variable
30 `org-protocol-protocol-alist'.
33 * About org-protocol.el
35 =org-protocol.el= is based on code and ideas from [[file:./org-annotation-helper.org][org-annotation-helper.el]] and
38 "=org-protocol:/sub-protocol:/=" triggers actions associated with =sub-protocol=
39 through the custom variable =org-protocol-protocol-alist=.
41 It comes with four predefined handlers:
42 - =org-protocol-store-link= ::
43 triggered through the sub-protocol "=store-link=". Stores an Org-link and
44 pushes the URL to the =kill-ring=.
45 - =org-protocol-capture= ::
46 Fill a =CAPTURE= buffer with information gathered somewhere else. This
47 handler is triggered through the "=capture=" sub-protocol and uses the
48 function =org-capture=.
49 - =org-protocol-remember= ::
50 Fills a remember buffer with information gathered somewhere else. This
51 handler is triggered through the "=remember=" sub-protocol and still
52 available for backward compatibility. This handler uses =org-remember=. Use
53 the current =org-protocol-capture=.
55 - =org-protocol-open-source= ::
56 "=open-source=". Maps URLs to local filenames. Use this to open sources of
57 already published contents in emacs for editing.
59 =org-protocol= helps creating custom handlers [[file:../org-tutorials/org-protocol-custom-handler.org][(tutorial)]] and so called
60 =org-protocol-projects=.
63 @<b>As of Org mode release 7.01 =org-protocol-remember= is now by =org-protocol-capture=.@</b>
64 If not stated otherwise, you may simply replace each occurrence of
65 /capture/ with /remember/ throughout this document, if you still want to use
66 remember templates. Use =M-x org-version= to find out about the version you're
74 - To load org-protocol.el add the following to your =.emacs=:
77 : (add-to-list 'load-path "~/path/to/org/protocol/")
78 : (require 'org-protocol)
80 * Browser / system setup
82 - [[Linux setup (Gnome)]]
83 - [[Linux setup (KDE)]]
87 *** Linux setup (Gnome)
89 For this to work, you'll need the Gnome-Libraries to be installed.
91 : gconftool-2 -s /desktop/gnome/url-handlers/org-protocol/command '/usr/local/bin/emacsclient %s' --type String
92 : gconftool-2 -s /desktop/gnome/url-handlers/org-protocol/enabled --type Boolean true
96 Add a file =org.protocol= to =~/.kde/share/kde4/services/=:
101 protocol=org-protocol
102 exec=/usr/bin/emacsclient '%u'
112 Description=A protocol for org-mode
118 Windows users may register the "=org-protocol=" once for all by adjusting the
119 following to their facts, save it as *.reg file and double-click it. This
120 worked for me on Windows-XP Professional and the emasc23 from ourcomments.org
121 ([[http://ourcomments.org/cgi-bin/emacsw32-dl-latest.pl]]). I'm no Windows user
122 though and enhancements are more than welcome on the org-mode mailinglist. The
123 original file is from http://kb.mozillazine.org/Register_protocol.
128 [HKEY_CLASSES_ROOT\org-protocol]
131 [HKEY_CLASSES_ROOT\org-protocol\shell]
132 [HKEY_CLASSES_ROOT\org-protocol\shell\open]
133 [HKEY_CLASSES_ROOT\org-protocol\shell\open\command]
134 @="\"C:\\Programme\\Emacs\\emacs\\bin\\emacsclientw.exe\" \"%1\""
139 Follow the directions for installing EmacsClient.app from https://github.com/neil-smithline-elisp/EmacsClient.app. This should configure the org-protocol for all Mac OS X browsers.
141 After installing EmacsClient.app you should then [[Verify the installation]]. Once verified, you can begin [[Using org-protocol]].
146 If you are using Firefox on Mac OS X, see [[Mac OS X setup]].
149 Please refer to http://kb.mozillazine.org/Register_protocol and use
150 "org-protocol" as protocol.
155 :CUSTOM_ID: acrobat-reader-setup
158 Adapted from [[http://article.gmane.org/gmane.emacs.orgmode/6810]]
160 You place a javascript file for each menu entry in
161 =~/.adobe/Acrobat/<VERSION>/JavaScripts= on unix-like systems or
162 =c:/Program Files/Adobe/Acrobat <VERSION>/Reader/Javascripts/= on
163 Windows, or wherever your Adobe Reader Installation might look for
166 The examples given here will place new menu entries in the "Tools"
167 menu, after restarting Adobe Reader.
169 # <<acrobat-store-link-js>>
170 ******* org-store-link.js
171 : // from http://article.gmane.org/gmane.emacs.orgmode/6810
172 : app.addMenuItem({cName:"org-store-link", cParent:"Tools",
173 : cExec:"app.launchURL('org-protocol://store-link://' + encodeURIComponent(this.URL) + '/' + encodeURIComponent(this.info.Title));"});
175 # <<acrobat-capture-js>>
176 ******* org-capture.js
177 : // from http://article.gmane.org/gmane.emacs.orgmode/6810
178 : app.addMenuItem({cName:"org-capture", cParent:"Tools",
179 : cExec:"app.launchURL('org-protocol://capture://' + encodeURIComponent(this.URL) + '/' + encodeURIComponent(this.info.Title) + '/');"});
181 And this one, if you still use remember templates:
183 # <<acrobat-remember-js>>
184 ******* org-remember.js
185 : // from http://article.gmane.org/gmane.emacs.orgmode/6810
186 : app.addMenuItem({cName:"org-remember", cParent:"Tools",
187 : cExec:"app.launchURL('org-protocol://remember://' + encodeURIComponent(this.URL) + '/' + encodeURIComponent(this.info.Title) + '/');"});
193 If you are using Opera on Mac OS X, see [[Mac OS X setup]].
195 Opera setup is described here:
196 http://www.opera.com/support/kb/view/535/.
198 To set up opera for use with org-protocol, follow these steps:
200 1. Choose "/Tools/" -> "/Prefences/" from the menu.
201 2. Select the tab "/Advanced/".
202 3. Choose "/Programs/" from the list on the left.
203 4. Now click the button "/Add/" on the very right.
204 5. In the new dialog window, enter "=org-protocol=" as "/Protocol/", choose the
205 radio button "/Open with other application/" and enter the path to
208 # <<test-org-protocol>>
211 Safari is only supported on Mac systems, not iOS systems.
213 See [[Mac OS X setup]] for directions.
216 *** Verify the installation
218 After your protocol is registered with your browser/OS, these links here
219 should work. Click on them and see if emacs reacts:
223 <li><a href="javascript:storeLink();">Org store-link</a></li>
224 <li><a href="javascript:capture();">Org capture (select some text if you like)</a></li>
225 <li><a href="javascript:remember();">Org remember (select some text please)</a></li>
230 # <<default-location>>
233 To actually use org-protocol add a bookmark to Firefox or Opera.
235 Here is the URL to use as "/Location/" for browser bookmarks. Just remove the
236 line breaks and replace "=sub-protocol=" with the real sub-protocol to use:
238 : javascript:location.href='org-protocol://sub-protocol://'+
239 : encodeURIComponent(location.href)+'/'+
240 : encodeURIComponent(document.title)+'/'+
241 : encodeURIComponent(window.getSelection())
243 This URL may be used for all three standard handlers in =org-protocol.el=. Some
244 of the values will be ignored (e.g. =store-link:/= will use the URL and title
247 # <<org-protocol-store-link>>
248 * Links and bookmarks: =org-protocol-store-link=
250 =org-store-link= stores an Org-link insertable through =M-x org-insert-link= and
251 pushes the URL found onto the =kill-ring= for yanking (=C-y=). The sub-protocol
252 used is "=store-link=":
254 : emacsclient org-protocol:/store-link:/URL/TITLE
256 will store this Org-link:
262 In addition, =URL= will be pushed on the =kill-ring= for yanking ('=C-y='). You will
263 have to encode =URL= and/or =TITLE= if they contain slashes, and probably quote
266 To use this feature, add a bookmark with an arbitrary name (e.g.
267 "/Org: store-link/") and enter this as "=Location=":
269 : javascript:location.href='org-protocol://store-link://'+encodeURIComponent(location.href)
272 # <<org-protocol-capture>>
273 * Note taking and citations: =org-protocol-capture=
275 This one is triggered through the sub-protocol "=capture=" and consumes up to
278 : emacsclient org-protocol:/capture:/URL/TITLE/BODY
280 will pop up an /*Capture*/ buffer and fill the template with the data
283 To use this feature, add a bookmark with an arbitrary name (e.g.
284 "/Org: capture/") and enter this as "=Location=":
286 : javascript:location.href='org-protocol://capture://'+
287 : encodeURIComponent(location.href)+'/'+
288 : encodeURIComponent(document.title)+'/'+
289 : encodeURIComponent(window.getSelection())
291 The result depends on the template used. See [[example-template][An example capture template]]
294 Note, that this one, as opposed to the other two standard handlers, does not
295 mix with more parameters to emacsclient. All parameters but the
296 #'=org-protocol://org-capture://...=' one will be discarded.
298 # <<which-capture-template>>
299 *** Which capture template is used?
301 :ID: org:f56bcb9a-20e7-4b37-99f1-839a8821cc4b
304 You don't need to setup a capture template to use =org-protocol-capture=,
305 since Org-mode provides a default template for those cases. Newer versions
306 provide an interactive interface for choosing a template. You may provide a
307 template to be used by customizing the variable
308 =org-capture-default-template= [fn:1].
310 The problem with this solution would be, that only one template can be used
311 with the fuction. Luckily, =org-protocol-capture= understands a slightly
312 extended syntax to choose between several templates: If the first field of
313 the data submitted is exactly one character in length, this character will
314 be used to select the template.
316 Here we choose to use the "=x=" template:
318 : emacsclient org-protocol:/capture:/x/URL/TITLE/BODY
320 And, again, as bookmark location:
321 : javascript:location.href='org-protocol://capture://x/'+
322 : encodeURIComponent(location.href)+'/'+
323 : encodeURIComponent(document.title)+'/'+
324 : encodeURIComponent(window.getSelection())
326 # <<example-template>>
327 ***** An example capture template
329 #+begin_src emacs-lisp
330 (setq org-capture-templates
335 (file+headline "~/org/capture.org" "Notes")
336 "* %^{Title}\n\n Source: %u, %c\n\n %i"
338 ;; ... more templates here ...
342 - "=w=" :: makes this one the default template used for
343 "=org-protocol://capture://=" URLs.
344 - =entry= :: makes it a regular entry with a headline.
345 - =file+headline= :: files the note in file "=~/org/capture.org=" as child of
346 the headline "=Notes="
347 - '=%c=' :: will be replaced by an Org-link pointing to the location of the
348 page you have been visiting when clicking on the link. The page
349 title will be the link's description.
350 - '=%i=' :: will be replaced by the selected text in your browser window if
353 In addition, you may use the following placeholders in your template:
355 | Placeholders | Replacement |
356 |---------------+---------------------------|
357 | =%:link= | URL of the web-page |
358 | =%:description= | The title of the web-page |
359 | =%:initial= | Selected text. |
361 You may read more about templates and their special escape characters in the
362 [[http://orgmode.org/manual/Capture-templates.html#Capture-templates][Org-mode manual]].
365 # <<org-protocol-remember>>
366 *** Org-protocol-remember
368 The =org-protocol-remember= handler is now obsolete. However, the handler is
369 still available for backward compatibility. To use this handler, closely
370 follow the setup for the current =org-protocol-capture= handler, and simply
371 replace each occurrence of /capture/ with /remember/.
373 As remember templates look slightly different than capture templates, we
374 provide an example here.
376 # <<example-remember-template>>
377 ***** An example remember template
379 #+begin_src emacs-lisp
380 (setq org-remember-templates
381 '((?w "* %^{Title}\n\n Source: %u, %c\n\n %i" nil "Notes")))
384 - '=?w=' :: makes this one the default template used for
385 "=org-protocol://remember://=" URLs.
386 - '=%c=' :: will be replaced by an Org-link pointing to the location of the
387 page you have been visiting when clicking on the link. The page
388 title will be the link's description.
389 - '=%i=' :: will be replaced by the selected text in your browser window if
392 In addition, you may use the following placeholders in your template:
394 | Placeholders | Replacement |
395 |---------------+---------------------------|
396 | =%:link= | URL of the web-page |
397 | =%:description= | The title of the web-page |
398 | =%:initial= | Selected text. |
400 You may read more about templates and their special escape characters in the
401 [[http://orgmode.org/manual/Capture-templates.html#Capture-templates][Org-mode manual]].
404 * Edit published content: =org-protocol-open-source=
406 This one was designed to help with opening sources for editing when browsing
407 in the first place. =org-protocol-open-source= uses the custom variable
408 =org-protocol-project-alist= to map URLs to (local) filenames.
410 Let's take http://orgmode.org/worg/ as our example.
412 Our intention is to click a bookmark (or link) to open the source of the
413 published file we are reading in our favourite editor. The bookmark-URL above
414 could be used again. But since =org-protocol-open-source= regards the first
415 field only, this here will do:
417 : javascript:location.href='org-protocol://open-source://'+encodeURIComponent(location.href)
419 To open files publihed on Worg locally, =org-protocol-project-alist= should look
420 like this (you may skip the second project):
422 #+begin_src emacs-lisp
423 (setq org-protocol-project-alist
425 :base-url "http://orgmode.org/worg/"
426 :working-directory "/home/user/worg/"
427 :online-suffix ".html"
428 :working-suffix ".org")
429 ("My local Org-notes"
430 :base-url "http://localhost/org/"
431 :working-directory "/home/user/org/"
432 :online-suffix ".php"
433 :working-suffix ".org")))
436 If you're now browsing http://orgmode.org/worg/org-contrib/org-protocol.html
437 and find a typo or have an idea how to enhance the documentation, simply click
438 the bookmark and start editing.
440 There are two functions to help you fill =org-protocol-project-alist= with
441 valid contents. One possibility is =org-protocol-create= that guides you through
442 the process. If you're editing an Org-mode file that is part of a publishing
443 project in =org-publish-project-alist=, try
445 : M-x org-protocol-create-for-org RET
447 # <<open-source-rewritten-urls>>
448 *** Handle rewritten URLs
450 In some cases, replacing =:base-url= with =:working-directory= and
451 =:online-suffix= with =:working-suffix= will not yield the desired results.
453 Suppose you maintain an online store located at =http://example.com/=. The
454 local sources reside in =/home/user/example/=. While most of the URLs map
455 directly to local file names by stripping URL parameters from the end and
456 replacing the =:base-url= with =:working-diretory= and =:online-suffix= with
457 =:working-suffix=, this might not work for rewritten URLs. It's common
458 practice to serve all products in such a store through one file and rewrite
459 URLs that do not match an existing file on the server.
461 That way, a request to =http://example.com/print/posters-A4.html= might be
462 rewritten on the server to something like
463 =http://example.com/shop/products.php/posters-A4.html.php=, where
464 =/posters-A4-digital.html.php= is the so called path info. Note that the
465 browser will not notice the rewrite.
467 If you now click your =org-protocol://open-source://= bookmark, the handler
468 will probably not find a file named
469 =/home/user/example/print/posters-A4.html.php= and fail.
471 Or, even more simple, assume you're browsing =http://example.com/=. A file
472 named =/home/user/example/.php= is not likely to exist.
474 Since Org-mode commit =69b46e10aab3b2374ecbc1a963ba56e77102a9a4= from 15th
475 Nov. 2009, such an entry in =org-protocol-project-alist= may hold an
476 additional property =:rewrites=. This property is a list of cons cells, each
477 of which maps a regular expression to a path relative to the
478 =:working-directory=.
480 Now map the URL to the path =/home/user/example/products.php= by adding the
481 =:rewrites= property like this:
483 #+begin_src emacs-lisp
484 (setq org-protocol-project-alist
486 :base-url "http://example.com/"
487 :working-directory "/home/user/example/"
488 :online-suffix ".php"
489 :working-suffix ".php"
490 :rewrites (("example.com/print/" . "products.php")
491 ("example.com/$" . "index.php"))
495 Guess what the second =:rewrites= element does. Since =example.com/$= is used as
496 a regular expression, it maps =http://example.com/=, =https://example.com=,
497 =http://www.example.com/= and similar to =/home/user/example/index.php=.
499 The =:rewrites= are searched as a last resort if and only if no existing file
506 Setting up org-protocol in [[http://conkeror.org/][Conkeror]] (an emacs inspired Mozilla web
507 browser) requires a slightly different method. You may simply add the
508 following snippets of code to your .conkerorrc file.[fn:tassilosblog]
510 For org-store-link, add the following to .conkerorrc:
512 : function org_store_link (url, title, window) {
513 : var cmd_str = 'emacsclient \"org-protocol://store-link://'+url+'/'+title+'\"';
514 : if (window != null) {
515 : window.minibuffer.message('Issuing ' + cmd_str);
517 : shell_command_blind(cmd_str);
520 : interactive("org-store-link", "Stores [[url][title]] as org link and copies url to emacs kill ring",
522 : org_store_link(encodeURIComponent(I.buffer.display_uri_string), encodeURIComponent(I.buffer.document.title), I.window);
525 For org-capture (or org-remember --- just exchange /capture/ with /remember/), use
528 : function org_capture (url, title, selection, window) {
529 : var cmd_str = 'emacsclient \"org-protocol://capture://'+url+'/'+title+'/'+selection+'\"';
530 : if (window != null) {
531 : window.minibuffer.message('Issuing ' + cmd_str);
533 : shell_command_blind(cmd_str);
536 : interactive("org-capture", "Clip url, title, and selection to capture via org-protocol",
538 : org_capture(encodeURIComponent(I.buffer.display_uri_string), encodeURIComponent(I.buffer.document.title), encodeURIComponent(I.buffer.top_frame.getSelection()), I.window);
541 Now, you should be able to invoke the commands from within conkeror
542 with =M-x org-store-link= and =M-x org-capture= (or remember).
544 Or, if you'd like your familiar emacs keybindings, you can add the
545 following to your .conkerorrc:
547 : define_key(content_buffer_normal_keymap, "C-c r", "org-capture");
548 : define_key(content_buffer_normal_keymap, "C-c l", "org-store-link");
550 [fn:tassilosblog] Adapted from Tassilo Horn's blog, "Calling
551 org-remember from inside conkeror," November 14, 2008.
552 http://tsdh.wordpress.com/2008/11/14/calling-org-remember-from-inside-conkeror/
559 Uzbl is a minimalistic webkit browser for Unix/Linux.
561 - [[http://www.uzbl.org/]]
563 You can pass encoded url data from uzbl to org-protocol by adding the
564 following lines to =.config/uzbl/config=.
570 @cbind \\r = sh 'emacsclient "org-protocol://capture://\@<encodeURIComponent(window.location.href)>\@/\@<encodeURIComponent(document.title)>\@/\@<document.getSelection()>\@"'
571 @cbind \\l = sh 'emacsclient "org-protocol://capture://\@<encodeURIComponent(window.location.href)>\@/\@<encodeURIComponent(document.title)>\@"'
575 These bind org-protocol-capture and org-store-line to "\r" and "\l" respectively.
577 # <<firefox-keybindings>>
578 * Keybindings for Firefox
580 You can add key bindings for the =org-protocol= commands using the keyconfig
583 First, install keyconfig from http://mozilla.dorando.at/keyconfig.xpi.
585 Open the keyconfig dialog by going to Tools and then Keyconfig.
587 Click the 'Add a new Key' button. Enter "Org store link" as the name.
588 Enter the following in the box with /* CODE */ in it:
590 : var orgProtoString = 'org-protocol://store-link://'+
591 : encodeURIComponent(gBrowser.currentURI.spec) + '/' +
592 : encodeURIComponent(gBrowser.contentWindow.document.title) + '/' +
593 : encodeURIComponent(gBrowser.contentWindow.getSelection());
595 : gBrowser.loadURI(orgProtoString);
597 Click OK. You will then need to bind a key by clicking in the box next to the
598 'Apply' button and pressing whatever key combination you want. Click 'Apply' to
599 store the keybinding.
601 Repeat the steps, but call the next key "Org capture" and use the code below:
603 : var orgProtoString = 'org-protocol://capture://'+
604 : encodeURIComponent(gBrowser.currentURI.spec) + '/' +
605 : encodeURIComponent(gBrowser.contentWindow.document.title) + '/' +
606 : encodeURIComponent(content.window.getSelection());
608 : gBrowser.loadURI(orgProtoString);
610 Click Close, then OK, and then restart Firefox. You should then be able to
611 access the org-protocol functions with your chosen keys.
613 # <<screencast-intro>>
614 * Screencast: small introduction to org-protocol.el
617 <object width="640" height="464"><param name="allowfullscreen"
618 value="true" /><param name="allowscriptaccess" value="always" /><param
620 value="http://vimeo.com/moogaloop.swf?clip_id=5662410&server=vimeo.com&show_title=1&show_byline=1&show_portrait=1&color=FF7700&fullscreen=1"
622 src="http://vimeo.com/moogaloop.swf?clip_id=5662410&server=vimeo.com&show_title=1&show_byline=1&show_portrait=1&color=FF7700&fullscreen=1"
623 type="application/x-shockwave-flash" allowfullscreen="true"
624 allowscriptaccess="always" width="640" height="464"></embed></object>
627 This screencast shows off some nice things you can do with Firefox,
628 Emacs, Org-mode and org-protocol.el.
630 It first shows how to create two bookmarklets, =org-capture= and
631 =org-store-link=. These bookmarklets enable your Firefox to talk to
632 emacsclient via a new protocol (=org-protocol://=); emacsclient then
633 parses the request and tells Emacs to capture or store stuff at the
634 relevant places in your Org files.
636 At the end of the screencast, we create two ubiquity commands from these
637 bookmarklets. Now in Firefox =ALT-SPC org-capture RET= creates a note
643 [fn:1] Before commit =fc49c1ec96b2c789f573ae1ba936b930a8494402=, 3rd Sept. 2010,
644 if a template with the key string "=w=" was defined, this one was chosen by
645 default. This was done to make bookmarks used for [[file:./org-annotation-helper.el][org-annotation-helper]] work
646 without changing the template.