-
Notifications
You must be signed in to change notification settings - Fork 74
/
ivy-bibtex.el
231 lines (200 loc) · 9.1 KB
/
ivy-bibtex.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
;;; ivy-bibtex.el --- A bibliography manager based on Ivy
;; Author: Justin Burkett <justin@burkett.cc>
;; Maintainer: Titus von der Malsburg <malsburg@posteo.de>
;; URL: https://github.com/tmalsburg/helm-bibtex
;; Version: 1.0.1
;; Package-Requires: ((bibtex-completion "1.0.0") (ivy "0.13.0") (cl-lib "0.5"))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; A BibTeX bibliography manager based on Ivy and the
;; bibtex-completion backend. If you are familiar with helm-bibtex,
;; this is the ivy version.
;;
;; News:
;; - 09/06/2018: Added virtual APA field `author-or-editor` for use in
;; notes templates.
;; - 02/06/2018: Reload bibliography proactively when bib files are
;; changed.
;; - 21/10/2017: Added support for multiple PDFs and other file
;; types. See `bibtex-completion-pdf-extension' and
;; `bibtex-completion-find-additional-pdfs' for details.
;; - 10/10/2017: Added support for ~@string~ constants.
;; - 02/10/2017: Date field is used when year is undefined.
;; - 29/09/2017: BibTeX entry, citation macro, or org-bibtex entry at
;; point, will be pre-selected in helm-bibtex and ivy-bibtex giving
;; quick access to PDFs and other functions.
;;
;; See NEWS.org for old news.
;;
;; Key features:
;; - Quick access to your bibliography from within Emacs
;; - Tightly integrated workflows
;; - Provides instant search results as you type
;; - Powerful search expressions
;; - Open the PDFs, URLs, or DOIs associated with an entry
;; - Insert LaTeX cite commands, Ebib links, or Pandoc citations,
;; BibTeX entries, or plain text references at point, attach PDFs to
;; emails
;; - Attach notes to publications
;;
;; Install:
;;
;; Put this file in a directory included in your load path or
;; install ivy-bibtex from MELPA (preferred). Then add the
;; following in your Emacs startup file:
;;
;; (require 'ivy-bibtex)
;;
;; Alternatively, you can use autoload:
;;
;; (autoload 'ivy-bibtex "ivy-bibtex" "" t)
;;
;; Requirements are parsebib, swiper, s, dash, and f. The easiest way
;; to install these packages is through MELPA.
;;
;; Let ivy-bibtex know where it can find your bibliography by
;; setting the variable `bibtex-completion-bibliography'. See the
;; manual for more details:
;;
;; https://github.com/tmalsburg/helm-bibtex/blob/master/README.ivy-bibtex.org
;;
;; Usage:
;;
;; Do M-x ivy-bibtex and start typing a search query when prompted.
;;; Code:
(require 'ivy)
(require 'bibtex-completion)
(defcustom ivy-bibtex-default-action 'ivy-bibtex-open-any
"The default action for the `ivy-bibtex` command."
:group 'bibtex-completion
:type 'function)
(defvar ivy-bibtex-default-multi-action 'ivy-bibtex-open-any
"The default multi-action for the `ivy-bibtex` command.")
(defvar ivy-bibtex-use-extra-keymap t
"Non-nil if `ivy-bibtex' has keys for marking candidates.")
(defvar ivy-bibtex-extra-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-SPC") 'ivy-mark)
(define-key map (kbd "S-SPC") 'ivy-unmark)
map)
"Optional extra keymap for `ivy-bibtex'.")
(defun ivy-bibtex-display-transformer (candidate)
"Prepare bib entry CANDIDATE for display."
(let* ((width (- (frame-width) 2))
(idx (get-text-property 1 'idx candidate))
(entry (cdr (nth idx (ivy-state-collection ivy-last)))))
(s-concat (if (s-starts-with-p ivy-mark-prefix candidate) ivy-mark-prefix "")
(bibtex-completion-format-entry entry width))))
(defmacro ivy-bibtex-ivify-action (action name)
"Wraps the function ACTION in two other functions named NAME and NAME-multi.
The first extracts the key from the candidate selected in ivy and
passes it to ACTION.
The second extracts the list of keys in mark candidates selected
in ivy and passes it to ACTION."
`(defun ,name (candidates)
,(format "Ivy wrapper for `%s' applied to one or more CANDIDATES." action)
(let ((keys (if (consp (car candidates))
(--map (cdr (assoc "=key=" (cdr it))) candidates)
(list (cdr (assoc "=key=" (cdr candidates)))))))
(,action keys))))
(ivy-bibtex-ivify-action bibtex-completion-open-any ivy-bibtex-open-any)
(ivy-bibtex-ivify-action bibtex-completion-open-pdf ivy-bibtex-open-pdf)
(ivy-bibtex-ivify-action bibtex-completion-open-url-or-doi ivy-bibtex-open-url-or-doi)
(ivy-bibtex-ivify-action bibtex-completion-insert-citation ivy-bibtex-insert-citation)
(ivy-bibtex-ivify-action bibtex-completion-insert-reference ivy-bibtex-insert-reference)
(ivy-bibtex-ivify-action bibtex-completion-insert-key ivy-bibtex-insert-key)
(ivy-bibtex-ivify-action bibtex-completion-insert-bibtex ivy-bibtex-insert-bibtex)
(ivy-bibtex-ivify-action bibtex-completion-add-PDF-attachment ivy-bibtex-add-PDF-attachment)
(ivy-bibtex-ivify-action bibtex-completion-edit-notes ivy-bibtex-edit-notes)
(ivy-bibtex-ivify-action bibtex-completion-show-entry ivy-bibtex-show-entry)
(ivy-bibtex-ivify-action bibtex-completion-add-pdf-to-library ivy-bibtex-add-pdf-to-library)
(defun ivy-bibtex-fallback (search-expression)
"Select a fallback option for SEARCH-EXPRESSION.
This is meant to be used as an action in `ivy-read`, with
`ivy-text` as search expression."
(ivy-read "Fallback options: "
(bibtex-completion-fallback-candidates)
:caller 'ivy-bibtex-fallback
:action (lambda (candidate) (bibtex-completion-fallback-action (cdr candidate) search-expression))))
(defvar ivy-bibtex-history nil
"Search history for `ivy-bibtex'.")
;;;###autoload
(defun ivy-bibtex (&optional arg local-bib)
"Search BibTeX entries using ivy.
With a prefix ARG the cache is invalidated and the bibliography
reread.
If LOCAL-BIB is non-nil, display that the BibTeX entries are read
from the local bibliography. This is set internally by
`ivy-bibtex-with-local-bibliography'."
(interactive "P")
(when arg
(bibtex-completion-clear-cache))
(bibtex-completion-init)
(let* ((candidates (bibtex-completion-candidates))
(key (bibtex-completion-key-at-point))
(preselect (and key
(cl-position-if (lambda (cand)
(member (cons "=key=" key)
(cdr cand)))
candidates))))
(ivy-read (format "BibTeX entries%s: " (if local-bib " (local)" ""))
candidates
:preselect preselect
:caller 'ivy-bibtex
:history 'ivy-bibtex-history
:action ivy-bibtex-default-action
:multi-action ivy-bibtex-default-multi-action
:keymap (when ivy-bibtex-use-extra-keymap ivy-bibtex-extra-keymap))))
;;;###autoload
(defun ivy-bibtex-with-local-bibliography (&optional arg)
"Search BibTeX entries with local bibliography.
With a prefix ARG the cache is invalidated and the bibliography
reread."
(interactive "P")
(let* ((local-bib (bibtex-completion-find-local-bibliography))
(bibtex-completion-bibliography (or local-bib
bibtex-completion-bibliography)))
(ivy-bibtex arg local-bib)))
;;;###autoload
(defun ivy-bibtex-with-notes (&optional arg)
"Search BibTeX entries with notes.
With a prefix ARG the cache is invalidated and the bibliography
reread."
(interactive "P")
(cl-letf* ((candidates (bibtex-completion-candidates))
((symbol-function 'bibtex-completion-candidates)
(lambda ()
(--filter (assoc "=has-note=" it) candidates))))
(ivy-bibtex arg)))
(ivy-set-display-transformer
'ivy-bibtex
'ivy-bibtex-display-transformer)
(ivy-set-actions
'ivy-bibtex
'(("p" ivy-bibtex-open-pdf "Open PDF file (if present)" ivy-bibtex-open-pdf)
("u" ivy-bibtex-open-url-or-doi "Open URL or DOI in browser" ivy-bibtex-open-url-or-doi)
("c" ivy-bibtex-insert-citation "Insert citation" ivy-bibtex-insert-citation)
("r" ivy-bibtex-insert-reference "Insert reference" ivy-bibtex-insert-reference)
("k" ivy-bibtex-insert-key "Insert BibTeX key" ivy-bibtex-insert-key)
("b" ivy-bibtex-insert-bibtex "Insert BibTeX entry" ivy-bibtex-insert-bibtex)
("a" ivy-bibtex-add-PDF-attachment "Attach PDF to email" ivy-bibtex-add-PDF-attachment)
("e" ivy-bibtex-edit-notes "Edit notes" ivy-bibtex-edit-notes)
("s" ivy-bibtex-show-entry "Show entry" ivy-bibtex-show-entry)
("l" ivy-bibtex-add-pdf-to-library "Add PDF to library" ivy-bibtex-add-pdf-to-library)
("f" (lambda (_candidate) (ivy-bibtex-fallback ivy-text)) "Fallback options")))
(provide 'ivy-bibtex)
;; Local Variables:
;; byte-compile-warnings: (not cl-functions obsolete)
;; coding: utf-8
;; indent-tabs-mode: nil
;; End:
;;; ivy-bibtex.el ends here