1

I would like to "augment" the org-refile function in such a way that, once I moved the heading from the source to the destination, a link to this last file is created and inserted in the source, in place of the pre-existing heading. The source will generally be a TODO item, but in case of a tree, the title of the link should be the top-level heading of course.

I'm new to elisp and don't know much about emacs customization either, so any hint or help towards a solution would be greatly appreciated. (I'll also try to find my way as soon as I get a minute to work on it, of course).

2

Here's a lightly tested walkthrough of how you could get started with this.

The first thing we need is a way to capture where the heading-to-be-refiled is. Org might store this information itself, but we don't need to worry about that. Let's create a variable that stores a marker to the location (see (info "(elisp)Markers")) and then use advice ((info "(elisp)Advising Functions")) to instruct org-refile to set the variable to that marker before refiling.

(defvar my/org-last-refile-marker nil)

(advice-add 'org-refile
            :before
            (lambda (&rest _)
              (save-excursion
                (org-back-to-heading)
                (setq my/org-last-refile-marker (point-marker))))
            '((name . "my/org-set-refile-marker")))

Next we need to store a link after the heading has been refiled. Org provides a hook, org-after-refile-insert-hook, that we can use.

(defvar my/org-last-refile-link nil)

(defun my/org-set-last-refile-link ()
  (setq my/org-last-refile-link (org-store-link nil)))

(add-hook 'org-after-refile-insert-hook #'my/org-set-last-refile-link)

Now the link text for that heading will be stored in the variable my/org-last-refile-link. The remaining piece is to go back to the original location and insert the link. Again, we can advise org-refile, this time to do something after instead of before.

(advice-add 'org-refile
            :after
            (lambda (&rest _)
              (when (and my/org-last-refile-marker
                         my/org-last-refile-link)
                (let ((buf (marker-buffer my/org-last-refile-marker)))
                  (when (buffer-live-p buf)
                    (with-current-buffer buf
                      (save-excursion
                        (goto-char my/org-last-refile-marker)
                        (insert (concat my/org-last-refile-link "\n"))))))
                (setq my/org-last-refile-marker nil)
                (setq my/org-last-refile-link nil)))
            '((name . "my/org-insert-refile-marker")))

That's got at least a few rough edges. For example, org-refile accepts a prefix argument that makes it do something other than refile. Also it might not work when called via org-agenda-refile. Another thing to consider is whether you want this behavior for every org-refile call. If not, it might make sense to make a custom command that wraps org-refile instead of using the :before advice above.

But hopefully above gives you something to build off of.

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.