Storing label links in org-mode

| categories: org-mode | tags:

I am continuing to evolve how I can use org-mode. I have created a label link, which if clicked on checks to see that the label is unique in the buffer. It would be nice to be able to be on a

label:some-label
link, and to store it so we could create a
ref:some-label
later. That ref link is also clickable, and it jumps to the label it refers to, and provides a C-c & option to get back to the ref link. org-mode allows you to create org-PREFIX-store-link functions which store the link information. These functions must determine if they are responsible for storing the link and return nil if not. The first challenge is figuring out if the cursor is on a label link. Here is a function that does that.

This was a little challenging. The strategy to determine if the cursor is in a link is to search backward for a regular expression matching a label link. I found this was not sufficient, because it appeared to me that the matched string was only between the beginning of the label link and the point where the cursor was. So, after finding the beginning of the first label link before the cursor, then we search forward to find the whole link. Then we determine if the cursor is between the beginning and end of the match. If it is, then we are on a label link. Here is the code.

(defun in-label-link ()
  "return label if in a label link, or return nil

we store point, search forward to the first space, and backward to the previous space. then make sure label: is between them."
  (interactive)
  (let ((current-point (point)))
    (save-excursion
      (re-search-backward "label:\\([a-zA-z0-9:-]*\\)" (point-min) t)
      (re-search-forward "label:\\([a-zA-Z0-9-:]*\\)" (point-max) t)   
      (if (and (> current-point (match-beginning 0))
               (< current-point (match-end 0)))
          t
        nil))))

This code works for these kinds of links as far as I can tell. Interestingly, it only works when the cursor is to the right of label:. I am not sure if that is because of the regular expression or not.

label:plain-beginning

label:telabel

label:fig:test

label:bracket-in-line

Now, we create the code that stores the link. We only execute the code if we pass the function that checks if we are on a label link. If we are, then the label is stored in (match-string 1), and we create the link and store it. Finally, we add the function to org-store-link-functions so that it will be used when C-c l is pressed.

(defun org-label-store-link ()
  "store a link to a label. The output will be a ref to that label"
  ;; First we have to make sure we are on a label link. 
  (when (in-label-link)
    (org-store-link-props
     :type "ref"
     :link (concat "ref:" (match-string 1)))))

(add-hook 'org-store-link-functions 'org-label-store-link)

So, here is the evidence that it worked:

ref:plain-beginning

ref:telabel

ref:fig:test

ref:bracket-in-line

For each of these, I put the cursor on the labels, pressed C-c l, and then moved the cursor down here and pressed C-c C-l, and pressed enter and PRESTO! I had the reference that I wanted! That seems like a handy trick.

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

org-mode source

Org-mode version = 8.2.5h

Discuss on Twitter