1 ;;; jmax-bibtex.el --- jmax-bibtex utilities
4 ;; Requires: s.el, dash.el, org-ref.el, doi-utils.el, key-chord.el
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
11 ;; jmax-replace-nonascii :: replace nonascii characters in a bibtex entry
13 ;; jmax-title-case-article
14 ;; jmax-sentence-case-article
16 ;; jmax-bibtex-next-entry :: bound to M-n
17 ;; jmax-bibtex-previous-entry :: bound to M-p
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.
27 (defgroup jmax-bibtex nil
28 "Customization group for jmax-bibtex.")
31 (defcustom jmax-bibtex-hydra-key-chord
33 "key-chord to run `jmax-bibtex-hydra'.
39 (defcustom jmax-bibtex-hydra-key-binding
41 "key-binding to run `jmax-bibtex-hydra'.
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.")
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'."
134 (with-temp-file "longtitles.bib"
135 (dolist (row jmax-bibtex-journal-abbreviations)
136 (insert (format "@string{%s=\"%s\"}\n"
141 (defun jmax-bibtex-generate-shorttitles ()
142 "Generate shorttitles.bib which are @string definitions.
143 The abbreviated journal names in `jmax-bibtex-journal-abbreviations'."
145 (with-temp-file "shorttitles.bib"
146 (dolist (row jmax-bibtex-journal-abbreviations)
147 (insert (format "@string{%s=\"%s\"}\n"
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'"
158 (bibtex-beginning-of-entry)
162 (cdr (assoc "=type=" (bibtex-parse-entry)))))
163 (let* ((full-names (mapcar
165 (cons (nth 1 row) (nth 0 row)))
166 jmax-bibtex-journal-abbreviations))
167 (abbrev-names (mapcar
169 (cons (nth 2 row) (nth 0 row)))
170 jmax-bibtex-journal-abbreviations))
171 (journal (s-trim (bibtex-autokey-get-field "journal")))
173 (cdr (assoc journal full-names))
174 (cdr (assoc journal abbrev-names)))))
176 (bibtex-set-field "journal" bstring t)
177 (bibtex-fill-entry)))))
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'."
188 jmax-bibtex-journal-abbreviations))))
189 ;; construct data alist for the string lookup.
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)
196 (bibtex-clean-entry)))
198 ;; see https://github.com/fxcoudert/tools/blob/master/doi2bib for more replacements
199 (defvar jmax-nonascii-latex-replacements
201 "Cons list of non-ascii characters and their LaTeX representations.")
203 (setq jmax-nonascii-latex-replacements
230 ("δ" . "$\\\\delta$")
235 ("θ" . "$\\\\theta$")
237 ("→" . "$\\\\rightarrow$")
238 ("⇌" . "$\\\\leftrightharpoons$")
239 ("×" . "$\\\\times$")
242 ("ı" . "i") ; I think this is a turkish i
243 ;; I think these are non-ascii spaces. there seems to be more than one.
256 (defun jmax-replace-nonascii ()
257 "Hook function to replace non-ascii characters in a bibtex entry."
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))))
269 (add-hook 'org-ref-clean-bibtex-entry-hook 'jmax-replace-nonascii)
272 (defvar jmax-lower-case-words
273 '("a" "an" "on" "and" "for"
275 "List of words to keep lowercase when changing case in a title.")
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."
284 (bibtex-beginning-of-entry)
286 (let* ((title (bibtex-autokey-get-field "title"))
287 (words (split-string title))
290 (string= "article" (downcase (cdr (assoc "=type=" (bibtex-parse-entry)))))
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)))
301 (s-capitalize word)))
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))))
308 (setq title (mapconcat 'identity words " "))
310 ;; Capitalize letters after a dash
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))))
318 ;; this is defined in doi-utils
322 (bibtex-fill-entry))))
324 (add-hook 'org-ref-clean-bibtex-entry-hook 'jmax-title-case-article)
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."
333 (bibtex-beginning-of-entry)
335 (let* ((title (bibtex-autokey-get-field "title"))
336 (words (split-string title))
339 (string= "article" (downcase (cdr (assoc "=type=" (bibtex-parse-entry)))))
343 ;; match words containing {} or \ which are probably
344 ;; LaTeX or protected words
345 (string-match "\\$\\|{\\|}\\|\\\\" word)
350 ;; capitalize first word
351 (setf (car words) (s-capitalize (car words)))
354 (setq title (mapconcat 'identity words " "))
356 ;; capitalize a word after a :, eg. a subtitle, and protect it
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))))
365 ;; this is defined in doi-utils
369 ;; clean and refill entry so it looks nice
371 (bibtex-fill-entry))))
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."
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)))
386 (jmax-bibtex-next-entry))
388 ;; search forward for an entry
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)))
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."
399 (bibtex-beginning-of-entry)
401 (re-search-backward bibtex-entry-head nil t (and (numberp n) n))
402 (bibtex-beginning-of-entry)))
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))
410 ;; add to bibtex-mode-hook
411 (add-hook 'bibtex-mode-hook 'jmax-bibtex-mode-keys)
414 (defun jmax-bibtex-entry-doi ()
415 "Get doi from entry at point."
418 (bibtex-beginning-of-entry)
419 (reftex-get-bib-field "doi" (bibtex-parse-entry t))))
422 (defun jmax-bibtex-wos ()
423 "Open bibtex entry in Web Of Science if there is a DOI."
425 (doi-utils-wos (jmax-bibtex-entry-doi)))
428 (defun jmax-bibtex-wos-citing ()
429 "Open citing articles for bibtex entry in Web Of Science if there is a DOI."
431 (doi-utils-wos-citing (jmax-bibtex-entry-doi)))
434 (defun jmax-bibtex-wos-related ()
435 "Open related articles for bibtex entry in Web Of Science if there is a DOI."
437 (doi-utils-wos-related (jmax-bibtex-entry-doi)))
440 (defun jmax-bibtex-wos-citing ()
441 "Open citing articles for bibtex entry in Web Of Science if there is a DOI."
443 (doi-utils-wos-citing (jmax-bibtex-entry-doi)))
446 (defun jmax-bibtex-crossref ()
447 "Open the bibtex entry in Crossref by its doi."
449 (doi-utils-crossref (jmax-bibtex-entry-doi)))
452 (defun jmax-bibtex-google-scholar ()
453 "Open the bibtex entry at point in google-scholar by its doi."
455 (doi-utils-google-scholar (jmax-bibtex-entry-doi)))
458 (defun jmax-bibtex-pubmed ()
459 "Open the bibtex entry at point in Pubmed by its doi."
461 (doi-utils-pubmed (jmax-bibtex-entry-doi)))
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."
469 (org-ref-open-bibtex-pdf))
472 ;; hydra menu for actions on bibtex entries
473 (defhydra jmax-bibtex-hydra (:color blue)
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
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)
499 (org-ref-set-bibtex-keywords
500 (read-input "Keywords: "
501 (bibtex-autokey-get-field "keywords"))
503 ("u" org-ref-open-in-browser)
504 ("r" (lambda () (interactive)
505 (bibtex-beginning-of-entry)
507 (find-file (ido-completing-read
509 (f-entries "." (lambda (f) (f-ext? f "bib")))))
510 (goto-char (point-max))
514 ("e" email-bibtex-entry)
515 ("U" (doi-utils-update-bibtex-entry-from-doi (jmax-bibtex-entry-doi)))
517 ("f" jmax-bibtex-file/body "File functions")
518 ("a" jmax-replace-nonascii "Replace non-ascii"))
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))
527 (when jmax-bibtex-hydra-key-binding
528 (global-set-key jmax-bibtex-hydra-key-binding 'jmax-bibtex-hydra/body))
531 ;; A hydra for adding new bibtex entries.
532 (defhydra jmax-bibtex-new-entry (:color blue)
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")
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"))
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.")
565 (setq jmax-bibtex-menu-funcs
566 '(("p" "df" jmax-bibtex-pdf)
567 ("C" "opy" (lambda (doi)
568 (kill-new (org-ref-bib-citation))
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)))
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
583 ;; construct menu string as a message
588 (concat "[" (elt tup 0) "]"
590 jmax-bibtex-menu-funcs "") ": "))
591 (let* ((input (read-char-exclusive))
593 (char-to-string input) jmax-bibtex-menu-funcs)))
599 (jmax-bibtex-entry-doi)
602 (defalias 'jb 'jmax-bibtex)
604 (provide 'jmax-bibtex)
606 ;;; jmax-bibtex.el ends here