Emacs 为核心,IOS 作为移动端补充,两者结合形成跨设备的 GTD 工作流

我的事务管理的核心是要将每天做的事项同步到日历中进行记录,以便于我查看某一天我做了哪些工作,某项工作都是在哪些时间完成的。类似下图

为了将事项记录到日历当中,我需要记录事项开始和结束的时间。这在电脑端很方便,在 Emacs 中 org-clock-in 和 org-clock-out 即可。但是总有不方便使用电脑的时候,这时利用手机计时则变成优先选项。目前,在 IOS 上以借助于 Beorg 可以进行任务的计时,其他软件好像都不太行。Beorg 在使用中有一些痛点,最终我还是取消了购买 Beorg 插件,如需要购买其插件才能进行计时,计时默认同步至 LOGBOOK 中,而不是 LOGCLOCK,这与我在 Emacs 中的配置不一致。

下面说说我是如何进行手机端任务计时的。基本的流程是,通过手机端的 Shortcuts 选择 Reminders 中的任务开始计时,将开始的时间写入到 Reminders 中条目的备注中。任务结束时,读取最新修改的任务的开始时间,结合当前时间,将任务的标题写入到 Calendar 中。

通过电脑和手机的结合,基本可以解决任务计时的问题。除了计时之外,还有几个问题需要解决。如 Emacs 中如何将计时的任务写入到日历当中?手机端记录的日历事项怎么同步回 org-agenda-files? org-agenda-files 中的任务怎么同步到 Reminders 中?

GTD 的第一步是捕捉出现在脑海中的任何一件事项。不要让任何可能性从脑海中流逝。我在不同的设备上使用同一个 Inbox.org(收集箱),这个通过文件通过 iCloud 进行多端同步。电脑端使用 Emacs 进行,手机端则是借助 Shortcuts 追加任务至收集箱中。收集箱中的任务处理将在方便的时候使用电脑进行进一步的处理,借助 org-gtd 这个包,会在 modeline 上显示 Inbox 中有几个条目未进行进一步处理。org-gtd 我认为在 Emacs 中执行 GTD 的最好的包。

通常情况是早晨检查 org-agenda,看看有哪些任务是需要今天处理。对于需要今天做的事情,将光标下的任务条目同步至 Apple Reminders 中。这一步是使用手机作为补充任务管理的重要一步。同步至 Reminders 是为了方便我检查今天规划的事项是否完成了,以及进行手机端的任务计时。

涉及到 Calendar 和 Reminders 同步的问题,都是通过 [[GitHub - SavchenkoValeriy/emacs-swift-module: Write Emacs packages in Swift!][SavchenkoValeriy/emacs-swift-module: Write Emacs packages in Swift!]] 实现的。原来我使用 osascript 脚本将 Emacs 中的事项同步至 Calendar 中,但是 osascript 这个太慢了,有点卡 Emacs。所以借助 AI 写了一些代码,基本上可以秒同步。

有人感兴趣的话,我把代码发出来。

5 个赞

之前用过,org-clock-in 和 org-clock-out 也需要手动调用呀。太繁琐了。

现在有了大模型了,是不是可以把在emacs中发生的事件整理,发送给大模型,然后再输出。 代码+测试用git归纳(要求提交git的时候分类规范)。会议用hook(腾讯、飞书)。有点意思

时间统计你是怎么让它自动化的?

这个还是在Emacs中生成的,用 org-report,利用电脑的定时自动生成。

下面是代码:

org-report.el

;; -*- lexical-binding: t; -*-

(defvar icloud "~/Library/Mobile Documents/"
  "This folder contains documents in icloud.")

(setopt org-gtd-directory (expand-file-name "iCloud~com~appsonthemove~beorg/Documents/org" icloud))

(setopt org-agenda-files (list org-gtd-directory))

(defun my/org-batch-generate-report-once ()
  "自动生成今日报告。"
  (interactive)
  (require 'org-datetree)
  (let* ((report-file (expand-file-name 
                       (format "org_report_%s.org" (format-time-string "%Y")) 
                       org-gtd-directory))
         (today-date (calendar-current-date))
         (today-str (format-time-string "%Y-%m-%d %A")))
    
    (with-current-buffer (find-file-noselect report-file)
      (save-excursion
        (goto-char (point-min))
        (if (re-search-forward (concat "^\\*\\*\\* " (regexp-quote today-str)) nil t)
            (let ((end (save-excursion (outline-next-heading) (point))))
              (if (re-search-forward "#\\+BEGIN: clocktable" end t)
                  (message "跳过:今日报告 (%s) 已存在。" today-str)
                (progn
                  (my/org-insert-and-update-clocktable)
                  (message "已更新报告。"))))
          (progn
            (org-datetree-find-date-create today-date)
            (my/org-insert-and-update-clocktable)
            (message "已新建 Datetree 并生成报告:%s" today-str))))
      (save-buffer))))

(defun my/org-insert-and-update-clocktable ()
  "在当前日期标题下插入并更新报告。"
  (end-of-line)
  (insert "\n#+BEGIN: clocktable :scope org-agenda-files :maxlevel 9 :block " 
          (format-time-string "%Y-%m-%d") 
          " :fileskip0 t \n#+END:\n")
  (forward-line -2)
  (org-update-dblock))

com.user.org-report.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.org-report</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Applications/Emacs.app/Contents/MacOS/Emacs</string>
        <string>--batch</string>
        <string>--eval</string>
        <string>(load "/Users/YouName/.emacs.d/report.el")</string>
        <string>--funcall</string>
        <string>my/org-batch-generate-report-once</string>
        <string>--kill</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>23</integer>
        <key>Minute</key>
        <integer>55</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>/tmp/org-report.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/org-report.err</string>
</dict>
</plist>

终端执行,开启定时。

launchctl load ~/Library/LaunchAgents/com.user.org-report.plist

立即执行一次,用于测试流程是否执行的通。

launchctl start com.user.org-report
1 个赞