org-shift hooks for ordering citations

| categories: org-mode, bibtex | tags:

I wrote a function that sorts citations by year, but there might be a reason to order them some other way. Here we develop a method to use shift-arrow keys to do the ordering. We will need to write a function that gets the citations in a link, gets the key under point, and then swap with neighboring keys depending on the arrow pressed. It is trivial to get the key under point (org-ref-get-bibtex-key-under-cursor), and we saw before it is easy to get the keys in a link. Let us examine swapping elements of a list here. This is an old algorithm, we store the first value, replace it with the second value, and then set the second value.

(defun org-ref-swap-keys (i j keys)
 "swap the keys in a list with index i and j"
 (let ((tempi (nth i keys)))
   (setf (nth i keys) (nth j keys))
   (setf (nth j keys) tempi))

(org-ref-swap-keys 2 3 '(1 2 3 4))
1 2 4 3

So, we need to get the keys in the link at point, the key at point, the index of the key at point, and then we can swap them, and reconstruct the link. Here is the function that does this, and that adds the hooks.

(defun org-ref-swap-citation-link (direction)
 "move citation at point in direction +1 is to the right, -1 to the left"
 (let* ((object (org-element-context))	 
        (type (org-element-property :type object))
	(begin (org-element-property :begin object))
	(end (org-element-property :end object))
	(link-string (org-element-property :path object))
        (key (org-ref-get-bibtex-key-under-cursor))
	(keys (org-ref-split-and-strip-string link-string))
        (i (index key keys)) point) ;; defined in org-ref
   (if (> direction 0) ;; shift right
     (org-ref-swap-keys i (+ i 1) keys)
     (org-ref-swap-keys i (- i 1) keys))	
  (setq keys (mapconcat 'identity keys ","))
  ;; and replace the link with the sorted keys
  (cl--set-buffer-substring begin end (concat type ":" keys))
  ;; now go forward to key so we can move with the key
  (re-search-forward key) 
  (goto-char (match-beginning 0))))

(add-hook 'org-shiftright-hook (lambda () (org-ref-swap-citation-link 1)))
(add-hook 'org-shiftleft-hook (lambda () (org-ref-swap-citation-link -1)))
lambda nil (org-ref-swap-citation-link -1)


That is it! Wow, not hard at all. Check out this video of the code in action:

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

org-mode source

Org-mode version = 8.2.6

Discuss on Twitter