(feat): rename file on title change (#1073)

Adds `org-roam-title-change-hook`. This now contains two functions:

1. `org-roam--update-links-on-title-change`: updates the link
description of all files that link to the current file.
2. `org-roam--update-file-name-on-title-change`: updates the current
buffer's filename to reflect the updated title.
This commit is contained in:
Jethro Kuan
2020-08-27 22:13:23 +08:00
committed by GitHub
parent f8c8fcee6b
commit a6aabf4038
3 changed files with 82 additions and 38 deletions

View File

@ -10,6 +10,7 @@ In this release we support fuzzy links of the form `[[Title]]`, `[[*Headline]]`
### Features
- [#1073](https://github.com/org-roam/org-roam/pull/1073) Rename file on title change, when `org-roam-rename-file-on-title-change` is non-nil.
- [#1071](https://github.com/org-roam/org-roam/pull/1071) Update link descriptions on title changes, and clean-up rename file advice
- [#1061](https://github.com/org-roam/org-roam/pull/1061) Speed up the extraction of file properties, headlines, and titles
- [#1046](https://github.com/org-roam/org-roam/pull/1046) New user option to exclude files from Org-roam

View File

@ -461,12 +461,15 @@ connections, nil is returned."
(org-roam-db--insert-headlines headlines))))
(defun org-roam-db--update-file (&optional file-path)
"Update Org-roam cache for FILE-PATH."
(when (org-roam--org-roam-file-p file-path)
(let ((buf (or (and file-path
(find-file-noselect file-path t))
(current-buffer))))
(with-current-buffer buf
"Update Org-roam cache for FILE-PATH.
If the file does not exist anymore, remove it from the cache.
If the file exists, update the cache with information."
(setq file-path (or file-path
(buffer-file-name (buffer-base-buffer))))
(cond ((not (file-exists-p file-path))
(org-roam-db--clear-file file-path))
((org-roam--org-roam-file-p file-path)
(with-current-buffer (find-file-noselect file-path t)
(org-with-wide-buffer
(emacsql-with-transaction (org-roam-db)
(org-roam-db--update-meta)
@ -475,8 +478,7 @@ connections, nil is returned."
(org-roam-db--update-refs)
(when org-roam-enable-headline-linking
(org-roam-db--update-headlines))
(org-roam-db--update-links)))
(org-roam-buffer--update-maybe :redisplay t)))))
(org-roam-db--update-links)))))))
(defun org-roam-db-build-cache (&optional force)
"Build the cache for `org-roam-directory'.

View File

@ -1527,23 +1527,45 @@ replaced links are made relative to the current buffer."
(replace-match (concat type ":" new-path)
nil t nil 1))))))))
(defcustom org-roam-rename-file-on-title-change t
"If non-nil, alter the filename on title change.
The new title is converted into a slug using
`org-roam-title-to-slug-function', and compared with the current
filename."
:group 'org-roam
:type 'boolean)
(defcustom org-roam-title-change-hook '(org-roam--update-file-name-on-title-change
org-roam--update-links-on-title-change)
"Hook run after detecting a title change.
Each hook is passed two arguments: the old title, and new title
respectively."
:group 'org-roam
:type 'hook)
(defvar-local org-roam-current-title nil
"The current title of the Org-roam file.")
(defun org-roam--handle-title-change ()
"Detect a title change, and run `org-roam-title-change-hook'."
(let ((new-title (car (org-roam--extract-titles)))
(old-title org-roam-current-title))
(unless (string-equal old-title new-title)
(run-hook-with-args 'org-roam-title-change-hook old-title new-title)
(setq-local org-roam-current-title new-title))))
(defun org-roam--setup-title-auto-update ()
"Setup automatic link description update on title change."
(setq-local org-roam-current-title (car (org-roam--extract-titles)))
(add-hook 'after-save-hook #'org-roam--update-links-on-title-change nil t))
(add-hook 'after-save-hook #'org-roam--handle-title-change nil t))
(defun org-roam--update-links-on-title-change ()
"Update the link description of other Org-roam files on title change.
This function is to be called in `after-save-hook'. If the title
of the Org-roam file has changed, it will iterate over all
Org-roam files that link to the current file, and replace the
link descriptions with the new title if applicable."
(let ((new-title (car (org-roam--extract-titles)))
(old-title org-roam-current-title))
(unless (string-equal old-title new-title)
(defun org-roam--update-links-on-title-change (old-title new-title)
"Update the link description of other Org-roam files.
Iterate over all Org-roam files that have link description of
OLD-TITLE, and replace the link descriptions with the NEW-TITLE
if applicable.
To be added to `org-roam-title-change-hook'."
(let* ((current-path (file-truename (buffer-file-name)))
(files-affected (org-roam-db-query [:select :distinct [from]
:from links
@ -1554,7 +1576,26 @@ link descriptions with the new title if applicable."
(find-file-noselect (car file)))
(org-roam--replace-link current-path current-path old-title new-title)
(save-buffer)))))
(setq-local org-roam-current-title new-title)))
(defun org-roam--update-file-name-on-title-change (old-title new-title)
"Update the file name on title change.
The slug is computed from OLD-TITLE using
`org-roam-title-to-slug-function'. If the slug is part of the
current filename, the new slug is computed with NEW-TITLE, and
that portion of the filename is renamed.
To be added to `org-roam-title-change-hook'."
(when org-roam-rename-file-on-title-change
(let* ((old-slug (funcall org-roam-title-to-slug-function old-title))
(file (buffer-file-name (buffer-base-buffer)))
(file-name (file-name-nondirectory file)))
(when (string-match-p old-slug file-name)
(let* ((new-slug (funcall org-roam-title-to-slug-function new-title))
(new-file-name (replace-regexp-in-string old-slug new-slug file-name)))
(rename-file file-name new-file-name)
(set-visited-file-name new-file-name t t)
(add-to-list 'org-roam--file-update-queue new-file-name)
(org-roam-message "File moved to %S" (abbreviate-file-name new-file-name)))))))
(defun org-roam--rename-file-advice (old-file new-file-or-dir &rest _args)
"Rename backlinks of OLD-FILE to refer to NEW-FILE-OR-DIR.