Automatically refiling Org Mode headings based on tags
| org, emacsI have lots of different things in my Org Mode inbox. Following the PARA method, I want to file them under projects, areas, resources, or archive so that I can find related things later. Actually, no, I don't want to refile them. I do want to be able to:
- find all the pieces related to something when I'm ready to start working on a task
- find useful links again, especially if I can use my own words
Refiling is annoying on my phone, so I tend to wait until I'm back at
my computer. But even with org-refile-use-outline-path
set to file
and the ability to specify substrings, there's still a bit of
friction.
Tagging is a little easier to do on my phone. I can add a few tags when I share a webpage or create a task.
I thought it would be nice to have something that automatically
refiles my inbox headings tagged with various tags to other subtrees
where I've set a :TAG_TARGET:
property or something like that. For
example, I can set the TAG_TARGET
property to emacsconf
to mean
that anything tagged with :emacsconf:
should get filed under there.
(defcustom my-org-refile-to-ids nil "Searches and IDs." :group 'sacha :type '(repeat (cons string string))) (defun my-org-update-tag-targets () (interactive) (setq my-org-refile-to-ids (let (list) (org-map-entries (lambda () (cons (concat "+" (org-entry-get (point) "TAG_TARGET")) (org-id-get-create))) "TAG_TARGET={.}" 'agenda))) (customize-save-variable 'my-org-refile-to-ids my-org-refile-to-ids)) (defun my-org-add-tag-target (tag) (interactive "MTag: ") (org-entry-put (point) "TAG_TARGET" tag) (push (cons (concat "+" tag) (org-id-get-create)) my-org-refile-to-ids) (customize-save-variable 'my-org-refile-to-ids my-org-refile-to-ids)) ;; Based on https://emacs.stackexchange.com/questions/36360/recursively-refiling-all-subtrees-with-tag-to-a-destination-org-mode (defun my-org-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")))) (nreverse 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))) (defun my-org-refile-to-tag-targets () (interactive) (dolist (rule my-org-refile-to-ids) (my-org-refile-matches-to-heading (car rule) (cdr rule))))
So when I'm ready, I can call my-org-refile-to-tag-targets
and have
lots of things disappear from my inbox.
Next step might be to write a function that will refile just the
current subtree (either going straight to the tag target or prompting
me for a destination if there isn't a matching one), so I can look at
stuff, decide if it needs to be scheduled first or something like
that, and then send it somewhere. There must be something I can pass a
property match to and it'll tell me if it matches the current
subtree - probably something along the lines of
org-make-tags-matcher
…
Anyway, just wanted to share this!