diff --git a/init.el b/init.el index 3345ce6..d026bc0 100644 --- a/init.el +++ b/init.el @@ -185,7 +185,7 @@ (bind-key "" #'bm-toggle) (bind-key "" #'bm-next) (bind-key "" #'bm-previous) - (bind-key "" #'helm-org-agenda-files-headings) + (bind-key "" #'db/org-find-links-to-current-item) (bind-key "C-," #'mc/skip-to-previous-like-this) (bind-key "C-." #'mc/skip-to-next-like-this) (bind-key "C-;" #'iedit-mode) @@ -715,7 +715,8 @@ db/find-csv-in-org db/org-mark-current-default-task db/export-diary - db/org-copy-template-for-periodic-task)) + db/org-copy-template-for-periodic-task + db/org-find-links-to-current-item)) (use-package org :pin "gnu" @@ -1333,7 +1334,19 @@ (apply orig-fun args))) (advice-add 'org-roam--update-file-name-on-title-change - :around #'db/org-roam--no-titlechange-if-title-is-nil))) + :around #'db/org-roam--no-titlechange-if-title-is-nil) + + ;; `org-roam--id-link-face' apparently changes the matching data, + ;; resulting in `org-finalize-agenda' to fail while applying text + ;; properties to ID links; let's warp `save-match-data' around calls + ;; to it. + + (defun db/save-match-data (orig-fun &rest args) + (save-match-data + (apply orig-fun args))) + + (advice-add 'org-roam--id-link-face + :around #'db/save-match-data))) (use-package org-ref :config (progn diff --git a/site-lisp/db-org.el b/site-lisp/db-org.el index 2de131f..7a57158 100644 --- a/site-lisp/db-org.el +++ b/site-lisp/db-org.el @@ -592,6 +592,49 @@ This is done only if the value of this variable is not null." (org-icalendar-combine-agenda-files) (message "Exporting diary ... done."))))))) + +;;; Find items by link to current headline + +(defun db/org-find-items-linking-by-id (id custom-id) + "List all Org Mode items that link to ID. +Uses `org-search-view' to conduct the actual search. ID must be +a UUID as generated by, e.g., `org-id-get-create', and CUSTOM-ID +must consist of ASCII letters, numbers, and hyphens only. Each +of ID and CUSTOM-ID may be nil, but at least one of them must be +not." + (unless (or (not id) + (and (stringp id) + (string-match-p "^[a-f0-9]\\{8\\}-[a-f0-9]\\{4\\}-[a-f0-9]\\{4\\}-[a-f0-9]\\{4\\}-[a-f0-9]\\{12\\}$" id))) + (user-error "Given ID is not a valid UUID: %s" id)) + (unless (or (not custom-id) + (and (stringp custom-id) + (string-match-p "[-a-zA-Z0-9]" custom-id))) + ;; sorry, only ASCII right now … + (user-error "CUSTOM_ID must consist of alphanumeric charaters only")) + + (let ((query (cond + ((and id custom-id) (format "{\\[\\[id:%s\\]\\|\\[\\[#%s\\]}" id custom-id)) + (id (format "[[id:%s]" id)) + (custom-id (format "[[#%s]" custom-id)) + (t (user-error "No ID given and not in Org Mode."))))) + (org-search-view nil query))) + +(defun db/org-find-links-to-current-item (arg) + "Find links to current item. +Only links using the ID or CUSTOM_ID property are considered. + +If ARG is given, or if not in an Org Mode buffer, interactively +prompt for an item." + (interactive "P") + (apply #'db/org-find-items-linking-by-id + (if (and (derived-mode-p 'org-mode) (not arg)) + (list (org-id-get) (org-entry-get nil "CUSTOM_ID")) + (let ((pom (nth 3 (org-refile-get-location nil (get-file-buffer db/org-default-org-file))))) + (if (not pom) + (user-error "Invalid location") + (org-with-point-at pom + (list (org-id-get) (org-entry-get nil "CUSTOM_ID")))))))) + ;;; End