使用 aider 辅助编程写了一个 org-mode 下自动根据标题生成 schedule 时间的函数

如题。今天第一次试用这种 AI 进行辅助编程。不然的话,以我的代码水平,写一个这种函数,可能得磨蹭一天时间了。

我试了 aider.el, 但一来没有高亮,二来似乎没法折行,体验比终端使用难免会差一些,所以体感上还是有 vterm 配合 aider 终端会好一些。

说回代码。功能其实很简单,就是写了一个 TODO 项之后,运行这个函数,就会自动将其中的时间解析成一个 schedule,从而可以在 agenda 中查看。

支持的句式举例:

  • TODO 周一10点到11点
  • TODO 星期二九点到20点
  • TODO Wednesday 6点32分 to 七点26
;;; org-time-parser.el --- Automatic time parsing for org-mode headings -*- lexical-binding: t; -*-
;;; package --- Summary
;;; Commentary:
;;; This is a function used to automatically parse and set SCHEDULED dates/times from TODO headings.
;;; Code:

(require 'org)
(defun my/org-parse-time-from-title ()
  "Automatically parse and set SCHEDULED dates/times from TODO headings.
Supports:
- Relative dates: today/今天, tomorrow/明天, day after tomorrow/后天
- Weekdays: Monday-Sunday, 周一-周日, 星期一-星期日
- Time ranges: 14h30-16h, 11点15分-13点, 9:00-10:30
- Automatic date fallback to today when no date specified"
  (interactive)
  (when (org-get-todo-state)
    (let ((title (org-get-heading))
          (today (format-time-string "<%Y-%m-%d %a>" (current-time)))
          time-range)
      ;; Check for date keywords
      (let ((date (cond
                   ((string-match-p "\\<today\\>\\|\\<今天\\>" title)
                    (current-time))
                   ((string-match-p "\\<tomorrow\\>\\|\\<明天\\>" title)
                    (time-add (current-time) (* 60 60 24 1)))
                   ((string-match-p "\\<day after tomorrow\\>\\|\\<后天\\>" title)
                    (time-add (current-time) (* 60 60 24 2)))
                   ((string-match "\\<\\(周[一二三四五六日]\\|星期[一二三四五六日]\\|Monday\\|Tuesday\\|Wednesday\\|Thursday\\|Friday\\|Saturday\\|Sunday\\)\\>" title)
                    (let* ((chn-weekday (match-string 1 title))
                           (translations '(("周一" . "Monday") ("周二" . "Tuesday") ("周三" . "Wednesday")
                                           ("周四" . "Thursday") ("周五" . "Friday") ("周六" . "Saturday")
                                           ("周日" . "Sunday") ("星期一" . "Monday") ("星期二" . "Tuesday")
                                           ("星期三" . "Wednesday") ("星期四" . "Thursday") ("星期五" . "Friday")
                                           ("星期六" . "Saturday") ("星期日" . "Sunday")))
                           (eng-weekday (or (cdr (assoc chn-weekday translations)) chn-weekday)))
                      (date-to-time (org-read-date nil nil (concat "next " eng-weekday)))))
                   (t (current-time))))) ; Default to today if no date specified
                  (when date
                    (setq today (format-time-string "<%Y-%m-%d %a>" date))
          ;; Check for time range
          ;; TODO conditions like 明天早上五点到明天晚上8点,明天早上8点到后天下午20点,明天打游戏到晚上8点,两天后睡觉
          (when (string-match "\\([0-9]+\\|[一二三四五六七八九十]+\\)\\(?:点\\([0-9]+\\|[一二三四五六七八九十]+\\)?分?\\|h\\([0-9]+\\|[一二三四五六七八九十]+\\)?\\)\\(?:\\s-*\\(?:到\\|to\\|-\\)\\s-*\\([0-9]+\\|[一二三四五六七八九十]+\\)\\(?:点\\([0-9]+\\|[一二三四五六七八九十]+\\)?分?\\|h\\([0-9]+\\|[一二三四五六七八九十]+\\)?\\)\\)?" title)
            (let* ((chn-number-map '(("一" . "1") ("二" . "2") ("三" . "3") ("四" . "4") 
                                    ("五" . "5") ("六" . "6") ("七" . "7") ("八" . "8")
                                    ("九" . "9") ("十" . "10") ("两" . "2")))
                   (to-arabic (lambda (s) 
                               (mapconcat (lambda (c) (or (cdr (assoc (string c) chn-number-map)) (string c)))
                                          (string-to-list s) "")))
                   (start-hr (funcall to-arabic (match-string 1 title)))
                   (start-min (funcall to-arabic (or (match-string 2 title) (match-string 3 title) "00")))
                   (end-hr (and (match-string 4 title) (funcall to-arabic (match-string 4 title))))
                   (end-min (and end-hr (funcall to-arabic (or (match-string 5 title) (match-string 6 title) "00")))))
              (setq time-range (if (and end-hr end-min)
                                   (format " %s:%s-%s:%s"
                                           start-hr (if (string-empty-p start-min) "00" start-min)
                                           end-hr (if (string-empty-p end-min) "00" end-min))
                                 (format " %s:%s"
                                         start-hr (if (string-empty-p start-min) "00" start-min))))))
          ;; (evil-open-below 1)
          (org-entry-put (point) "SCHEDULED"
                         (concat today (or time-range ""))))))))
;; Automatically run parser after heading creation
;; (add-hook 'org-capture-after-finalize-hook #'my/org-parse-time-from-title)
;; (add-hook 'org-roam-post-node-insertion-hook #'my/org-parse-time-from-title)
;; FIXME These hooks will be executed in the buffer which calls the capture, not the buffer where the node is inserted.

(provide 'org-time-parser)

;;; org-time-parser.el ends here
3 个赞

很赞!

这部分能够再缩写一下就好了,建议在 reddit 的 r/org-mode 宣传一下

使用 vterm 配合 aider 感兴趣的话可以看看我写的这两个 lisp file,把常用的从 emacs 端发送内容到任意 Tui App 的操作做了一个简单的抽象,配合 vterm 当后端使用 aider。

vterm-repl.el:一组用 vterm和 repl 进行交互的函数

vterm-repl-aider.el: 基于 vterm-repl 又定义了一些基本的专门针对 aider 的操作。

emacs 和 aider 的互操作性肯定还是 aider.el 最好,但是我很需要 vterm 的高亮效果,又不需要很复杂的和 emacs 的互操作性。所以就基于 vterm 实现了一些简单的互操作就够了。

以下是我自己的使用的快捷键,以及窗口配置(默认是 给 aider 分配一个专门的 tab)供参考


(defun mg--get-tab-name (buffer alist)
    "Retrieve the name of a tab associated with a BUFFER.  This
function is intended for use with `display-buffer-in-tab'.  The
behavior is straightforward: if a tab already exists with the same
name as the BUFFER, it is reused; otherwise, a new tab is created."
    (buffer-name buffer))

;; aider (a llm based code assistant) integration
(add-to-list 'display-buffer-alist
             `("\\*aider\\*"
               (display-buffer-in-tab)
               (tab-name . mg--get-tab-name)))

(general-create-definer mg-aider-map
    :prefix "SPC a"
    :non-normal-prefix "M-SPC a"
    :prefix-map 'mg-aider-map)

(mg-aider-map
    :keymaps 'override
    :states '(normal insert motion visual)
    "s" #'vtr~aider-start
    "r" #'vtr~aider-send-region-operator
    "h" #'vtr~aider-hide-window
    "e" #'vtr-aider-prompt
    "g" #'vtr-aider-set-prefix
    "G" #'vtr-aider-remove-prefix
    "y" #'vtr-aider-yes
    "n" #'vtr-aider-no
    "a" #'vtr-aider-abort
    "q" #'vtr-aider-exit
    "ma" #'vtr-aider-ask-mode
    "mA" #'vtr-aider-arch-mode
    "mc" #'vtr-aider-code-mode)


感谢大佬点评,我有点不太明白,请问是缩写成

\\(Mon\\|Tues\\|Wednes\\|Thurs\\|Fri\\|Satur\\|Sun\\)day

这样的形式吗?但这样缩写能提高正则的性能吗?

赞嘞,我研究研究

没有,只是方便输入,不用每次都输入这么长的英文。

比如我是用户,我更喜欢缩写而不是输入整个 Monday。

1 个赞