Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
(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)))
(unless (eq original-tags tags)
(apply #'vulpea-buffer-tags-set (seq-uniq 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'."
(setq org-agenda-files (vulpea-project-files)))
(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)
@d12frosted

This comment has been minimized.

Copy link
Owner Author

@d12frosted d12frosted commented Jan 16, 2021

Migration of existing notes can be achieved by evaluating the following code:

(dolist (file (org-roam--list-all-files))
  (message "processing %s" file)
  (with-current-buffer (or (find-buffer-visiting file)
                           (find-file-noselect file))
    (+org-notes-project-update-tag)
    (save-buffer)))
@rcgary

This comment has been minimized.

Copy link

@rcgary rcgary commented Jan 22, 2021

Nice one! thanks for share

@d12frosted

This comment has been minimized.

Copy link
Owner Author

@d12frosted d12frosted commented Jan 22, 2021

You are welcome! @rcgary

@Whil-

This comment has been minimized.

Copy link

@Whil- Whil- commented Mar 7, 2021

This is great. Really valuable in order for Org agenda to be usable together with Org roam.

One comment on the first function, +org-notes-project-p. I modified it slightly for my own use to also include schedules and deadlines. And while doing that realized that it can be optimized a bit. The difference is that org-element-map stops at the first non-nil result and that seq-find is not used at all. This is the result (including the added lines for schedules and deadlines):

(defun +org-notes-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."
    (org-element-map
        (org-element-parse-buffer 'headline)
        'headline
      (lambda (h)
        (let ((todo-type (org-element-property :todo-type h))
              (scheduled (org-element-property :scheduled h))
              (deadline (org-element-property :deadline h)))
          (or (eq todo-type 'todo)
              scheduled
              deadline)))
      nil 'first-match))
@d12frosted

This comment has been minimized.

Copy link
Owner Author

@d12frosted d12frosted commented Mar 8, 2021

@Whil- This function should be tuned for your needs 😸 All my items with schedule and deadline actually have a todo cookie.

When optional argument FIRST-MATCH is non-nil, stop at the first
match for which FUN doesn’t return nil, and return that value.

I didn't know about that, this is something I was looking for. I will update this Gist and my blog post. Thanks a lot.

@d12frosted

This comment has been minimized.

Copy link
Owner Author

@d12frosted d12frosted commented Mar 8, 2021

@Whil- I have updated both post and this Gist. Please keep in mind that I have updated the naming a little bit to reflect how things are called in my configurations.

@Whil-

This comment has been minimized.

Copy link

@Whil- Whil- commented Mar 8, 2021

Nice!

And thank you again for the code. Very valuable in the Org roam context since org agenda is so painfully slow (unless all files are already loaded into buffers)!

@d12frosted

This comment has been minimized.

Copy link
Owner Author

@d12frosted d12frosted commented Mar 8, 2021

@Whil- You are welcome :) I created this snipped for the same reason, org-agenda becomes very slow with relatively big number of notes. In my case, 1000-1500 notes already required ~50 seconds to build agenda. With this approach I am back to less than 1 second :D

@jinder1s

This comment has been minimized.

Copy link

@jinder1s jinder1s commented May 13, 2021

Since org-roam v2 no longer uses roam_tags, how would you suggest modifying this? Using org-mode file tags doesn't seem great since that ends up tagging all the headlines in the whole file.

@d12frosted

This comment has been minimized.

Copy link
Owner Author

@d12frosted d12frosted commented May 13, 2021

@jinder1s see updated post - https://d12frosted.io/posts/2021-01-16-task-management-with-roam-vol5.html

Update 1: regarding tags - I exclude project from tag inheritance - also briefly described in the post.

Update 2: actually tag inheritance is not described there, will update. But basically, I add the following line to my init.el:

  (setq
   org-tags-exclude-from-inheritance '("project"
                                       "litnotes"
                                       "people"))
@d12frosted

This comment has been minimized.

Copy link
Owner Author

@d12frosted d12frosted commented May 14, 2021

@jinder1s updated the post and this Gist. Thanks for giving it a try 😸

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment