简体   繁体   English

在org-mode中使用LOGBOOK中的时间戳进行自定义搜索

[英]Custom searches using timestamps in LOGBOOK in org-mode

I'd like to create a custom agenda search which will find TODO items based on time entries in the LOGBOOK. 我想创建一个自定义议程搜索,它将根据LOGBOOK中的时间条目找到TODO项目。 Specifically, I'd like to find items tagged WAITING based on the timestamp which marked the entry to the waiting state. 具体来说,我想根据标记等待状态条目的时间戳找到标记为WAITING的项目。 These entries look like this: 这些条目如下所示:

:LOGBOOK:
- State "WAITING"     from "TODO"    [2011-11-02 Wed 15:10] \\
  Emailed so-and-so about such-and-such.
:END:

Can I do this with the information in the logbook? 我可以使用日志中的信息吗? I'm using version 7.5 but can upgrade if necessary. 我使用的是7.5版本,但如果需要可以升级。

Thanks! 谢谢!

Edit: One use case might be to find WAITING todo's which have been the waiting state for more than a week. 编辑:一个用例可能是找到等待状态超过一周的WAITING待办事项。 (Which usually means I need to bug somebody again.) (这通常意味着我需要再次对某人进行攻击。)

The following should do what you need. 以下应该做你需要的。 You'll simply have to adjust the Custom Agenda commands to fit your use-case. 您只需调整自定义议程命令即可适合您的用例。 (When testing and configuring it I used my TODO keywords). (在测试和配置时,我使用了我的TODO关键字)。 It is possible that one portion of this code duplicates the work of a built-in org function, particularly since it resembles the Scheduled and Deadline approach/overdue behaviour, yet I could not see any specific function that would be reusable. 这段代码的一部分可能会复制内置组织函数的工作,特别是因为它类似于Scheduled和Deadline方法/过期行为,但我看不到任何可重用的特定函数。

The actual function to use in the custom command follows. 下面是在custom命令中使用的实际函数。

(defun zin/since-state (since todo-state &optional done all)
  "List Agenda items that are older than SINCE.

TODO-STATE is a regexp for matching to TODO states.  It is provided to
`zin/find-state' to match inactive timestamps.
SINCE is compared to the result of `zin/org-date-diff'.  If
`zin/org-date-diff' is greater than SINCE, the entry is shown in the
Agenda. 
Optional argument DONE allows for done and not-done headlines to be
evaluated.  If DONE is non-nil, match completed tasks.
Optional argument ALL is passed to `zin/find-state' to specify whether
to search for any possible match of STATE, or only in the most recent
log entry."
  (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
    ;; If DONE is non-nil, look for done keywords, if nil look for not-done
    (if (member (org-get-todo-state)
                (if done
                    org-done-keywords
                  org-not-done-keywords))
        (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
               (subtree-valid (save-excursion
                               (forward-line 1)
                               (if (and (< (point) subtree-end)
                                        ;; Find the timestamp to test
                                        (zin/find-state todo-state subtree-end all))
                                   (let ((startpoint (point)))
                                     (forward-word 3)
                                     ;; Convert timestamp into days difference from today
                                     (zin/org-date-diff startpoint (point)))))))
          (if (or (not subtree-valid)
                  (<= subtree-valid since))
              next-headline
            nil))
      (or next-headline (point-max)))))

The following function finds logbook entries through re-search-forward. 以下函数通过重新搜索转发来查找日志条目。

(defun zin/find-state (state &optional end all)
  "Used to search through the logbook of subtrees.

Tests to see if the first line of the logbook is a change of todo
status to status STATE
- Status \"STATE\" from ...
The search brings the point to the start of YYYY-MM-DD in inactive timestamps.

Optional argument END defines the point at which to stop searching.
Optional argument ALL when non-nil specifies to look for any occurence
of STATE in the subtree, not just in the most recent entry."
  (let ((drawer (if all "" ":.*:\\W")))
    (re-search-forward (concat drawer ".*State \\\"" state "\\\"\\W+from.*\\[") end t)))

The last function determines the number of days difference between today and the timestamp found by the above function. 最后一个函数确定今天与上述函数找到的时间戳之间的天数差。

(defun zin/org-date-diff (start end &optional compare)
  "Calculate difference between  selected timestamp to current date.

The difference between the dates is calculated in days.
START and END define the region within which the timestamp is found.
Optional argument COMPARE allows for comparison to a specific date rather than to current date."
  (let* ((start-date (if compare compare (calendar-current-date))))
    (- (calendar-absolute-from-gregorian start-date) (org-time-string-to-absolute (buffer-substring-no-properties start end)))
    ))

Two sample custom agenda commands using the above functions. 使用上述功能的两个示例自定义议程命令。 The first matches up to your use-case, you'll simply have to change "PEND" to "WAITING" for it to match the right keyword. 第一个匹配您的用例,您只需将“PEND”更改为“WAITING”即可匹配正确的关键字。 The second looks for DONE keywords that were completed more than 30 days ago (As opposed to looking for timestamps that have a month matching this/last month as done in the example I'd linked in my first comment). 第二个查找超过30天前完成的DONE关键字(而不是查找与我/上个月匹配的月份的时间戳,就像我在第一个评论中链接的示例中所做的那样)。

(setq org-agenda-custom-commands
      (quote (("T" "Tasks that have been pending more than 7 days." tags "-REFILE/"
               ((org-agenda-overriding-header "Pending tasks")
                (org-agenda-skip-function '(zin/since-state 7 "PEND"))))
              ("A" "Tasks that were completed more than 30 days ago." tags "-REFILE/"
               ((org-agenda-overriding-header "Archivable tasks")
                (org-agenda-skip-function '(zin/since-state 30 "\\\(DONE\\\|CANC\\\)" t))))
              )))

In addition to Jonathan Leech-Pepin answer, if you want to look at CLOSED: drawer added by (setq org-log-done 'time) configuration, you can improve the zin/find-state function like this: 除了Jonathan Leech-Pepin的回答,如果你想看一下CLOSED:抽屉(setq org-log-done 'time)配置,你可以像这样改进zin/find-state函数:

(defun zin/find-state (state &optional end all)
  (let ((drawer (if all "" ":.*:\\W" "CLOSED:")))
    (or (re-search-forward (concat drawer ".*State \\\"" state "\\\"\\W+from.*\\[") end t)
        (re-search-forward (concat drawer ".*\\[") end t))))

PS: This is just a improvement for the answer, the correct answer is the Jonathan's answer. PS:这只是对答案的改进,正确答案是Jonathan的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM