save buffer after replacing non-ascii
[org-ref.git] / jmax-bibtex.el
1 ;;; jmax-bibtex.el --- jmax-bibtex utilities
2
3 ;;; Commentary:
4 ;; Requires: s.el, dash.el, org-ref.el, doi-utils.el, key-chord.el
5 ;;
6 ;; jmax-bibtex-generate-longtitles
7 ;; jmax-bibtex-generate-shorttitles
8 ;; jmax-stringify-journal-name :: replace a journal name with a string in `jmax-bibtex-journal-abbreviations'
9 ;; jmax-set-journal-string :: in a bibtex entry run this to replace the journal with a string
10 ;;
11 ;; jmax-replace-nonascii :: replace nonascii characters in a bibtex entry
12 ;;
13 ;; jmax-title-case-article
14 ;; jmax-sentence-case-article
15 ;;
16 ;; jmax-bibtex-next-entry :: bound to M-n
17 ;; jmax-bibtex-previous-entry :: bound to M-p
18 ;;
19 ;; Functions to act on an entry
20 ;; jmax-bibtex-hydra/body gives a hydra menu to a lot of useful functions.
21 ;; jmax-bibtex-new-entry/body gives a hydra menu to add new bibtex entries.
22
23 (require 'hydra)
24 (require 'key-chord)
25
26 ;;; Code:
27 (defgroup jmax-bibtex nil
28   "Customization group for jmax-bibtex.")
29
30
31 (defcustom jmax-bibtex-hydra-key-chord
32   nil
33   "key-chord to run `jmax-bibtex-hydra'.
34 I like \"jj\""
35   :type 'string
36   :group 'jmax-bibtex)
37
38
39 (defcustom jmax-bibtex-hydra-key-binding
40   nil
41   "key-binding to run `jmax-bibtex-hydra'.
42 I like \C-cj."
43   :type 'string
44   :group 'jmax-bibtex)
45
46
47 (defvar jmax-bibtex-journal-abbreviations
48   '(("ACAT" "ACS Catalysis" "ACS Catal.")
49     ("AM" "Acta Materialia" "Acta Mater.")
50     ("AMM" "Acta Metallurgica et Materialia" "Acta Metall. Mater.")
51     ("AMiner" "American Mineralogist" "Am. Mineral.")
52     ("AngC" "Angewandte Chemie-International Edition" "Angew. Chem. Int. Edit.")
53     ("APLM" "APL Materials" "APL Mat.")
54     ("ACBE" "Applied Catalysis B: Environmental" "Appl. Catal. B-Environ.")
55     ("APL" "Applied Physics Letters" "Appl. Phys. Lett.")
56     ("ASS" "Applied Surface Science" "Appl. Surf. Sci.")
57     ("CL" "Catalysis Letters" "Catal. Lett.")
58     ("CST" "Catalysis Science & Technology" "Catal. Sci. Technol.")
59     ("CT" "Catalysis Today" "Catal. Today")
60     ("CPL" "Chemical Physics Letters" "Chem. Phys. Lett")
61     ("CR" "Chemical Reviews" "Chem. Rev.")
62     ("CSR" "Chemical Society Reviews" "Chem. Soc. Rev.")
63     ("CSR" "Chemical Society Reviews" "Chem. Soc. Rev.")
64     ("CM" "Chemistry of Materials" "Chem. Mater.")
65     ("CSA" "Colloids and Surfaces, A: Physicochemical and Engineering Aspects" "Colloids Surf., A")
66     ("CPMS" "Computational Materials Science" "Comp. Mater. Sci.")
67     ("CPC" "Computer Physics Communications" "Comput. Phys. Commun.")
68     ("CGD" "Crystal Growth \\& Design" "Cryst. Growth Des.")
69     ("CEC" "CrystEngComm" "CrystEngComm")
70     ("ECST" "ECS Transactions" "ECS Trans.")
71     ("EES" "Energy \\& Environmental Science" "Energy Environ. Sci.")
72     ("HPR" "High Pressure Research" "High Pressure Res.")
73     ("IC" "Inorganic Chemistry" "Inorg. Chem.")
74     ("IECR" "Industrial \\& Engineering Chemistry Research" "Ind. Eng. Chem. Res.")
75     ("JJAP" "Japanese Journal of Applied Physics" "Jpn. J. Appl. Phys.")
76     ("JMatR" "Journal of  Materials Research" "J. Mater. Res.")
77     ("JALC" "Journal of Alloys and Compounds" "J. Alloy Compd.")
78     ("JAC" "Journal of Applied Crystallography" "J. Appl. Crystallogr.")
79     ("JAP" "Journal of Applied Physics" "J. Appl. Phys.")
80     ("JC" "Journal of Catalysis" "J. Catal.")
81     ("JCP" "Journal of Chemical Physics" "J. Chem. Phys.")
82     ("JCC" "Journal of Computational Chemistry" "J. Comput. Chem.")
83     ("JCG" "Journal of Crystal Growth" "J. Crys. Growth")
84     ("JMC" "Journal of Materials Chemistry" "J. Mater. Chem.")
85     ("JMC" "Journal of Materials Chemistry" "J. Mater. Chem.")
86     ("JMSL" "Journal of Materials Science Letters" "J. Mater. Sci. Lett.")
87     ("JMS" "Journal of Membrane Science" "J. Memb. Sci.")
88     ("JPE" "Journal of Phase Equilibria" "J. Phase Equilib.")
89     ("JPCS" "Journal of Physics and Chemistry of Solids" "J. Phys. Chem. Solids")
90     ("JPCM" "Journal of Physics: Condensed Matter" "J. Phys.: Condens. Matter")
91     ("JSSC" "Journal of Solid State Chemistry" "J. Solid State Chem.")
92     ("JACerS" "Journal of the American Ceramic Society" "J. Am. Ceram. Soc.")
93     ("JACS" "Journal of the American Chemical Society" "J. Am. Chem. Soc.")
94     ("JES" "Journal of The Electrochemical Society" "J. Electrochem. Soc.")
95     ("JEaC" "Journal of Electroanalytical Chemistry" "J. Electroanal. Chem.")
96     ("JMS" "Journal of Membrane Science" "J. Memb. Sci.")
97     ("JVST" "Journal of Vacuum Science \\& Technology A" "J. Vac. Sci. Technol. A")
98     ("ML" "Materials Letters" "Mater. Lett.")
99     ("MSE-BS" "Materials Science and Engineering B" "Mat. Sci. Eng. B-Solid")
100     ("MOLSIM" "Molecular Simulation" "Mol. Sim.")
101     ("Nature" "Nature" "Nature")
102     ("NM" "Nature Materials" "Nat. Mater.")
103     ("PML" "Philosophical Magazine Letters" "Phil. Mag. Lett.")
104     ("PMA" "Philosophical Magazine A" "Phil. Mag. A")
105     ("PA" "Physica A: Statistical Mechanics and its Applications" "Physica A")
106     ("PB" "Physica B-Condensed Matter" "Physica B")
107     ("PCCP" "Physical Chemistry Chemical Physics" "Phys. Chem. Chem. Phys.")
108     ("PSSB" "physica status solidi (b)" "Phys. Status Solidi B")
109     ("PRA" "Physical Review A" "Phys. Rev. A")
110     ("PRB" "Physical Review B" "Phys. Rev. B")
111     ("PRL" "Physical Review Letters" "Phys. Rev. Lett.")
112     ("PCM" "Physics and Chemistry of Minerals" "Phys. Chem. Miner.")
113     ("PSurfSci" "Progress in Surface Science" "Prog. Surf. Sci.")
114     ("Science" "Science" "Science")
115     ("SABC" "Sensors and Actuators B: Chemical" "Sensor. Actuat. B-Chem.")
116     ("SS" "Surface Science" "Surf. Sci.")
117     ("EPJB" "The European Physical Journal B" "Eur. Phys. J. B")
118     ("JPC" "The Journal of Physical Chemistry" "J. Phys. Chem.")
119     ("JPCB" "The Journal of Physical Chemistry B" "J. Phys. Chem. B")
120     ("JPCC" "The Journal of Physical Chemistry C" "J. Phys. Chem. C")
121     ("JPCL" "The Journal of Physical Chemistry Letters" "J. Phys. Chem. Lett.")
122     ("JCP" "The Journal of Chemical Physics" "J. Chem. Phys.")
123     ("MSMSE" "Modelling and Simulation in Materials Science and Engineering" "Modell. Simul. Mater. Sci. Eng.")
124     ("TSF" "Thin Solid Films" "Thin Solid Films")
125     ("TC" "Topics in Catalysis" "Top. Catal.")
126     ("WR" "Water Research" "Water Res."))
127   "List of (string journal-full-name journal-abbreviation).  Find abbreviations at http://cassi.cas.org/search.jsp.")
128
129
130 (defun jmax-bibtex-generate-longtitles ()
131   "Generate longtitles.bib which are @string definitions.
132 The full journal names are in `jmax-bibtex-journal-abbreviations'."
133   (interactive)
134   (with-temp-file "longtitles.bib"
135     (dolist (row jmax-bibtex-journal-abbreviations)
136       (insert (format "@string{%s=\"%s\"}\n"
137                       (nth 0 row)
138                       (nth 1 row))))))
139
140
141 (defun jmax-bibtex-generate-shorttitles ()
142     "Generate shorttitles.bib which are @string definitions.
143 The abbreviated journal names in `jmax-bibtex-journal-abbreviations'."
144   (interactive)
145   (with-temp-file "shorttitles.bib"
146     (dolist (row jmax-bibtex-journal-abbreviations)
147       (insert (format "@string{%s=\"%s\"}\n"
148                       (nth 0 row)
149                       (nth 2 row))))))
150
151
152 (defun jmax-stringify-journal-name (&optional key start end)
153   "Replace journal name in a bibtex entry with a string.
154 The strings are defined in
155 `jmax-bibtex-journal-abbreviations'.  The optional arguments KEY,
156 START and END allow you to use this with `bibtex-map-entries'"
157   (interactive)
158   (bibtex-beginning-of-entry)
159   (when
160       (string= "article"
161                (downcase
162                 (cdr (assoc "=type=" (bibtex-parse-entry)))))
163     (let* ((full-names (mapcar
164                         (lambda (row)
165                           (cons  (nth 1 row) (nth 0 row)))
166                         jmax-bibtex-journal-abbreviations))
167            (abbrev-names (mapcar
168                           (lambda (row)
169                             (cons  (nth 2 row) (nth 0 row)))
170                           jmax-bibtex-journal-abbreviations))
171            (journal (s-trim (bibtex-autokey-get-field "journal")))
172            (bstring (or
173                      (cdr (assoc journal full-names))
174                      (cdr (assoc journal abbrev-names)))))
175       (when bstring
176         (bibtex-set-field "journal" bstring t)
177         (bibtex-fill-entry)))))
178
179 (defun jmax-set-journal-string (full-journal-name)
180   "Set a bibtex journal name to the string that represents FULL-JOURNAL-NAME.
181 This is defined in `jmax-bibtex-journal-abbreviations'."
182   (interactive (list
183                 (ido-completing-read
184                  "Journal: "
185                  (mapcar
186                   (lambda (x)
187                     (nth 1 x))
188                   jmax-bibtex-journal-abbreviations))))
189   ;; construct data alist for the string lookup.
190   (let ((alist (mapcar
191                 (lambda (x)
192                   (cons (nth 1 x) (nth 0 x)))
193                 jmax-bibtex-journal-abbreviations)))
194     (bibtex-set-field "journal" (cdr (assoc full-journal-name alist)) t)
195     (bibtex-fill-entry)
196     (bibtex-clean-entry)))
197
198 ;; see https://github.com/fxcoudert/tools/blob/master/doi2bib for more replacements
199 (defvar jmax-nonascii-latex-replacements
200   '()
201   "Cons list of non-ascii characters and their LaTeX representations.")
202
203 (setq jmax-nonascii-latex-replacements
204       '(("í" . "{\\\\'i}")
205         ("æ" . "{\\\\ae}")
206         ("ć" . "{\\\\'c}")
207         ("é" . "{\\\\'e}")
208         ("ä" . "{\\\\\"a}")
209         ("è" . "{\\\\`e}")
210         ("à" . "{\\\\`a}")
211         ("á" . "{\\\\'a}")
212         ("ø" . "{\\\\o}")
213         ("ë" . "{\\\\\"e}")
214         ("ü" . "{\\\\\"u}")
215         ("ñ" . "{\\\\~n}")
216         ("ņ" . "{\\\\c{n}}")
217         ("å" . "{\\\\aa}")
218         ("ö" . "{\\\\\"o}")
219         ("Á" . "{\\\\'A}")
220         ("á" . "{\\\\'a}")
221         ("í" . "{\\\\'i}")
222         ("ó" . "{\\\\'o}")
223         ("ó" . "{\\\\'o}")
224         ("ú" .  "{\\\\'u}")
225         ("ú" . "{\\\\'u}")
226         ("š" . "{\\\\v{s}}")
227         ("ř"  . "{\\\\v{r}}")
228         ("İ" . "{\\\\.I}")
229         ("ğ" . "{\\\\u{g}}")
230         ("δ" . "$\\\\delta$")
231         ("ç" . "{\\\\c{c}}")
232         ("ß" . "{\\\\ss}")
233         ("≤" . "$\\\\le$")
234         ("<" . "$\\\\lt$")
235         ("θ" . "$\\\\theta$")
236         ("μ" . "$\\\\mu$")
237         ("→" . "$\\\\rightarrow$")
238         ("⇌" . "$\\\\leftrightharpoons$")
239         ("×" . "$\\\\times$")
240         ("°" . "$\\\\deg$")
241         ("ş" . "{\\\\c{s}}")
242         ("ı" . "i")                    ; I think this is a turkish i
243         ;; I think these are non-ascii spaces. there seems to be more than one.
244         (" " . " ")
245         (" " . " ")
246         ("–" . "-")
247         ("−" . "-")
248         ("–" . "-")
249         ("—" . "-")
250         ("‘" . "'")
251         ("’" . "'")
252         ("“" . "\"")
253         ("’" . "'")
254         ("”" . "\"")))
255
256 (defun jmax-replace-nonascii ()
257   "Hook function to replace non-ascii characters in a bibtex entry."
258
259   (interactive)
260   (save-restriction
261     (bibtex-narrow-to-entry)
262     (goto-char (point-min))
263     (dolist (char (mapcar (lambda (x) (car x)) jmax-nonascii-latex-replacements))
264       (while (re-search-forward char nil t)
265         (replace-match (cdr (assoc char jmax-nonascii-latex-replacements))))
266       (goto-char (point-min))))
267   (save-buffer))
268
269 (add-hook 'org-ref-clean-bibtex-entry-hook 'jmax-replace-nonascii)
270
271
272 (defvar jmax-lower-case-words
273   '("a" "an" "on" "and" "for"
274     "the" "of" "in")
275   "List of words to keep lowercase when changing case in a title.")
276
277
278 (defun jmax-title-case-article (&optional key start end)
279   "Convert a bibtex entry article title to title-case.
280 The arguments KEY, START and END are optional, and are only there
281 so you can use this function with `bibtex-map-entries' to change
282 all the title entries in articles."
283   (interactive)
284   (bibtex-beginning-of-entry)
285
286   (let* ((title (bibtex-autokey-get-field "title"))
287          (words (split-string title))
288          (start 0))
289     (when
290         (string= "article" (downcase (cdr (assoc "=type=" (bibtex-parse-entry)))))
291       (setq words (mapcar
292                    (lambda (word)
293                      (if (or
294                           ;; match words containing {} or \ which are probably
295                           ;; LaTeX or protected words
296                           (string-match "\\$\\|{\\|}\\|\\\\" word)
297                           ;; these words should not be capitalized, unless they
298                           ;; are the first word
299                           (-contains? jmax-lower-case-words (s-downcase word)))
300                          word
301                        (s-capitalize word)))
302                    words))
303
304       ;; Check if first word should be capitalized
305       (when (-contains? jmax-lower-case-words (car words))
306         (setf (car words) (s-capitalize (car words))))
307
308       (setq title (mapconcat 'identity words " "))
309
310       ;; Capitalize letters after a dash
311       (while
312           (string-match "[a-zA-Z]-\\([a-z]\\)" title start)
313         (let ((char (substring title (match-beginning 1) (match-end 1))))
314           (setf (substring title (match-beginning 1) (match-end 1))
315                 (format "%s" (upcase char)))
316           (setq start (match-end 1))))
317
318       ;; this is defined in doi-utils
319       (bibtex-set-field
320        "title"
321        title)
322       (bibtex-fill-entry))))
323
324 (add-hook 'org-ref-clean-bibtex-entry-hook 'jmax-title-case-article)
325
326
327 (defun jmax-sentence-case-article (&optional key start end)
328   "Convert a bibtex entry article title to sentence-case.
329 The arguments KEY, START and END are optional, and are only there
330 so you can use this function with `bibtex-map-entries' to change
331 all the title entries in articles."
332   (interactive)
333   (bibtex-beginning-of-entry)
334
335   (let* ((title (bibtex-autokey-get-field "title"))
336          (words (split-string title))
337          (start 0))
338     (when
339         (string= "article" (downcase (cdr (assoc "=type=" (bibtex-parse-entry)))))
340       (setq words (mapcar
341                    (lambda (word)
342                      (if
343                          ;; match words containing {} or \ which are probably
344                          ;; LaTeX or protected words
345                          (string-match "\\$\\|{\\|}\\|\\\\" word)
346                          word
347                        (s-downcase word)))
348                    words))
349
350       ;; capitalize first word
351       (setf (car words) (s-capitalize (car words)))
352
353       ;; join the words
354       (setq title (mapconcat 'identity words " "))
355
356       ;; capitalize a word after a :, eg. a subtitle, and protect it
357       (while
358           (string-match "[a-z]:\\s-+\\([A-Z]\\)" title start)
359         (let ((char (substring title (match-beginning 1) (match-end 1))))
360           (setf (substring title (match-beginning 1) (match-end 1))
361 ;;              (format "{%s}" (upcase char)))
362                 (format "%s" (upcase char)))
363           (setq start (match-end 1))))
364
365       ;; this is defined in doi-utils
366       (bibtex-set-field
367        "title" title)
368
369       ;; clean and refill entry so it looks nice
370       (bibtex-clean-entry)
371       (bibtex-fill-entry))))
372
373
374
375
376 (defun jmax-bibtex-next-entry (&optional n)
377   "Jump to the beginning of the next bibtex entry.
378 N is a prefix argument.  If it is numeric, jump that many entries
379 forward.  Negative numbers do nothing."
380   (interactive "P")
381   ;; Note if we start at the beginning of an entry, nothing
382   ;; happens. We need to move forward a char, and call again.
383   (when (= (point) (save-excursion
384                      (bibtex-beginning-of-entry)))
385     (forward-char)
386     (jmax-bibtex-next-entry))
387
388   ;; search forward for an entry
389   (when
390       (re-search-forward bibtex-entry-head nil t (and (numberp n) n))
391     ;; go to beginning of the entry
392     (bibtex-beginning-of-entry)))
393
394
395 (defun jmax-bibtex-previous-entry (&optional n)
396   "Jump to beginning of the previous bibtex entry.
397 N is a prefix argument.  If it is numeric, jump that many entries back."
398   (interactive "P")
399   (bibtex-beginning-of-entry)
400  (when
401      (re-search-backward bibtex-entry-head nil t (and (numberp n) n))
402    (bibtex-beginning-of-entry)))
403
404
405 (defun jmax-bibtex-mode-keys ()
406   "Modify keymaps used by `bibtex-mode'."
407   (local-set-key (kbd "M-n") 'jmax-bibtex-next-entry)
408   (local-set-key (kbd "M-p") 'jmax-bibtex-previous-entry))
409
410 ;; add to bibtex-mode-hook
411 (add-hook 'bibtex-mode-hook 'jmax-bibtex-mode-keys)
412
413
414 (defun jmax-bibtex-entry-doi ()
415   "Get doi from entry at point."
416   (interactive)
417   (save-excursion
418     (bibtex-beginning-of-entry)
419     (reftex-get-bib-field "doi" (bibtex-parse-entry t))))
420
421
422 (defun jmax-bibtex-wos ()
423   "Open bibtex entry in Web Of Science if there is a DOI."
424   (interactive)
425   (doi-utils-wos (jmax-bibtex-entry-doi)))
426
427
428 (defun jmax-bibtex-wos-citing ()
429   "Open citing articles for bibtex entry in Web Of Science if there is a DOI."
430   (interactive)
431   (doi-utils-wos-citing (jmax-bibtex-entry-doi)))
432
433
434 (defun jmax-bibtex-wos-related ()
435   "Open related articles for bibtex entry in Web Of Science if there is a DOI."
436   (interactive)
437   (doi-utils-wos-related (jmax-bibtex-entry-doi)))
438
439
440 (defun jmax-bibtex-wos-citing ()
441   "Open citing articles for bibtex entry in Web Of Science if there is a DOI."
442   (interactive)
443   (doi-utils-wos-citing (jmax-bibtex-entry-doi)))
444
445
446 (defun jmax-bibtex-crossref ()
447   "Open the bibtex entry in Crossref by its doi."
448   (interactive)
449   (doi-utils-crossref (jmax-bibtex-entry-doi)))
450
451
452 (defun jmax-bibtex-google-scholar ()
453   "Open the bibtex entry at point in google-scholar by its doi."
454   (interactive)
455   (doi-utils-google-scholar (jmax-bibtex-entry-doi)))
456
457
458 (defun jmax-bibtex-pubmed ()
459   "Open the bibtex entry at point in Pubmed by its doi."
460   (interactive)
461   (doi-utils-pubmed (jmax-bibtex-entry-doi)))
462
463
464 (defun jmax-bibtex-pdf (doi)
465   "Open the pdf for the bibtex entry at point.
466 Thin wrapper to get `jmax-bibtex' to open pdf, because it calls
467 functions with a DOI argument."
468   (interactive)
469   (org-ref-open-bibtex-pdf))
470
471
472 ;; hydra menu for actions on bibtex entries
473 (defhydra jmax-bibtex-hydra (:color blue)
474    "
475 _p_: Open pdf     _y_: Copy key               _n_: New entry     _w_: WOS
476 _u_: Open url     _f_: Copy formatted entry   _o_: Copy entry    _c_: WOS citing
477 _r_: Refile entry _k_: Add keywords           _d_: delete entry  _r_: WOS related
478 _e_: Email entry  _K_: Edit keywords          _L_: clean entry   _P_: Pubmed
479 _U_: Update entry _N_: Open notes             _R_: Crossref      _g_: Google Scholar
480 _q_: quit
481 "
482    ("p" org-ref-open-bibtex-pdf)
483    ("P" jmax-bibtex-pubmed)
484    ("w" jmax-bibtex-wos)
485    ("c" jmax-bibtex-wos-citing)
486    ("r" jmax-bibtex-wos-related)
487    ("R" jmax-bibtex-crossref)
488    ("g" jmax-bibtex-google-scholar)
489    ("n" jmax-bibtex-new-entry/body)
490    ("N" org-ref-open-bibtex-notes)
491    ("o" bibtex-copy-entry-as-kill)
492    ("d" bibtex-kill-entry)
493    ("L" org-ref-clean-bibtex-entry)
494    ("y" (kill-new  (bibtex-autokey-get-field "=key=")))
495    ("f" bibtex-copy-summary-as-kill)
496    ("k" helm-tag-bibtex-entry)
497    ("K" (lambda ()
498           (interactive)
499           (org-ref-set-bibtex-keywords
500            (read-input "Keywords: "
501                        (bibtex-autokey-get-field "keywords"))
502            t)))
503    ("u" org-ref-open-in-browser)
504    ("r" (lambda () (interactive)
505           (bibtex-beginning-of-entry)
506           (bibtex-kill-entry)
507           (find-file (ido-completing-read
508                       "Bibtex file: "
509                       (f-entries "." (lambda (f) (f-ext? f "bib")))))
510           (goto-char (point-max))
511           (bibtex-yank)
512           (save-buffer)
513           (kill-buffer)))
514    ("e" email-bibtex-entry)
515    ("U" (doi-utils-update-bibtex-entry-from-doi (jmax-bibtex-entry-doi)))
516    ("q" nil "quit")
517    ("f" jmax-bibtex-file/body "File functions")
518    ("a" jmax-replace-nonascii "Replace non-ascii"))
519
520 ;; create key-chord and key binding for hydra
521 (when jmax-bibtex-hydra-key-chord
522   (key-chord-define-global
523    jmax-bibtex-hydra-key-chord
524    'jmax-bibtex-hydra/body))
525
526
527 (when jmax-bibtex-hydra-key-binding
528   (global-set-key jmax-bibtex-hydra-key-binding 'jmax-bibtex-hydra/body))
529
530
531 ;; A hydra for adding new bibtex entries.
532 (defhydra jmax-bibtex-new-entry (:color blue)
533   "New Bibtex entry:"
534   ("a" bibtex-Article "Article")
535   ("b" bibtex-Book "Book")
536   ("i" bibtex-InBook "In book")
537   ("l" bibtex-Booklet "Booklet")
538   ("P" bibtex-Proceedings "Proceedings")
539   ("p" bibtex-InProceedings "In proceedings")
540   ("m" bibtex-Misc "Misc.")
541   ("M" bibtex-Manual "Manual")
542   ("T" bibtex-PhdThesis "PhD Thesis")
543   ("t" bibtex-MastersThesis "MS Thesis")
544   ("R" bibtex-TechReport "Report")
545   ("u" bibtex-Unpublished "unpublished")
546   ("c" bibtex-InCollection "Article in collection")
547   ("q" nil "quit"))
548
549 ;; a hydra menu of functions to act on a bibtex file.
550 (defhydra jmax-bibtex-file (:color blue)
551   "Bibtex file functions: "
552   ("v" bibtex-validate "Validate entries")
553   ("s" bibtex-sort-buffer "Sort entries")
554   ("r" bibtex-reformat "Reformat entries")
555   ("c" bibtex-count-entries "Count entries")
556   ("p" org-ref-build-full-bibliography "PDF bibliography"))
557
558
559 (defvar jmax-bibtex-menu-funcs '()
560  "Functions to run in doi menu.
561 Each entry is a list of (key menu-name function).  The function
562 must take one argument, the doi.  This is somewhat deprecated, as
563 I prefer the hydra interfaces above.")
564
565 (setq jmax-bibtex-menu-funcs
566       '(("p" "df" jmax-bibtex-pdf)
567         ("C" "opy" (lambda (doi)
568                      (kill-new (org-ref-bib-citation))
569                      (bury-buffer)))
570         ("w" "os" doi-utils-wos)
571         ("c" "iting articles" doi-utils-wos-citing)
572         ("r" "elated articles" doi-utils-wos-related)
573         ("s" "Google Scholar" doi-utils-google-scholar)
574         ("P" "Pubmed" doi-utils-pubmed)
575         ("f" "CrossRef" doi-utils-crossref)))
576
577 (defun jmax-bibtex ()
578   "Menu command to run in a bibtex entry.
579 Functions from `jmax-bibtex-menu-funcs'.  They all rely on the
580 entry having a doi."
581
582   (interactive)
583   ;; construct menu string as a message
584   (message
585    (concat
586     (mapconcat
587      (lambda (tup)
588        (concat "[" (elt tup 0) "]"
589                (elt tup 1) " "))
590      jmax-bibtex-menu-funcs "") ": "))
591   (let* ((input (read-char-exclusive))
592          (choice (assoc
593                   (char-to-string input) jmax-bibtex-menu-funcs)))
594     (when choice
595       (funcall
596        (elt
597         choice
598         2)
599        (jmax-bibtex-entry-doi)
600        ))))
601
602 (defalias 'jb 'jmax-bibtex)
603
604 (provide 'jmax-bibtex)
605
606 ;;; jmax-bibtex.el ends here