I use org-num-mode to have headlines with a numbering 1.1.1 or 1.2.1... etc

When I use org-insert-link, I want the default description to be this number. For now, it is the text in the headline but I would much prefer the number to be the default setting.

I think if I can get the numbering for a given headline I should be able to cook up something using this thread but I did not find how to get the current headline's numbering.

EDIT: as indicated in the comments, for this to work I must most likely use an export hook to get the section numbers at export time.

  • What happens if you introduce another headline between two of the old headlines? I presume that the numbers change but the links wouldn't. Are you sure you want that?
    – NickD
    Apr 15, 2022 at 21:30
  • You are right I would not want that. Maybe a post-processing like org-export-before-parsing would do the trick. I guess the link would have dummy names that are then replaces in the org-export-before-parsing hook. I am a bit new to elisp but I think this should be doable.
    – TMat
    Apr 16, 2022 at 7:30

1 Answer 1


From org-num--make-overlay we find that org-nume-mode does not insert extra contents in a buffer, but only creates the numbers as overlays (via the 'after-string' property). So, to get the numbers, you should get the appropriate property of that overlay. The following function provides an example for how to achieve what you want:

(defun org-replace-links-descs (&rest _) ; accepts, any number of 'unused'; arguments
  (if (not org-num-mode)
      (message "org-num-mode not active")
    (goto-char (point-min))
    (while (not (stringp (org-next-link)))
      (let* ((context (org-element-context))
             (beg (org-element-property :begin context))
             (end (org-element-property :end context))
             (cbeg (org-element-property :contents-begin context))
             (cend (org-element-property :contents-end context))
             (raw-link (org-element-property :raw-link context))
        (when (string-match  "\\(^*\\|:\\*\\)" raw-link)
            (org-link-open context)
            (unless org-num-mode (org-num-mode))
            (skip-chars-forward "*")
            ;; there can be multiple overlays so we filter out 'org-num' overlay
            (when (string-match "^file" raw-link)
              (setq file (nth 1 (split-string raw-link ":"))))
            (setq num (substring
                        (delete nil
                                (mapcar (lambda (o)
                                          (when (overlay-get o 'org-num)
                                            (overlay-get o 'after-string)))
                                        (overlays-at (point)))))
                       0 -1)))
          (let ((new-desc (concat file (when file ":") num)))
            (if cbeg
                (replace-region-contents cbeg cend (lambda () new-desc))
              (goto-char (1- end))
              (insert "[" new-desc "]"))))))))

(defun my-org-export-dispatch ()
  (when org-num-mode

Now, you can call the org-replace-links-descs function 'manually' before export, or you can create a custom function, where you call org-replace-links-descs before you export function, like in the my-org-export-dispatch example, to 'trigger' the export (another option would be to advise the export function, but if using a 'custom export function' is an option, then that would be the easiest solution).

  • I tried to add this to the export using (add-hook 'org-export-before-parsing-hook #'org-replace-links-descs) but it did not work. Could you explain more what this function do ? How can I use it (i.e. will it change the description of any link I do ? How must I do the link in order for it to be recognized by your code ? ).
    – TMat
    May 9, 2022 at 17:34
  • As mentioned in the answer, you can call the function 'manually', i.e. via M-x, before export. There are two reasons why the function does not work in the hook. First, as mentioned in the hook's docstring, the hook passes a single argument when calling each function. Second, the function in the hook is executed in a copy of the original buffer where org-num-mode is not active. Therefore, you should execute the function in the original buffer before export. I have updated the answer. May 9, 2022 at 19:25
  • To answer your other two questions, it should work on any link in your buffer, as long as you have inserted it using (the format as inserted by) org-insert-link. May 9, 2022 at 19:45
  • Ok thanks. I tested and it does not work: it replaces the description with the number of the section in which the link is currently, it does not replace the description with the number from the target of the link.
    – TMat
    May 10, 2022 at 5:46
  • 1
    Thanks a lot, this work for me.
    – TMat
    May 10, 2022 at 16:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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