org-protocol.el – Intercept calls from emacsclient to trigger custom actions
org-protocol intercepts calls from emacsclient to trigger custom actions without external dependencies. Only one protocol has to be configured with your external applications or the operating system, to trigger an arbitrary number of custom actions. Just register your custom sub-protocol and handler with the variable `org-protocol-protocol-alist'.
About org-protocol.el
org-protocol.el
is based on code and ideas from
org-annotation-helper.el and org-browser-url.el
.
"org-protocol:/sub-protocol:/
" triggers actions associated with sub-protocol
through the custom variable org-protocol-protocol-alist
.
It comes with four predefined handlers:
org-protocol-store-link
- triggered through the sub-protocol "
store-link
". Stores an Org-link and pushes the URL to thekill-ring
. org-protocol-capture
- Fill a
CAPTURE
buffer with information gathered somewhere else. This handler is triggered through the "capture
" sub-protocol and uses the functionorg-capture
. org-protocol-remember
- Fills a remember buffer with information gathered somewhere else. This
handler is triggered through the "
remember
" sub-protocol and still available for backward compatibility. This handler usesorg-remember
. Use the currentorg-protocol-capture
. org-protocol-open-source
- "
open-source
". Maps URLs to local filenames. Use this to open sources of already published contents in emacs for editing.
org-protocol
helps creating custom handlers (tutorial) and so called
org-protocol-projects
.
@<b>As of Org mode release 7.01 org-protocol-remember
is now by org-protocol-capture
.@</b>
If not stated otherwise, you may simply replace each occurrence of
capture with remember throughout this document, if you still want to use
remember templates. Use M-x org-version
to find out about the version you're
using.
Installation
To load org-protocol.el add the following to your
.emacs
:(server-start) (add-to-list 'load-path "~/path/to/org/protocol/") (require 'org-protocol)
Browser / system setup
GNU/Linux setup
Most common desktop environments (Gnome, KDE et al) comply with the XDG Desktop Entry Specification.
This means setting up emacsclient
as the org-protocol
handler using a .desktop file can be regarded
as a, in most cases, standard way to set this up in most common desktop environments.
Some environments, e.g. Gnome as of Gnome 3, have deprecated other configuration methods,
e.g. gconftool-2
to set-up protocol handling.
Create an org-protocol.desktop
file either in ~/.local/share/applications/
to set-up emacsclient
as the
org-protocol
handler for the current user or in /usr/share/applications
to set-up a system-wide
configuration:
[Desktop Entry] Name=org-protocol Comment=Intercept calls from emacsclient to trigger custom actions Categories=Other; Keywords=org-protocol; Icon=emacs Type=Application Exec=emacsclient -- %u Terminal=false StartupWMClass=Emacs MimeType=x-scheme-handler/org-protocol;
Update the cache database of MIME types handled by desktop files via:
update-desktop-database ~/.local/share/applications/
Windows setup
Windows users may register the "org-protocol
" once for all by adjusting the
following to their facts, save it as *.reg file and double-click it. This
worked for me on Windows-XP Professional and the emasc23 from ourcomments.org
(http://ourcomments.org/cgi-bin/emacsw32-dl-latest.pl). I'm no Windows user
though and enhancements are more than welcome on the org-mode mailinglist. The
original file is from http://kb.mozillazine.org/Register_protocol.
REGEDIT4 [HKEY_CLASSES_ROOT\org-protocol] @="URL:Org Protocol" "URL Protocol"="" [HKEY_CLASSES_ROOT\org-protocol\shell] [HKEY_CLASSES_ROOT\org-protocol\shell\open] [HKEY_CLASSES_ROOT\org-protocol\shell\open\command] @="\"C:\\Programme\\Emacs\\emacs\\bin\\emacsclientw.exe\" \"%1\""
Mac OS X setup
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.
After installing EmacsClient.app you should then Verify the installation. Once verified, you can begin Using org-protocol.
If that doesn't work, you might check https://github.com/xuchunyang/setup-org-protocol-on-mac for building a custom handler, combined with the per-browser config information below.
Applications
Firefox
If you are using Firefox on Mac OS X, see Mac OS X setup.
Please refer to http://kb.mozillazine.org/Register_protocol and use "org-protocol" as protocol.
Acrobat Reader
Adapted from https://list.orgmode.org/loom.20080527T012114-502@post.gmane.org
You place a javascript file for each menu entry in
~/.adobe/Acrobat/<VERSION>/JavaScripts
on unix-like systems or
c:/Program Files/Adobe/Acrobat <VERSION>/Reader/Javascripts/
on
Windows, or wherever your Adobe Reader Installation might look for
javascript.
The examples given here will place new menu entries in the "Tools" menu, after restarting Adobe Reader.
- org-store-link.js
// from https://list.orgmode.org/loom.20080527T012114-502@post.gmane.org app.addMenuItem({cName:"org-store-link", cParent:"Tools", cExec:"app.launchURL('org-protocol://store-link://' + encodeURIComponent(this.URL) + '/' + encodeURIComponent(this.info.Title));"});
- org-capture.js
// from https://list.orgmode.org/loom.20080527T012114-502@post.gmane.org app.addMenuItem({cName:"org-capture", cParent:"Tools", cExec:"app.launchURL('org-protocol://capture://' + encodeURIComponent(this.URL) + '/' + encodeURIComponent(this.info.Title) + '/');"});
And this one, if you still use remember templates:
- org-remember.js
// from https://list.orgmode.org/loom.20080527T012114-502@post.gmane.org app.addMenuItem({cName:"org-remember", cParent:"Tools", cExec:"app.launchURL('org-protocol://remember://' + encodeURIComponent(this.URL) + '/' + encodeURIComponent(this.info.Title) + '/');"});
Opera
If you are using Opera on Mac OS X, see Mac OS X setup.
Opera setup is described here: http://www.opera.com/support/kb/view/535/.
To set up opera for use with org-protocol, follow these steps:
- Choose "Tools" -> "Prefences" from the menu.
- Select the tab "Advanced".
- Choose "Programs" from the list on the left.
- Now click the button "Add" on the very right.
- In the new dialog window, enter "
org-protocol
" as "Protocol", choose the radio button "Open with other application" and enter the path to emacsclient.
Safari
Safari is only supported on Mac systems, not iOS systems.
See Mac OS X setup for directions.
Verify the installation
After your protocol is registered with your browser/OS, these links here should work. Click on them and see if emacs reacts:
Using org-protocol
To actually use org-protocol add a bookmark to Firefox or Opera.
Here is the URL to use as "Location" for browser bookmarks. Just remove the
line breaks and replace "sub-protocol
" with the real sub-protocol to use:
javascript:location.href='org-protocol://sub-protocol://'+ encodeURIComponent(location.href)+'/'+ encodeURIComponent(document.title)+'/'+ encodeURIComponent(window.getSelection())
This URL may be used for all three standard handlers in org-protocol.el
. Some
of the values will be ignored (e.g. store-link:/
will use the URL and title
only).
Links and bookmarks: org-protocol-store-link
org-store-link
stores an Org-link insertable through M-x org-insert-link
and
pushes the URL found onto the kill-ring
for yanking (C-y
). The sub-protocol
used is "store-link
":
emacsclient org-protocol:/store-link:/URL/TITLE
will store this Org-link:
[[URL][TITLE]]
In addition, URL
will be pushed on the kill-ring
for yanking ('C-y
'). You will
have to encode URL
and/or TITLE
if they contain slashes, and probably quote
those for the shell.
To use this feature, add a bookmark with an arbitrary name (e.g.
"Org: store-link") and enter this as "Location
":
javascript:location.href='org-protocol://store-link://'+encodeURIComponent(location.href)
Note taking and citations: org-protocol-capture
This one is triggered through the sub-protocol "capture
" and consumes up to
three data fields:
emacsclient org-protocol:/capture:/URL/TITLE/BODY
will pop up an Capture buffer and fill the template with the data submitted.
To use this feature, add a bookmark with an arbitrary name (e.g.
"Org: capture") and enter this as "Location
":
javascript:location.href='org-protocol://capture://'+ encodeURIComponent(location.href)+'/'+ encodeURIComponent(document.title)+'/'+ encodeURIComponent(window.getSelection())
The result depends on the template used. See An example capture template further down.
Note, that this one, as opposed to the other two standard handlers, does not
mix with more parameters to emacsclient. All parameters but the
#'org-protocol://org-capture://...
' one will be discarded.
Which capture template is used?
You don't need to setup a capture template to use
org-protocol-capture
, since Org-mode provides a default template
for those cases. Newer versions provide an interactive interface
for choosing a template. You may provide a template to be used by
customizing the variable org-capture-default-template
1.
The problem with this solution would be, that only one template
can be used with the fuction. Luckily, org-protocol-capture
understands a slightly extended syntax to choose between several
templates: If the first field of the data submitted is exactly one
character in length, this character will be used to select the
template.
Here we choose to use the "x
" template:
emacsclient org-protocol:/capture:/x/URL/TITLE/BODY
And, again, as bookmark location:
javascript:location.href='org-protocol://capture://x/'+ encodeURIComponent(location.href)+'/'+ encodeURIComponent(document.title)+'/'+ encodeURIComponent(window.getSelection())
An example capture template
(setq org-capture-templates (quote (("w" "Default template" entry (file+headline "~/org/capture.org" "Notes") "* %^{Title}\n\n Source: %u, %c\n\n %i" :empty-lines 1) ;; ... more templates here ... )))
- "
w
" - makes this one the default template used for
"
org-protocol://capture://
" URLs. entry
- makes it a regular entry with a headline.
file+headline
- files the note in file "
~/org/capture.org
" as child of the headline "Notes
" - '
%c
' - will be replaced by an Org-link pointing to the location of the page you have been visiting when clicking on the link. The page title will be the link's description.
- '
%i
' - will be replaced by the selected text in your browser window if any.
In addition, you may use the following placeholders in your template:
Placeholders | Replacement |
---|---|
%:link |
URL of the web-page |
%:description |
The title of the web-page |
%:initial |
Selected text. |
You may read more about templates and their special escape characters in the Org-mode manual.
Org-protocol-remember
The org-protocol-remember
handler is now obsolete. However, the handler is
still available for backward compatibility. To use this handler, closely
follow the setup for the current org-protocol-capture
handler, and simply
replace each occurrence of capture with remember.
As remember templates look slightly different than capture templates, we provide an example here.
An example remember template
(setq org-remember-templates '((?w "* %^{Title}\n\n Source: %u, %c\n\n %i" nil "Notes")))
- '
?w
' - makes this one the default template used for
"
org-protocol://remember://
" URLs. - '
%c
' - will be replaced by an Org-link pointing to the location of the page you have been visiting when clicking on the link. The page title will be the link's description.
- '
%i
' - will be replaced by the selected text in your browser window if any.
In addition, you may use the following placeholders in your template:
Placeholders | Replacement |
---|---|
%:link |
URL of the web-page |
%:description |
The title of the web-page |
%:initial |
Selected text. |
You may read more about templates and their special escape characters in the Org-mode manual.
Edit published content: org-protocol-open-source
This one was designed to help with opening sources for editing when browsing
in the first place. org-protocol-open-source
uses the custom variable
org-protocol-project-alist
to map URLs to (local) filenames.
Let's take https://orgmode.org/worg/ as our example.
Our intention is to click a bookmark (or link) to open the source of the
published file we are reading in our favourite editor. The bookmark-URL above
could be used again. But since org-protocol-open-source
regards the first
field only, this here will do:
javascript:location.href='org-protocol://open-source://'+encodeURIComponent(location.href)
To open files publihed on Worg locally, org-protocol-project-alist
should look
like this (you may skip the second project):
(setq org-protocol-project-alist '(("Worg" :base-url "https://orgmode.org/worg/" :working-directory "/home/user/worg/" :online-suffix ".html" :working-suffix ".org") ("My local Org-notes" :base-url "http://localhost/org/" :working-directory "/home/user/org/" :online-suffix ".php" :working-suffix ".org")))
If you're now browsing https://orgmode.org/worg/org-contrib/org-protocol.html and find a typo or have an idea how to enhance the documentation, simply click the bookmark and start editing.
There are two functions to help you fill org-protocol-project-alist
with
valid contents. One possibility is org-protocol-create
that guides you through
the process. If you're editing an Org-mode file that is part of a publishing
project in org-publish-project-alist
, try
M-x org-protocol-create-for-org RET
Handle rewritten URLs
In some cases, replacing :base-url
with :working-directory
and
:online-suffix
with :working-suffix
will not yield the desired results.
Suppose you maintain an online store located at http://example.com/
. The
local sources reside in /home/user/example/
. While most of the URLs map
directly to local file names by stripping URL parameters from the end and
replacing the :base-url
with :working-diretory
and :online-suffix
with
:working-suffix
, this might not work for rewritten URLs. It's common
practice to serve all products in such a store through one file and rewrite
URLs that do not match an existing file on the server.
That way, a request to http://example.com/print/posters-A4.html
might be
rewritten on the server to something like
http://example.com/shop/products.php/posters-A4.html.php
, where
/posters-A4-digital.html.php
is the so called path info. Note that the
browser will not notice the rewrite.
If you now click your org-protocol://open-source://
bookmark, the handler
will probably not find a file named
/home/user/example/print/posters-A4.html.php
and fail.
Or, even more simple, assume you're browsing http://example.com/
. A file
named /home/user/example/.php
is not likely to exist.
Since Org-mode commit 69b46e10aab3b2374ecbc1a963ba56e77102a9a4
from 15th
Nov. 2009, such an entry in org-protocol-project-alist
may hold an
additional property :rewrites
. This property is a list of cons cells, each
of which maps a regular expression to a path relative to the
:working-directory
.
Now map the URL to the path /home/user/example/products.php
by adding the
:rewrites
property like this:
(setq org-protocol-project-alist '(("example.com" :base-url "http://example.com/" :working-directory "/home/user/example/" :online-suffix ".php" :working-suffix ".php" :rewrites (("example.com/print/" . "products.php") ("example.com/$" . "index.php")) )))
Guess what the second :rewrites
element does. Since example.com/$
is used as
a regular expression, it maps http://example.com/
, https://example.com
,
http://www.example.com/
and similar to /home/user/example/index.php
.
The :rewrites
are searched as a last resort if and only if no existing file
name is matched.
Other browsers
Conkeror setup
Setting up org-protocol in Conkeror (an emacs inspired Mozilla web browser) requires a slightly different method. You may simply add the following snippets of code to your .conkerorrc file2.
For org-store-link, add the following to .conkerorrc:
function org_store_link (url, title, window) { var cmd_str = 'emacsclient \"org-protocol://store-link://'+url+'/'+title+'\"'; if (window != null) { window.minibuffer.message('Issuing ' + cmd_str); } shell_command_blind(cmd_str); } interactive("org-store-link", "Stores [[url][title]] as org link and copies url to emacs kill ring", function (I) { org_store_link(encodeURIComponent(I.buffer.display_uri_string), encodeURIComponent(I.buffer.document.title), I.window); });
For org-capture (or org-remember — just exchange capture with remember), use the following:
function org_capture (url, title, selection, window) { var cmd_str = 'emacsclient \"org-protocol://capture://'+url+'/'+title+'/'+selection+'\"'; if (window != null) { window.minibuffer.message('Issuing ' + cmd_str); } shell_command_blind(cmd_str); } interactive("org-capture", "Clip url, title, and selection to capture via org-protocol", function (I) { org_capture(encodeURIComponent(I.buffer.display_uri_string), encodeURIComponent(I.buffer.document.title), encodeURIComponent(I.buffer.top_frame.getSelection()), I.window); });
Now, you should be able to invoke the commands from within conkeror
with M-x org-store-link
and M-x org-capture
(or remember).
Or, if you'd like your familiar emacs keybindings, you can add the following to your .conkerorrc:
define_key(content_buffer_normal_keymap, "C-c r", "org-capture"); define_key(content_buffer_normal_keymap, "C-c l", "org-store-link");
Uzbl
Uzbl is a minimalistic webkit browser for Unix/Linux.
You can pass encoded url data from uzbl to org-protocol by adding the
following lines to .config/uzbl/config
.
# Org-protocol @cbind \\r = sh 'emacsclient "org-protocol://capture://\@<encodeURIComponent(window.location.href)>\@/\@<encodeURIComponent(document.title)>\@/\@<document.getSelection()>\@"' @cbind \\l = sh 'emacsclient "org-protocol://capture://\@<encodeURIComponent(window.location.href)>\@/\@<encodeURIComponent(document.title)>\@"'
These bind org-protocol-capture and org-store-line to "\r" and "\l" respectively.
Keybindings for Firefox
You can add key bindings for the org-protocol
commands using the
keyconfig Firefox extension.
First, install keyconfig from http://mozilla.dorando.at/keyconfig.xpi.
Open the keyconfig dialog by going to Tools and then Keyconfig.
Click the 'Add a new Key' button. Enter "Org store link" as the name. Enter the following in the box with * CODE * in it:
var orgProtoString = 'org-protocol://store-link://'+ encodeURIComponent(gBrowser.currentURI.spec) + '/' + encodeURIComponent(gBrowser.contentWindow.document.title) + '/' + encodeURIComponent(gBrowser.contentWindow.getSelection()); gBrowser.loadURI(orgProtoString);
Click OK. You will then need to bind a key by clicking in the box next to the 'Apply' button and pressing whatever key combination you want. Click 'Apply' to store the keybinding.
Repeat the steps, but call the next key "Org capture" and use the code below:
var orgProtoString = 'org-protocol://capture://'+ encodeURIComponent(gBrowser.currentURI.spec) + '/' + encodeURIComponent(gBrowser.contentWindow.document.title) + '/' + encodeURIComponent(content.window.getSelection()); gBrowser.loadURI(orgProtoString);
Click Close, then OK, and then restart Firefox. You should then be able to access the org-protocol functions with your chosen keys.
Screencast: small introduction to org-protocol.el
This screencast shows off some nice things you can do with Firefox, Emacs, Org-mode and org-protocol.el.
It first shows how to create two bookmarklets, org-capture
and
org-store-link
. These bookmarklets enable your Firefox to talk to
emacsclient via a new protocol (org-protocol://
); emacsclient then
parses the request and tells Emacs to capture or store stuff at the
relevant places in your Org files.
At the end of the screencast, we create two ubiquity commands from
these bookmarklets. Now in Firefox ALT-SPC org-capture RET
creates
a note in my Org files.
Footnotes:
Before commit fc49c1ec96b2c789f573ae1ba936b930a8494402
, 3rd
Sept. 2010, if a template with the key string "w
" was defined, this
one was chosen by default. This was done to make bookmarks used for
org-annotation-helper work without changing the template.