diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b478a4..dbf889f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ In this release we support fuzzy links of the form `[[Title]]`, `[[*Headline]]` - [#910](https://github.com/org-roam/org-roam/pull/910) Deprecate `company-org-roam`, using `completion-at-point` instead. To use this with company, add the `company-capf` backend instead. ### 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 diff --git a/org-roam-db.el b/org-roam-db.el index 2dd247d..0fb3de8 100644 --- a/org-roam-db.el +++ b/org-roam-db.el @@ -461,22 +461,24 @@ 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 - (org-with-wide-buffer - (emacsql-with-transaction (org-roam-db) - (org-roam-db--update-meta) - (org-roam-db--update-tags) - (org-roam-db--update-titles) - (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))))) + "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) + (org-roam-db--update-tags) + (org-roam-db--update-titles) + (org-roam-db--update-refs) + (when org-roam-enable-headline-linking + (org-roam-db--update-headlines)) + (org-roam-db--update-links))))))) (defun org-roam-db-build-cache (&optional force) "Build the cache for `org-roam-directory'. diff --git a/org-roam.el b/org-roam.el index e629ebe..2dadd02 100644 --- a/org-roam.el +++ b/org-roam.el @@ -1527,34 +1527,75 @@ 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) - (let* ((current-path (file-truename (buffer-file-name))) - (files-affected (org-roam-db-query [:select :distinct [from] - :from links - :where (= to $s1)] - current-path))) - (dolist (file files-affected) - (with-current-buffer (or (find-buffer-visiting (car file)) - (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-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 + :where (= to $s1)] + current-path))) + (dolist (file files-affected) + (with-current-buffer (or (find-buffer-visiting (car file)) + (find-file-noselect (car file))) + (org-roam--replace-link current-path current-path old-title new-title) + (save-buffer))))) + +(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.