EMACS-DOCUMENT

=============>随便,谢谢

记录Org-mode的近期活动

我最近了解了一下concept工具。既然每个人都使用它,那它肯定差不了。但是作为emacs用户,我仍然更喜欢org-mode。

只不过我在使用org-mode时从未想过一个功能,那就是记录你活动的能力。比如你什么时候重新安排了某件事或者改变了任务的状态。

I did some search online and came up with a solution. I'm pretty sure there's better ways to do so. I'll just put the codes here. It leverages the org-agenda-custom-commands and the :LOGBOOK: feature. And the code is mainly from with some modification. 我在网上搜索了一下,找到了一个解决方案。当然肯定还有比这更好的方法。我把代码记在这里。它利用了 org-agenda-custom-commands:LOGBOOK: 特性。代码主要修改自 这里

;; enable the log feature
(setq org-log-into-drawer t)
(setq org-log-reschedule 'time)
(setq org-log-redeadline 'note)
(setq org-log-note-clock-out t)

;; add T: before timestamp for easy regex search
(setq org-log-note-headings '((done . "CLOSING NOTE T:%t")
                              (state . "State %-12s from %-12S T:%t")
                              (note . "Note taken on T:%t")
                              (reschedule . "Rescheduled from %S on T:%t")
                              (delschedule . "Not scheduled, was %S on T:%t")
                              (redeadline . "New deadline from %S on T:%t")
                              (deldeadline . "Removed deadline, was %S on T:%t")
                              (refile . "Refiled on T:%t")
                              (clock-out . "Clocked out on T:%t")))

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

Looking for T:[2018-09-14 Fri 10:50] kind of time stamp in logbook."
  (let* ((closed (re-search-forward "^CLOSED: \[" end t))
         (created (if (not closed) (re-search-forward "^:CREATED: \[" end t)))
         (logbook (if (not closed) (re-search-forward ".*T:\[" end t)))
         (result (or closed logbook created)))
    result))

(defun +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)))))

(defun +org/last-update-before (since)
  "List Agenda items that updated before SINCE day."
  (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
    (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
                                     (+org/find-state subtree-end))
                                (let ((startpoint (point)))
                                  (forward-word 3)
                                  ;; Convert timestamp into days difference from today
                                  (+org/date-diff startpoint (point)))
                              (point-max)))))
      (if (and subtree-valid (>= subtree-valid since))
          next-headline
        nil))))

(defun +org/has-child-and-last-update-before (day)
  (if (+org/has-child-p) (point)
    (+org/last-update-before day)))

之后我们就可以在 org-agenda-custom-commands 中通过 +org/last-update-before+org/has-child-and-last-update-before 函数来过滤 SINCE 天前更新过的活动了. 就像这样.

(setq org-agenda-custom-commands
      '(("R" "Recent activity"
         ((tags "*"
                ((org-agenda-overriding-header "Recent Activity")
                 (org-agenda-skip-function '(+org/has-child-and-last-update-before 7)))))
         nil nil)))

该代码将只搜索 “:LOGBOOK:” 中以 T:, :CREATED::CLOSED 开头的时间戳。它工作得很好,对我颇有帮助。也许我应该写一个议程排序功能,让他们按改变的时间排序。但现在对我来说足够了。

更新:2018-09-24 如果有人对自动记录标题的变化感兴趣,你可以看这个 这个 stackoverflow问题。答案中给出了一种方法,那就是使用散列来记录标题甚至是内容中做出任何更改的最后修改时间。