在 2021-07-17 org-roam v2 已经正式合并到master分支,已经不用再像本文一样折腾了。

写在前面

org-roam V2 终于到了 Pre-release 阶段,许多等不及的人已经开始尝鲜了,新版本最令人印象深刻的功能就是更细粒度的链接:之前,org-roam 的链接只能以文件为单位,而如今,它已经能够细化到任意层级的 headline 了。

具体来说,V2 有如下重大更新:

  • 链接从 file link 改为基于 org-id 的 link ,进而能链接任意 headline
  • tag 系统变更,从 ROAM_TAG 切换为 org-mode 原生的 tag 系统

链接效果如下:

然而 V2 也会引入新的问题:

  • 完全不兼容 V1 版本的笔记
  • 暂不支持 graph, org-roam-server 等图形化界面
  • 搜索列表中的标签展示功能还有待优化,我就遇到了中文标签显示不全的问题
  • ox-hugo, org-publish 之类的导出功能或许会受到影响

如果你已经了解了以上问题,但还是想要体验 V2, 并且用的也是 Doom Emacs, 那么请继续往下看,因为我已经提前蹚了大部分的坑,或者你也可以先读一读官方提供的文档

从 org-roam V1 切换到 V2

卸载旧版本

  • Doom Emacs 提供了 org-roam 的整合,在 ~/.doom.d/init.el 文件中注释掉相关代码:
       (org               ; organize your plain life in plain text
        ;; +roam          ; 注释掉这一行,如果有的话
        )
  • 注释掉 ~/.doom.d 目录下所有的 org-roam 配置,因为很多配置项 V2 已经不兼容了。
  • 删除 ~/.emacs.d/.local/straight/repos/org-roam 目录,避免旧版本代码的干扰。文档上没有这项要求,但是实测如果不删,会导致 doom 更新的时候拉取不了 v2 版本的代码。

安装新版本

org-roam 的开发者为 Doom Emacs 提供了安装说明(而 Spacemacs 却还没有……),这里只是添加了一些补充说明。

  • ~/.doom.d/package.el 中添加:
(package! org-roam
  :recipe (:host github :repo "org-roam/org-roam" :branch "v2"))
  • ~/.doom.d/config.el 中写入配置:
(setq org-roam-directory "~/Documents/org/roam") ;改成你的文件位置
(use-package! org-roam
  :after org
  :commands
  (org-roam-buffer
   org-roam-setup
   org-roam-capture
   org-roam-node-find)
  :config
  ;;(setq org-roam-mode-sections
  ;;      (list #'org-roam-backlinks-insert-section
  ;;            #'org-roam-reflinks-insert-section
  ;;            #'org-roam-unlinked-references-insert-section))
  (org-roam-setup))
  • 退出 emacs, 在终端依次执行 doom upgrade, doom build . 注意务必重新 build ,否则用的还是旧版本的程序,另外还会出现各种各样奇怪的 bug.

重开之后 org-roam V2 就安装好了,通过 M-x org-roam-version 确定版本更新成功。

迁移旧文件

由于 V2 版本完全不兼容之前的文件,因此必须通过其他方法导入。 在 github 上有网友提供了以下脚本,可以在任意 org-mode 代码块中 Ctrl-c Ctrl-c 执行:

(defun my/replace-file-with-id-link ()
  "Replaces file links with ID links where possible in current buffer."
  (interactive)
  (let (path desc)
    (org-with-point-at 1
      (while (re-search-forward org-link-bracket-re nil t)
        (setq desc (match-string 2))
        (when-let ((link (save-match-data (org-element-lineage (org-element-context) '(link) t))))
          (when (string-equal "file" (org-element-property :type link))
            (setq path (expand-file-name (org-element-property :path link)))
            (replace-match "")
            (insert (org-roam-format-link path desc))))))))

(dolist (file (org-roam--list-all-files))
  (with-current-buffer (or (find-buffer-visiting file)
                           (find-file-noselect file))
    (org-with-point-at 1
      (org-id-get-create))
    (save-buffer)))

(org-roam-db-build-cache)

(dolist (file (org-roam--list-all-files))
  (with-current-buffer (or (find-buffer-visiting file)
                           (find-file-noselect file))
    (my/replace-file-with-id-link)
    (save-buffer)))

(org-roam-db-build-cache)

这个脚本确实能正常使用,不过只是替换了链接格式,而没有将原来的 ROAM_TAGS 换成 filetags, 我们可以在 Doom Emacs 中用搜索命令简单地进行批量替换: SPC s p C-c C-e :%s/ROAM_TAGS/filetags/g RET Z Z

设置快捷键

之前在使用 Doom Emacs 整合的 org-roam 时,有非常好的体验,因为原生地提供了许多方便的快捷键,而如今这些东西当然都没了,好在我们可以自己绑定快捷键,在配置中添加:

;;; roam v2 configuration
(setq org-roam-directory "~/Documents/org/roam")
(use-package! org-roam
  :after org
  :commands
  (org-roam-buffer
   org-roam-setup
   org-roam-capture
   org-roam-node-find)

  ;; =====  快捷键设置=====
  :init
  (map!
        :leader
        :prefix ("m" . "org-roam")
        "f" #'org-roam-node-find
        "i" #'org-roam-node-insert
        "b" #'org-roam-buffer-toggle
        "t" #'org-roam-tag-add
        "T" #'org-roam-tag-remove)
  ;; ===== END HERE ====
  :config
  (org-roam-setup))

上述配置会产生如下的按键绑定:

快捷键 功能
SPC m f org-roam-node-find
SPC m i org-roam-node-insert
SPC m b org-roam-buffer-toggle
SPC m t org-roam-tag-add
SPC m T org-roam-tag-remove

如果你还需要其他功能,可以参考 ~/.emacs.d/modules/lang/org/contrib/roam.el 中的格式自己添加。

新版本的使用方法

新版本的 org-roam 几乎完全移除了 org-roam-file 相关操作,取而代之的是 org-roam-node ,以下是常用操作:

命令 功能
org-roam-node-find 查找、创建节点,相当于 org-roam-file-find
org-roam-node-insert 添加节点链接,相当于 org-roam-file-insert
org-roam-buffer-toggle 打开链接视图窗口
org-roam-tag-add 添加 org-mode 格式的标签
org-roam-db-sync 同步数据库,一般不需要手动执行,roam 会自动在保存的时候刷新

手动创建节点

在新版本中, org-roam 对节点的定义是有 org-id 的 entry, 具体来说,就是有如下属性的文本块都可以成为节点:

:PROPERTIES:
:ID:       e1a32413-17e0-4532-8ba2-31128c9a62a0
:END:

对于文件节点,org-roam 会在创建的时候自动生成 ID ,但是对于其他节点如 headline ,我们就必须手动添加这个属性,通过执行 M-x org-id-get-create, org-mode 就会生成 ID:

*** H3 :BST:
:PROPERTIES:
:ID:       427d5824-b09c-448e-b5db-5aa9f7a3fe4b
:END:
this is a headline node demo.

然后你就能通过 org-roam-node-find 找到这个节点了:

总结

org-roam 的新节点功能确实令人耳目一新,毕竟目前除了 roam-research 之外,其他卡片笔记软件的链接粒度都只到文件层次,而新版本的 org-roam 将粒度一次性地细化到了任意文本块,这几乎是一种降维打击。不过目前使用下来,感觉各方面的功能都还比较欠缺,如果你追求稳定,那么最好还是等待更完善的版本发布吧。