(defvar org-para-base-dir "~/org"
"PARA 方法的根目录。")
(setq org-capture-templates
`(("p" "Project - 项目任务" entry
(file+headline ,(expand-file-name "projects/inbox.org" org-para-base-dir)
"Projects Inbox")
"* TODO %?\n %U\n %a\n %i"
:empty-lines 1)
("a" "Area - 领域任务" entry
(file+headline ,(expand-file-name "areas/inbox.org" org-para-base-dir)
"Areas Inbox")
"* TODO %?\n %U\n %a\n %i"
:empty-lines 1)
("r" "Resource - 资源笔记" entry
(file ,(expand-file-name "resources/inbox.org" org-para-base-dir))
"* %? :resource:\n %U\n %i"
:empty-lines 1)
("j" "Journal - 日记" entry
(file+datetree ,(expand-file-name "journal.org" org-para-base-dir))
"* %?\n %U"
:empty-lines 1)
("c" "Capture with choice" entry
(file+headline ,(expand-file-name "projects/inbox.org" org-para-base-dir)
"Projects Inbox")
"* TODO %^{任务描述}\n %U\n %a\n %i"
:empty-lines 1)))
(setq org-refile-targets
`((,(expand-file-name "projects/*.org" org-para-base-dir) :maxlevel . 2)
(,(expand-file-name "projects/**/*.org" org-para-base-dir) :maxlevel . 2)
(,(expand-file-name "areas/*.org" org-para-base-dir) :maxlevel . 2)
(,(expand-file-name "areas/**/*.org" org-para-base-dir) :maxlevel . 2)
(,(expand-file-name "resources/*.org" org-para-base-dir) :maxlevel . 1)
(,(expand-file-name "resources/**/*.org" org-para-base-dir) :maxlevel . 1)
(,(expand-file-name "archives/*.org" org-para-base-dir) :maxlevel . 1)))
(setq org-refile-use-outline-path 'file)
(setq org-outline-path-complete-in-steps t)
(setq org-agenda-files
(list (expand-file-name "projects" org-para-base-dir)
(expand-file-name "areas" org-para-base-dir)))
(setq org-agenda-custom-commands
'(("P" "PARA 视图"
((agenda "" ((org-agenda-span 'week)))
(todo "TODO|INPROGRESS"
((org-agenda-overriding-header "活跃项目任务")
(org-agenda-files (list (expand-file-name "projects" org-para-base-dir)))))
(todo "TODO"
((org-agenda-overriding-header "领域维护任务")
(org-agenda-files (list (expand-file-name "areas" org-para-base-dir)))))))
("p" "仅项目任务"
todo "TODO|INPROGRESS"
((org-agenda-overriding-header "项目任务")
(org-agenda-files (list (expand-file-name "projects" org-para-base-dir)))))))
(with-eval-after-load 'org-roam
(setq org-roam-directory org-para-base-dir)
(setq org-roam-node-display-template
"${tags:20} ${title:*}")
(defun my/org-roam-filter-by-tag (tag)
"返回一个过滤函数,只保留带有 TAG 的 org-roam 节点。"
(lambda (node)
(member tag (org-roam-node-tags node))))
(defun my/org-roam-list-notes-by-tag (tag)
"列出所有带有 TAG 的 org-roam 笔记文件路径。"
(mapcar #'org-roam-node-file
(seq-filter
(my/org-roam-filter-by-tag tag)
(org-roam-node-list))))
(defun my/org-roam-find-project ()
"查找或创建项目笔记。"
(interactive)
(org-roam-node-find nil nil (my/org-roam-filter-by-tag "project")))
(defun my/org-roam-find-area ()
"查找或创建领域笔记。"
(interactive)
(org-roam-node-find nil nil (my/org-roam-filter-by-tag "area")))
(defun my/org-roam-find-resource ()
"查找或创建资源笔记。"
(interactive)
(org-roam-node-find nil nil (my/org-roam-filter-by-tag "resource"))))
(defun my/para-archive-project (project-file)
"将一个完成的项目移到 archives 目录。
PROJECT-FILE 是项目文件或目录的路径。"
(interactive
(list (completing-read "归档项目: "
(directory-files
(expand-file-name "projects" org-para-base-dir)
t directory-files-no-dot-files-regexp))))
(let* ((archive-dir (expand-file-name "archives" org-para-base-dir))
(project-name (file-name-nondirectory project-file))
(dest (expand-file-name project-name archive-dir)))
(rename-file project-file dest)
(message "已归档: %s -> %s" project-name dest)))
(defun my/para-show-stats ()
"显示当前 PARA 各层的文件数量统计。"
(interactive)
(let ((stats
(cl-loop for category in '("projects" "areas" "resources" "archives")
for dir = (expand-file-name category org-para-base-dir)
for count = (length (directory-files-recursively dir "\\.org$"))
collect (cons category count))))
(with-output-to-temp-buffer "*PARA Stats*"
(princ "PARA 目录统计\n")
(princ (make-string 30 ?=)) (terpri)
(cl-loop for (cat . cnt) in stats
do (princ (format "%-15s %d 个文件\n" cat cnt)))
(terpri)
(princ (format "总计: %d 个文件\n"
(cl-loop for (_ . cnt) in stats sum cnt))))))
(global-set-key (kbd "C-c p c") #'org-capture)
(global-set-key (kbd "C-c p a") #'org-agenda)
(global-set-key (kbd "C-c p s") #'my/para-show-stats)
(global-set-key (kbd "C-c p A") #'my/para-archive-project)
(provide 'para-config)