0

After reading the org-mode manual I didn't find a way to construct structured links referring to headings with endless depth, like:

having a file.org:

* 1  
** 1  
** 2  
*** 1
<---link here

with the link: [[path/to/file.org::*1:2:1]]

It should work also with link abbreviations:

#+LINK: file path/to/file.org::*%s

[[file:1:2:1]]

I was told that I need to write a custom link type to achieve this. I'm aware of the <<target>>, CUSTOM_ID and ID options but they are not good for my use case, where I have a fixed, non-changing structure with a lot of short "leaves". E.g. the Bible. It doesn't make sense to mark each verse with a CUSTOM_ID, when you already have all this information in the headings hierarchy. The raw text will become less readable without any advantage in flexibility (those verses are not going to be restructured).

I'm not that experienced in writing in elisp. Is it difficult to create such custom link type? What is the closest link type that you would recommend to take as starting point (link on code, if possible)?

P.S.:

Maybe, for a more general case, it will be a good idea to be able to also add a <<target>> at the end of the tree, like:

[[MyBook:Chapter 1:Section 5:Subsection 3:target]]

* Chapter 1
...
** Section 5
...
*** Subsection 3
...
<<target>>
...
1

Ignoring a lot of complexities (in particular, the possible presence of todo keywords etc. in the headings and what to do exactly when the file or the heading is not found), a very simple search function to follow this type of links could be something along the lines of

(defun follow-org-heading-link (path)
  "Follow an org-heading link with PATH."
  (let* ((main-parts (split-string path "::\\*"))
         (file (car main-parts))
         (headings (split-string (cadr main-parts) ":")))
    (find-file file)
    (goto-char (point-min))
    (let ((level 1))
      (while (and headings
                  (re-search-forward 
                    (concat "^\\*\\{" (number-to-string level)
                            "\\} +" (car headings))
                    nil t))
        (pop headings)
        (setq level (1+ level)))
    (org-show-set-visibility 'minimal))))

Having defined the follow function, the "org-heading" custom link type itself can be defined simply by

(org-link-set-parameters "org-heading" :follow #'follow-org-heading-link)

The evaluation of the above expressions makes it possible to use and follow [[org-heading:/path/to/file.org::*1:2:1]] type links. Hopefully, this provides a useful starting point for the full solution.

  • Thank you! This is definitely beyond my elisp skills :) One question: the link have to have "org-heading:" at the beginning or will [[/path/to/file.org::*1:2:1]] also work? Otherwise it's kind of heavy syntax for a link... – user1876484 Mar 13 '18 at 18:07
  • Unfortunately, as far as I can see, a custom link type needs to have a special prefix corresponding to the type. Possible simplifications are to choose a very short type/prefix, a shorter separator between the file and the headings, and to omit the brackets. That is, you could get away with something as short as oh:/path/to/file.org|1:2:1. Maybe using non-alphabetic symbols (or possibly a single symbol) as type/prefix is also option -- I don't know whether that is allowed. – Simka Mar 13 '18 at 18:47
  • Will link abbreviation help here, like: #+LINK: My_Book org-heading:path/to/MyBook::*%s and then [[My_Book:1:2:1]]? – user1876484 Mar 13 '18 at 20:46
  • Yes, I've tried it and link abbreviation works. – Simka Mar 13 '18 at 20:54
  • @Simka Can you add :complete function to complete headings for org-link definition? – stardiviner Mar 14 '18 at 5:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.