Last update: 2023-11-16

Nodeを挿入時に自動でTAGを追加する   Emacs OrgMode OrgRoam

Org-roamでNodeをInsertした時にタグを引き継げないかと思って、 探していたら関連記事を見つけたので、参考にして実装してみた。

この記事では org-roam-node-insert にadviceしているが、現在この関数はRoamNodeを返さないようだ。 つまりそのままコピペするだけで動作しない。残念。

(defun org-roam-node-insert-wrapper (fn)
  "Insert a link to the note using FN.

If inserted node has PEOPLE tag on it, tag the current outline
accordingly."
  (interactive)
  (when-let*
      ((node (funcall fn))  ; ← この箇所でNodeを取得できない
...
https://d12frosted.io/posts/2020-07-07-task-management-with-roam-vol4.html

post-node-insert-hook を利用する

org-roam-post-node-insert-hook という、今回の用途にぴったりのHookを見つけたのでこれを使うことにする。 おそらく引用記事の執筆時点では実装されていなかったのだろう。

記事では people タグがついている場合のみタグをInsertするようにしているが、 私はそれに関わらずタグを付与したい場合もあるので、別途 NODE_INSERT_WITH_TAGS というプロパティを用意して判定することにした。 ちなみに新しいプロパティをつける場合 ROAM_* prefixをつけるとroam-dbに保存されないので、それ以外のPrefixを使うこと。プチハマりした。

(defun my/org-roam-node-add-auto-tag (id _description)
  "Insert node with tags. Node found with iD."
  (interactive)
  (when-let*
      ((node (org-roam-node-from-id id))
       (tags (org-roam-node-tags node))
       (prop (org-roam-node-properties node))
       (inherit (assoc "NODE_INSERT_WITH_TAGS" prop)))
    (save-excursion
      (ignore-errors
        (org-back-to-heading)
        (org-set-tags
         (seq-uniq
          (append
           tags
           (org-get-tags nil t))))))))

(add-hook
 'org-roam-post-node-insert-hook
 #'my/org-roam-node-add-auto-tag)

 ;; (org-roam-node-insert)

同じようにCategoryを継承するためのHookも作った。冗長だが、まあ動くのでよし。

(defun my/org-roam-node-add-auto-category (id _description)
  "Insert node with category as prop. Node found with iD."
  (interactive)
  (when-let*
      ((node (org-roam-node-from-id id))
       (prop (org-roam-node-properties node))
       (inherit (assoc "NODE_INSERT_WITH_CATEGORY" prop))
       (category (cdr (assoc "CATEGORY" prop))))
    (save-excursion
      (ignore-errors
        (org-back-to-heading)
        (org-set-property "CATEGORY" category)))))

(add-hook
 'org-roam-post-node-insert-hook
 #'my/org-roam-node-add-auto-category)

;; (org-roam-node-insert)

completion-at-point に対応する

Nodeの挿入は completion-at-point による補完を使うこともできるが、先の方法では対応できない。

completion-at-point による挿入直後は roam:[Description] 形式でIDの解決を行うが、この時点ではまだ対応するNodeへのリンクにはなっていない。 これは before-save-hook で解決されるので、この変数を見れば org-roam-link-replace-all という関数が設定されていることがわかった。 さらに内部で各リンクごとに org-roam-link-replace-at-point が呼ばれているので、この関数に対して advice すればよさそうだ。

(defun my/org-roam-link-repalce-auto-tags-to-heading (old-func &rest args)
  (apply old-func args)
  (let* ((link (org-element-context))
         (id (org-element-property :path link)))
    (my/org-roam-node-add-auto-tag id nil)))

(advice-add
 #'org-roam-link-replace-at-point
 :around
 #'my/org-roam-link-repalce-auto-tags-to-heading)