I am using org roam to write all of my research notes.
Often I have a note, which part of it is an idea or a question.
I tend to mark these in a section with a TODO tag, or IDEA tag, etc.
The question is: What would be the best practice in displaying say all “TODO” sections that I have in my org roam directory?
I saw this post, but I was not sure if this implements what I am looking for, and even if so if this is a good way of doing that.
Actually, I still did not really try something special for that.
Currently, I am using deft to find free text in notes, but since moving to org-roam v2, it doesn’t work so well.
I thought that marking sections or subsections with TODO, IDEA, etc., would make it easy to integrate with org-agenda later. But the problem is that I do not use org-agenda, so I’d have to learn that fast.
I recall that I read somewhere that org-agenda does not work so well when there are many files, so I think this is not the way to go.
I just saw this post about consult-ripgrep, and I am wondering if this is a good way. Though, I still did not figure out how to use consult-ripgrep.
What I want is to be able to see all notes in which I have an IDEA, or a TODO, or some other keyword, and be able to preview these notes easily.
The performance issue isn’t so bad, really. I have an optimization that I use in mine which only adds files which have TODO entries to the agenda list.
My Emacs Configuration - Search in this page for “vulpea” which shows the relevant section.
Adding the text here for ease:
;; vulpea stuff from https://d12frosted.io/posts/2021-01-16-task-management-with-roam-vol5.html
(use-package vulpea
:after org-roam
;; hook into org-roam-db-autosync-mode you wish to enable
;; persistence of meta values (see respective section in README to
;; find out what meta means)
:hook ((org-roam-db-autosync-mode . vulpea-db-autosync-enable)))
(defun vulpea-project-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."
(seq-find ; (3)
(lambda (type)
(eq type 'todo))
(org-element-map ; (2)
(org-element-parse-buffer 'headline) ; (1)
'headline
(lambda (h)
(org-element-property :todo-type h)))))
(defun vulpea-project-update-tag ()
"Update PROJECT tag in the current buffer."
(when (and (not (active-minibuffer-window))
(vulpea-buffer-p))
(save-excursion
(goto-char (point-min))
(let* ((tags (vulpea-buffer-tags-get))
(original-tags tags))
(if (vulpea-project-p)
(setq tags (cons "project" tags))
(setq tags (remove "project" tags)))
;; cleanup duplicates
(setq tags (seq-uniq tags))
;; update tags if changed
(when (or (seq-difference tags original-tags)
(seq-difference original-tags tags))
(apply #'vulpea-buffer-tags-set tags))))))
(defun vulpea-buffer-p ()
"Return non-nil if the currently visited buffer is a note."
(and buffer-file-name
(string-prefix-p
(expand-file-name (file-name-as-directory org-roam-directory))
(file-name-directory buffer-file-name))))
(defun vulpea-project-files ()
"Return a list of note files containing 'project' tag." ;
(seq-uniq
(seq-map
#'car
(org-roam-db-query
[:select [nodes:file]
:from tags
:left-join nodes
:on (= tags:node-id nodes:id)
:where (like tag (quote "%\"project\"%"))]))))
(defun vulpea-agenda-files-update (&rest _)
"Update the value of `org-agenda-files'."
;;; Not yet fully on org-roam, so also include things in the top level directory
(setq org-agenda-files (append
(remove-if
(lambda (x)
(string-match (regexp-quote ".#") x))
(directory-files org-directory t "org$"))
(vulpea-project-files))))
(require 'vulpea)
(add-hook 'find-file-hook #'vulpea-project-update-tag)
(add-hook 'before-save-hook #'vulpea-project-update-tag)
(advice-add 'org-agenda :before #'vulpea-agenda-files-update)
I just have regular Org-roam nodes called TODO, IDEA etc., and I link to them from other nodes as appropriate. When I want a list of all my TODOs, I just open the TODO node and take a look at the backlinks. It’s nothing fancy, but it has the advantage of being quite performant, since it leans on the node indexing that Org-roam does anyway, precisely for performance reasons.
What I personally do is display the TODO state of an item in the org-roam-node-find UI. This way I always know if a recent file has such a state. I define a cl-defmethod for this. Note that this isn’t necessary, but I dislike the format the existing defmethod uses, so I made my own variation.
(cl-defmethod org-roam-node-todostate ((node org-roam-node))
"Modified version of org-roam-node-todo to look a bit better"
(if-let ((state (org-roam-node-todo node)))
(format "Status: %s" state)))
Then you just add this to org-roam-node-display-template like this (setq org-roam-node-display-template "${title:100} ${backlinkscount:6} ${todostate:20} ${directories:10} ${tags:25}")
Finally, I have a function which runs org-roam-node-find with a filter to only show items which have a todo state. This is rather easy to make
(defun org-roam-node-find-todos ()
"Filtered view of org-roam-node-find which displays only nodes
with a todo state. All my fleeting notes typically have a todo
state indicating I need to work on them so this filter helps me
out"
(interactive)
(org-roam-node-find nil nil #'org-roam-node-todo))
Thanks very much for your tip.
The only thing is that I would like to find also section-items that are not org-roam-nodes…
So I guess this method does not help me with that.
I have a question about your config.
You wrote that this method
(cl-defmethod org-roam-node-todostate ((node org-roam-node))
"Modified version of org-roam-node-todo to look a bit better"
(if-let ((state (org-roam-node-todo node)))
(format "Status: %s" state)))
is not really needed.
However, without it, the org-roam-node-find cannot recognize todostate. Why is that?
The one org-roam has by default is org-roam-node-todo. So instead of todostate you need to put todo. But I personally disliked how it printed that.
Yeah, for non node items, I can’t say I have a solution. I just make fleeting notes exclusively in the org-roam directory so they always show up if they get a todo state.
Edit: Just saw your second message on agenda. I personally dont use it as I do all my “querying” through the org-roam completion UIs or org-ql if that is necessary
There isn’t anything roam specific about agenda. It’s just the normal org mode thing. The snippet I shared just ensures that the variable the org agenda looks at to determine which files to scan is kept up to date.