Keeping todo items in org-roam v2
Org-roam v2 has been released and yes, it broke my config a bit. Unfortunately the v1-to-v2 upgrade wizard didn't work for me. I realized later that it might have been due to the roam-related functions I'd hooked into `'before-save-hook`. I didn't think about it until I'd already manually touched up almost all my files (there aren't that many) so I can't say anything for sure. However, I think it might be a good idea to keep hooks in mind if one runs into issues with upgrading.
The majority of the time I didn't spend on my notes though, but on the setup I've written about in an earlier post, Keeping todo items in org-roam. Due to some of the changes in v2, changes that I think make org-roam slightly more "org-y", that setup needed a bit of love.
The basis is still the same 4 functions I described in that post, only the details had to be changed.
I hope the following is useful, and as always I'm always happy to receive commends and suggestions for improvements.
Some tag helpers
The very handy functions for extracting tags as lists seem to be gone, in their
place I found org-roam-{get,set}-keyword
. Using these I wrote three wrappers
that allow slightly nicer handling of tags.
(defun roam-extra:get-filetags () (split-string (or (org-roam-get-keyword "filetags") ""))) (defun roam-extra:add-filetag (tag) (let* ((new-tags (cons tag (roam-extra:get-filetags))) (new-tags-str (combine-and-quote-strings new-tags))) (org-roam-set-keyword "filetags" new-tags-str))) (defun roam-extra:del-filetag (tag) (let* ((new-tags (seq-difference (roam-extra:get-filetags) `(,tag))) (new-tags-str (combine-and-quote-strings new-tags))) (org-roam-set-keyword "filetags" new-tags-str)))
The layer
roam-extra:todo-p
needed no changes at all. I'm including it here only for
easy reference.
(defun roam-extra:todo-p () "Return non-nil if current buffer has any TODO entry. TODO entries marked as done are ignored, meaning the this function returns nil if current buffer contains only completed tasks." (org-element-map (org-element-parse-buffer 'headline) 'headline (lambda (h) (eq (org-element-property :todo-type h) 'todo)) nil 'first-match))
As pretty much all functions I used in the old version of
roam-extra:update-todo-tag
are gone I took the opportunity to rework it
completely. I think it ended up being slightly simpler. I suspect the the use of
org-with-point-at 1 ...
is unnecessary, but I haven't tested it yet so I'm
leaving it in for now.
(defun roam-extra:update-todo-tag () "Update TODO tag in the current buffer." (when (and (not (active-minibuffer-window)) (org-roam-file-p)) (org-with-point-at 1 (let* ((tags (roam-extra:get-filetags)) (is-todo (roam-extra:todo-p))) (cond ((and is-todo (not (seq-contains-p tags "todo"))) (roam-extra:add-filetag "todo")) ((and (not is-todo) (seq-contains-p tags "todo")) (roam-extra:del-filetag "todo")))))))
In the previous version roam-extra:todo-files
was built using an SQL query.
That felt a little brittle to me, so despite that my original inspiration
contains an updated SQL query I decided to go the route of using the org-roam
API instead. The function org-roam-node-list
makes it easy to get all nodes
and then finding the files is just a matter of using seq-filter
and seq-map
.
Now that headings may be nodes, and that heading-based nodes seem to inherit the
top-level tags, a file may appear more than once, hence the call to seq-unique
at the end.
Based on what I've seen V2 appears less eager to sync the DB, so to make sure all nodes are up-to-date it's best to start off with forcing a sync.
(defun roam-extra:todo-files () "Return a list of roam files containing todo tag." (org-roam-db-sync) (let ((todo-nodes (seq-filter (lambda (n) (seq-contains-p (org-roam-node-tags n) "todo")) (org-roam-node-list)))) (seq-uniq (seq-map #'org-roam-node-file todo-nodes))))
With that in place it turns out that also roam-extra:update-todo-files
worked
without any changes. I'm including it here for easy reference as well.
(defun roam-extra:update-todo-files (&rest _) "Update the value of `org-agenda-files'." (setq org-agenda-files (roam-extra:todo-files)))
Hooking it up
The variable org-roam-file-setup-hook
is gone, so the the more general
find-file-hook
will have to be used instead.
(add-hook 'find-file-hook #'roam-extra:update-todo-tag) (add-hook 'before-save-hook #'roam-extra:update-todo-tag) (advice-add 'org-agenda :before #'roam-extra:update-todo-files)