Emacs的org-mode实现自动的internal archive

缘由

org-mode是一个Emacs内置的major mode,当打开一个后缀为.org的文件时就会被启用。在官网的介绍中提到,它可以用于管理待办事项,而这也正是我目前使用org-mode最多的场合。比如,我用它来记录漫画的阅读进度,每一话或每一章就是一个标记了TODO关键字的条目,读完那一话或那一章后就会将对应的条目标记为DONE。一般我会一周一次地归档自己标记为DONE的条目,但由于一次要处理的条目可能很多,逐一将它们归档比较繁琐,因此,便打算二次开发实现一个自动归档的功能。

需要事先声明的是,本文不是org-mode的入门教程,也不会讲解如何配置org-mode。对这方面有兴趣的读者,可以自己搜索一番,资料还是相当丰富的。

菜谱

对于每一个被完成的单独的阅读任务,我的做法是将其internal archive。等到一整本漫画都读完之后,再将整个以漫画名命名的条目归档到别的文件中去。要实现自动的internal archive,最简单直接的办法是借助于org-mode提供的各种hook。

org-mode提供了许多的hook,在官方的文档中有一一列举 。其中,名为org-after-todo-state-change-hook的便是我所需要的钩子。只需往这个变量所绑定的列表中添加一个函数,那么这个函数便会在条目切换状态时(比如从TODO切换到DONE)被org-mode调用。

最终的ELisp代码如下

1
2
3
4
5
6
7
8
(defun lt-archive-if-manga ()
(let ((state org-state))
(when (string= state "DONE")
(let ((tags (org-get-tags-at)))
(when (member "漫画" tags)
(org-toggle-archive-tag))))))

(add-to-list 'org-after-todo-state-change-hook 'lt-archive-if-manga t)

稍微解释一下。从C-h v org-after-todo-state-change-hook RET的文档可以得知,条目的新状态可以通过变量org-state获取。取得新状态(是个字符串)后,首先检查其是否为"DONE"。如果是,再检查这个条目是否为一个阅读漫画的任务。

在我的用法中,凡是漫画条目,都打上了名为"漫画"的标签。因此,使用函数org-get-tags-at取得一个条目的所有标签(包括从父级条目继承下来的),再用member函数判断这些标签中是否包含字符串"漫画"。如果有,就调用org-toggle-archive-tag将该条目internal archive。

传给函数add-to-list的第三个参数t的作用,是让这个新加入钩子的函数最后被调用。

全文完