One of the many selling point of using Org-mode as a personal wiki (aka digital garden, see previous post) is its (hyper)link feature.

As we’ve seen previously, we can define internal links between Org-file (and/or their outlines), but also external links targeting external files & sytems. Those can either point to stuff openable in Emacs itself (e.g. link to files, to a shell command…) or external applications if configured as such (e.g. web pages).

URL abbrevs

Conveniently, pasted URL are directly resolved as http(s) links.

As usually, we may have a bunch of links to a few websites, it can be convenient to be able to have those in a shorter form.

Conveniently, Org-mode support link abbreviations.

For example, we may define our list of recurrent linked website.

(setq org-link-abbrev-alist '(("gh" . "")
                              ("gl" . "")
                              ("hn" . "")
                              ("lines" . "")
                              ;; [...]
                              ("thing" . "")))

One would just have to type [[gh:emacs-mirror/emacs]] instead of to insert a link to Emacs’ github mirror.

Even faster & shorter URL abbrevs

The above solution is nice if we use org-insert-link to insert links.

But I personally find this command cumbersome. It prompts me 3 times (link type, actual link, description).

I want to go faster and just having to type gh:emacs-mirror/emacs to get a valid link.

One way to achieve this is to declare custom link types.

The solution becomes:

(require 'dash)

(setq my-org-link-abbrev-alist '(("gh" . "")
                                 ;; [...]
                                 ("thing" . "")))

(--each my-org-link-abbrev-alist
  (let* ((link-prefix (car it))
         (browse-fn `(lambda (e)
                       (let ((org-link-abbrev-alist my-org-link-abbrev-alist))
                         (browse-url (org-link-expand-abbrev (concat ,link-prefix ":" e)))))))
    (org-link-set-parameters link-prefix :follow browse-fn)))

Please note that we renamed org-link-abbrev-alist to my-org-link-abbrev-alist to prevent having duplicated prefix entries if we ever want to call org-insert-link.

Most of the time, I just copy/paste an URL into an Org buffer.

Wouldn’t it be convenient if it would automagically shorten it if it correspond to a known abbrev?

Thankfully, this is relatively trivial by advising org-yank.

(require 's)

(defun my-org-link-apply-prefix (txt)
  "Rework link TXT, swapping prefix w/ shorted one if matches `my-org-link-abbrev-alist'."
  (let ((prfx (--some (and (s-starts-with? (cdr it) txt) (not (string= (cdr it) txt)) it) my-org-link-abbrev-alist)))
    (if prfx
        (s-replace (cdr prfx) (concat (car prfx) ":") txt)

(defadvice org-yank (around prf/org-yank-prefix-link activate)
  "Advice around `org-yank' that will auto-compact current entry in `kill-ring' if it matches `my-org-link-abbrev-alist'."
  (let* ((kill (or (and kill-ring (current-kill 0)) ""))
         (new-kill (my-org-link-apply-prefix kill)))
    (unless (s-blank? new-kill)
      (kill-new new-kill t))

Please not that my-org-link-apply-prefix only covers “basic” prefix abbrevs. It doesn’t support formatted abbrevs (%s, %h) nor formatting using a custom function (%(<CUSTOM-FN>) for which we’d need the inverse function).


As always, this shows how flexible Emacs is and how expressive Elisp can be (once you are used to its quirks).

We showcased a very basic example of custom links. One could really go crazy with those.

For more in-depth examples, check out this article from the The Kitchin Research Group blog. They wrote a bunch of advanced articles about Org, notably about Babel (Org’s JupyterLab equivalent).

Tagged #emacs, #elisp, #productivity.