有没有办法根据子标题 todo-keywords 计算 org-mode 标题属性?
Is there a way to calculate org-mode heading properties based on sub heading todo-keywords?
这就是我使用 org-capture 记录一天的方式
*** 2020-05-14 Thursday
:PROPERTIES:
:DoneA: 1
:DoneB: 1
:DoneC: 0
:Done: 0
:Kill: 1
:Gone: 1
:Rate: 5
:END:
:LOGBOOK:
CLOCK: [2020-05-14 Thu 04:55]--[2020-05-14 Thu 05:05] => 0:10
:END:
**** DONE [#A] task a
**** GONE [#A] another task a
**** DONE [#B] task b
**** KILL other task
我手动计算并输入每个属性
并使用简单汇率手动填写汇率属性
对于完成 [#A] 我给分数 5,#B 3,杀死 2,完成 -5
所以比率 属性 是 = 5
是否有内置的函数或 emacs 可以根据 org-todo-keywords 计算子标题并将其放入 upper-level 标题属性中?
我的 elisp 技术不够好,无法制作自定义函数
没有这样的功能(这取决于你想找到什么的细节和你想记录它的方式)但是肯定有构建你自己的积木,所以我鼓励你改进你的elisp 技能,尽管我会尝试在下面给出一个有启发性的例子来说明你将如何去做。
首先要知道的是 Org 模式提供 a powerful function、org-map-entries
,它可以迭代一组选定的标题,并在访问每个标题时应用任意函数。例如。这是一个简单的使用示例(直接来自手册 - 请参阅上面的 link),以计算子树中与某些表达式 match
匹配的条目数:
(defun count-tasks (match)
(length (org-map-entries t match 'tree)))
如果您定义此函数,请将光标放在感兴趣日期的标题上(在您的示例中为 *** 2020-05-14 Thursday
),然后像这样调用它:
ESC-ESC-: (count-tasks "/+DONE) RET
它将 return 子树中 DONE
条目的数量 - 在您的示例中,该数字应为 2。
第二个要知道的是,有一个 Property API 提供了在标题上获取 (org-entry-get
) 和设置 (org-entry-put
) 属性的函数。因此,例如,您可以通过执行此操作将 "Done" 属性 设置为子树中 DONE
任务的数量(我假设您的光标仍然像以前一样位于标题处) :
ESC-ESC-: (org-entry-put (point) "Done" (format "%d" (count-tasks "/+DONE")) RET
我们对任务进行计数,将数字转换为带有 format
的字符串并添加(或修改)一个名为 Done
的 属性 以将字符串化数字作为值。
这些是碎片。你现在必须把它们放在一起做你想做的事。有些匹配有点复杂,例如要计算优先级为 A
的所有 DONE
个标题,您需要说 (count-tasks "PRIORITY=\"A\"/+DONE")
.
所以您只需要为每个要计算的项目执行此操作,并设置适当的 属性 但还要记住每个计数,以便计算您的费率。这只是这些计数的加权和,如果您对向量有所了解,您可能会意识到它是两个向量的 dot (scalar) product
:权重向量和计数向量,通过相乘得到将两个向量的相应元素放在一起并将所有结果相加(顺便说一句,您的权重未完全指定:您缺少 DoneC 类别的权重 - 我选择为下面的该类别添加权重 1)。在 lisp 中有很多方法可以做到这一点,具体取决于您如何表示这些向量。举一个简单的例子,我可以将它们表示为元素列表,然后将速率实现为对两个列表的 map-reduce 操作:
(defun rate (counts)
(let ((weights '(5 3 1 2 -5)))
(seq-reduce #'+ (mapcar* #'* weights counts) 0)))
你应该阅读 mapcar*
和 seq-reduce
的文档字符串:它们非常有用(APL 是一种大量使用这些操作的语言),但是如果你发现有点晦涩,你也可以使用循环实现它:
(defun rate-iter (counts)
(let ((weights '(5 3 1 2 -5))
(rate 0))
(while counts
(setq rate (+ rate (* (car counts) (car weights)))
counts (cdr counts)
weights (cdr weights)))
rate))
然后您可以按照与上面完全相同的方式将其作为 属性 输入:
ESC-ESC-: (org-entry-put (point) "Rate" (format "%d" (rate counts)))
这些都是碎片,但您仍然需要编写一些代码将它们组合在一起。
希望这有帮助。
这就是我使用 org-capture 记录一天的方式
*** 2020-05-14 Thursday
:PROPERTIES:
:DoneA: 1
:DoneB: 1
:DoneC: 0
:Done: 0
:Kill: 1
:Gone: 1
:Rate: 5
:END:
:LOGBOOK:
CLOCK: [2020-05-14 Thu 04:55]--[2020-05-14 Thu 05:05] => 0:10
:END:
**** DONE [#A] task a
**** GONE [#A] another task a
**** DONE [#B] task b
**** KILL other task
我手动计算并输入每个属性 并使用简单汇率手动填写汇率属性
对于完成 [#A] 我给分数 5,#B 3,杀死 2,完成 -5 所以比率 属性 是 = 5
是否有内置的函数或 emacs 可以根据 org-todo-keywords 计算子标题并将其放入 upper-level 标题属性中?
我的 elisp 技术不够好,无法制作自定义函数
没有这样的功能(这取决于你想找到什么的细节和你想记录它的方式)但是肯定有构建你自己的积木,所以我鼓励你改进你的elisp 技能,尽管我会尝试在下面给出一个有启发性的例子来说明你将如何去做。
首先要知道的是 Org 模式提供 a powerful function、org-map-entries
,它可以迭代一组选定的标题,并在访问每个标题时应用任意函数。例如。这是一个简单的使用示例(直接来自手册 - 请参阅上面的 link),以计算子树中与某些表达式 match
匹配的条目数:
(defun count-tasks (match)
(length (org-map-entries t match 'tree)))
如果您定义此函数,请将光标放在感兴趣日期的标题上(在您的示例中为 *** 2020-05-14 Thursday
),然后像这样调用它:
ESC-ESC-: (count-tasks "/+DONE) RET
它将 return 子树中 DONE
条目的数量 - 在您的示例中,该数字应为 2。
第二个要知道的是,有一个 Property API 提供了在标题上获取 (org-entry-get
) 和设置 (org-entry-put
) 属性的函数。因此,例如,您可以通过执行此操作将 "Done" 属性 设置为子树中 DONE
任务的数量(我假设您的光标仍然像以前一样位于标题处) :
ESC-ESC-: (org-entry-put (point) "Done" (format "%d" (count-tasks "/+DONE")) RET
我们对任务进行计数,将数字转换为带有 format
的字符串并添加(或修改)一个名为 Done
的 属性 以将字符串化数字作为值。
这些是碎片。你现在必须把它们放在一起做你想做的事。有些匹配有点复杂,例如要计算优先级为 A
的所有 DONE
个标题,您需要说 (count-tasks "PRIORITY=\"A\"/+DONE")
.
所以您只需要为每个要计算的项目执行此操作,并设置适当的 属性 但还要记住每个计数,以便计算您的费率。这只是这些计数的加权和,如果您对向量有所了解,您可能会意识到它是两个向量的 dot (scalar) product
:权重向量和计数向量,通过相乘得到将两个向量的相应元素放在一起并将所有结果相加(顺便说一句,您的权重未完全指定:您缺少 DoneC 类别的权重 - 我选择为下面的该类别添加权重 1)。在 lisp 中有很多方法可以做到这一点,具体取决于您如何表示这些向量。举一个简单的例子,我可以将它们表示为元素列表,然后将速率实现为对两个列表的 map-reduce 操作:
(defun rate (counts)
(let ((weights '(5 3 1 2 -5)))
(seq-reduce #'+ (mapcar* #'* weights counts) 0)))
你应该阅读 mapcar*
和 seq-reduce
的文档字符串:它们非常有用(APL 是一种大量使用这些操作的语言),但是如果你发现有点晦涩,你也可以使用循环实现它:
(defun rate-iter (counts)
(let ((weights '(5 3 1 2 -5))
(rate 0))
(while counts
(setq rate (+ rate (* (car counts) (car weights)))
counts (cdr counts)
weights (cdr weights)))
rate))
然后您可以按照与上面完全相同的方式将其作为 属性 输入:
ESC-ESC-: (org-entry-put (point) "Rate" (format "%d" (rate counts)))
这些都是碎片,但您仍然需要编写一些代码将它们组合在一起。 希望这有帮助。