I've cleaned it up and turned it into a patch. It now correctly handles
(ignores) buffers without associated file names (which don't work with IDs).

>From 1861637d7b05f2e7ac11edf89f6939145c7be091 Mon Sep 17 00:00:00 2001
From: Steven Allen <ste...@stebalien.com>
Date: Wed, 27 Aug 2025 09:05:08 -0700
Subject: [PATCH] org-id: implement org-insert-link completion for ID links

* lisp/org-id.el (org-id-complete): add a function to prompt for a
headline in both the the current buffer and all known files with IDs,
returning a valid "id" link to said headline.
(org-id-description): add a function to describe an ID link based on its
target heading.
(org-link-set-parameters "id" ...): use these functions for
`org-insert-link' completion.
---
 lisp/org-id.el | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/lisp/org-id.el b/lisp/org-id.el
index 6ff63b295..87d8a1190 100644
--- a/lisp/org-id.el
+++ b/lisp/org-id.el
@@ -888,9 +888,42 @@ defun org-id-open
                          (org-element-lineage (org-element-at-point) 'headline t))))
     (org-fold-show-context)))
 
+(defun org-id-complete (&optional _arg)
+  "Complete IDs for `org-insert-link'.
+
+If a headline without an ID is selected, one will automatically be
+created."
+  (unless org-id-locations (org-id-locations-load))
+  (when-let* ((id (org-id-get-with-outline-path-completion
+                   `((nil . ,(if (buffer-file-name)
+                                 '(:maxlevel . 10)
+                               ;; IDs can only be used to link to
+                               ;; buffers with file names.
+                               '(:level . 0)))
+                     (org-id-files . (:maxlevel . 10))))))
+    (concat "id:" id)))
+
+(defun org-id-description (link desc)
+  "ID link description, derived from the LINKs target headline.
+
+TODO keywords, tags, and priorities are stripped from the description.
+
+Calling convention is similar to `org-link-make-description-function'.
+DESC has higher priority and returned when it is not nil or empty string.
+If LINK is not an info link then DESC is returned."
+  (or (org-string-nw-p desc)
+      (when-let* ((loc (org-id-find (string-remove-prefix "id:" link))))
+        (org-with-file-buffer (car loc)
+          (org-with-wide-buffer
+           (goto-char (cdr loc))
+           (org-link-display-format
+            (org-get-heading t t t t)))))))
+
 (org-link-set-parameters "id"
   :follow #'org-id-open
-  :store #'org-id-store-link-maybe)
+  :store #'org-id-store-link-maybe
+  :complete #'org-id-complete
+  :insert-description #'org-id-description)
 
 (provide 'org-id)
 
-- 
2.51.0

Reply via email to