Klimi's new dotfiles with stow.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

1507 lignes
69 KiB

il y a 4 ans
  1. ;;; bibtex-completion.el --- A BibTeX backend for completion frameworks
  2. ;; Author: Titus von der Malsburg <malsburg@posteo.de>
  3. ;; Justin Burkett <justin@burkett.cc>
  4. ;; Maintainer: Titus von der Malsburg <malsburg@posteo.de>
  5. ;; Version: 1.0.0
  6. ;; Package-Requires: ((parsebib "1.0") (s "1.9.0") (dash "2.6.0") (f "0.16.2") (cl-lib "0.5"))
  7. ;; This program is free software; you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; This program is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; A BibTeX backend for completion frameworks
  19. ;; There are currently two fronends: helm-bibtex and ivy-bibtex.
  20. ;;
  21. ;; See the github page for details:
  22. ;;
  23. ;; https://github.com/tmalsburg/helm-bibtex
  24. ;;; Code:
  25. (require 'browse-url)
  26. (require 'parsebib)
  27. (require 'cl-lib)
  28. (require 'dash)
  29. (require 's)
  30. (require 'f)
  31. (require 'biblio)
  32. (require 'filenotify)
  33. ;; Silence byte-compiler
  34. (declare-function reftex-what-macro "reftex-parse")
  35. (declare-function reftex-get-bibfile-list "reftex-cite")
  36. (declare-function outline-show-all "outline")
  37. (declare-function org-narrow-to-subtree "org")
  38. (declare-function org-cycle-hide-drawers "org")
  39. (declare-function org-find-property "org")
  40. (declare-function org-show-entry "org")
  41. (declare-function org-entry-get "org")
  42. (declare-function org-element-parse-buffer "org-element")
  43. (declare-function org-element-map "org-element")
  44. (declare-function org-element-property "org-element")
  45. (defgroup bibtex-completion nil
  46. "Helm plugin for searching entries in a BibTeX bibliography."
  47. :group 'completion)
  48. (defcustom bibtex-completion-bibliography nil
  49. "The BibTeX file or list of BibTeX files. Org-bibtex users can
  50. also specify org-mode bibliography files, in which case it will
  51. be assumed that a BibTeX file exists with the same name and
  52. extension bib instead of org. If the bib file has a different
  53. name, use a cons cell (\"orgfile.org\" . \"bibfile.bib\") instead."
  54. :group 'bibtex-completion
  55. :type '(choice file (repeat file)))
  56. (defcustom bibtex-completion-library-path nil
  57. "A directory or list of directories in which PDFs are stored.
  58. Bibtex-completion assumes that the names of these PDFs are
  59. composed of the BibTeX-key plus a \".pdf\" suffix."
  60. :group 'bibtex-completion
  61. :type '(choice directory (repeat directory)))
  62. (defcustom bibtex-completion-pdf-open-function 'find-file
  63. "The function used for opening PDF files. This can be an
  64. arbitrary function that takes one argument: the path to the PDF
  65. file. The default is `find-file' which opens the PDF in
  66. Emacs (either with docview or, if installed, the much superior
  67. pdf-tools. When set to `helm-open-file-with-default-tool', the
  68. systems default viewer for PDFs is used."
  69. :group 'bibtex-completion
  70. :type 'function)
  71. (defcustom bibtex-completion-pdf-extension ".pdf"
  72. "The extension of a BibTeX entry's \"PDF\" file. This makes it
  73. possible to use another file type. It can also be a list of
  74. file types, which are then tried sequentially until a file is
  75. found. Beware that adding file types can reduce performance for
  76. large bibliographies. This variable has no effect if PDFs are
  77. referenced via the file field."
  78. :group 'bibtex-completion
  79. :type 'string)
  80. (defcustom bibtex-completion-find-additional-pdfs nil
  81. "If non-nil, all files whose base name starts with the BibTeX
  82. key and ends with `bibtex-completion-pdf-extension' are
  83. considered as PDFs, not only \"<key>.<extension>\". Note that
  84. for performance reasons, an entry is only marked as having a
  85. PDF if \"<key>.<extension\" exists."
  86. :group 'bibtex-completion
  87. :type 'boolean)
  88. (defcustom bibtex-completion-pdf-symbol ""
  89. "Symbol used to indicate that a PDF file is available for a
  90. publication. This should be a single character."
  91. :group 'bibtex-completion
  92. :type 'string)
  93. (defcustom bibtex-completion-format-citation-functions
  94. '((org-mode . bibtex-completion-format-citation-ebib)
  95. (latex-mode . bibtex-completion-format-citation-cite)
  96. (markdown-mode . bibtex-completion-format-citation-pandoc-citeproc)
  97. (default . bibtex-completion-format-citation-default))
  98. "The functions used for formatting citations. The publication
  99. can be cited, for example, as \cite{key} or ebib:key depending on
  100. the major mode of the current buffer. Note that the functions
  101. should accept a list of keys as input. With multiple marked
  102. entries one can insert multiple keys at once,
  103. e.g. \cite{key1,key2}. See the functions
  104. `bibtex-completion-format-citation-ebib' and
  105. `bibtex-completion-format-citation-cite' as examples."
  106. :group 'bibtex-completion
  107. :type '(alist :key-type symbol :value-type function))
  108. (defcustom bibtex-completion-notes-path nil
  109. "The place where notes are stored. This is either a file, in
  110. which case all notes are stored in that file, or a directory, in
  111. which case each publication gets its own notes file in that
  112. directory. In the latter case, bibtex-completion assumes that the
  113. names of the note files are composed of the BibTeX-key plus a
  114. suffix that is specified in `bibtex-completion-notes-extension'."
  115. :group 'bibtex-completion
  116. :type '(choice file directory (const nil)))
  117. (defcustom bibtex-completion-notes-template-multiple-files
  118. "#+TITLE: Notes on: ${author-or-editor} (${year}): ${title}\n\n"
  119. "Template used to create a new note when each note is stored in a
  120. separate file. '${field-name}' can be used to insert the value of a
  121. BibTeX field into the template. Apart from the fields defined in the
  122. entry, one can also use the virtual fields `author-or-editor` -- which
  123. contains the author names if defined and otherwise the names of the
  124. editors -- and `author-abbrev` -- which abbreviates to 'First author
  125. et al.' when there are three or more authors."
  126. :group 'bibtex-completion
  127. :type 'string)
  128. (defcustom bibtex-completion-notes-template-one-file
  129. "\n* ${author-or-editor} (${year}): ${title}\n :PROPERTIES:\n :Custom_ID: ${=key=}\n :END:\n\n"
  130. "Template used to create a new note when all notes are stored
  131. in one file. '${field-name}' can be used to insert the value of
  132. a BibTeX field into the template. Apart from the fields defined in
  133. the entry, one can also use the virtual field `author-or-editor` -- which
  134. contains the author names if defined and otherwise the names of the
  135. editors -- and `author-abbrev` -- which abbreviates to 'First author
  136. et al.' when there are three or more authors."
  137. :group 'bibtex-completion
  138. :type 'string)
  139. (defcustom bibtex-completion-notes-key-pattern
  140. ":Custom_ID: +%s\\( \\|$\\)"
  141. "The pattern used to find entries in the notes file. Only
  142. relevant when all notes are stored in one file. The key can be
  143. inserted into the pattern using the `format` function."
  144. :group 'bibtex-completion
  145. :type 'string)
  146. (defcustom bibtex-completion-notes-extension ".org"
  147. "The extension of the files containing notes. This is only
  148. used when `bibtex-completion-notes-path' is a directory (not a file)."
  149. :group 'bibtex-completion
  150. :type 'string)
  151. (defcustom bibtex-completion-notes-symbol ""
  152. "Symbol used to indicate that a publication has notes. This
  153. should be a single character."
  154. :group 'bibtex-completion
  155. :type 'string)
  156. (defcustom bibtex-completion-fallback-options
  157. '(("CrossRef (biblio.el)"
  158. . (lambda (search-expression) (biblio-lookup #'biblio-crossref-backend search-expression)))
  159. ("arXiv (biblio.el)"
  160. . (lambda (search-expression) (biblio-lookup #'biblio-arxiv-backend search-expression)))
  161. ("DBLP (computer science bibliography) (biblio.el)"
  162. . (lambda (search-expression) (biblio--lookup-1 #'biblio-dblp-backend search-expression)))
  163. ("HAL (French open archive) (biblio.el)"
  164. . (lambda (search-expression) (biblio--lookup-1 #'biblio-hal-backend search-expression)))
  165. ("IEEE (biblio.el)"
  166. . (lambda (search-expression) (biblio--lookup-1 #'biblio-ieee-backend search-expression)))
  167. ("Google Scholar (web)"
  168. . "https://scholar.google.co.uk/scholar?q=%s")
  169. ("Pubmed (web)"
  170. . "https://www.ncbi.nlm.nih.gov/pubmed/?term=%s")
  171. ("Bodleian Library (web)"
  172. . "http://solo.bodleian.ox.ac.uk/primo_library/libweb/action/search.do?vl(freeText0)=%s&fn=search&tab=all")
  173. ("Library of Congress (web)"
  174. . "https://www.loc.gov/search/?q=%s&all=true&st=list")
  175. ("Deutsche Nationalbibliothek (web)"
  176. . "https://portal.dnb.de/opac.htm?query=%s")
  177. ("British National Library (web)"
  178. . "http://explore.bl.uk/primo_library/libweb/action/search.do?&vl(freeText0)=%s&fn=search")
  179. ("Bibliothèque nationale de France (web)"
  180. . "http://catalogue.bnf.fr/servlet/RechercheEquation?host=catalogue?historique1=Recherche+par+mots+de+la+notice&niveau1=1&url1=/jsp/recherchemots_simple.jsp?host=catalogue&maxNiveau=1&categorieRecherche=RechercheMotsSimple&NomPageJSP=/jsp/recherchemots_simple.jsp?host=catalogue&RechercheMotsSimpleAsauvegarder=0&ecranRechercheMot=/jsp/recherchemots_simple.jsp&resultatsParPage=20&x=40&y=22&nbElementsHDJ=6&nbElementsRDJ=7&nbElementsRCL=12&FondsNumerise=M&CollectionHautdejardin=TVXZROM&HDJ_DAV=R&HDJ_D2=V&HDJ_D1=T&HDJ_D3=X&HDJ_D4=Z&HDJ_SRB=O&CollectionRezdejardin=UWY1SPQM&RDJ_DAV=S&RDJ_D2=W&RDJ_D1=U&RDJ_D3=Y&RDJ_D4=1&RDJ_SRB=P&RDJ_RLR=Q&RICHELIEU_AUTRE=ABCDEEGIKLJ&RCL_D1=A&RCL_D2=K&RCL_D3=D&RCL_D4=E&RCL_D5=E&RCL_D6=C&RCL_D7=B&RCL_D8=J&RCL_D9=G&RCL_D10=I&RCL_D11=L&ARSENAL=H&LivrePeriodique=IP&partitions=C&images_fixes=F&son=S&images_animees=N&Disquette_cederoms=E&multimedia=M&cartes_plans=D&manuscrits=BT&monnaies_medailles_objets=JO&salle_spectacle=V&Monographie_TN=M&Periodique_TN=S&Recueil_TN=R&CollectionEditorial_TN=C&Ensemble_TN=E&Spectacle_TN=A&NoticeB=%s")
  181. ("Gallica Bibliothèque Numérique (web)"
  182. . "http://gallica.bnf.fr/Search?q=%s"))
  183. "Alist of online sources that can be used to search for
  184. publications. The key of each entry is the name of the online
  185. source. The value is the URL used for retrieving results. This
  186. URL must contain a %s in the position where the search term
  187. should be inserted. Alternatively, the value can be a function
  188. that will be called when the entry is selected."
  189. :group 'bibtex-completion
  190. :type '(alist :key-type string
  191. :value-type (choice (string :tag "URL")
  192. (function :tag "Function"))))
  193. (defcustom bibtex-completion-browser-function nil
  194. "The browser that is used to access online resources. If
  195. nil (default), the value of `browse-url-browser-function' is
  196. used. If that value is nil, Helm uses the first available
  197. browser in `helm-browse-url-default-browser-alist'"
  198. :group 'bibtex-completion
  199. :type '(choice
  200. (const :tag "Default" :value nil)
  201. (function-item :tag "Emacs interface to w3m" :value w3m-browse-url)
  202. (function-item :tag "Emacs W3" :value browse-url-w3)
  203. (function-item :tag "W3 in another Emacs via `gnudoit'"
  204. :value browse-url-w3-gnudoit)
  205. (function-item :tag "Mozilla" :value browse-url-mozilla)
  206. (function-item :tag "Firefox" :value browse-url-firefox)
  207. (function-item :tag "Chromium" :value browse-url-chromium)
  208. (function-item :tag "Galeon" :value browse-url-galeon)
  209. (function-item :tag "Epiphany" :value browse-url-epiphany)
  210. (function-item :tag "Netscape" :value browse-url-netscape)
  211. (function-item :tag "eww" :value eww-browse-url)
  212. (function-item :tag "Mosaic" :value browse-url-mosaic)
  213. (function-item :tag "Mosaic using CCI" :value browse-url-cci)
  214. (function-item :tag "Text browser in an xterm window"
  215. :value browse-url-text-xterm)
  216. (function-item :tag "Text browser in an Emacs window"
  217. :value browse-url-text-emacs)
  218. (function-item :tag "KDE" :value browse-url-kde)
  219. (function-item :tag "Elinks" :value browse-url-elinks)
  220. (function-item :tag "Specified by `Browse Url Generic Program'"
  221. :value browse-url-generic)
  222. (function-item :tag "Default Windows browser"
  223. :value browse-url-default-windows-browser)
  224. (function-item :tag "Default Mac OS X browser"
  225. :value browse-url-default-macosx-browser)
  226. (function-item :tag "GNOME invoking Mozilla"
  227. :value browse-url-gnome-moz)
  228. (function-item :tag "Default browser"
  229. :value browse-url-default-browser)
  230. (function :tag "Your own function")
  231. (alist :tag "Regexp/function association list"
  232. :key-type regexp :value-type function)))
  233. (defcustom bibtex-completion-additional-search-fields nil
  234. "The fields that are used for searching in addition to author,
  235. editor, title, year, BibTeX key, and entry type."
  236. :group 'bibtex-completion
  237. :type '(repeat string))
  238. (defcustom bibtex-completion-no-export-fields nil
  239. "A list of fields that should be ignored when exporting BibTeX
  240. entries."
  241. :group 'bibtex-completion
  242. :type '(repeat string))
  243. (defcustom bibtex-completion-cite-commands '("cite" "Cite" "parencite"
  244. "Parencite" "footcite" "footcitetext" "textcite" "Textcite"
  245. "smartcite" "Smartcite" "cite*" "parencite*" "supercite" "autocite"
  246. "Autocite" "autocite*" "Autocite*" "citeauthor" "Citeauthor"
  247. "citeauthor*" "Citeauthor*" "citetitle" "citetitle*" "citeyear"
  248. "citeyear*" "citedate" "citedate*" "citeurl" "nocite" "fullcite"
  249. "footfullcite" "notecite" "Notecite" "pnotecite" "Pnotecite"
  250. "fnotecite")
  251. "The list of LaTeX cite commands. When creating LaTeX
  252. citations, these can be accessed as future entries in the
  253. minibuffer history, i.e. by pressing the arrow down key. The
  254. default entries are taken from biblatex. There is currently no
  255. special support for multicite commands and volcite et al. These
  256. commands can be used but bibtex-completion does not prompt for their
  257. extra arguments."
  258. :group 'bibtex-completion
  259. :type '(choice string (repeat string)))
  260. (defcustom bibtex-completion-cite-default-command "cite"
  261. "The LaTeX cite command that is used if the user doesn't enter
  262. anything when prompted for such a command."
  263. :group 'bibtex-completion
  264. :type 'string)
  265. (defcustom bibtex-completion-cite-prompt-for-optional-arguments t
  266. "If t, bibtex-completion prompts for pre- and postnotes for
  267. LaTeX cite commands. Choose nil for no prompts."
  268. :group 'bibtex-completion
  269. :type 'boolean)
  270. (defcustom bibtex-completion-cite-default-as-initial-input nil
  271. "This variable controls how the default command defined in
  272. `bibtex-completion-cite-default-command' is used. If t, it is inserted
  273. into the minibuffer before reading input from the user. If nil,
  274. it is used as the default if the user doesn't enter anything."
  275. :group 'bibtex-completion
  276. :type 'boolean)
  277. (defcustom bibtex-completion-pdf-field nil
  278. "The name of the BibTeX field in which the path to PDF files is
  279. stored or nil if no such field should be used. If an entry has
  280. no value for this field, or if the specified file does not exist,
  281. or if this variable is nil, bibtex-completion will look up the PDF in
  282. the directories listed in `bibtex-completion-library-path'."
  283. :group 'bibtex-completion
  284. :type 'string)
  285. (defcustom bibtex-completion-display-formats
  286. '((t . "${author:36} ${title:*} ${year:4} ${=has-pdf=:1}${=has-note=:1} ${=type=:7}"))
  287. "Alist of format strings for displaying entries in the results list.
  288. The key of each element of this list is either a BibTeX entry
  289. type (in which case the format string applies to entries of this
  290. type only) or t (in which case the format string applies to all
  291. other entry types). The value is the format string.
  292. In the format string, expressions like \"${author:36}\",
  293. \"${title:*}\", etc, are expanded to the value of the
  294. corresponding field. An expression like \"${author:N}\" is
  295. truncated to a width of N characters, whereas an expression like
  296. \"${title:*}\" is truncated to the remaining width in the results
  297. window. Three special fields are available: \"=type=\" holds the
  298. BibTeX entry type, \"=has-pdf=\" holds
  299. `bibtex-completion-pdf-symbol' if the entry has a PDF file, and
  300. \"=has-notes=\" holds `bibtex-completion-notes-symbol' if the
  301. entry has a notes file. The \"author\" field is expanded to
  302. either the author names or, if the entry has no author field, the
  303. editor names."
  304. :group 'bibtex-completion
  305. :type '(alist :key-type symbol :value-type string))
  306. (defvar bibtex-completion-cross-referenced-entry-types
  307. '("proceedings" "mvproceedings" "book" "mvbook" "collection" "mvcollection")
  308. "The list of potentially cross-referenced entry types (in
  309. lowercase). Only entries of these types are checked in
  310. order to resolve cross-references. The default list is usually
  311. sufficient; adding more types can slow down resolution for
  312. large biblioraphies.")
  313. (defvar bibtex-completion-display-formats-internal nil
  314. "Stores `bibtex-completion-display-formats' together with the
  315. \"used width\" of each format string. This is set internally.")
  316. (defvar bibtex-completion-cache nil
  317. "A cache storing the hash of the bibliography content and the
  318. corresponding list of entries, for each bibliography file,
  319. obtained when the bibliography was last parsed. When the
  320. current bibliography hash is identical to the cached hash, the
  321. cached list of candidates is reused, otherwise the bibliography
  322. file is reparsed.")
  323. (defvar bibtex-completion-string-cache nil
  324. "A cache storing bibtex strings, for each bibliography file, obtained when the bibliography was last parsed.")
  325. (defvar bibtex-completion-string-hash-table nil
  326. "A hash table used for string replacements.")
  327. (defun bibtex-completion-normalize-bibliography (&optional type)
  328. "Returns a list of bibliography file(s) in
  329. `bibtex-completion-bibliography'. If there are org-mode
  330. bibliography-files, their corresponding bibtex files are listed
  331. as well, unless TYPE is 'main. If TYPE is 'bibtex, org-mode
  332. bibliography-files are instead replaced with their associated
  333. bibtex files."
  334. (delete-dups
  335. (cl-loop
  336. for bib-file in (-flatten (list bibtex-completion-bibliography))
  337. for main-file = (if (consp bib-file)
  338. (car bib-file)
  339. bib-file)
  340. for bibtex-file = (if (consp bib-file)
  341. (cdr bib-file)
  342. (concat (file-name-sans-extension main-file) ".bib"))
  343. unless (equal type 'bibtex)
  344. collect main-file
  345. unless (equal type 'main)
  346. collect bibtex-file)))
  347. (defvar bibtex-completion-file-watch-descriptors nil
  348. "List of file watches monitoring bibliography files for changes.")
  349. (defun bibtex-completion-init ()
  350. "Checks that the files and directories specified by the user
  351. actually exist. Also sets `bibtex-completion-display-formats-internal'."
  352. ;; Remove current watch-descriptors for bibliography files:
  353. (mapc (lambda (watch-descriptor)
  354. (file-notify-rm-watch watch-descriptor))
  355. bibtex-completion-file-watch-descriptors)
  356. (setq bibtex-completion-file-watch-descriptors nil)
  357. ;; Check that all specified bibliography files exist and add file
  358. ;; watches for automatic reloading of the bibliography when a file
  359. ;; is changed:
  360. (mapc (lambda (file)
  361. (if (f-file? file)
  362. (let ((watch-descriptor
  363. (file-notify-add-watch file
  364. '(change)
  365. (lambda (event) (bibtex-completion-candidates)))))
  366. (setq bibtex-completion-file-watch-descriptors
  367. (cons watch-descriptor bibtex-completion-file-watch-descriptors)))
  368. (user-error "Bibliography file %s could not be found." file)))
  369. (bibtex-completion-normalize-bibliography))
  370. ;; Pre-calculate minimal widths needed by the format strings for
  371. ;; various entry types:
  372. (setq bibtex-completion-display-formats-internal
  373. (mapcar (lambda (format)
  374. (let* ((format-string (cdr format))
  375. (fields-width 0)
  376. (string-width
  377. (length
  378. (s-format format-string
  379. (lambda (field)
  380. (setq fields-width
  381. (+ fields-width
  382. (string-to-number
  383. (or (cadr (split-string field ":"))
  384. ""))))
  385. "")))))
  386. (-cons* (car format) format-string (+ fields-width string-width))))
  387. bibtex-completion-display-formats)))
  388. (defun bibtex-completion-clear-cache (&optional files)
  389. "Clears FILES from cache. If FILES is omitted, all files in `bibtex-completion-biblography' are cleared."
  390. (setq bibtex-completion-cache
  391. (cl-remove-if
  392. (lambda (x)
  393. (member (car x)
  394. (or files
  395. (bibtex-completion-normalize-bibliography 'bibtex))))
  396. bibtex-completion-cache)))
  397. (defun bibtex-completion-clear-string-cache (&optional files)
  398. "Clears FILES from cache. If FILES is omitted, all files in `bibtex-completion-bibliography' are cleared."
  399. (setq bibtex-completion-string-cache
  400. (cl-remove-if
  401. (lambda (x)
  402. (member (car x)
  403. (or files
  404. (-flatten (list bibtex-completion-bibliography)))))
  405. bibtex-completion-string-cache)))
  406. (defun bibtex-completion-parse-strings (&optional ht-strings)
  407. "Parse the BibTeX strings listed in the current buffer and
  408. return a list of entries in the order in which they appeared in
  409. the BibTeX file.
  410. If HT-STRINGS is provided it is assumed to be a hash table used
  411. for string replacement."
  412. (goto-char (point-min))
  413. (let ((strings (cl-loop
  414. with ht = (if ht-strings ht-strings (make-hash-table :test #'equal))
  415. for entry-type = (parsebib-find-next-item)
  416. while entry-type
  417. if (string= (downcase entry-type) "string")
  418. collect (let ((entry (parsebib-read-string (point) ht)))
  419. (puthash (car entry) (cdr entry) ht)
  420. entry)
  421. )))
  422. (-filter (lambda (x) x) strings)))
  423. (defun bibtex-completion-update-strings-ht (ht strings)
  424. (cl-loop
  425. for entry in strings
  426. do (puthash (car entry) (cdr entry) ht)))
  427. (defvar bibtex-completion-cached-notes-keys nil
  428. "A cache storing notes keys obtained when the bibliography was last parsed.")
  429. (defun bibtex-completion-candidates ()
  430. "Reads the BibTeX files and returns a list of conses, one for
  431. each entry. The first element of these conses is a string
  432. containing authors, editors, title, year, type, and key of the
  433. entry. This is string is used for matching. The second element
  434. is the entry (only the fields listed above) as an alist."
  435. (let ((files (nreverse (bibtex-completion-normalize-bibliography 'bibtex)))
  436. (ht-strings (make-hash-table :test #'equal))
  437. reparsed-files)
  438. ;; Open each bibliography file in a temporary buffer,
  439. ;; check hash of bibliography and mark for reparsing if necessary:
  440. (cl-loop
  441. for file in files
  442. do
  443. (with-temp-buffer
  444. (insert-file-contents file)
  445. (let ((bibliography-hash (secure-hash 'sha256 (current-buffer))))
  446. (unless (string= (cadr (assoc file bibtex-completion-cache))
  447. bibliography-hash)
  448. ;; Mark file as reparsed.
  449. ;; This will be useful to resolve cross-references:
  450. (push file reparsed-files)))))
  451. (when (and bibtex-completion-notes-path
  452. (f-file? bibtex-completion-notes-path))
  453. (require 'org-element)
  454. (with-temp-buffer
  455. (org-mode) ;; need this to avoid error in emacs 25.3.1
  456. (insert-file-contents bibtex-completion-notes-path)
  457. (setq bibtex-completion-cached-notes-keys
  458. (let ((tree (org-element-parse-buffer 'headline)))
  459. (org-element-map tree 'headline
  460. (lambda (key) (org-element-property :CUSTOM_ID key)))))))
  461. ;; reparse if necessary
  462. (when reparsed-files
  463. (cl-loop
  464. for file in files
  465. do
  466. (with-temp-buffer
  467. (insert-file-contents file)
  468. (let ((bibliography-hash (secure-hash 'sha256 (current-buffer))))
  469. (if (not (member file reparsed-files))
  470. (bibtex-completion-update-strings-ht ht-strings
  471. (cddr (assoc file bibtex-completion-string-cache)))
  472. (progn
  473. (message "Parsing bibliography file %s ..." file)
  474. (bibtex-completion-clear-string-cache (list file))
  475. (push (-cons* file
  476. bibliography-hash
  477. (bibtex-completion-parse-strings ht-strings))
  478. bibtex-completion-string-cache)
  479. (bibtex-completion-clear-cache (list file))
  480. (push (-cons* file
  481. bibliography-hash
  482. (bibtex-completion-parse-bibliography ht-strings))
  483. bibtex-completion-cache))))))
  484. (setf bibtex-completion-string-hash-table ht-strings))
  485. ;; If some files were reparsed, resolve cross-references:
  486. (when reparsed-files
  487. (message "Resolving cross-references ...")
  488. (bibtex-completion-resolve-crossrefs files reparsed-files))
  489. ;; Finally return the list of candidates:
  490. (message "Done (re)loading bibliography.")
  491. (nreverse
  492. (cl-loop
  493. for file in files
  494. append (cddr (assoc file bibtex-completion-cache))))))
  495. (defun bibtex-completion-resolve-crossrefs (files reparsed-files)
  496. "Expand all entries with fields from cross-referenced entries
  497. in FILES, assuming that only those files in REPARSED-FILES were
  498. reparsed whereas the other files in FILES were up-to-date."
  499. (cl-loop
  500. with entry-hash = (bibtex-completion-make-entry-hash files reparsed-files)
  501. for file in files
  502. for entries = (cddr (assoc file bibtex-completion-cache))
  503. if (member file reparsed-files)
  504. ;; The file was reparsed.
  505. ;; Resolve crossrefs then make candidates for all entries:
  506. do (setf
  507. (cddr (assoc file bibtex-completion-cache))
  508. (cl-loop
  509. for entry in entries
  510. ;; Entries are alists of \(FIELD . VALUE\) pairs.
  511. for crossref = (bibtex-completion-get-value "crossref" entry)
  512. collect (bibtex-completion-make-candidate
  513. (if crossref
  514. (bibtex-completion-remove-duplicated-fields
  515. ;; Insert an empty field so we can discard the crossref info if needed:
  516. (append entry
  517. (cl-acons "" ""
  518. (gethash (downcase crossref) entry-hash))))
  519. entry))))
  520. else
  521. ;; The file was not reparsed.
  522. ;; Resolve crossrefs then make candidates for the entries with a crossref field:
  523. do (setf
  524. (cddr (assoc file bibtex-completion-cache))
  525. (cl-loop
  526. for entry in entries
  527. ;; Entries are \(STRING . ALIST\) conses.
  528. for entry-alist = (cdr entry)
  529. for crossref = (bibtex-completion-get-value "crossref" entry-alist)
  530. collect (if crossref
  531. (bibtex-completion-make-candidate
  532. (bibtex-completion-remove-duplicated-fields
  533. ;; Discard crossref info and resolve crossref again:
  534. (append (--take-while (> (length (car it)) 0) entry-alist)
  535. (cl-acons "" ""
  536. (gethash (downcase crossref) entry-hash)))))
  537. entry)))))
  538. (defun bibtex-completion-make-entry-hash (files reparsed-files)
  539. "Return a hash table of all potentially cross-referenced bibliography entries in FILES,
  540. assuming that only those files in REPARSED-FILES were reparsed
  541. whereas the other files in FILES were up-to-date. Only entries
  542. whose type belongs to
  543. `bibtex-completion-cross-referenced-entry-types' are included in
  544. the hash table."
  545. (cl-loop
  546. with entries =
  547. (cl-loop
  548. for file in files
  549. for entries = (cddr (assoc file bibtex-completion-cache))
  550. if (member file reparsed-files)
  551. ;; Entries are alists of \(FIELD . VALUE\) pairs.
  552. append entries
  553. ;; Entries are \(STRING . ALIST\) conses.
  554. else
  555. append (mapcar 'cdr entries))
  556. with ht = (make-hash-table :test #'equal :size (length entries))
  557. for entry in entries
  558. for key = (bibtex-completion-get-value "=key=" entry)
  559. if (member (downcase (bibtex-completion-get-value "=type=" entry))
  560. bibtex-completion-cross-referenced-entry-types)
  561. do (puthash (downcase key) entry ht)
  562. finally return ht))
  563. (defun bibtex-completion-make-candidate (entry)
  564. "Return a candidate for ENTRY."
  565. (cons (bibtex-completion-clean-string
  566. (s-join " " (-map #'cdr entry)))
  567. entry))
  568. (defun bibtex-completion-parse-bibliography (&optional ht-strings)
  569. "Parse the BibTeX entries listed in the current buffer and
  570. return a list of entries in the order in which they appeared in
  571. the BibTeX file. Also do some preprocessing of the entries.
  572. If HT-STRINGS is provided it is assumed to be a hash table."
  573. (goto-char (point-min))
  574. (cl-loop
  575. with fields = (append '("title" "crossref")
  576. (-map (lambda (it) (if (symbolp it) (symbol-name it) it))
  577. bibtex-completion-additional-search-fields))
  578. for entry-type = (parsebib-find-next-item)
  579. while entry-type
  580. unless (member-ignore-case entry-type '("preamble" "string" "comment"))
  581. collect (let* ((entry (parsebib-read-entry entry-type (point) ht-strings))
  582. (fields (append
  583. (list (if (assoc-string "author" entry 'case-fold)
  584. "author"
  585. "editor")
  586. (if (assoc-string "date" entry 'case-fold)
  587. "date"
  588. "year"))
  589. fields)))
  590. (-map (lambda (it)
  591. (cons (downcase (car it)) (cdr it)))
  592. (bibtex-completion-prepare-entry entry fields)))))
  593. (defun bibtex-completion-get-entry (entry-key)
  594. "Given a BibTeX key this function scans all bibliographies
  595. listed in `bibtex-completion-bibliography' and returns an alist of the
  596. record with that key. Fields from crossreferenced entries are
  597. appended to the requested entry."
  598. (let* ((entry (bibtex-completion-get-entry1 entry-key))
  599. (crossref (bibtex-completion-get-value "crossref" entry))
  600. (crossref (when crossref (bibtex-completion-get-entry1 crossref))))
  601. (bibtex-completion-remove-duplicated-fields (append entry crossref))))
  602. (defun bibtex-completion-get-entry1 (entry-key &optional do-not-find-pdf)
  603. (let ((bib (bibtex-completion-normalize-bibliography 'bibtex)))
  604. (with-temp-buffer
  605. (mapc #'insert-file-contents bib)
  606. (goto-char (point-min))
  607. (if (re-search-forward (concat "^[ \t]*@\\(" parsebib--bibtex-identifier
  608. "\\)[[:space:]]*[\(\{][[:space:]]*"
  609. (regexp-quote entry-key) "[[:space:]]*,")
  610. nil t)
  611. (let ((entry-type (match-string 1)))
  612. (reverse (bibtex-completion-prepare-entry
  613. (parsebib-read-entry entry-type (point) bibtex-completion-string-hash-table) nil do-not-find-pdf)))
  614. (progn
  615. (display-warning :warning (concat "Bibtex-completion couldn't find entry with key \"" entry-key "\"."))
  616. nil)))))
  617. (defun bibtex-completion-find-pdf-in-field (key-or-entry)
  618. "Returns the path of the PDF specified in the field
  619. `bibtex-completion-pdf-field' if that file exists. Returns nil if no
  620. file is specified, or if the specified file does not exist, or if
  621. `bibtex-completion-pdf-field' is nil."
  622. (when bibtex-completion-pdf-field
  623. (let* ((entry (if (stringp key-or-entry)
  624. (bibtex-completion-get-entry1 key-or-entry t)
  625. key-or-entry))
  626. (value (bibtex-completion-get-value bibtex-completion-pdf-field entry)))
  627. (cond
  628. ((not value) nil) ; Field not defined.
  629. ((f-file? value) (list value)) ; A bare full path was found.
  630. ((-any 'f-file? (--map (f-join it (f-filename value)) (-flatten bibtex-completion-library-path))) (-filter 'f-file? (--map (f-join it (f-filename value)) (-flatten bibtex-completion-library-path))))
  631. (t ; Zotero/Mendeley/JabRef format:
  632. (let ((value (replace-regexp-in-string "\\([^\\]\\);" "\\1\^^" value)))
  633. (cl-loop ; Looping over the files:
  634. for record in (s-split "\^^" value)
  635. ; Replace unescaped colons by field separator:
  636. for record = (replace-regexp-in-string "\\([^\\]\\|^\\):" "\\1\^_" record)
  637. ; Unescape stuff:
  638. for record = (replace-regexp-in-string "\\\\\\(.\\)" "\\1" record)
  639. ; Now we can safely split:
  640. for record = (s-split "\^_" record)
  641. for file-name = (nth 0 record)
  642. for path = (or (nth 1 record) "")
  643. for paths = (if (s-match "^[A-Z]:" path)
  644. (list path) ; Absolute Windows path
  645. ; Something else:
  646. (append
  647. (list
  648. path
  649. file-name
  650. (f-join (f-root) path) ; Mendeley #105
  651. (f-join (f-root) path file-name)) ; Mendeley #105
  652. (--map (f-join it path)
  653. (-flatten bibtex-completion-library-path)) ; Jabref #100
  654. (--map (f-join it path file-name)
  655. (-flatten bibtex-completion-library-path)))) ; Jabref #100
  656. for result = (-first (lambda (path)
  657. (if (and (not (s-blank-str? path))
  658. (f-exists? path))
  659. path nil)) paths)
  660. if result collect result)))))))
  661. (defun bibtex-completion-find-pdf-in-library (key-or-entry &optional find-additional)
  662. "Searches the directories in `bibtex-completion-library-path'
  663. for a PDF whose name is composed of the BibTeX key plus
  664. `bibtex-completion-pdf-extension'. The path of the first matching
  665. PDF is returned.
  666. If FIND-ADDITIONAL is non-nil, the paths of all PDFs whose name
  667. starts with the BibTeX key and ends with
  668. `bibtex-completion-pdf-extension' are returned instead."
  669. (let* ((key (if (stringp key-or-entry)
  670. key-or-entry
  671. (bibtex-completion-get-value "=key=" key-or-entry)))
  672. (main-pdf (cl-loop
  673. for dir in (-flatten bibtex-completion-library-path)
  674. append (cl-loop
  675. for ext in (-flatten bibtex-completion-pdf-extension)
  676. collect (f-join dir (s-concat key ext))))))
  677. (if find-additional
  678. (sort ; move main pdf on top of the list if needed
  679. (cl-loop
  680. for dir in (-flatten bibtex-completion-library-path)
  681. append (directory-files dir t
  682. (s-concat "^" (regexp-quote key)
  683. ".*\\("
  684. (mapconcat 'regexp-quote
  685. (-flatten bibtex-completion-pdf-extension)
  686. "\\|")
  687. "\\)$")))
  688. (lambda (x y)
  689. (and (member x main-pdf)
  690. (not (member y main-pdf)))))
  691. (-flatten (-first 'f-file? main-pdf)))))
  692. (defun bibtex-completion-find-pdf (key-or-entry &optional find-additional)
  693. "Returns the path of the PDF associated with the specified
  694. entry. This is either the path(s) specified in the field
  695. `bibtex-completion-pdf-field' or, if that does not exist, the
  696. first PDF in any of the directories in
  697. `bibtex-completion-library-path' whose name is composed of the
  698. the BibTeX key plus `bibtex-completion-pdf-extension' (or if
  699. FIND-ADDITIONAL is non-nil, all PDFs in
  700. `bibtex-completion-library-path' whose name starts with the
  701. BibTeX key and ends with `bibtex-completion-pdf-extension').
  702. Returns nil if no PDF is found."
  703. (or (bibtex-completion-find-pdf-in-field key-or-entry)
  704. (bibtex-completion-find-pdf-in-library key-or-entry find-additional)))
  705. (defun bibtex-completion-prepare-entry (entry &optional fields do-not-find-pdf)
  706. "Prepare ENTRY for display.
  707. ENTRY is an alist representing an entry as returned by
  708. parsebib-read-entry. All the fields not in FIELDS are removed
  709. from ENTRY, with the exception of the \"=type=\" and \"=key=\"
  710. fields. If FIELDS is empty, all fields are kept. Also add a
  711. =has-pdf= and/or =has-note= field, if they exist for ENTRY. If
  712. DO-NOT-FIND-PDF is non-nil, this function does not attempt to
  713. find a PDF file."
  714. (when entry ; entry may be nil, in which case just return nil
  715. (let* ((fields (when fields (append fields (list "=type=" "=key=" "=has-pdf=" "=has-note="))))
  716. ; Check for PDF:
  717. (entry (if (and (not do-not-find-pdf) (bibtex-completion-find-pdf entry))
  718. (cons (cons "=has-pdf=" bibtex-completion-pdf-symbol) entry)
  719. entry))
  720. (entry-key (cdr (assoc "=key=" entry)))
  721. ; Check for notes:
  722. (entry (if (or
  723. ;; One note file per entry:
  724. (and bibtex-completion-notes-path
  725. (f-directory? bibtex-completion-notes-path)
  726. (f-file? (f-join bibtex-completion-notes-path
  727. (s-concat entry-key
  728. bibtex-completion-notes-extension))))
  729. ;; All notes in one file:
  730. (and bibtex-completion-notes-path
  731. (f-file? bibtex-completion-notes-path)
  732. (member entry-key bibtex-completion-cached-notes-keys)))
  733. (cons (cons "=has-note=" bibtex-completion-notes-symbol) entry)
  734. entry))
  735. ; Remove unwanted fields:
  736. (entry (if fields
  737. (--filter (member-ignore-case (car it) fields) entry)
  738. entry)))
  739. ;; Normalize case of entry type:
  740. (setcdr (assoc "=type=" entry) (downcase (cdr (assoc "=type=" entry))))
  741. ;; Remove duplicated fields:
  742. (bibtex-completion-remove-duplicated-fields entry))))
  743. (defun bibtex-completion-remove-duplicated-fields (entry)
  744. "Remove duplicated fields from ENTRY."
  745. (cl-remove-duplicates entry
  746. :test (lambda (x y) (string= (s-downcase x) (s-downcase y)))
  747. :key 'car :from-end t))
  748. (defun bibtex-completion-format-entry (entry width)
  749. "Formats a BibTeX ENTRY for display in results list. WIDTH is
  750. the width of the results list. The display format is governed by
  751. the variable `bibtex-completion-display-formats'."
  752. (let* ((format
  753. (or (assoc-string (bibtex-completion-get-value "=type=" entry)
  754. bibtex-completion-display-formats-internal
  755. 'case-fold)
  756. (assoc t bibtex-completion-display-formats-internal)))
  757. (format-string (cadr format)))
  758. (s-format
  759. format-string
  760. (lambda (field)
  761. (let* ((field (split-string field ":"))
  762. (field-name (car field))
  763. (field-width (cadr field))
  764. (field-value (bibtex-completion-get-value field-name entry)))
  765. (when (and (string= field-name "author")
  766. (not field-value))
  767. (setq field-value (bibtex-completion-get-value "editor" entry)))
  768. (when (and (string= field-name "year")
  769. (not field-value))
  770. (setq field-value (car (split-string (bibtex-completion-get-value "date" entry "") "-"))))
  771. (setq field-value (bibtex-completion-clean-string (or field-value " ")))
  772. (when (member field-name '("author" "editor"))
  773. (setq field-value (bibtex-completion-shorten-authors field-value)))
  774. (if (not field-width)
  775. field-value
  776. (setq field-width (string-to-number field-width))
  777. (truncate-string-to-width
  778. field-value
  779. (if (> field-width 0)
  780. field-width
  781. (- width (cddr format)))
  782. 0 ?\s)))))))
  783. (defun bibtex-completion-clean-string (s)
  784. "Removes quoting and superfluous white space from BibTeX field
  785. values."
  786. (if s (replace-regexp-in-string "[\n\t ]+" " "
  787. (replace-regexp-in-string "[\"{}]+" "" s))
  788. nil))
  789. (defun bibtex-completion-shorten-authors (authors)
  790. "Returns a comma-separated list of the surnames in authors."
  791. (if authors
  792. (cl-loop for a in (s-split " and " authors)
  793. for p = (s-split "," a t)
  794. for sep = "" then ", "
  795. concat sep
  796. if (eq 1 (length p))
  797. concat (-last-item (s-split " +" (car p) t))
  798. else
  799. concat (car p))
  800. nil))
  801. (defun bibtex-completion-open-pdf (keys &optional fallback-action)
  802. "Open the PDFs associated with the marked entries using the
  803. function specified in `bibtex-completion-pdf-open-function'.
  804. If multiple PDFs are found for an entry, ask for the one to
  805. open using `completion-read'. If FALLBACK-ACTION is non-nil, it is called in
  806. case no PDF is found."
  807. (dolist (key keys)
  808. (let ((pdf (bibtex-completion-find-pdf key bibtex-completion-find-additional-pdfs)))
  809. (cond
  810. ((> (length pdf) 1)
  811. (let* ((pdf (f-uniquify-alist pdf))
  812. (choice (completing-read "File to open: " (mapcar 'cdr pdf) nil t))
  813. (file (car (rassoc choice pdf))))
  814. (funcall bibtex-completion-pdf-open-function file)))
  815. (pdf
  816. (funcall bibtex-completion-pdf-open-function (car pdf)))
  817. (fallback-action
  818. (funcall fallback-action (list key)))
  819. (t
  820. (message "No PDF(s) found for this entry: %s"
  821. key))))))
  822. (defun bibtex-completion-open-url-or-doi (keys)
  823. "Open the associated URL or DOI in a browser."
  824. (dolist (key keys)
  825. (let* ((entry (bibtex-completion-get-entry key))
  826. (url (bibtex-completion-get-value "url" entry))
  827. (doi (bibtex-completion-get-value "doi" entry))
  828. (browse-url-browser-function
  829. (or bibtex-completion-browser-function
  830. browse-url-browser-function)))
  831. (if url
  832. (browse-url url)
  833. (if doi (browse-url
  834. (s-concat "http://dx.doi.org/" doi))
  835. (message "No URL or DOI found for this entry: %s"
  836. key))))))
  837. (defun bibtex-completion-open-any (keys)
  838. "Open the PDFs associated with the marked entries using the
  839. function specified in `bibtex-completion-pdf-open-function'.
  840. If multiple PDFs are found for an entry, ask for the one to
  841. open using `completion-read'. If no PDF is found, try to open a URL
  842. or DOI in the browser instead."
  843. (bibtex-completion-open-pdf keys 'bibtex-completion-open-url-or-doi))
  844. (defun bibtex-completion-format-citation-default (keys)
  845. "Default formatter for keys, separates multiple keys with commas."
  846. (s-join ", " keys))
  847. (defvar bibtex-completion-cite-command-history nil
  848. "History list for LaTeX citation commands.")
  849. (defun bibtex-completion-format-citation-cite (keys)
  850. "Formatter for LaTeX citation commands. Prompts for the command
  851. and for arguments if the commands can take any. If point is
  852. inside or just after a citation command, only adds KEYS to it."
  853. (let (macro)
  854. (cond
  855. ((and (require 'reftex-parse nil t)
  856. (setq macro (reftex-what-macro 1))
  857. (stringp (car macro))
  858. (string-match "\\`\\\\cite\\|cite\\'" (car macro)))
  859. ;; We are inside a cite macro. Insert key at point, with appropriate delimiters.
  860. (delete-horizontal-space)
  861. (concat (pcase (preceding-char)
  862. (?\{ "")
  863. (?, " ")
  864. (_ ", "))
  865. (s-join ", " keys)
  866. (if (member (following-char) '(?\} ?,))
  867. ""
  868. ", ")))
  869. ((and (equal (preceding-char) ?\})
  870. (require 'reftex-parse nil t)
  871. (save-excursion
  872. (forward-char -1)
  873. (setq macro (reftex-what-macro 1)))
  874. (stringp (car macro))
  875. (string-match "\\`\\\\cite\\|cite\\'" (car macro)))
  876. ;; We are right after a cite macro. Append key and leave point at the end.
  877. (delete-char -1)
  878. (delete-horizontal-space t)
  879. (concat (pcase (preceding-char)
  880. (?\{ "")
  881. (?, " ")
  882. (_ ", "))
  883. (s-join ", " keys)
  884. "}"))
  885. (t
  886. ;; We are not inside or right after a cite macro. Insert a full citation.
  887. (let* ((initial (when bibtex-completion-cite-default-as-initial-input
  888. bibtex-completion-cite-default-command))
  889. (default (unless bibtex-completion-cite-default-as-initial-input
  890. bibtex-completion-cite-default-command))
  891. (default-info (if default (format " (default \"%s\")" default) ""))
  892. (cite-command (completing-read
  893. (format "Cite command%s: " default-info)
  894. bibtex-completion-cite-commands nil nil initial
  895. 'bibtex-completion-cite-command-history default nil)))
  896. (if (member cite-command '("nocite" "supercite")) ; These don't want arguments.
  897. (format "\\%s{%s}" cite-command (s-join ", " keys))
  898. (let ((prenote (if bibtex-completion-cite-prompt-for-optional-arguments
  899. (read-from-minibuffer "Prenote: ")
  900. ""))
  901. (postnote (if bibtex-completion-cite-prompt-for-optional-arguments
  902. (read-from-minibuffer "Postnote: ")
  903. "")))
  904. (cond ((not (string= "" prenote))
  905. (format "\\%s[%s][%s]{%s}" cite-command prenote postnote (s-join ", " keys)))
  906. ((not (string= "" postnote))
  907. (format "\\%s[%s]{%s}" cite-command postnote (s-join ", " keys)))
  908. (t
  909. (format "\\%s{%s}" cite-command (s-join ", " keys)))))))))))
  910. (defun bibtex-completion-format-citation-pandoc-citeproc (keys)
  911. "Formatter for pandoc-citeproc citations."
  912. (let* ((prenote (if bibtex-completion-cite-prompt-for-optional-arguments (read-from-minibuffer "Prenote: ") ""))
  913. (postnote (if bibtex-completion-cite-prompt-for-optional-arguments (read-from-minibuffer "Postnote: ") ""))
  914. (prenote (if (string= "" prenote) "" (concat prenote " ")))
  915. (postnote (if (string= "" postnote) "" (concat ", " postnote))))
  916. (format "[%s%s%s]" prenote (s-join "; " (--map (concat "@" it) keys)) postnote)))
  917. (defun bibtex-completion-format-citation-ebib (keys)
  918. "Formatter for ebib references."
  919. (s-join ", "
  920. (--map (format "ebib:%s" it) keys)))
  921. (defun bibtex-completion-format-citation-org-link-to-PDF (keys)
  922. "Formatter for org-links to PDF. Uses first matching PDF if
  923. several are available. Entries for which no PDF is available are
  924. omitted."
  925. (s-join ", " (cl-loop
  926. for key in keys
  927. for pdfs = (bibtex-completion-find-pdf key bibtex-completion-find-additional-pdfs)
  928. append (--map (format "[[%s][%s]]" it key) pdfs))))
  929. (defun bibtex-completion-format-citation-org-apa-link-to-PDF (keys)
  930. "Formatter for org-links to PDF. Link text loosely follows APA
  931. format. Uses first matching PDF if several are available."
  932. (s-join ", " (cl-loop
  933. for key in keys
  934. for entry = (bibtex-completion-get-entry key)
  935. for author = (bibtex-completion-shorten-authors
  936. (or (bibtex-completion-get-value "author" entry)
  937. (bibtex-completion-get-value "editor" entry)))
  938. for year = (or (bibtex-completion-get-value "year" entry)
  939. (car (split-string (bibtex-completion-get-value "date" entry "") "-")))
  940. for pdf = (car (bibtex-completion-find-pdf key))
  941. if pdf
  942. collect (format "[[file:%s][%s (%s)]]" pdf author year)
  943. else
  944. collect (format "%s (%s)" author year))))
  945. ;; When you want to create a todo list about reading, I think using
  946. ;; PDF's title is more intuitive.
  947. (defun bibtex-completion-format-citation-org-title-link-to-PDF (keys)
  948. "Formatter for org-links to PDF. Link text follows file title format.
  949. Uses first matching PDF if several are available."
  950. (s-join ", " (cl-loop
  951. for key in keys
  952. for entry = (bibtex-completion-get-entry key)
  953. for title = (bibtex-completion-get-value "title" entry)
  954. for pdf = (or (car (bibtex-completion-find-pdf key))
  955. (bibtex-completion-get-value "url" entry))
  956. if pdf
  957. collect (format "[[file:%s][%s]]" pdf title)
  958. else
  959. collect (format "%s" title))))
  960. (defun bibtex-completion-insert-citation (keys)
  961. "Insert citation at point. The format depends on
  962. `bibtex-completion-format-citation-functions'."
  963. (let ((format-function
  964. (cdr (or (assoc major-mode bibtex-completion-format-citation-functions)
  965. (assoc 'default bibtex-completion-format-citation-functions)))))
  966. (insert
  967. (funcall format-function keys))))
  968. (defun bibtex-completion-insert-reference (keys)
  969. "Insert a reference for each selected entry."
  970. (let* ((refs (--map
  971. (s-word-wrap fill-column
  972. (concat "\n- " (bibtex-completion-apa-format-reference it)))
  973. keys)))
  974. (insert "\n" (s-join "\n" refs) "\n")))
  975. (defun bibtex-completion-apa-format-reference (key)
  976. "Returns a plain text reference in APA format for the
  977. publication specified by KEY."
  978. (let*
  979. ((entry (bibtex-completion-get-entry key))
  980. (ref (pcase (downcase (bibtex-completion-get-value "=type=" entry))
  981. ("article"
  982. (s-format
  983. "${author} (${year}). ${title}. ${journal}, ${volume}(${number}), ${pages}.${doi}"
  984. 'bibtex-completion-apa-get-value entry))
  985. ("inproceedings"
  986. (s-format
  987. "${author} (${year}). ${title}. In ${editor}, ${booktitle} (pp. ${pages}). ${address}: ${publisher}."
  988. 'bibtex-completion-apa-get-value entry))
  989. ("book"
  990. (s-format
  991. "${author} (${year}). ${title}. ${address}: ${publisher}."
  992. 'bibtex-completion-apa-get-value entry))
  993. ("phdthesis"
  994. (s-format
  995. "${author} (${year}). ${title} (Doctoral dissertation). ${school}, ${address}."
  996. 'bibtex-completion-apa-get-value entry))
  997. ("inbook"
  998. (s-format
  999. "${author} (${year}). ${title}. In ${editor} (Eds.), ${booktitle} (pp. ${pages}). ${address}: ${publisher}."
  1000. 'bibtex-completion-apa-get-value entry))
  1001. ("incollection"
  1002. (s-format
  1003. "${author} (${year}). ${title}. In ${editor} (Eds.), ${booktitle} (pp. ${pages}). ${address}: ${publisher}."
  1004. 'bibtex-completion-apa-get-value entry))
  1005. ("proceedings"
  1006. (s-format
  1007. "${editor} (Eds.). (${year}). ${booktitle}. ${address}: ${publisher}."
  1008. 'bibtex-completion-apa-get-value entry))
  1009. ("unpublished"
  1010. (s-format
  1011. "${author} (${year}). ${title}. Unpublished manuscript."
  1012. 'bibtex-completion-apa-get-value entry))
  1013. (_
  1014. (s-format
  1015. "${author} (${year}). ${title}."
  1016. 'bibtex-completion-apa-get-value entry)))))
  1017. (replace-regexp-in-string "\\([.?!]\\)\\." "\\1" ref))) ; Avoid sequences of punctuation marks.
  1018. (defun bibtex-completion-apa-get-value (field entry &optional default)
  1019. "Return FIELD or ENTRY formatted following the APA
  1020. guidelines. Return DEFAULT if FIELD is not present in ENTRY."
  1021. ;; Virtual fields:
  1022. (cond
  1023. ((string= field "author-or-editor")
  1024. (let ((value (bibtex-completion-get-value "author" entry)))
  1025. (if value
  1026. (bibtex-completion-apa-format-authors value)
  1027. (bibtex-completion-apa-format-editors
  1028. (bibtex-completion-get-value "editor" entry)))))
  1029. ((string= field "author-abbrev")
  1030. (let ((value (bibtex-completion-get-value "author" entry)))
  1031. (bibtex-completion-apa-format-authors-abbrev value)))
  1032. (t
  1033. ;; Real fields:
  1034. (let ((value (bibtex-completion-get-value field entry)))
  1035. (if value
  1036. (pcase field
  1037. ;; https://owl.english.purdue.edu/owl/resource/560/06/
  1038. ("author" (bibtex-completion-apa-format-authors value))
  1039. ("editor" (bibtex-completion-apa-format-editors value))
  1040. ;; When referring to books, chapters, articles, or Web pages,
  1041. ;; capitalize only the first letter of the first word of a
  1042. ;; title and subtitle, the first word after a colon or a dash
  1043. ;; in the title, and proper nouns. Do not capitalize the first
  1044. ;; letter of the second word in a hyphenated compound word.
  1045. ("title" (replace-regexp-in-string ; remove braces
  1046. "[{}]"
  1047. ""
  1048. (replace-regexp-in-string ; remove macros
  1049. "\\\\[[:alpha:]]+{"
  1050. ""
  1051. (replace-regexp-in-string ; upcase initial letter
  1052. "^[[:alpha:]]"
  1053. 'upcase
  1054. (replace-regexp-in-string ; preserve stuff in braces from being downcased
  1055. "\\(^[^{]*{\\)\\|\\(}[^{]*{\\)\\|\\(}.*$\\)\\|\\(^[^{}]*$\\)"
  1056. (lambda (x) (downcase (s-replace "\\" "\\\\" x)))
  1057. value)))))
  1058. ("booktitle" value)
  1059. ;; Maintain the punctuation and capitalization that is used by
  1060. ;; the journal in its title.
  1061. ("pages" (s-join "" (s-split "[^0-9]+" value t)))
  1062. ("doi" (s-concat " http://dx.doi.org/" value))
  1063. ("year" (or value
  1064. (car (split-string (bibtex-completion-get-value "date" entry "") "-"))))
  1065. (_ value))
  1066. "")))))
  1067. (defun bibtex-completion-apa-format-authors (value)
  1068. (cl-loop for a in (s-split " and " value t)
  1069. if (s-index-of "{" a)
  1070. collect
  1071. (replace-regexp-in-string "[{}]" "" a)
  1072. into authors
  1073. else if (s-index-of "," a)
  1074. collect
  1075. (let ((p (s-split " *, *" a t)))
  1076. (concat
  1077. (car p) ", "
  1078. (s-join " " (-map (lambda (it) (concat (s-left 1 it) "."))
  1079. (s-split " " (cadr p))))))
  1080. into authors
  1081. else
  1082. collect
  1083. (let ((p (s-split " " a t)))
  1084. (concat
  1085. (-last-item p) ", "
  1086. (s-join " " (-map (lambda (it) (concat (s-left 1 it) "."))
  1087. (-butlast p)))))
  1088. into authors
  1089. finally return
  1090. (let ((l (length authors)))
  1091. (cond
  1092. ((= l 1) (car authors))
  1093. ((< l 8) (concat (s-join ", " (-butlast authors))
  1094. ", & " (-last-item authors)))
  1095. (t (concat (s-join ", " (-slice authors 0 7)) ", …"))))))
  1096. (defun bibtex-completion-apa-format-authors-abbrev (value)
  1097. (cl-loop for a in (s-split " and " value t)
  1098. if (s-index-of "{" a)
  1099. collect
  1100. (replace-regexp-in-string "[{}]" "" a)
  1101. into authors
  1102. else if (s-index-of "," a)
  1103. collect
  1104. (let ((p (s-split " *, *" a t)))
  1105. (concat
  1106. (car p) ", "
  1107. (s-join " " (-map (lambda (it) (concat (s-left 1 it) "."))
  1108. (s-split " " (cadr p))))))
  1109. into authors
  1110. else
  1111. collect
  1112. (let ((p (s-split " " a t)))
  1113. (concat
  1114. (-last-item p) ", "
  1115. (s-join " " (-map (lambda (it) (concat (s-left 1 it) "."))
  1116. (-butlast p)))))
  1117. into authors
  1118. finally return
  1119. (let ((l (length authors)))
  1120. (cond
  1121. ((= l 1) (car authors))
  1122. ((= l 2) (concat (s-join " & " authors)))
  1123. (t (format "%s et al." (car authors)))))))
  1124. (defun bibtex-completion-apa-format-editors (value)
  1125. (cl-loop for a in (s-split " and " value t)
  1126. if (s-index-of "," a)
  1127. collect
  1128. (let ((p (s-split " *, *" a t)))
  1129. (concat
  1130. (s-join " " (-map (lambda (it) (concat (s-left 1 it) "."))
  1131. (s-split " " (cadr p))))
  1132. " " (car p)))
  1133. into authors
  1134. else
  1135. collect
  1136. (let ((p (s-split " " a t)))
  1137. (concat
  1138. (s-join " " (-map (lambda (it) (concat (s-left 1 it) "."))
  1139. (-butlast p)))
  1140. " " (-last-item p)))
  1141. into authors
  1142. finally return
  1143. (let ((l (length authors)))
  1144. (cond
  1145. ((= l 1) (car authors))
  1146. ((< l 8) (concat (s-join ", " (-butlast authors))
  1147. ", & " (-last-item authors)))
  1148. (t (concat (s-join ", " authors) ", ..."))))))
  1149. (defun bibtex-completion-get-value (field entry &optional default)
  1150. "Return the requested value or `default' if the value is not
  1151. defined. Surrounding curly braces are stripped."
  1152. (let ((value (cdr (assoc-string field entry 'case-fold))))
  1153. (if value
  1154. (replace-regexp-in-string
  1155. "\\(^[[:space:]]*[\"{][[:space:]]*\\)\\|\\([[:space:]]*[\"}][[:space:]]*$\\)"
  1156. ""
  1157. (s-collapse-whitespace value))
  1158. default)))
  1159. (defun bibtex-completion-insert-key (keys)
  1160. "Insert BibTeX key at point."
  1161. (insert
  1162. (funcall 'bibtex-completion-format-citation-default keys)))
  1163. (defun bibtex-completion-insert-bibtex (keys)
  1164. "Insert BibTeX key at point."
  1165. (insert (s-join "\n" (--map (bibtex-completion-make-bibtex it) keys))))
  1166. (defun bibtex-completion-make-bibtex (key)
  1167. (let* ((entry (bibtex-completion-get-entry key))
  1168. (entry-type (bibtex-completion-get-value "=type=" entry)))
  1169. (format "@%s{%s,\n%s}\n"
  1170. entry-type key
  1171. (cl-loop
  1172. for field in entry
  1173. for name = (car field)
  1174. for value = (cdr field)
  1175. unless (member name
  1176. (append (-map (lambda (it) (if (symbolp it) (symbol-name it) it))
  1177. bibtex-completion-no-export-fields)
  1178. '("=type=" "=key=" "=has-pdf=" "=has-note=" "crossref")))
  1179. concat
  1180. (format " %s = {%s},\n" name value)))))
  1181. (defun bibtex-completion-add-PDF-attachment (keys)
  1182. "Attach the PDFs of the selected entries where available."
  1183. (dolist (key keys)
  1184. (let ((pdf (bibtex-completion-find-pdf key bibtex-completion-find-additional-pdfs)))
  1185. (if pdf
  1186. (mapc 'mml-attach-file pdf)
  1187. (message "No PDF(s) found for this entry: %s"
  1188. key)))))
  1189. (define-minor-mode bibtex-completion-notes-mode
  1190. "Minor mode for managing notes."
  1191. :keymap (let ((map (make-sparse-keymap)))
  1192. (define-key map (kbd "C-c C-c") 'bibtex-completion-exit-notes-buffer)
  1193. (define-key map (kbd "C-c C-w") 'org-refile)
  1194. map)
  1195. (setq-local
  1196. header-line-format
  1197. (substitute-command-keys
  1198. " Finish \\[bibtex-completion-exit-notes-buffer], refile \\[org-refile]")))
  1199. ;; Define global minor mode. This is needed to the toggle minor mode.
  1200. (define-globalized-minor-mode bibtex-completion-notes-global-mode bibtex-completion-notes-mode bibtex-completion-notes-mode)
  1201. (defun bibtex-completion-exit-notes-buffer ()
  1202. "Exit notes buffer and delete its window.
  1203. This will also disable `bibtex-completion-notes-mode' and remove the header
  1204. line."
  1205. (interactive)
  1206. (widen)
  1207. (bibtex-completion-notes-global-mode -1)
  1208. (setq-local
  1209. header-line-format nil)
  1210. (save-buffer)
  1211. (let ((window (get-buffer-window (get-file-buffer bibtex-completion-notes-path))))
  1212. (if (and window (not (one-window-p window)))
  1213. (delete-window window)
  1214. (switch-to-buffer (other-buffer)))))
  1215. (defun bibtex-completion-edit-notes (keys)
  1216. "Open the notes associated with the selected entries using `find-file'."
  1217. (dolist (key keys)
  1218. (let* ((entry (bibtex-completion-get-entry key))
  1219. (year (or (bibtex-completion-get-value "year" entry)
  1220. (car (split-string (bibtex-completion-get-value "date" entry "") "-"))))
  1221. (entry (push (cons "year" year) entry)))
  1222. (if (and bibtex-completion-notes-path
  1223. (f-directory? bibtex-completion-notes-path))
  1224. ; One notes file per publication:
  1225. (let* ((path (f-join bibtex-completion-notes-path
  1226. (s-concat key bibtex-completion-notes-extension))))
  1227. (find-file path)
  1228. (unless (f-exists? path)
  1229. (insert (s-format bibtex-completion-notes-template-multiple-files
  1230. 'bibtex-completion-apa-get-value
  1231. entry))))
  1232. ; One file for all notes:
  1233. (unless (and buffer-file-name
  1234. (f-same? bibtex-completion-notes-path buffer-file-name))
  1235. (find-file-other-window bibtex-completion-notes-path))
  1236. (widen)
  1237. (outline-show-all)
  1238. (goto-char (point-min))
  1239. (if (re-search-forward (format bibtex-completion-notes-key-pattern (regexp-quote key)) nil t)
  1240. ; Existing entry found:
  1241. (when (eq major-mode 'org-mode)
  1242. (org-narrow-to-subtree)
  1243. (re-search-backward "^\*+ " nil t)
  1244. (org-cycle-hide-drawers nil)
  1245. (bibtex-completion-notes-mode 1))
  1246. ; Create a new entry:
  1247. (goto-char (point-max))
  1248. (save-excursion (insert (s-format bibtex-completion-notes-template-one-file
  1249. 'bibtex-completion-apa-get-value
  1250. entry)))
  1251. (re-search-forward "^*+ " nil t))
  1252. (when (eq major-mode 'org-mode)
  1253. (org-narrow-to-subtree)
  1254. (re-search-backward "^\*+ " nil t)
  1255. (org-cycle-hide-drawers nil)
  1256. (goto-char (point-max))
  1257. (bibtex-completion-notes-mode 1))))))
  1258. (defun bibtex-completion-buffer-visiting (file)
  1259. (or (get-file-buffer file)
  1260. (find-buffer-visiting file)))
  1261. (defun bibtex-completion-show-entry (keys)
  1262. "Show the first selected entry in the BibTeX file."
  1263. (catch 'break
  1264. (dolist (bib-file (bibtex-completion-normalize-bibliography 'main))
  1265. (let ((key (car keys))
  1266. (buf (bibtex-completion-buffer-visiting bib-file)))
  1267. (find-file bib-file)
  1268. (widen)
  1269. (if (eq major-mode 'org-mode)
  1270. (let* ((prop (if (boundp 'org-bibtex-key-property)
  1271. org-bibtex-key-property
  1272. "CUSTOM_ID"))
  1273. (match (org-find-property prop key)))
  1274. (when match
  1275. (goto-char match)
  1276. (org-show-entry)
  1277. (throw 'break t)))
  1278. (goto-char (point-min))
  1279. (when (re-search-forward
  1280. (concat "^@\\(" parsebib--bibtex-identifier
  1281. "\\)[[:space:]]*[\(\{][[:space:]]*"
  1282. (regexp-quote key) "[[:space:]]*,") nil t)
  1283. (throw 'break t)))
  1284. (unless buf
  1285. (kill-buffer))))))
  1286. (defun bibtex-completion-add-pdf-to-library (keys)
  1287. "Add a PDF to the library for the first selected entry. The PDF
  1288. can be added either from an open buffer, a file, or a URL."
  1289. (let* ((key (car keys))
  1290. (source (char-to-string
  1291. (read-char-choice "Add pdf from [b]uffer, [f]ile, or [u]rl? " '(?b ?f ?u))))
  1292. (buffer (when (string= source "b")
  1293. (read-buffer-to-switch "Add pdf buffer: ")))
  1294. (file (when (string= source "f")
  1295. (expand-file-name (read-file-name "Add pdf file: " nil nil t))))
  1296. (url (when (string= source "u")
  1297. (read-string "Add pdf URL: ")))
  1298. (path (-flatten (list bibtex-completion-library-path)))
  1299. (path (if (cdr path)
  1300. (completing-read "Add pdf to: " path nil t)
  1301. (car path)))
  1302. (pdf (expand-file-name (completing-read "Rename pdf to: "
  1303. (--map (s-concat key it)
  1304. (-flatten bibtex-completion-pdf-extension))
  1305. nil nil key)
  1306. path)))
  1307. (cond
  1308. (buffer
  1309. (with-current-buffer buffer
  1310. (write-file pdf t)))
  1311. (file
  1312. (copy-file file pdf 1))
  1313. (url
  1314. (url-copy-file url pdf 1)))))
  1315. (defun bibtex-completion-fallback-action (url-or-function search-expression)
  1316. (let ((browse-url-browser-function
  1317. (or bibtex-completion-browser-function
  1318. browse-url-browser-function)))
  1319. (cond
  1320. ((stringp url-or-function)
  1321. (browse-url (format url-or-function (url-hexify-string search-expression))))
  1322. ((functionp url-or-function)
  1323. (funcall url-or-function search-expression))
  1324. (t (error "Don't know how to interpret this: %s" url-or-function)))))
  1325. (defun bibtex-completion-fallback-candidates ()
  1326. "Compile list of fallback options. These consist of the online
  1327. resources defined in `bibtex-completion-fallback-options' plus
  1328. one entry for each bibliography file that will open that file for
  1329. editing."
  1330. (let ((bib-files (bibtex-completion-normalize-bibliography 'main)))
  1331. (-concat
  1332. (--map (cons (s-concat "Create new entry in " (f-filename it))
  1333. `(lambda (_search-expression) (find-file ,it) (goto-char (point-max)) (newline)))
  1334. bib-files)
  1335. bibtex-completion-fallback-options)))
  1336. (defun bibtex-completion-find-local-bibliography ()
  1337. "Return a list of BibTeX files associated with the current
  1338. file. If the current file is a BibTeX file, return this
  1339. file. Otherwise, try to use `reftex' to find the associated
  1340. BibTeX files. If this fails, return nil."
  1341. (or (and (buffer-file-name)
  1342. (string= (or (f-ext (buffer-file-name)) "") "bib")
  1343. (list (buffer-file-name)))
  1344. (and (buffer-file-name)
  1345. (require 'reftex-cite nil t)
  1346. (ignore-errors (reftex-get-bibfile-list)))))
  1347. (defun bibtex-completion-key-at-point ()
  1348. "Return the key of the BibTeX entry at point. If the current
  1349. file is a BibTeX file, return the key of the entry at
  1350. point. Otherwise, try to use `reftex' to check whether point is
  1351. at a citation macro, and if so return the key at
  1352. point. Otherwise, if the current file is an org-mode file, return
  1353. the value of `org-bibtex-key-property' (or
  1354. default to \"CUSTOM_ID\"). Otherwise, return nil."
  1355. (or (and (eq major-mode 'bibtex-mode)
  1356. (save-excursion
  1357. (bibtex-beginning-of-entry)
  1358. (and (looking-at bibtex-entry-maybe-empty-head)
  1359. (bibtex-key-in-head))))
  1360. (and (require 'reftex-parse nil t)
  1361. (save-excursion
  1362. (skip-chars-backward "[:space:],;}")
  1363. (let ((macro (reftex-what-macro 1)))
  1364. (and (stringp (car macro))
  1365. (string-match "\\`\\\\cite\\|cite\\'" (car macro))
  1366. ;; allow '_' in citekeys
  1367. (let ((temp-syn-table (make-syntax-table)))
  1368. (modify-syntax-entry ?_ "_" temp-syn-table)
  1369. (with-syntax-table temp-syn-table
  1370. (thing-at-point 'symbol)))))))
  1371. (and (eq major-mode 'org-mode)
  1372. (let (key)
  1373. (and (setq key (org-entry-get nil
  1374. (if (boundp 'org-bibtex-key-property)
  1375. org-bibtex-key-property
  1376. "CUSTOM_ID")
  1377. t))
  1378. ;; KEY may be the empty string the the property is
  1379. ;; present but has no value
  1380. (> (length key) 0)
  1381. key)))))
  1382. (provide 'bibtex-completion)
  1383. ;; Local Variables:
  1384. ;; byte-compile-warnings: (not cl-functions obsolete)
  1385. ;; coding: utf-8
  1386. ;; indent-tabs-mode: nil
  1387. ;; End:
  1388. ;;; bibtex-completion.el ends here