From 40e984f5390370cfa032995c48a7a3b02d1a398f Mon Sep 17 00:00:00 2001 From: Valentin Herrmann Date: Sat, 22 Apr 2023 22:31:48 +0200 Subject: [PATCH 1/2] (feat): Increase speed of org-roam-node-find --- org-roam-db.el | 5 +++++ org-roam-node.el | 55 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/org-roam-db.el b/org-roam-db.el index 99150f0f1c..1407687f71 100644 --- a/org-roam-db.el +++ b/org-roam-db.el @@ -787,6 +787,11 @@ OLD-FILE is cleared from the database, and NEW-FILE-OR-DIR is added." (interactive) (prin1 (org-roam-node-at-point))) +;;; Misc +(defun org-roam-db--get-mtime () + "Get last modification time of database." + (file-attribute-modification-time (file-attributes org-roam-db-location))) + (provide 'org-roam-db) ;;; org-roam-db.el ends here diff --git a/org-roam-node.el b/org-roam-node.el index 720c3a0819..af43a41fb8 100644 --- a/org-roam-node.el +++ b/org-roam-node.el @@ -33,6 +33,7 @@ ;; ;;; Code: (require 'org-roam) +(require 'org-roam-db) ;;; Options ;;;; Completing-read @@ -343,7 +344,7 @@ nodes." (org-roam-node-aliases node) alias-info))) node) -(defun org-roam-node-list () +(defun org-roam-node--get-list () "Return all nodes stored in the database as a list of `org-roam-node's." (let ((rows (org-roam-db-query "SELECT @@ -437,6 +438,22 @@ GROUP BY id"))) :refs refs)) all-titles))))) +(defvar org-roam-node--list nil + "Last value of the nodes.") +(defvar org-roam-node--list-mtime nil + "Last time `org-roam-node--list' was changed.") +(defun org-roam-node-list (&optional force-refresh) + "Return all nodes stored in the database as a list of `org-roam-node's. + +Returns `org-roam-node--list' if the database didn't change." + (if (and (not force-refresh) + org-roam-node--list-mtime + (time-less-p (org-roam-db--get-mtime) org-roam-node--list-mtime)) + org-roam-node--list + (setq org-roam-node--list (org-roam-node--get-list)) + (setq org-roam-node--list-mtime (current-time)) + org-roam-node--list)) + ;;;; Finders (defun org-roam-node-marker (node) "Get the marker for NODE." @@ -550,6 +567,12 @@ PROMPT is a string to show at the beginning of the mini-buffer, defaulting to \" (or (cdr (assoc node nodes)) (org-roam-node-create :title node)))) +(defvar org-roam-node--candidate-list nil + "List with last value of the nodes formatted as candidates.") +(defvar org-roam-node--candidate-list-mtime nil + "Last time `org-roam-node--candidate-list' was changed.") +(defvar org-roam-node--candidate-list-prev-filter-fn nil + "Last value of parameter `filter-fn' of `org-roam-node-read--completions'.") (defun org-roam-node-read--completions (&optional filter-fn sort-fn) "Return an alist for node completion. The car is the displayed title or alias for the node, and the cdr @@ -559,15 +582,27 @@ and when nil is returned the node will be filtered out. SORT-FN is a function to sort nodes. See `org-roam-node-read-sort-by-file-mtime' for an example sort function. The displayed title is formatted according to `org-roam-node-display-template'." - (let* ((template (org-roam-node--process-display-format org-roam-node-display-template)) - (nodes (org-roam-node-list)) - (nodes (if filter-fn - (cl-remove-if-not - (lambda (n) (funcall filter-fn n)) - nodes) - nodes)) - (nodes (mapcar (lambda (node) - (org-roam-node-read--to-candidate node template)) nodes)) + ;; update `org-roam-node--candidate-list' if needed + (let ((nodes (org-roam-node-list))) + (unless (and (eq filter-fn org-roam-node--candidate-list-prev-filter-fn) + org-roam-node--candidate-list-mtime + org-roam-node--list-mtime + (time-less-p org-roam-node--list-mtime + org-roam-node--candidate-list-mtime)) + (let* ((template (org-roam-node--process-display-format org-roam-node-display-template)) + (nodes (if filter-fn + (cl-remove-if-not + (lambda (n) (funcall filter-fn n)) + nodes) + nodes)) + (nodes (mapcar (lambda (node) + (org-roam-node-read--to-candidate node template)) nodes))) + (setq org-roam-node--candidate-list nodes) + (setq org-roam-node--candidate-list-mtime (current-time)) + (setq org-roam-node--candidate-list-prev-filter-fn filter-fn) + org-roam-node--candidate-list))) + + (let* ((nodes org-roam-node--candidate-list) (sort-fn (or sort-fn (when org-roam-node-default-sort (intern (concat "org-roam-node-read-sort-by-" From c0fdb40a284c51a883d9dca3732da452202563de Mon Sep 17 00:00:00 2001 From: Valentin Herrmann Date: Mon, 22 Apr 2024 10:53:06 +0200 Subject: [PATCH 2/2] Cache sort-fn as well --- org-roam-node.el | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/org-roam-node.el b/org-roam-node.el index 3399cfec60..89e3f878ed 100644 --- a/org-roam-node.el +++ b/org-roam-node.el @@ -266,11 +266,11 @@ If NOCASE is non-nil, the query is case insensitive. It is case sensitive other (let ((matches (seq-uniq (append (org-roam-db-query (vconcat [:select [id] :from nodes - :where (= title $s1)] + :where (= title $s1)] (if nocase [ :collate NOCASE ])) s) (org-roam-db-query (vconcat [:select [node-id] :from aliases - :where (= alias $s1)] + :where (= alias $s1)] (if nocase [ :collate NOCASE ])) s))))) (cond @@ -577,6 +577,8 @@ PROMPT is a string to show at the beginning of the mini-buffer, defaulting to \" "Last time `org-roam-node--candidate-list' was changed.") (defvar org-roam-node--candidate-list-prev-filter-fn nil "Last value of parameter `filter-fn' of `org-roam-node-read--completions'.") +(defvar org-roam-node--candidate-list-prev-sort-fn nil + "Last internal value of parameter `sort-fn' in `org-roam-node-read--completions'.") (defun org-roam-node-read--completions (&optional filter-fn sort-fn) "Return an alist for node completion. The car is the displayed title or alias for the node, and the cdr @@ -587,12 +589,18 @@ SORT-FN is a function to sort nodes. See `org-roam-node-read-sort-by-file-mtime' for an example sort function. The displayed title is formatted according to `org-roam-node-display-template'." ;; update `org-roam-node--candidate-list' if needed - (let ((nodes (org-roam-node-list))) - (unless (and (eq filter-fn org-roam-node--candidate-list-prev-filter-fn) - org-roam-node--candidate-list-mtime - org-roam-node--list-mtime - (time-less-p org-roam-node--list-mtime - org-roam-node--candidate-list-mtime)) + (let ((nodes (org-roam-node-list)) + (sort-fn (or sort-fn + (when org-roam-node-default-sort + (intern (concat "org-roam-node-read-sort-by-" + (symbol-name org-roam-node-default-sort))))))) + (if (and org-roam-node--candidate-list-mtime + org-roam-node--list-mtime + (time-less-p org-roam-node--list-mtime + org-roam-node--candidate-list-mtime) + (eq filter-fn org-roam-node--candidate-list-prev-filter-fn) + (eq sort-fn org-roam-node--candidate-list-prev-sort-fn)) + org-roam-node--candidate-list (let* ((template (org-roam-node--process-display-format org-roam-node-display-template)) (nodes (if filter-fn (cl-remove-if-not @@ -600,20 +608,14 @@ The displayed title is formatted according to `org-roam-node-display-template'." nodes) nodes)) (nodes (mapcar (lambda (node) - (org-roam-node-read--to-candidate node template)) nodes))) + (org-roam-node-read--to-candidate node template)) nodes)) + (nodes (if sort-fn (seq-sort sort-fn nodes) + nodes))) (setq org-roam-node--candidate-list nodes) (setq org-roam-node--candidate-list-mtime (current-time)) (setq org-roam-node--candidate-list-prev-filter-fn filter-fn) - org-roam-node--candidate-list))) - - (let* ((nodes org-roam-node--candidate-list) - (sort-fn (or sort-fn - (when org-roam-node-default-sort - (intern (concat "org-roam-node-read-sort-by-" - (symbol-name org-roam-node-default-sort)))))) - (nodes (if sort-fn (seq-sort sort-fn nodes) - nodes))) - nodes)) + (setq org-roam-node--candidate-list-prev-sort-fn sort-fn) + org-roam-node--candidate-list)))) (defun org-roam-node-read--to-candidate (node template) "Return a minibuffer completion candidate given NODE.