From a62ccb43bf494c57e39897d5a6c65e810e944ffa Mon Sep 17 00:00:00 2001 From: Bruce D'Arcus Date: Tue, 3 Aug 2021 14:05:06 -0400 Subject: [PATCH 1/4] Add local file support - add new buffer-local cache - enhance logic to know what to locally cache --- bibtex-actions.el | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/bibtex-actions.el b/bibtex-actions.el index a6d3bf79..6f717fc0 100644 --- a/bibtex-actions.el +++ b/bibtex-actions.el @@ -207,8 +207,26 @@ offering the selection candidates" collect (cdr (or (assoc choice candidates) (rassoc choice candidates)))))) -(defun bibtex-actions--format-candidates () - "Transform candidates from 'bibtex-completion-candidates'. +(defun bibtex-actions--normalize-paths (file-paths) + "Return a list of FILE-PATHS normalized with truename." + (if (stringp file-paths) + ;; If path is a string, return as a list. + (list (file-truename file-paths)) + (delete-dups (mapcar (lambda (p) (file-truename p)) file-paths)))) + +(defun bibtex-actions--local-files-to-cache () + "The local bibliographic files not included in the global bibliography." + ;; We cache these locally to the buffer. + (let* ((local-bib-files + (bibtex-actions--normalize-paths + (bibtex-completion-find-local-bibliography))) + (global-bib-files + (bibtex-actions--normalize-paths + bibtex-completion-bibliography))) + (seq-difference local-bib-files global-bib-files))) + +(defun bibtex-actions--format-candidates (&optional context) + "Format candidates, with optional hidden CONTEXT metadata. This both propertizes the candidates for display, and grabs the key associated with each one." (let* ((main-template @@ -240,7 +258,7 @@ key associated with each one." ;; We display this content already using symbols; here we add back ;; text to allow it to be searched, and citekey to ensure uniqueness ;; of the candidate. - (candidate-hidden (s-join " " (list pdf note link citekey)))) + (candidate-hidden (s-join " " (list pdf note link context citekey)))) (cons ;; If we don't trim the trailing whitespace, 'completing-read-multiple' will ;; get confused when there are multiple selected candidates. @@ -276,16 +294,23 @@ key associated with each one." (list pdf note link))" ") suffix)))) (defvar bibtex-actions--candidates-cache nil - "Store the candidates list.") + "Store the global candidates list.") + +(defvar-local bibtex-actions--local-candidates-cache nil + ;; We use defvar-local so can maintain per-buffer candidate caches. + "Store the local (per-buffer) candidates list.") (defun bibtex-actions--get-candidates (&optional force-rebuild-cache) "Get the cached candidates. If the cache is nil, this will load the cache. If FORCE-REBUILD-CACHE is t, force reloading the cache." (when (or force-rebuild-cache - (not bibtex-actions--candidates-cache)) + (not bibtex-actions--candidates-cache) + (not bibtex-actions--local-candidates-cache)) (bibtex-actions-refresh force-rebuild-cache)) - bibtex-actions--candidates-cache) + (seq-concatenate 'list + ((lambda (x) (if (eq x t) nil x)) bibtex-actions--local-candidates-cache) + ((lambda (x) (if (eq x t) nil x)) bibtex-actions--candidates-cache))) ;;;###autoload (defun bibtex-actions-refresh (&optional force-rebuild-cache) @@ -295,8 +320,14 @@ is non-nil, also run the `bibtex-actions-before-refresh-hook' hook." (interactive "P") (when force-rebuild-cache (run-hooks 'bibtex-actions-force-refresh-hook)) + ;; t in the result indicates that cache was computed but came out nil nil + ;; itself is used to indicate a cache that hasn't been computed this is to + ;; work around the fact that we can't differentiate between empty list and nil (setq bibtex-actions--candidates-cache - (bibtex-actions--format-candidates))) + ((lambda (x) (if x x t)) (bibtex-actions--format-candidates))) + (let ((bibtex-completion-bibliography (bibtex-actions--local-files-to-cache))) + (setq bibtex-actions--local-candidates-cache + ((lambda (x) (if x x t)) (bibtex-actions--format-candidates "is:local"))))) ;;;###autoload (defun bibtex-actions-insert-preset () From a0c01acd61f08ec7ca5c6386356c790a9a34bfbd Mon Sep 17 00:00:00 2001 From: Bruce D'Arcus Date: Thu, 5 Aug 2021 11:21:32 -0400 Subject: [PATCH 2/4] Update README --- README.org | 51 ++++++++------------------------------------------- 1 file changed, 8 insertions(+), 43 deletions(-) diff --git a/README.org b/README.org index 2aa9a325..dcccbb5b 100644 --- a/README.org +++ b/README.org @@ -222,61 +222,26 @@ You then have two ways to access these strings from the completion prompt: =Bibtex-actions= also preserves the history of your selections (see caveat below about multiple candidate selection though), which are also accessible in your completion UI, but by using =M-p=. You can save this history across sessions by adding =bibtex-actions-history= to =savehist-additional-variables=. -** Pre-filtering entries - :PROPERTIES: - :CUSTOM_ID: prefiltering-entries - :END: - -By default, =bibtex-actions= will, assuming you are using =orderless= or =prescient= to filter candidates, pre-filter entries for the following commands. - -1. =bibtex-actions-open=: pre-narrows the list to those which have associated pdf or links -2. =bibtex-actions-open-link=: pre-narrows the list to those which have associated links -3. =bibtex-actions-open-pdf=: -pre-narrows the list to those which have associated pdf(s) - -That is, upon running the command, an =initial-input= value will be inserted to narrow the results. -You can also delete that if you prefer to see the full list of candidates. - -By default, pre-filtering of =bibtex-actions-open-notes= is off, because the command by default will create a new note if none is available, and therefore it makes sense to have access to your full library. -But you can customize this to pre-filter if you prefer. - -If you want to modify those values, or remove them entirely, you can set =bibtex-actions-initial-inputs= like so; in this case turning off pre-filtering for =bibtex-actions-open-pdf=: - -#+begin_src elisp -(setq bibtex-actions-initial-inputs - '((pdf . nil) - (note . nil) - (link . "has:link") - (source . "has:link\\|has:pdf")) -#+end_src - ** Refreshing the library display :PROPERTIES: :CUSTOM_ID: refreshing-the-library-display :END: -Bibtex-actions uses a cache to speed up library display. +=Bibtex-actions= uses two caches to speed up library display; one for the global bibliography, and another for local files specific to a buffer. This is great for performance, but means the data can become stale if you modify it. -The =bibtex-actions-refresh= command will reload the cache, and you can call this manually. +The =bibtex-actions-refresh= command will reload the caches, and you can call this manually. You can also call any of the =bibtex-actions= commands with a prefix argument: =C-u M-x bibtex-actions-insert-key=. -Finally, another option is to add =bibtex-completion=-style proactive loading externally by using =filenotify= something like this: - -#+BEGIN_SRC emacs-lisp - ;; Of course, you could also use `bibtex-completion-bibliography` here, but would need - ;; to adapt this if you specify multiple files. - (file-notify-add-watch - "/path/to/file.bib" '(change) 'bibtex-actions-refresh) -#+END_SRC - -You can also extend this to do the same thing for your PDF files, or notes: +Another option is to add a hook, something like this: #+BEGIN_SRC emacs-lisp - (file-notify-add-watch - bibtex-completion-library-path '(change) 'bibtex-actions-refresh) +(defun gen-bib-cache-idle () + "Generate bib item caches with idle timer" + (run-with-idle-timer 0.5 nil #'bibtex-actions-refresh)) - (file-notify-add-watch - bibtex-completion-note-path '(change) 'bibtex-actions-refresh) +(add-hook 'LaTeX-mode-hook #'gen-bib-cache-idle) +(add-hook 'org-mode-hook #'gen-bib-cache-idle) #+END_SRC For additional configuration options on this, see [[https://github.com/bdarcus/bibtex-actions/wiki/Configuration#automating-path-watches][the wiki]]. From 9ea0d12f21dd2efd2a9e98206d81980f4c271d0b Mon Sep 17 00:00:00 2001 From: Bruce D'Arcus Date: Thu, 5 Aug 2021 12:04:10 -0400 Subject: [PATCH 3/4] Update README.org Co-authored-by: aikrahguzar <88336724+aikrahguzar@users.noreply.github.com> --- README.org | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.org b/README.org index dcccbb5b..d7259f68 100644 --- a/README.org +++ b/README.org @@ -233,7 +233,7 @@ This is great for performance, but means the data can become stale if you modify The =bibtex-actions-refresh= command will reload the caches, and you can call this manually. You can also call any of the =bibtex-actions= commands with a prefix argument: =C-u M-x bibtex-actions-insert-key=. -Another option is to add a hook, something like this: +Another option to make the completion interface more seamless is to add a hook which generates the cache after a buffer is opened. This can be done when emacs has been idle (half a second in the example below) with something like this: #+BEGIN_SRC emacs-lisp (defun gen-bib-cache-idle () From 80d2ed311a2b35610161c87f81201bb6237a6769 Mon Sep 17 00:00:00 2001 From: Bruce D'Arcus Date: Fri, 6 Aug 2021 07:03:37 -0400 Subject: [PATCH 4/4] Simplify cache handling Co-authored-by: aikrahguzar <88336724+aikrahguzar@users.noreply.github.com> --- bibtex-actions.el | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bibtex-actions.el b/bibtex-actions.el index 6f717fc0..ffc129f7 100644 --- a/bibtex-actions.el +++ b/bibtex-actions.el @@ -293,10 +293,10 @@ key associated with each one." (s-join bibtex-actions-symbol-separator (list pdf note link))" ") suffix)))) -(defvar bibtex-actions--candidates-cache nil +(defvar bibtex-actions--candidates-cache 'uninitialized "Store the global candidates list.") -(defvar-local bibtex-actions--local-candidates-cache nil +(defvar-local bibtex-actions--local-candidates-cache 'uninitialized ;; We use defvar-local so can maintain per-buffer candidate caches. "Store the local (per-buffer) candidates list.") @@ -305,12 +305,12 @@ key associated with each one." If the cache is nil, this will load the cache. If FORCE-REBUILD-CACHE is t, force reloading the cache." (when (or force-rebuild-cache - (not bibtex-actions--candidates-cache) - (not bibtex-actions--local-candidates-cache)) + (eq 'uninitialized bibtex-actions--candidates-cache) + (eq 'uninitialized bibtex-actions--local-candidates-cache)) (bibtex-actions-refresh force-rebuild-cache)) (seq-concatenate 'list - ((lambda (x) (if (eq x t) nil x)) bibtex-actions--local-candidates-cache) - ((lambda (x) (if (eq x t) nil x)) bibtex-actions--candidates-cache))) + bibtex-actions--local-candidates-cache + bibtex-actions--candidates-cache)) ;;;###autoload (defun bibtex-actions-refresh (&optional force-rebuild-cache) @@ -324,10 +324,10 @@ is non-nil, also run the `bibtex-actions-before-refresh-hook' hook." ;; itself is used to indicate a cache that hasn't been computed this is to ;; work around the fact that we can't differentiate between empty list and nil (setq bibtex-actions--candidates-cache - ((lambda (x) (if x x t)) (bibtex-actions--format-candidates))) + (bibtex-actions--format-candidates)) (let ((bibtex-completion-bibliography (bibtex-actions--local-files-to-cache))) (setq bibtex-actions--local-candidates-cache - ((lambda (x) (if x x t)) (bibtex-actions--format-candidates "is:local"))))) + (bibtex-actions--format-candidates "is:local")))) ;;;###autoload (defun bibtex-actions-insert-preset ()