[想法]Org agenda 显示时间块


#1

org-agenda-log-mode 会显示记录了时间的条目,比如 17:00-19:00 Clocked: (2:00) blabla 这样一行文字。虽然包括了起止时间和耗时,但我总感觉这个功能有点鸡肋。因为我使用 Clock 记录时间的主要目的是方便自己看每天花了多少时间在哪些事情上,便于在夜深人静的时候为自己的碌碌无为的一天而感到悔恨。但是在 agenda 里每个条目占用的页面比例(行高)都是一样的,虽然可以一个一个看总耗时,但是直观上看起来每件事都占了差不多的时间。比如打了十个小时游戏和学了五分钟 Emacs 在视觉上都差不多,都是一行字。我希望能像 Google Calendar 或者别的时间记录软件那样,通过时间块的形式来可视化展现在每件事上花费时间的多少。一开始我打算用定时导出 Agenda 之类的方式生成图片然后设置为桌面背景。但是由于我每天看桌面的次数寥寥无几,最终这个方案就无疾而终了。昨天发现 text property 里面有 line-heightline-spacing 两个属性,想到能不能用行高来模拟时间块。折腾了一番最终效果如图:

代码如下:

(defun my:org-agenda-time-grid-spacing ()
  "Set different line spacing w.r.t. time duration."
  (save-excursion
    (let ((colors (list "#F6B1C3" "#FFFF9D" "#BEEB9F" "#ADD5F7"))
          pos
          duration)
      (nconc colors colors)
      (goto-char (point-min))
      (while (setq pos (next-single-property-change (point) 'duration))
        (goto-char pos)
        (when (and (not (equal pos (point-at-eol)))
                   (setq duration (org-get-at-bol 'duration)))
          (let ((line-height (if (< duration 30) 1.0 (+ 0.5 (/ duration 60))))
                (ov (make-overlay (point-at-bol) (1+ (point-at-eol)))))
            (overlay-put ov 'face `(:background ,(car colors)))
            (setq colors (cdr colors))
            (overlay-put ov 'line-height line-height)
            (overlay-put ov 'line-spacing (1- line-height))))))))

然后在 org-agenda-finalize-hook 里加上这个函数。现在是30分钟以下都用正常的一行显示,30分钟以上按比例扩展行高,这样如果不记录睡眠时间的话差不多一个屏幕正好显示一天的记录。屏幕大一点的话可以用20分钟为单位,这样更精确一点。当然最重要的还是不要忘记记录时间以及回顾总结,让 log 好看一点主要只是激发我记录的兴趣和动力。

不知道有没有人也有类似需求的可以一起讨论下。另外这是我第一次写超过10行的 defun,代码只是 works for me,可能有很多问题正在疯狂编辑……


#2

这个特性很赞,我觉得可以添加到Org Mode里去,有没有考虑贡献给Org Mode?这样别人也会改善这个功能的。你觉得呢?


#3

我加上了根据主题背景是黑还是白来自动选择颜色配色。

(defun my:org-agenda-time-grid-spacing ()
  "Set different line spacing w.r.t. time duration."
  (save-excursion
    (let* ((background (alist-get 'background-mode (frame-parameters)))
           (background-dark-p (string= background "dark"))
           (colors (if background-dark-p
                       (list "#aa557f" "DarkGreen" "DarkSlateGray" "DarkSlateBlue")
                     (list "#F6B1C3" "#FFFF9D" "#BEEB9F" "#ADD5F7")))
           pos
           duration)
      (nconc colors colors)
      (goto-char (point-min))
      (while (setq pos (next-single-property-change (point) 'duration))
        (goto-char pos)
        (when (and (not (equal pos (point-at-eol)))
                   (setq duration (org-get-at-bol 'duration)))
          (let ((line-height (if (< duration 30) 1.0 (+ 0.5 (/ duration 60))))
                (ov (make-overlay (point-at-bol) (1+ (point-at-eol)))))
            (overlay-put ov 'face `(:background ,(car colors)
                                                :foreground
                                                ,(if background-dark-p "black" "white")))
            (setq colors (cdr colors))
            (overlay-put ov 'line-height line-height)
            (overlay-put ov 'line-spacing (1- line-height))))))))

(add-hook 'org-agenda-finalize-hook #'my:org-agenda-time-grid-spacing)

#4

啊谢谢!我还没有了解过这种内置包的贡献方式,等有时间了看一下,不知道你有什么建议吗。然后我感觉这种方式有一个问题就是用背景色来区分不同时间块会不会有点激进,毕竟和主题背景和各种 face 都很容易冲突。我一开始用的是 box 但是效果不太好,有些左右边框不显示,所以用了色块来区分。另外一点就是终端下没有用。还有我也打算对当前正在计时的条目采用相同的显示方式,但还没试过太懒了


#5

你可以看看这两个页面:

如果是第一次贡献给FSF,你需要PDF电子签署一份声明,也就是你的代码版权问题。 如果是minor patch,比如2,3行代码,就不用的。你这个应该需要。签署一次以后,以后都不用签署了,所有FSF下的都能用。很快的。以前需要邮寄文本,现在电子PDF就能签了。