Capturing links quickly with emacsclient, org-protocol, and Chrome Shortcut Manager on Microsoft Windows 8

UPDATE 2015-11-30: Well, that bitrotted quickly! Chrome Shortcut Manager is no longer available, but maybe Shortkeys will work instead.

Since I’ll be snipping lots of Emacs-related resources and organizing them into Emacs news roundups, I figured it was time to get org-protocol working.

Step 1: Get emacsclient to work

I was getting the error “No connection could be made because the target machine actively refused it.” I needed to change my Windows Firewall rules. From the Windows Firewall screen, I clicked on Advanced settings and chose Inbound Rules. On the Programs and Services tab, I confirmed that the right Emacs binary was selecI looked for the rules for GNU Emacs, consolidating them down to two rules (UDP and TCP). I limited the scope to local/remote 127.0.0.1. On the advanced tab, I selected all the profiles and changed edge traversal to blocked.

I was still getting the error despite a fresh M-x server-start. After I deleted the contents of ~/.emacs.d/server and did another M-x server-start. When I ran emacsclient test.txt from the command-line, it correctly opened the file in my existing Emacs instance. Hooray!

Step 2: Load org-protocol

I added org-protocol to the org-modules variable so that Org would load it when Emacs reaches the (org-load-modules-maybe t) in my config. Since I didn’t want to restart Emacs, I also evaluated (load-library "org-protocol") to load it.

Step 3: Register the protocol

I ran an org-protocol.reg that set up the appropriate org protocol entry:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\org-protocol]
"URL Protocol"=""
@="URL:Org Protocol"

[HKEY_CLASSES_ROOT\org-protocol\shell]

[HKEY_CLASSES_ROOT\org-protocol\shell\open]

[HKEY_CLASSES_ROOT\org-protocol\shell\open\command]
@="\"c:\\Program Files (x86)\\GNU Emacs 24.4\\bin\\emacsclientw.exe\"  \"%1\""

You can find a similar one in the org-protocol documentation.

Step 4: Add support to Chrome

I wanted something a bit different from the org-capture extensions available for Chrome. In particular, I wanted:

  • a keyboard-friendly way to quickly store a link
  • a keyboard-friendly way to capture a link with some notes

The Shortcut Manager extension for Chrome lets you specify your own keyboard shortcuts for running short Javascript. Inline Javascript doesn’t work on all sites. For example, Github blocks it with the following error: Refused to execute inline script because it violates the following Content Security Policy directive: "script-src assets-cdn.github.com". Either the 'unsafe-inline' keyword, a hash ('...'), or a nonce ('nonce-...') is required to enable inline execution. Still, it works for many sites, so it’s a start. Here are the shortcuts I put together.

l Store link
L Store link (prompt for title, default to selection or document title)
c Capture link (prompt for template)

You can import them by going to Chrome’s More Tools > Extensions screen and choosing the Options link for Shortcut Manager. From there, use Import settings.

// ==UserScript==
// @ShortcutManager
// @name Store link
// @namespace XPrUJhE4wRsC
// @key l
// @include *
// ==/UserScript==
var storeLink = function(){
  var selection = window.getSelection().toString();
  var uri = 'org-protocol://store-link://' +
        encodeURIComponent(window.location.href) + '/' +
        encodeURIComponent(selection || document.title);
  window.location = uri;
  return uri;
};
storeLink();

// ==UserScript==
// @ShortcutManager
// @name Capture link
// @namespace XPrUJhE4wRsC
// @key c
// @include *
// ==/UserScript==
var captureLink =function(){
  var uri = 'org-protocol://capture://' +
        encodeURIComponent(window.location.href) + '/' +
        encodeURIComponent(document.title) + '/' +
        encodeURIComponent(window.getSelection().toString());
  window.location = uri;
  return uri;
};
captureLink();


// ==UserScript==
// @ShortcutManager
// @name Store link with prompt
// @namespace XPrUJhE4wRsC
// @key Shift+l
// @include *
// ==/UserScript==
var storeLinkWithPrompt = function(){
  var selection = window.getSelection().toString();
  var uri = 'org-protocol://store-link://' +
        encodeURIComponent(window.location.href) + '/' +
        encodeURIComponent(window.prompt('Title', selection || document.title));
  window.location = uri;
  return uri;
};
storeLinkWithPrompt();

Shortcut Manager looks like a really useful extension. Here are some other shortcuts I set up:

x close the current tab
r reload (cacheless)
t open a new tab
n select the right tab
p select the left tab
b back
f forward

Step 5: Add shortcuts for managing stored links

I added my/org-insert-link and org-insert-last-stored-link to my main hydra, which is on my hh keychord. my/org-insert-link is like org-insert-link, except it adds a newline if the cursor is at an Org link so that we don’t trigger org-insert-link‘s behaviour of editing links.

(defun my/org-insert-link ()
  (interactive)
  (when (org-in-regexp org-bracket-link-regexp 1)
    (goto-char (match-end 0))
    (insert "\n"))
  (call-interactively 'org-insert-link))

(key-chord-define-global "hh"
                         (defhydra my/key-chord-commands ()
                           "Main"
                           ;; ...
                           ("L" my/org-insert-link)
                           ("l" org-insert-last-stored-link)
                           ;; ...
                           ))

This lets me quickly insert a bunch of links with a key sequence like h h l l l l or select a link to insert with h h L. C-y (yank) pulls in the URL of the last stored link, too.

Let’s see how this works out!

One Pingback/Trackback

  • You can also use Ultimate Org Capture if you are using chrome :P https://chrome.google.com/webstore/detail/ultimate-org-capture/ijcpiacdhbjjpfookgaodhblgainmcbf

    • Yeah, I looked at that, but I wanted more keyboard-friendliness and customizability. =) Thanks for making and sharing that, though!

      As it turns out, Shortcut Manager can sometimes get confused by text areas, so I’ve changed my shortcuts to be more like the keychords I use in Emacs: hh followed by another key.

      • The whole point of it is to have a keyboard-friendly interface, like using `Control+Shift-L` in chrome would make the same action as clicking on the extension :P But I guess a more Windows friendly approach is that one. (http://cestdiego.github.io/blog/2015/08/19/org-protocol/) this is the post that explains my usage of ultimate org-capture

        • I looked into it too briefly to determine whether I could set up multiple keyboard shortcuts to do different things (in particular, I wanted quickly storing multiple links vs. storing a link but changing the title vs. capturing a link and writing more of a note about it). I might still end up going with some kind of extension if that gets me around the security limits for sites like Github. We’ll see!

  • Pingback: Capturing Links with org-protocol | Irreal()

  • NoonianAtall

    You may find this useful: https://github.com/alphapapa/org-protocol-capture-html It lets you convert the HTML of the browser selection to org-mode using Pandoc, and capture it with org-protocol.

    Also, here are some straightforward, up-to-date instructions for setting up org-protocol on Linux: http://stackoverflow.com/a/32851154/712624

    • Nice! I usually capture short snippets, but that will come in handy for lists.

  • I was trying to pull all this together for my working environment, which is compiled emacs 24.5 on OSX, rather than using Aquamacs and EmacsClient as suggested in the org-protocol docs, as well as Chrome. I ended up tossing together a tiny Sinatra app to handle the call to emacsclient, and slightly different shortkey & bookmarklet javascript. I threw it up on Github at https://github.com/tamouse/emacs_org_protocol_server