[想法]Org agenda 显示时间块

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,可能有很多问题正在疯狂编辑……

26 个赞

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

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

(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)
2 个赞

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

你可以看看这两个页面:

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

我看这个patch好像还没进入Org Mode,不知道楼主现在有时间提交patch么?

啊抱歉最近没怎么用 Emacs 就没上论坛 :sweat:。我对贡献 patch 那一套不太熟,如果你有兴趣的话就提交试试?版权什么的不用带上我。

1 个赞

@hawnzug 好的,我在Org Mode邮件列表上问问,我把 commit的author设为你的邮箱和名字,把commiter设置为我。这样的代码量不知道是否超出了GNU的最低限制。 感谢。

1 个赞

Ok, 想要合并提交PATCH到Org contrib,但是维护者Bastien没同意,说应该放在Worg。于是推送到Worg上了。

3 个赞

any reference? why?

这是我在邮件列表里的thread

https://lists.gnu.org/archive/html/emacs-orgmode/2020-02/msg00438.html

还有我推送到 org-hacks.org 的更新:

https://orgmode.org/worg/org-hacks.html

1 个赞

好奇怪啊,我把这段代码放到了我的 spacemacs 的配置里,结果看到时间块颜色生效了,但是时间块的高度却没有生效

你是不是世间不够长,你clock in,然后clock out,然后手动把clock时间加长到2小时,看会不会有高度。

时间不短,好几个小时呢。

(if (< duration 30) 1.0 (+ 0.5 (/ duration 60)))

这是半小时内高度为1个单位,超过半小时的,每满1小时增加0.5个单位吧?


对了,我把 CLOCK 放到 LOGBOOK 里了: 这会不会导致识别不到 duration?

(setq org-log-into-drawer "LOGBOOK")

不会,我也是放在logbook里的。 你要不自己edebug调试下。我这边也想不到什么情况会导致这个问题。

额,我也遇到这个问题了,调试了好多地方,就是找不到原因。 @ziyuanjun 你找到原因了么?

  • [X] 我 git bisect 了下 Org Mode “master” branch 里近4个月的commit,没有找到 bad commit
  • [X] Edebug 调试了几个相关的函数 (所有调用了 org-agenda-finalize 这个函数的函数),有颜色重绘的效果,但是调用 hook上的自定义函数 从来没有被Edebug捕获到过,这个真是奇怪,当我edebug在 org-agenda-redo 函数上的时候,倒是能捕获edebug断点了。但是只有一次能够重现 overlay 被设置了高度。其他几次都看不到效果。这个也很奇怪。
  • [X] 我bisect 了下我Emacs的配置,也没发现问题。

这个真是让我相当困惑。

你看截图,edebug调试的时候, overlay 确实在设置高度。这个就是那个唯一一次捕获到调用的情况。

即使我手动在 org agenda buffer 里执行函数 (org-agenda-log-mode-colorize-block) 也没效果。

我测试了下 emacs -q 然后加载 hook 函数,还是无法设置高度。不知道到底是哪里出了问题。怀疑是在绘制 colorized blocks 后又被什么操作给自动覆盖了。

没有啊。我还不会Edebug 这么高级的操作

只能求教原作者了。 @hawnzug 在么?求教下这个是什么原因导致的?

哇,您agenda中 category 前面的icon是怎么设置的呢?就是日历,电脑的小图标。