Whoa, this is perfect. Basically, one can use #+filetags: TODO and the little snippet I posted has to be updated, and you can find all the nodes (either file notes or headings) with TODO, like so:
I’d love to hear of any other improvements and adjustments you make
Of course. Here’s what I did:
I wrote a function to toggle TODO states in note-files
Advised org-todo function, now, it is possible to toggle TODO state with C-c C-t, and not only in the headings, but also the note-files
Improved “find-nodes-with-todo-state”
Here’s the full set of functions, sorry @magthe, I slightly changed the names of those awesome helpers you wrote (for consistency with the rest of my config)
(require 'dash)
;; filetag helpers borrowed from:
;; https://magnus.therning.org/2021-07-23-keeping-todo-items-in-org-roam-v2.html
(defun org-roam/get-filetags ()
(split-string (or (org-roam-get-keyword "filetags") "")))
(defun org-roam/add-filetag (tag)
(let* ((new-tags (cons tag (org-roam/get-filetags)))
(new-tags-str (combine-and-quote-strings new-tags)))
(org-roam-set-keyword "filetags" new-tags-str)))
(defun org-roam/kill-filetag (tag)
(let* ((new-tags (seq-difference (org-roam/get-filetags) `(,tag)))
(new-tags-str (combine-and-quote-strings new-tags)))
(org-roam-set-keyword "filetags" new-tags-str)))
(defun org-roam/org-todo-keywords->list ()
(let ((lst (-partition-by
(lambda (s) (string-equal s "|"))
(seq-map
(lambda (s) (replace-regexp-in-string "\(.*" "" s))
(cl-rest (car org-todo-keywords))))))
`(,(car lst) ,(caddr lst))))
(defun org-roam/find-nodes-with-todo-state (todo-state)
"Finds all nodes with selected TODO state.
For headings that would be regular Org-mode TODO cookie,
for file notes it's managed with TODO filetag."
(interactive "P")
(let ((todo-state (or todo-state
(completing-read
"Choose TODO state"
(-flatten (org-roam/org-todo-keywords->list))))))
(org-roam-node-find
nil nil
(lambda (node)
(or (string-equal todo-state (org-roam-node-todo node))
(seq-contains-p (org-roam-node-tags node) todo-state)
(seq-contains-p (org-roam-node-tags node) todo-state))))))
(defun org-roam/toggle-todo-state-in-node (&optional new-state)
"Togggle TODO filetag in Org-roam node file."
(interactive "P")
(when (and (not (active-minibuffer-window))
(org-roam-file-p))
(let* ((all-states (-flatten (org-roam/org-todo-keywords->list)))
(new-state (or new-state
(completing-read "Choose TODO state" all-states)))
(current (seq-find
(lambda (tag)
(seq-contains-p all-states tag))
(org-roam/get-filetags))))
(when current (org-roam/kill-filetag current))
(when (not (string-equal current new-state))
(org-roam/add-filetag new-state)))))
(defun org-todo--around (old-fn &rest args)
(if (and (not (active-minibuffer-window))
(org-roam-file-p)
(not (ignore-errors (org-get-outline-path 'with-self?))))
(funcall 'org-roam/toggle-todo-state-in-node)
(apply old-fn args)))
(advice-add 'org-todo :around #'org-todo--around)
Thanks to your initial idea, I was able to take my TODO-fu to another level
This entire snippet is “fresh out of the press”; please let me know if I’ve missed something (most likely I have)
Before this, I used a few Org-roam Nodes named: TODO 1, ONGOING, DONE, CANCELLED, and I’d add a link to a node (to designate its todo state).
And then, to find all nodes that are in “TODO” state, I would navigate to the * TODO heading and toggle backlinks buffer.
That’s pretty straightforward, simple, very “Org-Roamy” and has some benefits, like for example you can see all the items that are in todo state as a sub-section in the graph.
But this new approach with filetags and vanilla Org todo states feels a bit more ergonomic.
Of course, the austere simplicity of Org mode allows you to automate it and use both these ways, i.e., whenever you toggle TODO state (with C-c C-t) - it would add/remove/change link to the relevant todo state Org-Roam node.
I’m not sure now if I end up using both ways, or would stick to one. But it’s nice to have different ways.
1 Actually, Org wouldn’t let me create a heading named “TODO”, so I used a different name and addded :roam_alises: TODO