(feature): update cache on file rename (#124)

This commit is contained in:
Daniel Koudouna
2020-02-20 00:32:54 +00:00
committed by GitHub
parent 2522b9d2fa
commit bdc13cd6bf
4 changed files with 126 additions and 10 deletions

View File

@ -10,6 +10,7 @@
* [#103][gh-103] Change `org-roam-file-format` to a function: `org-roam-file-name-function` to allow more flexible file name customizaton. Also changes `org-roam-use-timestamp-as-filename` to `org-roam-filename-noconfirm` to better describe what it does. * [#103][gh-103] Change `org-roam-file-format` to a function: `org-roam-file-name-function` to allow more flexible file name customizaton. Also changes `org-roam-use-timestamp-as-filename` to `org-roam-filename-noconfirm` to better describe what it does.
### New Features ### New Features
* [#124](https://github.com/jethrokuan/org-roam/pull/124) Maintain cache consistency on file rename
* [#87][gh-87], [#90][gh-90] Support encrypted Org files * [#87][gh-87], [#90][gh-90] Support encrypted Org files
* [#110][gh-110] Add prefix to `org-roam-insert`, for inserting titles down-cased * [#110][gh-110] Add prefix to `org-roam-insert`, for inserting titles down-cased
* [#99](https://github.com/jethrokuan/org-roam/pull/99) Add keybinding so that `<return>` or `mouse-1` in the backlinks buffer visits the source file of the backlink at point * [#99](https://github.com/jethrokuan/org-roam/pull/99) Add keybinding so that `<return>` or `mouse-1` in the backlinks buffer visits the source file of the backlink at point

View File

@ -162,11 +162,12 @@ If called interactively, then PARENTS is non-nil."
(org-roam--build-cache-async) (org-roam--build-cache-async)
(user-error "Your Org-Roam cache isn't built yet! Please wait"))) (user-error "Your Org-Roam cache isn't built yet! Please wait")))
(defun org-roam--org-roam-file-p () (defun org-roam--org-roam-file-p (&optional file)
"Return t if file is part of org-roam system, false otherwise." "Return t if FILE is part of org-roam system, defaulting to the name of the current buffer. Else, return nil."
(and (buffer-file-name (current-buffer)) (let ((path (or file
(f-descendant-of-p (file-truename (buffer-file-name (current-buffer))) (buffer-file-name (current-buffer)))))
(file-truename org-roam-directory)))) (f-descendant-of-p (file-truename path)
(file-truename org-roam-directory))))
(defun org-roam--get-title-from-cache (file) (defun org-roam--get-title-from-cache (file)
"Return title of `FILE' from the cache." "Return title of `FILE' from the cache."
@ -340,11 +341,13 @@ If PREFIX, downcase the title before insertion."
(setq org-roam-backward-links-cache (make-hash-table :test #'equal)) (setq org-roam-backward-links-cache (make-hash-table :test #'equal))
(setq org-roam-titles-cache (make-hash-table :test #'equal))) (setq org-roam-titles-cache (make-hash-table :test #'equal)))
(defun org-roam--clear-file-from-cache () (defun org-roam--clear-file-from-cache (&optional filepath)
"Remove any related links to the file. "Remove any related links to the file.
This is equivalent to removing the node from the graph." This is equivalent to removing the node from the graph."
(let ((file (file-truename (buffer-file-name (current-buffer))))) (let* ((path (or filepath
(buffer-file-name (current-buffer))))
(file (file-truename path)))
;; Step 1: Remove all existing links for file ;; Step 1: Remove all existing links for file
(when-let ((forward-links (gethash file org-roam-forward-links-cache))) (when-let ((forward-links (gethash file org-roam-forward-links-cache)))
;; Delete backlinks to file ;; Delete backlinks to file
@ -589,6 +592,50 @@ This needs to be quick/infrequent, because this is run at
(call-process org-roam-graphviz-executable nil 0 nil temp-dot "-Tsvg" "-o" temp-graph) (call-process org-roam-graphviz-executable nil 0 nil temp-dot "-Tsvg" "-o" temp-graph)
(call-process org-roam-graph-viewer nil 0 nil temp-graph))) (call-process org-roam-graph-viewer nil 0 nil temp-graph)))
(defun org-roam--rename-file-links (file new-file &rest args)
"Rename backlinks of FILE to refer to NEW-FILE."
(when (and (not (auto-save-file-name-p file))
(not (auto-save-file-name-p new-file))
(org-roam--org-roam-file-p new-file))
(org-roam--ensure-cache-built)
(org-roam--clear-file-from-cache file)
(let* ((files (gethash file org-roam-backward-links-cache nil))
(path (file-truename file))
(new-path (file-truename new-file))
(slug (org-roam--get-title-or-slug file))
(old-title (format org-roam-link-title-format slug))
(new-slug (or (org-roam--get-title-from-cache path)
(org-roam--get-title-or-slug new-path)))
(new-title (format org-roam-link-title-format new-slug)))
(when files
(maphash (lambda (file-from props)
(let* ((file-dir (file-name-directory file-from))
(relative-path (file-relative-name new-path file-dir))
(old-relative-path (file-relative-name path file-dir))
(slug-regex (regexp-quote (format "[[file:%s][%s]]" old-relative-path old-title)))
(named-regex (concat
(regexp-quote (format "[[file:%s][" old-relative-path))
"\\(.*\\)"
(regexp-quote "]]"))))
(with-temp-file file-from
(insert-file-contents file-from)
(while (re-search-forward slug-regex nil t)
(replace-match (format "[[file:%s][%s]]" relative-path new-title)))
(goto-char (point-min))
(while (re-search-forward named-regex nil t)
(replace-match (format "[[file:%s][\\1]]" relative-path))))
(save-window-excursion
(find-file file-from)
(org-roam--update-cache))))
files))
(save-window-excursion
(find-file new-path)
(org-roam--update-cache)))))
(advice-add 'rename-file :after 'org-roam--rename-file-links)
(provide 'org-roam) (provide 'org-roam)
;;; org-roam.el ends here ;;; org-roam.el ends here

5
tests/roam-files/f3.org Normal file
View File

@ -0,0 +1,5 @@
#+TITLE: File 3
This file has a link to an file with no title.
[[file:no-title.org][no-title]]

View File

@ -29,6 +29,7 @@
(require 'buttercup) (require 'buttercup)
(require 'with-simulated-input) (require 'with-simulated-input)
(require 'org-roam) (require 'org-roam)
(require 'dash)
(defun abs-path (file-path) (defun abs-path (file-path)
(file-truename (expand-file-name file-path org-roam-directory))) (file-truename (expand-file-name file-path org-roam-directory)))
@ -69,9 +70,9 @@
;; Caches should be populated ;; Caches should be populated
(expect org-roam-cache-initialized :to-be t) (expect org-roam-cache-initialized :to-be t)
(expect (hash-table-count org-roam-forward-links-cache) :to-be 3) (expect (hash-table-count org-roam-forward-links-cache) :to-be 4)
(expect (hash-table-count org-roam-backward-links-cache) :to-be 4) (expect (hash-table-count org-roam-backward-links-cache) :to-be 5)
(expect (hash-table-count org-roam-titles-cache) :to-be 4) (expect (hash-table-count org-roam-titles-cache) :to-be 5)
;; Forward cache ;; Forward cache
(let ((f1 (gethash (abs-path "f1.org") org-roam-forward-links-cache)) (let ((f1 (gethash (abs-path "f1.org") org-roam-forward-links-cache))
@ -148,3 +149,65 @@
"Nested SPC File SPC 1 RET" "Nested SPC File SPC 1 RET"
(org-roam-insert nil)))) (org-roam-insert nil))))
(expect (buffer-string) :to-match (regexp-quote "file:../../nested/f1.org")))) (expect (buffer-string) :to-match (regexp-quote "file:../../nested/f1.org"))))
(describe "rename file updates cache"
(before-each
(org-roam--test-init)
(org-roam--clear-cache)
(org-roam--test-build-cache))
(it "f1 -> new_f1"
(rename-file (abs-path "f1.org")
(abs-path "new_f1.org"))
;; Cache should be cleared of old file
(expect (gethash (abs-path "f1.org") org-roam-forward-links-cache) :to-be nil)
(expect (->> org-roam-backward-links-cache
(gethash (abs-path "nested/f1.org"))
(hash-table-keys)
(member (abs-path "f1.org"))) :to-be nil)
(expect (->> org-roam-forward-links-cache
(gethash (abs-path "new_f1.org"))) :not :to-be nil)
(expect (->> org-roam-forward-links-cache
(gethash (abs-path "new_f1.org"))
(member (abs-path "nested/f1.org"))) :not :to-be nil)
;; Links are updated
(expect (with-temp-buffer
(insert-file-contents (abs-path "nested/f1.org"))
(buffer-string)) :to-match (regexp-quote "[[file:../new_f1.org][File 1]]")))
(it "f1 -> f1 with spaces"
(rename-file (abs-path "f1.org")
(abs-path "f1 with spaces.org"))
;; Cache should be cleared of old file
(expect (gethash (abs-path "f1.org") org-roam-forward-links-cache) :to-be nil)
(expect (->> org-roam-backward-links-cache
(gethash (abs-path "nested/f1.org"))
(hash-table-keys)
(member (abs-path "f1.org"))) :to-be nil)
;; Links are updated
(expect (with-temp-buffer
(insert-file-contents (abs-path "nested/f1.org"))
(buffer-string)) :to-match (regexp-quote "[[file:../f1 with spaces.org][File 1]]")))
(it "no-title -> meaningful-title"
(rename-file (abs-path "no-title.org")
(abs-path "meaningful-title.org"))
;; File has no forward links
(expect (gethash (abs-path "no-title.org") org-roam-forward-links-cache) :to-be nil)
(expect (gethash (abs-path "meaningful-title.org") org-roam-forward-links-cache) :to-be nil)
(expect (->> org-roam-forward-links-cache
(gethash (abs-path "f3.org"))
(member (abs-path "no-title.org"))) :to-be nil)
(expect (->> org-roam-forward-links-cache
(gethash (abs-path "f3.org"))
(member (abs-path "meaningful-title.org"))) :not :to-be nil)
;; Links are updated with the appropriate name
(expect (with-temp-buffer
(insert-file-contents (abs-path "f3.org"))
(buffer-string)) :to-match (regexp-quote "[[file:meaningful-title.org][meaningful-title]]"))))