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

GTD的第一条原则是“搜集”,为此我有一个inbox.org文件,专门记录所有的新想法、新任务。我会在每晚的固定时间处理其中的内容——有些可以马上开始做并做完,更多的则是移动到其它.org文件中,等待排期。

org-mode有一个内置的快捷键C-c C-w,专门完成将条目(org-mode的术语,即.org文件中带星号前缀的一行,参见An Explanation of Basic Org-Mode Concepts)移动到其它.org文件的需求,但它有一个缺陷——不能把条目移动到其它.org文件的顶层,而这是我经常需要做的。

为了移动到顶层,需要:

  1. 使用org-cut-subtree命令剪切当前条目(其实还会包括条目的子节点,但inbox.org中的条目基本上都没有子节点);
  2. 打开目标的.org文件;
  3. 将光标定位到文件末尾;
  4. 使用org-paste-subtree命令粘贴条目。

为了轻松完成上述四个步骤,org-refile-to-eof函数应运而生。

org-refile-to-eof函数

废话不多说,直接亮相吧

;;; 定义一个Helm的source,以便选择要粘贴的.org文件
(defvar *org-refile-eof--helm-source* nil
  "用于提供目标.org文件下拉菜单的来源")

;;; 将当前条目剪切并粘贴到某个目标.org文件的末尾
(defun org-refile-to-eof ()
  "将当前条目剪切到一个.org文件的末尾。"
  (interactive)
  ;; 先调用Helm获取目标.org文件。这里需要处理没有选中任何文件的情况
  (let ((path (helm :sources '(*org-refile-eof--helm-source*))))
    (when path
      (org-cut-subtree)
      (save-excursion
        ;; 打开选中的文件的buffer,并移动到最后
        (find-file path)
        (end-of-buffer)
        ;; 调用org-paste-subtree粘贴进去
        (org-paste-subtree)))))

变量*org-refile-eof--helm-source*定义了helm函数所要求的下拉列表名称、选项,以及选中后的处理逻辑(Helm的使用可以从How to write helm extension入门)。在我的环境中,它的值是

(setq *org-refile-eof--helm-source*
      '((name . "refile到下列的哪个文件")
        (candidates . org-agenda-files)
        (action . (lambda (candidate)
                    candidate))))

现在,只需要敲入M-: org-refile-to-eof RET便能轻松完成之前繁琐的四个步骤。

后记

如果有迫切需求的话,我会考虑将org-refile(也就是C-c C-w对应的命令)和org-refile-to-eof合并在一起。例如,按下C-c C-w时调用的是org-refile,而按下C-u C-c C-w时调用的则是org-refile-to-eof,想想也有点小激动呢。

阅读原文


用户bPGfS
169 声望3.7k 粉丝