At Mentions for Org-Mode

A pattern I really like in Notion is that you can a @ (at) mention any page with search as you type and autocomplete. I’d like to do something similar in org-mode so that I can quickly link related headlines.

Using the fantastic org-ql library for Emacs, I integrated it into completions triggered by letters following the @ symbol. This translates the input after the @ symbol into a query and inserts a org-id link when selecting a match.

(require 'org-ql)

(defun my/org-agenda-completions-at-point ()
  "Function to be used as `completion-at-point' in Org mode."
  (when (looking-back "@\\(\\(?:\\sw\\|\\s_\\|\\s-\\|\\s-:\\)+\\)")
    (defvar heading-to-id (make-hash-table :test 'equal))
    (let* ((start (match-beginning 1))
           (end (point))
           (input (match-string-no-properties 1))
           (candidates (org-ql-select (org-agenda-files) (org-ql--query-string-to-sexp input)
                         :action (lambda ()
                                   (let* ((heading (org-get-heading t))
                                          (id (org-id-get (point))))
                                     ;; Avoid having to look
                                     ;; up the ID again since
                                     ;; we are visiting all
                                     ;; the locations with
                                     ;; org-ql anyway
                                     (puthash heading id heading-to-id)
           (exit-function (lambda (heading status)
                            (when (eq status 'finished)
                              ;; The +1 removes the @ symbol
                              (delete-char (- (+ (length heading) 1)))
                               (format "[[id:%s][%s]]" (gethash heading heading-to-id) heading))))))
      (list start end candidates :exit-function exit-function))))

(defun my/org-agenda-completion-hook ()
  "Configure org-mode for completion at point for org-agenda headlines."
  (add-to-list 'completion-at-point-functions 'my/org-agenda-completions-at-point))

(add-hook 'org-mode-hook 'my/org-agenda-completion-hook)

See also: