在直接修改org的纯文本内容之后,如何一键更新org的所有动态更新的内容(如重复任务的下一次时间,任务的总进度,计时任务的总用时)?

在使用org的时候, 我发现有一点不太方便的是,很多时候如果你是对org的纯文本直接修改(比如emacs不在身边,选择使用在纯文本上直接修改,然后再用版本控制推送会emacs本地,或者直接云盘云同步),这个时候很多动态更新的内容是不会更新的,比如progress,比如对任务进行计时,比如repeater。

以下是几个常见的例子:

  1. 更新子任务与总任务的进度
#+title: test
#+STARTUP: logdone

* 测试 [66%]
** DONE 测试子任务一
** DONE 测试子任务二
** TODO 测试子任务三

为了让 org 自动更新测试的总进度,每次更新的时候需要调用 #'org-to-do,这样才会自动更新测试的总进度,比如如果在纯文本上直接修改,将 子任务三的TODO 改成了 DONE,那么测试的总进度不会更新,这个时候你就必须到子任务三所在的标题栏再调用一次#'org-to-do,然后选择进度为DONE,这样才会更新总进度。

  1. checkbox

如果是使用checkbox来更新子任务的话,例如

* 测试 [50%]
- [X] 子任务一
- [  ] 子任务二

这个时候如果手动的修改文本,把子任务二的 [ ] 修改为X,这个时候测试的 50%进度并不会更新,需要在测试这一个大标题所在的这一行调用函数 #'org-update-check-box-count 才能更新。

  1. 修改计时任务的时间
* 遛狗
** 09/01/2022
*** DONE Corridor Walk
CLOSED: [2022-09-01 Thu 16:29]
:LOGBOOK:
CLOCK: [2022-09-01 Thu 16:05]--[2022-09-01 Thu 16:29] =>  0:24
:END:

以上是我使用org来记录每日遛狗的次数以及用时,但是遛狗的时候emacs不在身边,很多时候需要遛完狗之后再过一段时间才能回来更新emacs,这个时候我就只能先随便调用#'org-clock-in以及#'org-clock-out来随便记录一段时间,然后再手动把时间修改为正确的时间,之后在手动调用#'org-evaluate-time-range来更新此次任务时长。

以上的都是我找到对应的函数可以重新更新的,但是对于如果修改了重复任务的时间以后,如何正确的更新 last 以及 下一个 schedule 所对应的日期,我是根本没有找到对应的函数去完成这件事情,难道我真的只能够手动的修改纯文本上的 next schedule 以及 last_property?

  1. 修改重复任务的完成时间
* TODO 测试
SCHEDULED: <2022-09-02 Fri 00:50 .+3h>
:PROPERTIES:
:LAST_REPEAT: [2022-09-01 Thu 21:50]
:END:
- State "DONE"       from "TODO"       [2022-09-01 Thu 21:50]
- State "DONE"       from "TODO"       [2022-09-01 Thu 20:50]
- State "DONE"       from "TODO"       [2022-09-01 Thu 19:50]

这个时候如果我手动将最新的最后一次的任务时间从21:50修改为了22:35,我希望有一个函数(或者说我没找到这个函数)能够自动将LAST_REPEAT属性也修改为22:35,同时schedule的下一次的时间能够自动从00:50更新为01:35。事实上这个功能对于我来说我觉得是非常重要的,因为现实中每一次完成任务的的时候你刚好emacs都在身边能够立即更新完成任务的时间实在是罕见的,很多时候完成了任务以后,都要过一段时间才能使用emacs。

以上问题的总结

对于每一个这种可以动态更新的内容,如果手动修改了纯文本,那么想重新更新得到对应的内容,每一个内容可能都对应了一个不同的函数(而且org的函数特别多,找起来很费时间),而且有的动态更新的内容到目前我甚至还没有找到对应的函数(比如对于一个repeat的任务,如果修改了最后一次完成的时间以后。如何将下一次schedule的时间也对应的做更新)。

如果自己手动实现这样的函数,实现难点在于,首先这些动态更新的函数都不是更新整个文本,而只更新你当前所处于的标题的层级,你需要遍历所有的标题层级依次调用这些函数,其次有些修改纯文本后要如何动态更新到底对应什么函数,我根本就不知道。 想知道有没有一个函数实现可以将org的所有的这些需要动态更新的内容都一键更新。

PS:org里有一个函数叫做·org-update-all-dblocks·,但是org官方文档所指的dblocks似乎和我这里指的可以动态更新的内容并不是一回事。

这个应该没有人会直接修改吧,都是用的快捷键,shift+left|right调整任务状态,然后一级标题也会一并更新

第二、三个例子我也不知道怎么操作,但我觉得应该都不会是用输入文本修改的方式解决,而是有快捷键可以用的吧。如果是觉得快捷键不好用,可以随意改的,比如 我的改法 应该比较独特,我还没见过也这么用的人

他的问题是没有用emacs,有emacs当然是直接使用快捷键最好了。

如果有机会使用emacs的话,对于计时任务的修改、可以使用S+方向键在原地修改时间,这样的话计时长会自动更新。 但是对于重复任务的时间记录,我发现使用S+方向键也不会更新LAST_REPEAT和next scheduled time,非常蛋疼,或者如果直接在文本上直接删除了一整条完成任务的记录,emacs也不会更新next scheduled time。

在reddit上提问了类似的问题,结论是对于最后一个问题, 4. 修改重复任务的完成时间,是无解的。理由是因为org内部更新 next schedule time并不会追踪LAST REPEAT的值,也不会去追踪最新一条LOG NOTE的完成时间。看来如果我想要实现workaround的或多或少的“半自动更新”能力的话,只能手动的写一个小的hack函数了。

可能你可以参考一下这个 package 的思路: