Last active
August 30, 2024 14:03
-
-
Save lyndhurst/d88860083f19985db6de045c2e92d5a7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; org-roam-link-utils.el | |
(defun org-roam-link-find () | |
"Find \"roam:\" links in Org-Roam" | |
(interactive) | |
(let* ((link-type "roam") | |
(query "select | |
files.title, links.source, links.pos, | |
links.dest, links.properties | |
from links | |
inner join nodes on links.source = nodes.id | |
inner join files on nodes.file = files.file | |
where links.type = $s1") | |
(links (org-roam-db-query query link-type)) | |
(choices (mapcar (lambda (link) | |
(let* ((file-title (nth 0 link)) | |
(pos (nth 2 link)) | |
(dest (nth 3 link)) | |
(outline (mapconcat #'identity | |
(plist-get (nth 4 link) :outline) | |
" > ")) | |
(description (format "%s: %s [%d] %s" | |
dest | |
file-title | |
pos | |
(if (not (string= "" outline)) | |
(concat "> " outline) | |
"")))) | |
(cons description (list pos (nth 1 link))))) | |
links)) | |
(selection (completing-read "Select a roam link: " (mapcar #'car choices))) | |
(selected-data (cdr (assoc selection choices))) | |
(pos (nth 0 selected-data)) | |
(id (nth 1 selected-data))) | |
(org-roam-id-open id) | |
(goto-char pos))) | |
(defun org-roam-link-replace-all-backlinks () | |
"For all \"roam:\" links referencing current node, | |
Convert to an id link &, | |
Convert every raw id link - if any - [[id:uuid]] to | |
[[id:uuid][description]] where description is node-title." | |
(interactive) | |
(when-let* ((original-buffer (current-buffer)) | |
(node (org-roam-node-at-point)) | |
(title (org-roam-node-title node)) | |
(id (org-roam-node-id node)) | |
(query (format "select links.source | |
from links inner join nodes on links.source = nodes.id | |
where links.dest = '\"%s\"' | |
or links.dest = '\"%s\"' | |
group by nodes.file;" | |
title id)) | |
(links (org-roam-db-query query))) | |
(mapc (lambda (link) | |
(+org-roam-id-goto (car link)) | |
(org-with-point-at 1 | |
(while (re-search-forward org-link-bracket-re nil t) | |
(cond ((and (string-match-p (concat "^roam:" title "$") (match-string 1)) | |
(y-or-n-p (format "Convert %s?" (match-string 1)))) | |
(org-roam-link-replace-at-point)) | |
((and (string-match-p (concat "^id:" id "$") (match-string 1)) | |
(not (match-string 2)) | |
(y-or-n-p (format "Update description of %s?" (match-string 1)))) | |
(goto-char (match-end 1)) | |
(forward-char 1) | |
(insert (format "[%s]" title)))))) | |
(write-file (buffer-file-name))) | |
links) | |
;; switch to our orignal-buffer | |
(switch-to-buffer original-buffer))) | |
(defun org-roam-link-rename-all-backlinks () | |
"Rename the current node title and propagate changes | |
to links referencing current node. | |
1. Propagates changes to \"roam:\" links by updating the destination, and | |
2. For \"id:\" links - | |
If it is a raw ID link `[[id:uuid]]' add a description with the new node title | |
[[id:uuid][new-title]], | |
whereas for any standard ID link `[[id:uuid][old-title]]', | |
update to `[[id:uuid][new-title]],' | |
does not affect the description of non-standard IDs, | |
`[[id:uuid][custom-description]]'." | |
(interactive) | |
(when-let* ((original-buffer (current-buffer)) | |
(node (org-roam-node-at-point)) | |
(title (org-roam-node-title node)) | |
(new-title title) | |
(id (org-roam-node-id node)) | |
(level (org-roam-node-level node)) | |
(pos (org-roam-node-point node)) | |
(query (format "select links.source | |
from links inner join nodes on links.source = nodes.id | |
where links.dest = '\"%s\"' | |
or links.dest = '\"%s\"' | |
group by nodes.file;" | |
title id)) | |
(links (org-roam-db-query query))) | |
(setq new-title (read-from-minibuffer (format "Enter new node-title \n | |
[Currently \"%s\"]: " title))) | |
(when (string= "" new-title) | |
(user-error "Warning! You have decided to delete current node-title and propagate changes. | |
Aborting! This is not allowed.")) | |
(if (= level 0) | |
(org-roam-set-keyword "TITLE" new-title) | |
(org-with-point-at pos | |
(org-edit-headline new-title))) | |
(write-file (buffer-file-name)) | |
(mapc (lambda (link) | |
(+org-roam-id-goto (car link)) | |
(org-with-point-at 1 | |
(while (re-search-forward org-link-bracket-re nil t) | |
;; HHHH--------------------------------------------------- | |
;; Hotfix - transfer the values of some variables to fix a bug with unknown cause | |
;; that nullifies some position pointers | |
;; Also in some cases Emacs may decide to hide the link string from user by making it invisible | |
;; extract out the raw string from the propertized string. | |
(let ((desc-beg (match-beginning 2)) | |
(desc-end (match-end 2)) | |
(link-str (substring-no-properties (match-string 1)))) | |
;; HHHH--------------------------------------------------- | |
(cond ((and (string-match-p (concat "^roam:" title "$") (match-string 1)) | |
(y-or-n-p (format "Update %s? (Warning! answering no may disjoint this link!)" link-str))) | |
(goto-char (match-beginning 1)) | |
(delete-region (match-beginning 1) (match-end 1)) | |
(insert (format "roam:%s" new-title))) | |
((string-match-p (concat "^id:" id "$") (match-string 1)) | |
(when (and (not (match-string 2)) | |
(y-or-n-p (format "Update Description of %s?" link-str))) | |
(goto-char (match-end 1)) | |
(forward-char 1) | |
(insert (format "[%s]" new-title)) | |
(goto-char (match-beginning 0)) | |
(re-search-forward org-link-bracket-re nil t) | |
;; HHHH--------------------------------------------------- | |
;; Also reset the values here | |
(setq desc-beg (match-beginning 2) | |
desc-end (match-end 2))) | |
;; HHHH--------------------------------------------------- | |
(when (and (match-string 2) | |
(string-match-p (concat "^" title "$") (match-string 2)) | |
(y-or-n-p (format "Update Description of %s?" link-str))) | |
(goto-char desc-beg) | |
(delete-region desc-beg desc-end) | |
(insert new-title))))))) | |
(write-file (buffer-file-name))) | |
links) | |
;; switch to our orignal-buffer | |
(switch-to-buffer original-buffer))) | |
(defun +org-roam-id-goto (id) | |
"Switch to the buffer containing the entry with id ID. | |
Move the cursor to that entry in that buffer. | |
Like `org-id-goto', but additionally uses the Org-roam database" | |
(interactive "sID: ") | |
(let ((m (org-roam-id-find id 'marker))) | |
(unless m | |
(error "Cannot find entry with ID \"%s\"" id)) | |
(pop-to-buffer-same-window (marker-buffer m)) | |
(goto-char m) | |
(move-marker m nil) | |
(org-fold-show-context))) | |
;; end | |
(provide 'org-roam-link-utils) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment