Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use org-capture to create new notes #263

Closed
wants to merge 9 commits into from
154 changes: 103 additions & 51 deletions bibtex-completion.el
Original file line number Diff line number Diff line change
Expand Up @@ -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)
(declare-function org-element-parse-buffer "org-element")
(declare-function org-element-map "org-element")
(declare-function org-element-property "org-element")
Expand Down Expand Up @@ -157,6 +158,17 @@ editors."
: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
Expand Down Expand Up @@ -477,6 +489,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
Expand Down Expand Up @@ -506,16 +520,30 @@ is the entry (only the fields listed above) as an alist."
(f-file? bibtex-completion-notes-path))
(require 'org-element)
(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)))
(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
(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
do
Expand Down Expand Up @@ -546,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
Expand Down Expand Up @@ -858,10 +887,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)
Expand Down Expand Up @@ -1244,7 +1275,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 ()
Expand All @@ -1254,56 +1285,77 @@ 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)))
(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)
(unless (assoc-default "bibtex" org-capture-templates)
(cl-pushnew bibtex-completion-capture-template
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sese to remove "bibtex" from org-capture-templates after completion of bibtex-completion-edit-notes-one-file? My concern is, that running org-capture separately from bibtex-completion-edit-notes-one-file should not show the "bibtex" action. (I haven't tested if this is the case with your code, but it seems to be the case?)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I agree.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even better, could we just let-bind org-capture-templates?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use let binding since opening #260 and didn't observe any interference with "normal" org-capture use.

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)
Expand Down