用org-roam管理笔记一段时间了,记录、捕获、文献管理都用得舒服,就是任务管理不方便。我原来的agenda是固定在几个文件中(手动设置org-agenda-files),使用org-roam后会生成大量org,如果全部设置为agenda目录,则生成agenda太慢也太乱。
于是提出如下想法:
- 固定的agenda文件仍然在org-agenda-files中
- 由一个变量维护动态agenda文件,在任何org文件中,当org entry状态变为todo类时,自动把文件加到该变量,当任务完成后,如果该文件中所有任务都完成,则从变量去除org文件
- 变量保存到custom中(不知道更好办法)
经过折腾,如下代码暂时可用:
(defvar dynamic-agenda-files nil
"dynamic generate agenda files list when changing org state")
(defun update-dynamic-agenda-hook ()
(let ((done (or (not org-state) ;; nil when no TODO list
(member org-state org-done-keywords)))
(file (buffer-file-name))
(agenda (funcall (ad-get-orig-definition 'org-agenda-files)) ))
(unless (member file agenda)
(if done
(save-excursion
(goto-char (point-min))
;; Delete file from dynamic files when all TODO entry changed to DONE
(unless (search-forward-regexp org-not-done-heading-regexp nil t)
(customize-save-variable
'dynamic-agenda-files
(cl-delete-if (lambda (k) (string= k file))
dynamic-agenda-files))))
;; Add this file to dynamic agenda files
(unless (member file dynamic-agenda-files)
(customize-save-variable 'dynamic-agenda-files
(add-to-list 'dynamic-agenda-files file)))))))
(defun dynamic-agenda-files-advice (orig-val)
(union orig-val dynamic-agenda-files :test #'equal))
(advice-add 'org-agenda-files :filter-return #'dynamic-agenda-files-advice)
(add-to-list 'org-after-todo-state-change-hook 'update-dynamic-agenda-hook t)
22 个赞
很好用。Agenda 集中管理任务的优势可以和 Org-roam 的发散思维优势合并在一起。
把楼主的代码,也搬运到了 Org-roam 的英文社区,让更多的人用到你的函数。
2 个赞
我现在是只用一个task文件, 添加新任务通过org-roam-capture往task.org中来添加.
提示symbol’s function definition is void: union
问下有啥解决方法吗
1 个赞
我也遇到了这个问题,暂时没精力去 debug。 d12frosted 给出了类似的解决办法,可供参考。另外 Org-roam 最近在准备一次大的的升级,可以等新版本出来以后再折腾。
很奇怪的问题, 我使用org-roam-capture追加的内容, 会添加到文档的首行, 而不是末行. 不知道中哪儿有问题, 也不知道怎么解决.
leo
7
因为union是common lisp 的一个函数,在emacs中通过cl-union来模拟这个函数。
所以把union换成cl-union就可以了
leo
8
多谢楼主,已经在使用这个方案了。非常棒。 稍微有些小瑕疵,不过不影响使用
谢谢补充,union在我这是cl-seq.el文件中,换成cl-union吧
最新遇到了个问题,有时候会出现agenda视图不能用,我的是doom emacs,执行org-agenda,会出现org-check-agenda-file: Wrong type argument: stringp, nil错误。然后我把楼主的配置去掉,重启就又好了
我也是在doom emacs下用,没出现这个问题。看下你的org-agenda-files
,还可检查下dynamic-agenda-files
的值。我是手动设置org-agenda-files
固定几个文件作日常任务。然后动态配合其他笔记作任务管理。
我昨天也刚好读到,不过由于我的是静态与动态agenda files相结合,暂时没用上。
ddaren
15
我目前的方式是,把 org-agenda-files 变量设置成一个文档,比如 “gtd.org”。然后把 daily 目录添加到这个文档里面。如果在其他笔记里面有任务,就通过 “C-c [” 手工添加到 “gtd.org” 这个文档里。
目前用的是下面这个,以前的性能不是太好。参考过的都在代码的链接里了。
主要想法:
- org-agenda-files 列表,里面放固定作为agenda扫描的目录或文件。
- 所有在 org-roam 中的文件,当一个headline变为 TODO了,就把这个文件作为agenda file。当完成时,自动排除。省去考虑agenda的心智。
;;* dynamic agenda https://github.com/brianmcgillion/doomd/blob/master/config.org
;; https://d12frosted.io/posts/2021-01-16-task-management-with-roam-vol5.html
;; The 'roam-agenda' tag is used to tell vulpea that there is a todo item in this file
(add-to-list 'org-tags-exclude-from-inheritance "roam-agenda")
(require 'vulpea)
(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-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 (&optional arg)
"Update PROJECT tag in the current buffer."
(interactive "P")
(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 "roam-agenda" tags))
(setq tags (remove "roam-agenda" 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))))))
;; https://systemcrafters.net/build-a-second-brain-in-emacs/5-org-roam-hacks/
(defun my/org-roam-filter-by-tag (tag-name)
(lambda (node)
(member tag-name (org-roam-node-tags node))))
(defun my/org-roam-list-notes-by-tag (tag-name)
(mapcar #'org-roam-node-file
(seq-filter
(my/org-roam-filter-by-tag tag-name)
(org-roam-node-list))))
(defun dynamic-agenda-files-advice (orig-val)
(let ((roam-agenda-files (delete-dups (my/org-roam-list-notes-by-tag "roam-agenda"))))
(cl-union orig-val roam-agenda-files :test #'equal)))
(add-hook 'before-save-hook #'vulpea-project-update-tag)
(advice-add 'org-agenda-files :filter-return #'dynamic-agenda-files-advice)
3 个赞
挺好的, 正好需要这个.
我现在还只能到处抄代码的小白阶段, 用的是 doom emacs,
把上面这段复制到 config.el 里, 第一行就报错. 是不是我还应该安装其它的什么东西?
我也是好久之前用过下doom,快忘光了。你试下把它放在after!宏里面:
(after! org-roam
;;放在这里
)
还有要安装个 vulpea
包
安装了 vulpea 包, 也把代码用 after! 括起来了, 测试了一下, emacs 没有报错, 也可以找得到 roam 里面刚刚添加的 todo 了. 多谢多谢…
不过, 发现一个小问题: 之前我有个目录~/roam/, 保存的是 roam v1 的 org 文档. 后来升级了 roam v2, 现在指定的 org 目录是 ~/roam2/, 在运行 org-agenda 命令的时候, 它把 v1 里面的 todo 也显示出来了. 而且, 第一次运行的时候, 非常慢.