2

Suppose we have:

* Parent
** Child1 :@Tag:
*** Child of Child1
** Child2
*** Child of Child2
** Child3 :@Tag:
*** Child of Child3

Is there a way to copy all subtrees of * Parent with tag @Tag to a destination (say * Destination), so that we get:

* Destination
** Child1 :@Tag:
*** Child of Child1
** Child3 :@Tag:
*** Child of Child3

1 Answer 1

2

Sadly `org-refile' isn't a programmatically friendly function. What you want to do is generate a RFLOC parameter value for your desired target and use "Copy" as the MSG value. Here's some code to do it programmatically.

I recommend using org ID's whenever possible to virtually eliminate any ambiguity in reference to headings. First, create an ID for the destination and use that.

(let* ((target-heading "Destination")
       (target-marker (org-find-exact-headline-in-buffer target-heading))
       (target-id (save-excursion (goto-char target-marker)
                                  (org-id-get-create))))
  target-id)
;; => "22bdee5f-3c93-4ca7-b944-48db2ddc3538"

Then here is a function to help programmatically refile or copy those headings:

(defun ebpa/refile-matches-to-heading (match target-heading-id &optional scope copy)
  "Refile all headings within SCOPE (per `org-map-entries') to TARGET-HEADING-ID."
  (if-let (target-marker (org-id-find target-heading-id t))
      (let* ((target-rfloc (with-current-buffer (marker-buffer target-marker)
                             (goto-char target-marker)
                             (list (org-get-heading)
                                   (buffer-file-name (marker-buffer target-marker))
                                   nil
                                   target-marker)))
             (headings-to-copy (org-map-entries (lambda () (point-marker)) match scope)))
        (mapc
         (lambda (heading-marker)
           (with-current-buffer (marker-buffer heading-marker)
             (goto-char heading-marker)
             (org-refile nil nil target-rfloc (when copy "Copy"))))
         headings-to-copy)
        (message "%s %d headings!"
                 (if copy "Copied" "Refiled")
                 (length headings-to-copy)))
    (warn "Could not find target heading %S" target-heading-id)))

You can use it in the following way:

(ebpa/refile-matches-to-heading
 "TAGS={@Tag}"
 "22bdee5f-3c93-4ca7-b944-48db2ddc3538"
 'file
 t)
2
  • This works, but it has a weird effect of joining header lines together (from the original org header that you're trying to partially refile) after running. I skimmed your code and don't see anything that could affect the layout of the original org-headers though. Any ideas of what's causing this?
    – George
    Oct 23, 2017 at 13:17
  • 1
    @George Sorry about that. The bug in my code is early use of marker-position. I'll fix it shortly. (Fixed) I don't know why I thought org-refile would accept a position, but not a marker.
    – ebpa
    Oct 23, 2017 at 16:07

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.