快速设置任务的开始时间(上)

本文是“实战Elisp”系列的第一篇。本系列旨在讲述我使用Elisp定制Emacs的经验,抛砖引玉,还请广大Emacs同好不吝赐教——如果真的有广大Emacs用户的话,哈哈哈。

序言

用Emacs的org-mode安排业余时间颇有些时日,渐渐地开始编写一些Elisp函数来改善自己的使用体验。

日程管理中一个常见的需求,便是给任务设定一个开始时间。在org-mode中,这可以调用函数org-schedule实现:将光标移动到一个任务上,再按下C-c C-s,会出现一个日历界面,帮助选择日期和时间来作为日程的开始时间。具体效果如下图所示

久而久之发现,设置的开始时间不外乎是中午12点、下午1点、晚上10点等。这是因为业余时间是相对固定的,比如午饭、午休,以及晚上在家洗完澡等。有规律便有优化的空间。既然每次输入的内容都一样,干脆预设几个开始时间,直接选择即可。

平凡的实现

一个朴素的想法,是为这些固定的时间点各自编写一个Elisp函数,并绑定到不同的快捷键上,每次设置开始时间时就按下对应的快捷键。循着这个思路,我定义了如下的Elisp函数:

(defun lt-lunch-todo ()
  "将开始时间设置为中午12点"
  (lt-next-todo 12 0))
(defun lt-rest-todo ()
  "将开始时间设置为下午1点"
  (lt-next-todo 13 0))
(defun lt-supper-todo ()
  "将开始时间设置为傍晚6点35分"
  (lt-next-todo 18 40))
(defun lt-night-todo ()
  "将开始时间设置为晚上10点"
  (lt-next-todo 21 30))

lt-next-todo的定义如下

(defun lt-next-todo (hour minute)
  "设置光标所在行为一个TODO条目,并设置其SCHEDULED为HOUR:MINUTE。

如果当前的时间已经晚于HOUR:MINUTE,那么将会设定为明天的目标小时。"
  (cl-assert (integerp hour))
  (cl-assert (integerp minute))
  (org-todo "TODO")
  (org-set-tags nil t)
  (let ((current-hour (string-to-number (format-time-string "%H")))
        scheduled)
    (cond ((> current-hour hour)
           (setf scheduled (format "+1d %02d:%02d" hour minute)))
          (t (setf scheduled (format "%02d:%02d" hour minute))))
    (message "scheduled: %s" scheduled)
    (org-schedule nil scheduled)))

除了绑定不同快捷键,也可以直接调用:将光标移动到任务标题上,按下M-:,输入lt-lunch-todo,最后按下回车。鉴于每次都按这么多键实在是太麻烦,我又编写了四个AppleScript脚本代劳键盘操作,再用BetterTouchTools定制了四个Touchbar按钮,以便一键调用这四个AppleScript脚本。举个例子,负责调用lt-lunch-todo的AppleScript脚本的内容为

tell application "Emacs"
    activate
end tell
tell application "System Events"
    keystroke ":" using {option down}
    keystroke "(lt-lunch-todo)"
    keystroke return
end tell

BetterTouchTools中的按钮的设置如下图所示

后记

这套方法用久后发现缺陷蛮多:

  1. 要定义很多高度雷同的Elisp函数;
  2. 要编写很多高度雷同的AppleScript脚本;
  3. 要定制很多高度雷同的BetterTouchTools按钮;

高度雷同、高度雷同、高度雷同,重要的事情说三遍。有规律便有优化的空间,于是我换了一种更好的方式,实现了可扩展的、优雅的快速设置任务开始时间的办法。

欲知后事如何,且听下回分解。

如果你希望观看排版效果更好的版本(比如视频可以成功嵌入),可以阅读原文

你可能感兴趣的:(emacs,elisp,org-mode,后端)