Extending the org-mode link syntax with attributes

| categories: emacs, orgmode | tags:

I make super heavy use of links in org-mode. I use them extensively in org-ref to create functional citations. One detail that has never been very satisfactory is the need for pre/post text in citations. I don't need that capability often, but it seems important to some. I have implemented a kind of clunky solution where I use the description part of a link with the pre/post text separated by a ::. Although that works, I dislike the way it looks, the need to parse it, and that the description covers the link.

[[cite:key][pre text::post text]]

Some time ago there was a suggestion of how to extend the link syntax, which was to my knowledge never implemented. Here is the proposed syntax:

$[link http://google.com
         :last-followed [2009-02-25 Wed 02:00]
         :label "click here for evil search engine"
         :export-label "click here for nice search engine"]

This is interesting because this syntax suggests the link has attributes which can be updated.

We will show here how to implement part of this idea with the existing link syntax. We will make a link that has attributes like that. The basic idea is to simply incorporate the attributes into the path, and use lisp to read them. We will wrap the link path in parentheses and read that as a lisp data structure. So, a link like link:key :pre "some pre text" :post "some post text" will be parsed as:

(read "(key :pre \"some pre text\" :post \"some post text\")")
key :pre some pre text :post some post text

The car of that list is the key, and the cdr contains the attributes. The quotes are necessary here to make sure all the text is correctly parsed as a single element for each attribute. So, here is an example link

(org-add-link-type
 "slink"
 ;;  follow function
 (lambda (path)
   (let* ((data (read (format "(%s)" path)))
          (head (car data))
          (plist (cdr data))
          (link (org-element-context))
          (begin (org-element-property :begin link))
          (end (org-element-property :end link)))
     (setq plist (plist-put plist :last-clicked (current-time-string)))
     (save-excursion
     (setf (buffer-substring begin end) "")
     (goto-char begin)
     (insert (format "[[slink:%s %s]]" head
         (substring (format "%S" plist) 1 -1))))))
 ;; format function
 (lambda (path description backend)
   (let* ((data (read (concat "(" path ")")))
          (head (car data))
          (plist (cdr data)))
     (format "\\%s[%s][%s]{%s}"
             (plist-get plist :type)
             (plist-get plist :pre)
             (plist-get plist :post)
             head))))

Now, each time I click on this link, the time stamp gets updated.

\cite[See for example][page 47]{kitchin-2010}

[[slink:kitchin-2010 :pre "See for example" :post "page 47" :type "cite" :last-clicked "Thu Feb  5 09:31:15 2015"]]

And, the generic export of this link is:

\cite[See for example][page 47]{kitchin-2010}

Is this a good idea? I am not using this for anything right now. Sometimes my version of org-mode has trouble recognizing that is a link. It is strange, as I am typing, sometimes it flashes in and out of being recognized as a link. Anyway, it is an interesting idea!

Copyright (C) 2015 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter