一箭双雕——org-mode中的ID和CUSTOM_ID字段

org-mode中,一个条目(entry)可以设置多个属性(Properties)。有的属性是org-mode内置的,有它们的特殊用途。有的属性是自定义的,用在一些插件或仅仅用于记录信息。CUSTOM_ID属于前者,而ID属性后者。

CUSTOM_ID

CUSTOM_ID用于跳转。org-mode支持丰富的外部链接格式,其中之一便是链接到指定.org文件的指定CUSTOM_ID的条目。

比如在一个.org文件中有file:/Users/liutos/Dropbox/gtd/roles/writer.org::#d1bdc978-a8ce-4266-9ffa-b6041f818431这么一段文本,那么当光标置于这个文本中时,按下快捷键C-c C-o,Emacs便会打开文件/Users/liutos/Dropbox/gtd/roles/writer.org,并将光标对应的条目上。

ID

ID用于联系两个条目。一个名叫org-edna的第三方插件能够实现两个条目间的依赖,其中一个要素便是条目的ID属性。

比如我有一个讲解Ada语言的任务(以一个条目的形式存在),同时也有一个学习Ada语言的任务(另一个条目)。显然,必须先学习一番才能讲给他人听,所以第一个条目依赖于第二个条目,于是我先给学习Ada语言的条目设置一个ID属性,值为905fc2f4-4e28-4966-84fa-84c9e6bae96c,然后再为讲解Ada语言的条目中设置一个BLOCKER属性,值为ids(905fc2f4-4e28-4966-84fa-84c9e6bae96c)。如此一来,当讲解Ada语言的条目出现在*Org Agenda*中时,Emacs会将其置灰显示,代表它处于阻塞的状态,必须先处理它的依赖才行。

自动填充CUSTOM_ID和ID

建立依赖和跳转都是很常用的功能,因此我会给每一个条目都设置CUSTOM_IDID属性。为了免除每次都手动设置的麻烦,我用org-modecapture-template特性来实现自动填充。

capture-template是org-mode的又一项利器,用于生成条目间共性的内容,比如行首的星号、关键字,以及写入到哪一个文件的哪一个层级中。org-mode的官网便有一个例子

(setq org-capture-templates
      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
         "* TODO %?\n  %i\n  %a")
        ("j" "Journal" entry (file+datetree "~/org/journal.org")
         "* %?\nEntered on %U\n  %i\n  %a")))

在capture-template中除了可以用预置的占位符(比如上文的%U%i,以及%a),还可以调用任意的Elisp函数——这正适合填充IDCUSTOM_ID这类不重复,并且有一定的格式要求的属性。ID属性的值可以用来自于第三方插件uuidgenuuidgen-4函数来生成

(setq org-capture-templates
      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
         "* TODO %?  :PROPERTIES:\n  :CUSTOM_ID: %(uuidgen-4)\n  :ID: %(uuidgen-4)\n  :END:")))

美中不足的是,CUSTOM_IDID的值是不同的,因为uuidgen-4每次都会返回不同的字符串。有没有什么办法能够让它们一样的呢?答案是肯定的。

一式两份

既然两次调用uuidgen-4的结果不同,那么就将第一次调用后的结果保存起来,然后重复使用即可。思路很简单,实现代码也很直白

(let (lt-org-capture--uuid)
  (defun lt-org-capture-uuidgen ()
    "生成一个UUID并填充到词法作用域的变量中。"
    (setf lt-org-capture--uuid (uuidgen-4))
    lt-org-capture--uuid)
  (defun lt-org-capture-uuidclr ()
    "返回生成好的UUID并清空它。"
    lt-org-capture--uuid))

capture-template也是水到渠成的

(setq org-capture-templates
      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
         "* TODO %?  :PROPERTIES:\n  :CUSTOM_ID: %(lt-org-capture-uuidgen)\n  :ID: %(lt-org-capture-uuidclr)\n  :END:")))

后记

在上面的函数定义中,我试图利用词法作用域特性,使得lt-org-capture--uuid只能被lt-org-capture-uuidgenlt-org-capture-uuidclr读写。遗憾的是,Elisp并不支持词法作用域,lt-org-capture--uuid实际上是一个全局变量——完全可以用C-h v来审视它。

全文完。

阅读原文


留坨诗
一些与编程有关的有趣的东西
169 声望
3.7k 粉丝
0 条评论
推荐阅读
如何在CommonLisp中解析命令行参数
clingon 是一个 Common Lisp 的命令行选项的解析器,它可以轻松地解析具有复杂格式的命令行选项。例如,下面的代码可以打印给定次数的打招呼信息

用户bPGfS阅读 603

封面图
一个HTTP请求的曲折经历
作为程序员的我们每天都在和网络请求打交道,而前端程序员接触的最多的就是HTTP请求。平时工作中,处理网络请求之类的操作是最多的了。但是一个请求从客户端发出到被服务端处理、再回送响应,再被客户端接收这一...

nero24阅读 5.1k评论 1

Nginx 一网打尽:动静分离、压缩、缓存、黑白名单、跨域、高可用、性能优化...
早期的业务都是基于单体节点部署,由于前期访问流量不大,因此单体结构也可满足需求,但随着业务增长,流量也越来越大,那么最终单台服务器受到的访问压力也会逐步增高。时间一长,单台服务器性能无法跟上业务增...

民工哥23阅读 1.1k

封面图
Golang 中 []byte 与 string 转换
string 类型和 []byte 类型是我们编程时最常使用到的数据结构。本文将探讨两者之间的转换方式,通过分析它们之间的内在联系来拨开迷雾。

机器铃砍菜刀24阅读 58.3k评论 2

最好用的 python 库合集
🎈 分词 - jieba优秀的中文分词库,依靠中文词库,利用词库确定汉子之间关联的概率,形成分词结果 {代码...} 🎈 词云库 - wordcloud对数据中出现频率较高的 关键词 生成的一幅图像,予以视觉上的突出 {代码...} 🎈 ...

tiny极客11阅读 2.9k评论 2

封面图
计算机网络连环炮40问
本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~

程序员大彬14阅读 1.8k

万字详解,吃透 MongoDB!
MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常...

JavaGuide8阅读 1.7k

封面图
169 声望
3.7k 粉丝
宣传栏