From 4d04dab244d7a0aef177b13730e367868f8dabe9 Mon Sep 17 00:00:00 2001 From: Jonathan Gregory Date: Wed, 17 Oct 2018 16:29:12 -0300 Subject: [PATCH 1/8] Load Org conditionally Loading Org here makes helm-bibtex load slower with recent versions of Org. --- bibtex-completion.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bibtex-completion.el b/bibtex-completion.el index b881899..f48e3a1 100644 --- a/bibtex-completion.el +++ b/bibtex-completion.el @@ -496,7 +496,8 @@ is the entry (only the fields listed above) as an alist." (when (and bibtex-completion-notes-path (f-file? bibtex-completion-notes-path)) (with-temp-buffer - (org-mode) ;; need this to avoid error in emacs 25.3.1 + (when (< (string-to-number (org-version)) 9) + (org-mode)) ; Avoid error in older versions of Org (see pull/231) (insert-file-contents bibtex-completion-notes-path) (setq bibtex-completion-cached-notes-keys (let ((tree (org-element-parse-buffer 'headline))) From b8d31373281888b2c612284d5a075c25dccafccf Mon Sep 17 00:00:00 2001 From: Jonathan Gregory Date: Wed, 17 Oct 2018 16:31:55 -0300 Subject: [PATCH 2/8] Refactor code and add string replacements --- bibtex-completion.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/bibtex-completion.el b/bibtex-completion.el index f48e3a1..3958073 100644 --- a/bibtex-completion.el +++ b/bibtex-completion.el @@ -848,10 +848,12 @@ the variable `bibtex-completion-display-formats'." (defun bibtex-completion-clean-string (s) - "Removes quoting and superfluous white space from BibTeX field -values." - (if s (replace-regexp-in-string "[\n\t ]+" " " - (replace-regexp-in-string "[\"{}]+" "" s)) + "Remove quoting and superfluous white space from BibTeX field values." + (if s + (--> (replace-regexp-in-string "[\n\t ]+" " " s) + (replace-regexp-in-string "\\\\&" "&" it) + (replace-regexp-in-string "\\\\%" "%" it) + (replace-regexp-in-string "[\"{}]+" "" it)) nil)) (defun bibtex-completion-shorten-authors (authors) @@ -1230,7 +1232,7 @@ defined. Surrounding curly braces are stripped." (substitute-command-keys " Finish \\[bibtex-completion-exit-notes-buffer], refile \\[org-refile]"))) -;; Define global minor mode. This is needed to the toggle minor mode. +;; Define global minor mode. This is needed for toggling minor mode. (define-globalized-minor-mode bibtex-completion-notes-global-mode bibtex-completion-notes-mode bibtex-completion-notes-mode) (defun bibtex-completion-exit-notes-buffer () @@ -1240,8 +1242,7 @@ line." (interactive) (widen) (bibtex-completion-notes-global-mode -1) - (setq-local - header-line-format nil) + (setq-local header-line-format nil) (save-buffer) (let ((window (get-buffer-window (file-name-nondirectory bibtex-completion-notes-path)))) (if (and window (not (one-window-p window))) From 2181af15ee7798abfd2a8ab542973e4e5c46aa86 Mon Sep 17 00:00:00 2001 From: Jonathan Gregory Date: Wed, 17 Oct 2018 16:32:37 -0300 Subject: [PATCH 3/8] Recycle cached notes keys when available --- bibtex-completion.el | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/bibtex-completion.el b/bibtex-completion.el index 3958073..d788615 100644 --- a/bibtex-completion.el +++ b/bibtex-completion.el @@ -468,6 +468,8 @@ for string replacement." (defvar bibtex-completion-cached-notes-keys nil "A cache storing notes keys obtained when the bibliography was last parsed.") +(defvar bibtex-completion-notes-hash nil) + (defun bibtex-completion-candidates () "Reads the BibTeX files and returns a list of conses, one for each entry. The first element of these conses is a string @@ -499,14 +501,26 @@ is the entry (only the fields listed above) as an alist." (when (< (string-to-number (org-version)) 9) (org-mode)) ; Avoid error in older versions of Org (see pull/231) (insert-file-contents bibtex-completion-notes-path) - (setq bibtex-completion-cached-notes-keys - (let ((tree (org-element-parse-buffer 'headline))) - (org-element-map tree 'headline - (lambda (key) (org-element-property :CUSTOM_ID key))))))) + (let ((notes-hash (secure-hash 'sha256 (current-buffer)))) + ;; Check that we have cached notes keys and that the notes + ;; file hasn't changed + (if (and bibtex-completion-cached-notes-keys + (string= notes-hash bibtex-completion-notes-hash)) + bibtex-completion-cached-notes-keys + (setq bibtex-completion-cached-notes-keys + (let ((tree (org-element-parse-buffer 'headline))) + (org-element-map tree 'headline + (lambda (key) (org-element-property :CUSTOM_ID key))))))))) ;; reparse if necessary (when reparsed-files + + (with-temp-buffer + (insert-file-contents bibtex-completion-notes-path) + (let ((notes-hash (secure-hash 'sha256 (current-buffer)))) + (setq bibtex-completion-notes-hash notes-hash))) + (cl-loop for file in files do From 4888706c1b7390dbca23a2462301f09b1548b29a Mon Sep 17 00:00:00 2001 From: Jonathan Gregory Date: Wed, 17 Oct 2018 16:33:13 -0300 Subject: [PATCH 4/8] Use org-capture to create new notes --- bibtex-completion.el | 108 ++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 38 deletions(-) diff --git a/bibtex-completion.el b/bibtex-completion.el index d788615..7c562a6 100644 --- a/bibtex-completion.el +++ b/bibtex-completion.el @@ -148,6 +148,17 @@ a BibTeX field into the template." :group 'bibtex-completion :type 'string) +(defcustom bibtex-completion-capture-template + '("bibtex" "helm-bibtex" entry (file bibtex-completion-notes-path) + "%(bibtex-completion-capture-placeholder)") + + "Template for creating new notes with org-capture. +You should use \"bibtex\" as the key of the template and +`bibtex-completion-capture-placeholder' as the placeholder. See +`org-capture-templates'." + :group 'bibtex-completion + :type 'list) + (defcustom bibtex-completion-notes-key-pattern ":Custom_ID: +%s\\( \\|$\\)" "The pattern used to find entries in the notes file. Only @@ -1263,48 +1274,69 @@ line." (delete-window window) (switch-to-buffer (other-buffer))))) -(defun bibtex-completion-edit-notes (keys) - "Open the notes associated with the selected entries using `find-file'." +(defun bibtex-completion-edit-notes-multiple-files (keys) + "Using one notes file per publication, open notes associated with the selected entries." (dolist (key keys) - (let* ((entry (bibtex-completion-get-entry key)) - (year (or (bibtex-completion-get-value "year" entry) - (car (split-string (bibtex-completion-get-value "date" entry "") "-")))) - (entry (push (cons "year" year) entry))) - (if (and bibtex-completion-notes-path - (f-directory? bibtex-completion-notes-path)) - ; One notes file per publication: - (let* ((path (f-join bibtex-completion-notes-path - (s-concat key bibtex-completion-notes-extension)))) - (find-file path) - (unless (f-exists? path) - (insert (s-format bibtex-completion-notes-template-multiple-files - 'bibtex-completion-apa-get-value - entry)))) - ; One file for all notes: + (let ((entry (bibtex-completion-get-entry key)) + (path (f-join bibtex-completion-notes-path + (s-concat key bibtex-completion-notes-extension)))) + ;; Why not `find-file-other-window'? + (find-file path) + (unless (f-exists? path) + (insert (s-format bibtex-completion-notes-template-multiple-files + 'bibtex-completion-apa-get-value + entry)))))) + +(defun bibtex-completion-clean-notes-string (s) + "Unescape ampersand and remove brackets from S." + (--> (replace-regexp-in-string "\\\\&" "&" s) + (replace-regexp-in-string "[\\\{}]+" "" it))) + +(defun bibtex-completion-capture-placeholder () + "Placeholder for `bibtex-completion-capture-template'." + (bibtex-completion-clean-notes-string + (s-format bibtex-completion-notes-template-one-file + 'bibtex-completion-apa-get-value entry))) + +(defun bibtex-completion-edit-notes-one-file (keys) + "Using one file for all notes, open notes associated with the selected entries. +If notes are not found, create one using org-capture (see +`bibtex-completion-capture-template')." + (dolist (key keys) + (let ((entry (bibtex-completion-get-entry key))) + (if (not (assoc "=has-note=" entry)) + ;; No notes found, so create one + (progn + (require 'org-capture) + (cl-pushnew bibtex-completion-capture-template + org-capture-templates :test 'equal) + (org-capture nil "bibtex") + ;; Move point past drawer and empty lines + (org-end-of-meta-data t) + (when (eobp) + (newline) + (save-excursion + (newline)))) + ;; Existing notes found (unless (and buffer-file-name (f-same? bibtex-completion-notes-path buffer-file-name)) (find-file-other-window bibtex-completion-notes-path)) - (widen) - (outline-show-all) - (goto-char (point-min)) - (if (re-search-forward (format bibtex-completion-notes-key-pattern (regexp-quote key)) nil t) - ; Existing entry found: - (when (eq major-mode 'org-mode) - (org-narrow-to-subtree) - (re-search-backward "^\*+ " nil t) - (org-cycle-hide-drawers nil) - (bibtex-completion-notes-mode 1)) - ; Create a new entry: - (goto-char (point-max)) - (insert (s-format bibtex-completion-notes-template-one-file - 'bibtex-completion-apa-get-value - entry))) - (when (eq major-mode 'org-mode) - (org-narrow-to-subtree) - (re-search-backward "^\*+ " nil t) - (org-cycle-hide-drawers nil) - (goto-char (point-max)) - (bibtex-completion-notes-mode 1)))))) + (widen) + (outline-show-all) + (org-link-search (concat "#" (regexp-quote key))) + (org-narrow-to-subtree) + (org-end-of-meta-data t) + (bibtex-completion-notes-mode 1))))) + +(defun bibtex-completion-edit-notes (keys) + "Open notes associated with the selected entries. +If `bibtex-completion-notes-path' points to a directory run +`bibtex-completion-edit-notes-multiple-files'. Otherwise run +`bibtex-completion-edit-notes-one-file'." + (if (and bibtex-completion-notes-path + (f-directory? bibtex-completion-notes-path)) + (bibtex-completion-edit-notes-multiple-files keys) + (bibtex-completion-edit-notes-one-file keys))) (defun bibtex-completion-buffer-visiting (file) (or (get-file-buffer file) From 4bb5f7878471c0a27b4fb701af9ad05698ba02de Mon Sep 17 00:00:00 2001 From: Jonathan Gregory Date: Wed, 17 Oct 2018 17:00:29 -0300 Subject: [PATCH 5/8] Fix byte compile warning --- bibtex-completion.el | 1 + 1 file changed, 1 insertion(+) diff --git a/bibtex-completion.el b/bibtex-completion.el index 7c562a6..5084828 100644 --- a/bibtex-completion.el +++ b/bibtex-completion.el @@ -50,6 +50,7 @@ (declare-function org-find-property "org") (declare-function org-show-entry "org") (declare-function org-entry-get "org") +(defvar org-capture-templates) (defgroup bibtex-completion nil "Helm plugin for searching entries in a BibTeX bibliography." From 652b188b522682cde6f6d04fb8a2e2074927bd76 Mon Sep 17 00:00:00 2001 From: Jonathan Gregory Date: Wed, 17 Oct 2018 23:00:49 -0300 Subject: [PATCH 6/8] Check that notes file exists --- bibtex-completion.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bibtex-completion.el b/bibtex-completion.el index 68fcc95..85c778d 100644 --- a/bibtex-completion.el +++ b/bibtex-completion.el @@ -539,9 +539,10 @@ is the entry (only the fields listed above) as an alist." (when reparsed-files (with-temp-buffer - (insert-file-contents bibtex-completion-notes-path) - (let ((notes-hash (secure-hash 'sha256 (current-buffer)))) - (setq bibtex-completion-notes-hash notes-hash))) + (when-let (notes-file bibtex-completion-notes-path) + (insert-file-contents notes-file) + (let ((notes-hash (secure-hash 'sha256 (current-buffer)))) + (setq bibtex-completion-notes-hash notes-hash)))) (cl-loop for file in files From ee133add88bede6dc7fc48772376244bc2c7664f Mon Sep 17 00:00:00 2001 From: Jonathan Gregory Date: Wed, 17 Oct 2018 23:01:17 -0300 Subject: [PATCH 7/8] Show message only when reloading --- bibtex-completion.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bibtex-completion.el b/bibtex-completion.el index 85c778d..ff471af 100644 --- a/bibtex-completion.el +++ b/bibtex-completion.el @@ -574,7 +574,8 @@ is the entry (only the fields listed above) as an alist." (bibtex-completion-resolve-crossrefs files reparsed-files)) ;; Finally return the list of candidates: - (message "Done (re)loading bibliography.") + (when reparsed-files + (message "Done reloading bibliography")) (nreverse (cl-loop for file in files From ee2e1c1f95f5e8aa6097e1d42b6cd327f9c8f55f Mon Sep 17 00:00:00 2001 From: Jonathan Gregory Date: Wed, 17 Oct 2018 23:01:32 -0300 Subject: [PATCH 8/8] Push to list only if elt is not in the list --- bibtex-completion.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bibtex-completion.el b/bibtex-completion.el index ff471af..c3806ed 100644 --- a/bibtex-completion.el +++ b/bibtex-completion.el @@ -1326,8 +1326,9 @@ If notes are not found, create one using org-capture (see ;; No notes found, so create one (progn (require 'org-capture) - (cl-pushnew bibtex-completion-capture-template - org-capture-templates :test 'equal) + (unless (assoc-default "bibtex" org-capture-templates) + (cl-pushnew bibtex-completion-capture-template + org-capture-templates :test 'equal)) (org-capture nil "bibtex") ;; Move point past drawer and empty lines (org-end-of-meta-data t)