乍听之下,不无道理;仔细揣摩,胡说八道

0%

优化org-mode管理观影进度

“实战Elisp”系列旨在讲述我使用Elisp定制Emacs的经验,抛砖引玉,还请广大Emacs同好不吝赐教——如果真的有广大Emacs用户的话,哈哈哈。

序言

在之前的文章中,我提到自己用org-mode管理工作日午餐和晚餐要看的动画及其进度。简单来说,就是为每部动画创建同名的二级条目(它们有一个共同的一级条目叫“动画”),每当准备看新一集时,就在对应二级条目下创建形如“观看第X话”的三级条目并设为TODO。

按这种方式,在《钢炼FA》下最终会创建出64个三级条目——而可怜的Emacs甚至一屏只能显示50行!这些“阅后即焚”的三级条目浪费了其它(或许)更有价值的内容的展示空间,因此最好将每一个切换至 DONE状态的三级条目藏起来。

org-mode可以“internal archive”一个条目,但这样仍无法节省它们占据的纵向空间。后来,我想到了org-mode的drawer特性。

思路及函数定义

基于drawer的方案很直接:在org-after-todo-state-change-hook中新增一个钩子。每当一个条目切换至DONE状态、并满足一些条件(比如条目的heading符合“观看第X话”这个模式)时,就将heading的文本与当前时间一起追加到父级条目下、名为“观看进度”的drawer的末端。

org-mode没有内置的函数可以往某个条目的某个drawer中追加内容,需要自行利用“移动光标”和“字符串搜索”来实现。最终的成品如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
(require 'cl)

(defun lt-org-move-episode-to-drawer ()
"往上级heading的drawer中插入一个内容,并删除当前heading。"
;; 用cl-block来实现nonlocal-exit
(cl-block lt-org-move-episode-to-drawer
(let ((state org-state))
(unless (string= state "DONE")
(cl-return-from lt-org-move-episode-to-drawer)))

(let ((tags (org-get-tags-at))
(text (nth 4 (org-heading-components))))
;; 只处理内容以“观看”开头、带有“动画”标签的heading
(unless (and (or (string-prefix-p "观看" text)
(string-prefix-p "继续阅读" text))
(or (member "动画" tags)
(member "阅读" tags)))
(cl-return-from lt-org-move-episode-to-drawer))

(save-excursion
(let (current-position)
;; 记下当前的位置,之后搜索的时候到这里为止
(setq current-position (point))
;; 往上走一级,以便寻找一个名字叫做“观看进度”的drawer
(widen)
(outline-up-heading 1)
(unless (search-forward ":观看进度:" current-position t)
(message "请自行创建“观看进度”的drawer")
(cl-return-from lt-org-move-episode-to-drawer))

;; 继续往前找到:END:的标记
(unless (search-forward ":END:" current-position t)
(message "请确保有完整的“观看进度”的drawer")
(cl-return-from lt-org-move-episode-to-drawer))
;; 往左走五步
(backward-char 5)
;; 开辟一行新的,然后把刚刚完成的任务的内容和时间戳放进来
(org-open-line 1)
(insert (format "“%s” DONE at %s" text (current-time-string)))))
(org-cut-subtree))))

别忘了加入到钩子中

1
(add-hook 'org-after-todo-state-change-hook 'lt-org-move-episode-to-drawer t)

后记

lt-org-move-episode-to-drawer的缺点在于它会删掉切换至DONE状态的条目,因此这个观看记录在*Org Agenda*中会完全消失——这一点尚能接受。

此外,上面的defun完全可以修改为cl-defun,并移除cl-block

Liutos wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
你的一点心意,我的十分动力。