Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

920 lines
34 KiB

4 years ago
  1. ;;; org-ref-utils.el --- Utility functions for org-ref -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2016 John Kitchin
  3. ;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
  4. ;; Keywords:
  5. ;; This program is free software; you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; This program is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. (require 'org)
  18. (require 'org-ref-pdf) ; for pdftotext-executable
  19. (defcustom org-ref-bib-html "<h1 class='org-ref-bib-h1'>Bibliography</h1>\n"
  20. "HTML header to use for bibliography in HTML export."
  21. :type 'string
  22. :group 'org-ref)
  23. (defcustom org-ref-bib-html-sorted nil
  24. "Determine whether the HTML bibliography should be sorted."
  25. :type 'boolean
  26. :group 'org-ref)
  27. (defcustom org-ref-search-whitespace-regexp "\\s-+"
  28. "A whitespace regexp for use in `org-ref-strip-string."
  29. :group 'org-ref)
  30. (defvar org-ref-cite-types)
  31. (defvar org-ref-get-pdf-filename-function)
  32. (defvar org-ref-notes-function)
  33. (defvar org-ref-bibliography-entry-format)
  34. (declare-function 'org-ref-get-bibtex-key-and-file "org-ref-core.el")
  35. (declare-function 'org-ref-key-in-file-p "org-ref-core.el")
  36. (declare-function 'org-ref-find-bibliography "org-ref-core.el")
  37. (declare-function 'org-ref-bib-citation "org-ref-core.el")
  38. (declare-function 'org-ref-get-bibtex-key-under-cursor "org-ref-core.el")
  39. ;;; Code:
  40. ;;;###autoload
  41. (defun org-ref-version ()
  42. "Provide a version string for org-ref.
  43. Copies the string to the clipboard."
  44. (interactive)
  45. ;; version in the el file.
  46. (let* ((org-ref-el (concat
  47. (file-name-sans-extension
  48. (locate-library "org-ref"))
  49. ".el"))
  50. (org-ref-dir (file-name-directory org-ref-el))
  51. org-version
  52. git-commit
  53. version-string)
  54. (setq org-version (with-temp-buffer
  55. (insert-file-contents org-ref-el)
  56. (goto-char (point-min))
  57. (re-search-forward ";; Version:")
  58. (s-trim (buffer-substring (point)
  59. (line-end-position)))))
  60. (setq git-commit
  61. ;; If in git, get current commit
  62. (let ((default-directory org-ref-dir))
  63. (when (= 0 (shell-command "git rev-parse --git-dir"))
  64. (s-trim (shell-command-to-string "git rev-parse HEAD")))))
  65. (setq version-string (format "org-ref: Version %s%s" org-version
  66. (if git-commit
  67. (format " (git-commit %s)" git-commit)
  68. "")))
  69. (kill-new version-string)
  70. (message version-string)))
  71. (defun org-ref-report-issue ()
  72. "Report an issue in org-ref.
  73. Opens https://github.com/jkitchin/org-ref/issues/new."
  74. (save-window-excursion
  75. (org-ref-debug)
  76. (kill-new (buffer-string)))
  77. (message "org-ref-debug has been run. You can paste the results in the issue website if you like.")
  78. (browse-url "https://github.com/jkitchin/org-ref/issues/new"))
  79. ;;* Debug(require 'org-ref-pdf)
  80. (defmacro ords (&rest body)
  81. "Evaluate BODY and return a string."
  82. `(format "%s" (progn ,@body)))
  83. ;;;###autoload
  84. (defun org-ref-debug ()
  85. "Print some debug information to a buffer."
  86. (interactive)
  87. (switch-to-buffer "*org-ref-debug*")
  88. (erase-buffer)
  89. (org-mode)
  90. (insert
  91. (s-format "#+TITLE: org-ref debug
  92. ${org-ref-version}
  93. * Variables
  94. 1. org-ref-completion-library: ${org-ref-completion-library}
  95. 2. org-ref-bibliography-notes: ${org-ref-bibliography-notes} (exists ${orbn-p})
  96. 3. org-ref-default-bibliography: ${org-ref-default-bibliography} (exists ${ordb-p}) (listp ${ordb-listp})
  97. 4. org-ref-pdf-directory: ${org-ref-pdf-directory} (exists ${orpd-p})
  98. * System
  99. system-type: ${system}
  100. system-configuration: ${system-configuration}
  101. window system: ${window-system}
  102. Emacs: ${emacs-version}
  103. org-version: ${org-version}
  104. * about org-ref
  105. org-ref installed in ${org-ref-location}.
  106. ** Dependencies
  107. helm-bibtex ${helm-bibtex-path}
  108. * org-ref-pdf (loaded: ${org-ref-pdf-p})
  109. system pdftotext: ${pdftotext}
  110. You set pdftotext-executable to ${pdftotext-executable} (exists: ${pdftotext-executable-p})
  111. * org-ref-url-utils (loaded: ${org-ref-url-p})
  112. * export variables
  113. org-latex-pdf-process:
  114. ${org-latex-pdf-process}
  115. "
  116. 'aget
  117. `(("org-ref-completion-library" . ,(format "%s" org-ref-completion-library))
  118. ("org-ref-bibliography-notes" . ,(format "%s" org-ref-bibliography-notes))
  119. ("org-ref-bibliography-notes exists" . ,(format "%s" (when org-ref-bibliography-notes
  120. (file-exists-p org-ref-bibliography-notes))))
  121. ("org-ref-version" . ,(org-ref-version))
  122. ("org-latex-pdf-process" . ,(format "%S" org-latex-pdf-process))
  123. ("org-ref-default-bibliography" . ,(format "%s" org-ref-default-bibliography))
  124. ("ordb-p" . ,(format "%s" (mapcar 'file-exists-p org-ref-default-bibliography)))
  125. ("ordb-listp" . ,(ords (listp org-ref-default-bibliography)))
  126. ("org-ref-pdf-directory" . ,(format "%s" org-ref-pdf-directory))
  127. ("orpd-p" . ,(format "%s" (file-exists-p org-ref-pdf-directory)))
  128. ("org-ref-location" . ,(format "%s" (locate-library "org-ref")))
  129. ("system" . ,(format "System: %s" system-type))
  130. ("system-configuration" . ,(ords system-configuration))
  131. ("window-system" . ,(format "Window system: %s" window-system))
  132. ("emacs-version" . ,(ords (emacs-version)))
  133. ("org-version" . ,(org-version))
  134. ("helm-bibtex-path" . ,(ords (locate-library "helm-bibtex")))
  135. ("org-ref-pdf-p" . ,(ords (featurep 'org-ref-pdf)))
  136. ("pdftotext" . ,(ords (if (featurep 'org-ref-pdf)
  137. (executable-find "pdftotext")
  138. "org-ref-pdf not loaded")))
  139. ("pdftotext-executable" . ,(ords (if (featurep 'org-ref-pdf)
  140. pdftotext-executable
  141. "org-ref-pdf not loaded")))
  142. ("pdftotext-executable-p" . ,(ords (if (featurep 'org-ref-pdf)
  143. (or
  144. (executable-find pdftotext-executable)
  145. (file-exists-p pdftotext-executable))
  146. "org-ref-pdf not loaded")))
  147. ("org-ref-url-p" . ,(ords (featurep 'org-ref-url)))))))
  148. (defun org-ref-reftex-get-bib-field (field entry &optional format)
  149. "Get FIELD from a bibtex ENTRY in optional FORMAT.
  150. Similar to `reftex-get-bib-field', but removes enclosing braces
  151. and quotes in FIELD in the bibtex ENTRY."
  152. (let ((result))
  153. (setq result (reftex-get-bib-field field entry format))
  154. (when (and (not (string= result "")) (string= "{" (substring result 0 1)))
  155. (setq result (substring result 1 -1)))
  156. (when (and (not (string= result "")) (string= "\"" (substring result 0 1)))
  157. (setq result (substring result 1 -1)))
  158. result))
  159. (defun org-ref-reftex-format-citation (entry format)
  160. "Format the bibtex ENTRY according to the FORMAT argument.
  161. ENTRY is from `bibtex-parse-entry'
  162. The FORMAT is a string with these percent escapes.
  163. In the format, the following percent escapes will be expanded.
  164. %l The BibTeX label of the citation.
  165. %a List of author names, see also `reftex-cite-punctuation'.
  166. %2a Like %a, but abbreviate more than 2 authors like Jones et al.
  167. %A First author name only.
  168. %e Works like %a, but on list of editor names. (%2e and %E work as well)
  169. It is also possible to access all other BibTeX database fields:
  170. %b booktitle %c chapter %d edition %h howpublished
  171. %i institution %j journal %k key %m month
  172. %n number %o organization %p pages %P first page
  173. %r address %s school %u publisher %t title
  174. %v volume %y year
  175. %B booktitle, abbreviated %T title, abbreviated
  176. %U url
  177. %D doi
  178. %S series %N note
  179. %f pdf filename
  180. %F absolute pdf filename
  181. Usually, only %l is needed. The other stuff is mainly for the echo area
  182. display, and for (setq reftex-comment-citations t).
  183. %< as a special operator kills punctuation and space around it after the
  184. string has been formatted.
  185. A pair of square brackets indicates an optional argument, and RefTeX
  186. will prompt for the values of these arguments.
  187. Beware that all this only works with BibTeX database files. When
  188. citations are made from the \bibitems in an explicit thebibliography
  189. environment, only %l is available."
  190. ;; Format a citation from the info in the BibTeX ENTRY
  191. (unless (stringp format) (setq format "\\cite{%l}"))
  192. (if (and reftex-comment-citations
  193. (string-match "%l" reftex-cite-comment-format))
  194. (error "Reftex-cite-comment-format contains invalid %%l"))
  195. (while (string-match
  196. "\\(\\`\\|[^%]\\)\\(\\(%\\([0-9]*\\)\\([a-zA-Z]\\)\\)[.,;: ]*\\)"
  197. format)
  198. (let ((n (string-to-number (match-string 4 format)))
  199. (l (string-to-char (match-string 5 format)))
  200. rpl b e)
  201. (save-match-data
  202. (setq rpl
  203. (cond
  204. ((= l ?l) (concat
  205. (org-ref-reftex-get-bib-field "&key" entry)
  206. (if reftex-comment-citations
  207. reftex-cite-comment-format
  208. "")))
  209. ((= l ?a) (replace-regexp-in-string
  210. "\n\\|\t\\|\s+" " "
  211. (reftex-format-names
  212. (reftex-get-bib-names "author" entry)
  213. (or n 2))))
  214. ((= l ?A) (replace-regexp-in-string
  215. "\n\\|\t\\|\s+" " "
  216. (car (reftex-get-bib-names "author" entry))))
  217. ((= l ?b) (org-ref-reftex-get-bib-field "booktitle" entry "in: %s"))
  218. ((= l ?B) (reftex-abbreviate-title
  219. (org-ref-reftex-get-bib-field "booktitle" entry "in: %s")))
  220. ((= l ?c) (org-ref-reftex-get-bib-field "chapter" entry))
  221. ((= l ?d) (org-ref-reftex-get-bib-field "edition" entry))
  222. ((= l ?D) (org-ref-reftex-get-bib-field "doi" entry))
  223. ((= l ?e) (reftex-format-names
  224. (reftex-get-bib-names "editor" entry)
  225. (or n 2)))
  226. ((= l ?E) (car (reftex-get-bib-names "editor" entry)))
  227. ((= l ?f) (concat (org-ref-reftex-get-bib-field "=key=" entry) ".pdf"))
  228. ((= l ?F) (concat org-ref-pdf-directory (org-ref-reftex-get-bib-field "=key=" entry) ".pdf"))
  229. ((= l ?h) (org-ref-reftex-get-bib-field "howpublished" entry))
  230. ((= l ?i) (org-ref-reftex-get-bib-field "institution" entry))
  231. ((= l ?j) (let ((jt (reftex-get-bib-field "journal" entry)))
  232. (if (string= "" jt)
  233. (reftex-get-bib-field "journaltitle" entry)
  234. jt)))
  235. ((= l ?k) (org-ref-reftex-get-bib-field "=key=" entry))
  236. ((= l ?m) (org-ref-reftex-get-bib-field "month" entry))
  237. ((= l ?n) (org-ref-reftex-get-bib-field "number" entry))
  238. ((= l ?N) (org-ref-reftex-get-bib-field "note" entry))
  239. ((= l ?o) (org-ref-reftex-get-bib-field "organization" entry))
  240. ((= l ?p) (org-ref-reftex-get-bib-field "pages" entry))
  241. ((= l ?P) (car (split-string
  242. (org-ref-reftex-get-bib-field "pages" entry)
  243. "[- .]+")))
  244. ((= l ?s) (org-ref-reftex-get-bib-field "school" entry))
  245. ((= l ?S) (org-ref-reftex-get-bib-field "series" entry))
  246. ((= l ?u) (org-ref-reftex-get-bib-field "publisher" entry))
  247. ((= l ?U) (org-ref-reftex-get-bib-field "url" entry))
  248. ((= l ?r) (org-ref-reftex-get-bib-field "address" entry))
  249. ;; strip enclosing brackets from title if they are there
  250. ((= l ?t) (replace-regexp-in-string
  251. "\n\\|\t\\|\s+" " "
  252. (org-ref-reftex-get-bib-field "title" entry)))
  253. ((= l ?T) (reftex-abbreviate-title
  254. (replace-regexp-in-string
  255. "\n\\|\t\\|\s+" " "
  256. (org-ref-reftex-get-bib-field "title" entry))))
  257. ((= l ?v) (org-ref-reftex-get-bib-field "volume" entry))
  258. ((= l ?y) (org-ref-reftex-get-bib-field "year" entry)))))
  259. (if (string= rpl "")
  260. (setq b (match-beginning 2) e (match-end 2))
  261. (setq b (match-beginning 3) e (match-end 3)))
  262. (setq format (concat (substring format 0 b) rpl (substring format e)))))
  263. (while (string-match "%%" format)
  264. (setq format (replace-match "%" t t format)))
  265. (while (string-match "[ ,.;:]*%<" format)
  266. (setq format (replace-match "" t t format)))
  267. format)
  268. (defun org-ref-get-bibtex-entry-citation (key)
  269. "Return a string for the bibliography entry corresponding to KEY.
  270. Format according to the type in `org-ref-bibliography-entry-format'."
  271. (let ((org-ref-bibliography-files (org-ref-find-bibliography))
  272. (file) (entry) (bibtex-entry) (entry-type) (format))
  273. (setq file (catch 'result
  274. (cl-loop for file in org-ref-bibliography-files do
  275. (if (org-ref-key-in-file-p key (file-truename file))
  276. (throw 'result file)
  277. (message "%s not found in %s"
  278. key (file-truename file))))))
  279. (with-temp-buffer
  280. (insert-file-contents file)
  281. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  282. (bibtex-search-entry key nil 0)
  283. (setq bibtex-entry (bibtex-parse-entry))
  284. ;; downcase field names so they work in the format-citation code
  285. (dolist (cons-cell bibtex-entry)
  286. (setf (car cons-cell) (downcase (car cons-cell))))
  287. (setq entry-type (downcase (cdr (assoc "=type=" bibtex-entry))))
  288. (setq format (cdr (assoc entry-type org-ref-bibliography-entry-format)))
  289. (if format
  290. (setq entry (org-ref-reftex-format-citation bibtex-entry format))
  291. ;; if no format, we use the bibtex entry itself as a fallback
  292. (save-restriction
  293. (bibtex-narrow-to-entry)
  294. (setq entry (buffer-string)))))
  295. entry))
  296. (defun org-ref-get-bibtex-entry (key)
  297. "Return the bibtex entry as a string."
  298. (let ((org-ref-bibliography-files (org-ref-find-bibliography))
  299. (file) (entry))
  300. (setq file (catch 'result
  301. (cl-loop for file in org-ref-bibliography-files do
  302. (if (org-ref-key-in-file-p key (file-truename file))
  303. (throw 'result file)
  304. (message "%s not found in %s"
  305. key (file-truename file))))))
  306. (with-temp-buffer
  307. (insert-file-contents file)
  308. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  309. (bibtex-search-entry key nil 0)
  310. (save-restriction
  311. (bibtex-narrow-to-entry)
  312. (setq entry (buffer-string)))
  313. entry)))
  314. ;;*** key at point functions
  315. (defun org-ref-get-pdf-filename (key)
  316. "Return the pdf filename associated with a bibtex KEY.
  317. This searches for the pattern KEY*.pdf. If one result is found it
  318. is returned, but if multiple results are found, e.g. there are
  319. related files to the KEY you are prompted for which one you want."
  320. (if org-ref-pdf-directory
  321. (let ((pdfs (-flatten (--map (file-expand-wildcards
  322. (f-join it (format "%s*.pdf" key)))
  323. (-flatten (list org-ref-pdf-directory))))))
  324. (cond
  325. ((= 0 (length pdfs))
  326. (expand-file-name (format "%s.pdf" key) org-ref-pdf-directory))
  327. ((= 1 (length pdfs))
  328. (car pdfs))
  329. ((> (length pdfs) 1)
  330. (completing-read "Choose: " pdfs))))
  331. ;; No org-ref-pdf-directory defined so return just a file name.
  332. (format "%s.pdf" key)))
  333. (defun org-ref-get-mendeley-filename (key)
  334. "Return the pdf filename indicated by mendeley file field.
  335. Falls back to `org-ref-get-pdf-filename' if file field does not exist.
  336. Contributed by https://github.com/autosquid.
  337. Argument KEY is the bibtex key."
  338. (let* ((results (org-ref-get-bibtex-key-and-file key))
  339. (bibfile (cdr results))
  340. entry)
  341. (with-temp-buffer
  342. (insert-file-contents bibfile)
  343. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  344. (bibtex-search-entry key nil 0)
  345. (setq entry (bibtex-parse-entry))
  346. (let ((e (org-ref-reftex-get-bib-field "file" entry)))
  347. (if (> (length e) 4)
  348. (let ((clean-field (replace-regexp-in-string "{\\|}\\|\\\\" "" e)))
  349. (let ((first-file (car (split-string clean-field ";" t))))
  350. (format "/%s" (substring first-file 1
  351. (- (length first-file) 4)))))
  352. (format (concat
  353. (file-name-as-directory org-ref-pdf-directory)
  354. "%s.pdf")
  355. key))))))
  356. (defun org-ref-get-pdf-filename-helm-bibtex (key)
  357. "Use helm-bibtex to retrieve a PDF filename for KEY.
  358. helm-bibtex looks in both the configured directory
  359. `bibtex-completion-library-path' and in the fields of the bibtex
  360. item for a filename. It understands file fields exported by
  361. Jabref, Mendeley and Zotero. See `bibtex-completion-find-pdf'."
  362. (let ((bibtex-completion-bibliography (org-ref-find-bibliography)))
  363. (or (car (bibtex-completion-find-pdf key)) "")))
  364. ;;;###autoload
  365. (defun org-ref-open-pdf-at-point ()
  366. "Open the pdf for bibtex key under point if it exists."
  367. (interactive)
  368. (let* ((results (org-ref-get-bibtex-key-and-file))
  369. (key (car results))
  370. (pdf-file (funcall org-ref-get-pdf-filename-function key)))
  371. (if (file-exists-p pdf-file)
  372. (org-open-file pdf-file)
  373. (message "no pdf found for %s" key))))
  374. ;;;###autoload
  375. (defun org-ref-open-url-at-point ()
  376. "Open the url for bibtex key under point."
  377. (interactive)
  378. (let* ((results (org-ref-get-bibtex-key-and-file))
  379. (key (car results))
  380. (bibfile (cdr results)))
  381. (save-excursion
  382. (with-temp-buffer
  383. (insert-file-contents bibfile)
  384. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  385. (bibtex-search-entry key)
  386. ;; I like this better than bibtex-url which does not always find
  387. ;; the urls
  388. (catch 'done
  389. (let ((url (s-trim (bibtex-autokey-get-field "url"))))
  390. (unless (s-blank? url)
  391. (browse-url url)
  392. (throw 'done nil)))
  393. (let ((doi (s-trim (bibtex-autokey-get-field "doi"))))
  394. (unless (s-blank? doi)
  395. (if (string-match "^http" doi)
  396. (browse-url doi)
  397. (browse-url (format "http://dx.doi.org/%s" doi)))
  398. (throw 'done nil))))))))
  399. ;;;###autoload
  400. (defun org-ref-open-notes-at-point (&optional thekey)
  401. "Open the notes for bibtex key under point in a cite link in a buffer.
  402. Can also be called with THEKEY in a program."
  403. (interactive)
  404. (funcall org-ref-notes-function thekey))
  405. ;;;###autoload
  406. (defun org-ref-citation-at-point ()
  407. "Give message of current citation at point."
  408. (interactive)
  409. (org-ref-format-entry (org-ref-get-bibtex-key-under-cursor))
  410. ;; (let* ((results (org-ref-get-bibtex-key-and-file))
  411. ;; (key (car results))
  412. ;; (bibfile (cdr results)))
  413. ;; (message "%s" (progn
  414. ;; (with-temp-buffer
  415. ;; (insert-file-contents bibfile)
  416. ;; (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  417. ;; (bibtex-search-entry key)
  418. ;; (org-ref-bib-citation)))))
  419. )
  420. ;;;###autoload
  421. (defun org-ref-open-citation-at-point ()
  422. "Open bibtex file to key at point."
  423. (interactive)
  424. (let* ((results (org-ref-get-bibtex-key-and-file))
  425. (key (car results))
  426. (bibfile (cdr results)))
  427. (find-file bibfile)
  428. (bibtex-search-entry key)))
  429. ;;*** cite menu
  430. (defvar org-ref-cite-menu-funcs '()
  431. "Functions to run on cite click menu.
  432. Each entry is a list of (key menu-name function). The function
  433. must take no arguments and work on the key at point. Do not
  434. modify this variable, it is set to empty in the menu click
  435. function, and functions are conditionally added to it.")
  436. (defvar org-ref-user-cite-menu-funcs
  437. '(("C" "rossref" org-ref-crossref-at-point)
  438. ("y" "Copy entry to file" org-ref-copy-entry-at-point-to-file)
  439. ("s" "Copy summary" org-ref-copy-entry-as-summary))
  440. "User-defined functions to run on bibtex key at point.")
  441. ;;;###autoload
  442. (defun org-ref-copy-entry-as-summary ()
  443. "Copy the bibtex entry for the citation at point as a summary."
  444. (interactive)
  445. (kill-new (org-ref-bib-citation)))
  446. ;;;###autoload
  447. (defun org-ref-copy-cite-as-summary ()
  448. "Copy a summary for the citation at point to the clipboard."
  449. (interactive)
  450. (kill-new (org-ref-link-message)))
  451. ;;;###autoload
  452. (defun org-ref-copy-entry-at-point-to-file ()
  453. "Copy the bibtex entry for the citation at point to NEW-FILE.
  454. Prompt for NEW-FILE includes bib files in
  455. `org-ref-default-bibliography', and bib files in current working
  456. directory. You can also specify a new file."
  457. (interactive)
  458. (let ((new-file (completing-read
  459. "Copy to bibfile: "
  460. (append org-ref-default-bibliography
  461. (f-entries "." (lambda (f) (f-ext? f "bib"))))))
  462. (key (org-ref-get-bibtex-key-under-cursor)))
  463. (save-window-excursion
  464. (org-ref-open-citation-at-point)
  465. (bibtex-copy-entry-as-kill))
  466. (let ((bibtex-files (list (file-truename new-file))))
  467. (if (assoc key (bibtex-global-key-alist))
  468. (message "That key already exists in %s" new-file)
  469. ;; add to file
  470. (save-window-excursion
  471. (find-file new-file)
  472. (goto-char (point-max))
  473. ;; make sure we are at the beginning of a line.
  474. (unless (looking-at "^") (insert "\n\n"))
  475. (bibtex-yank)
  476. (save-buffer))))))
  477. (defun org-ref-get-doi-at-point ()
  478. "Get doi for key at point."
  479. (let* ((results (org-ref-get-bibtex-key-and-file))
  480. (key (car results))
  481. (bibfile (cdr results))
  482. doi)
  483. (save-excursion
  484. (with-temp-buffer
  485. (insert-file-contents bibfile)
  486. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  487. (bibtex-search-entry key)
  488. (setq doi (bibtex-autokey-get-field "doi"))
  489. ;; in case doi is a url, remove the url part.
  490. (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))))
  491. ;;**** functions that operate on key at point for click menu
  492. ;;;###autoload
  493. (defun org-ref-wos-at-point ()
  494. "Open the doi in wos for bibtex key under point."
  495. (interactive)
  496. (doi-utils-wos (org-ref-get-doi-at-point)))
  497. ;;;###autoload
  498. (defun org-ref-wos-citing-at-point ()
  499. "Open the doi in wos citing articles for bibtex key under point."
  500. (interactive)
  501. (doi-utils-wos-citing (org-ref-get-doi-at-point)))
  502. ;;;###autoload
  503. (defun org-ref-wos-related-at-point ()
  504. "Open the doi in wos related articles for bibtex key under point."
  505. (interactive)
  506. (doi-utils-wos-related (org-ref-get-doi-at-point)))
  507. ;;;###autoload
  508. (defun org-ref-google-scholar-at-point ()
  509. "Search google scholar for bibtex key under point using the title."
  510. (interactive)
  511. (browse-url
  512. (format
  513. "http://scholar.google.com/scholar?q=%s"
  514. (let* ((key-file (org-ref-get-bibtex-key-and-file))
  515. (key (car key-file))
  516. (file (cdr key-file))
  517. entry)
  518. (with-temp-buffer
  519. (insert-file-contents file)
  520. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  521. (bibtex-search-entry key nil 0)
  522. (setq entry (bibtex-parse-entry))
  523. (org-ref-reftex-get-bib-field "title" entry))))))
  524. ;;;###autoload
  525. (defun org-ref-pubmed-at-point ()
  526. "Open the doi in pubmed for bibtex key under point."
  527. (interactive)
  528. (doi-utils-pubmed (org-ref-get-doi-at-point)))
  529. ;;;###autoload
  530. (defun org-ref-crossref-at-point ()
  531. "Open the doi in crossref for bibtex key under point."
  532. (interactive)
  533. (doi-utils-crossref (org-ref-get-doi-at-point)))
  534. ;;* General org-ref utilities
  535. (defun org-ref-strip-string (string)
  536. "Strip leading and trailing whitespace from the STRING."
  537. (replace-regexp-in-string
  538. (concat org-ref-search-whitespace-regexp "$" ) ""
  539. (replace-regexp-in-string
  540. (concat "^" org-ref-search-whitespace-regexp ) "" string)))
  541. (defun org-ref-split-and-strip-string (string)
  542. "Split key-string and strip keys in STRING.
  543. Assumes the key-string is comma delimited."
  544. (mapcar 'org-ref-strip-string (split-string string ",")))
  545. (defun org-ref-get-bibtex-keys (&optional sort)
  546. "Return a list of unique keys in the buffer.
  547. Use SORT to specify alphabetical order by key."
  548. (let ((keys '()))
  549. (org-element-map (org-element-parse-buffer) 'link
  550. (lambda (link)
  551. (let ((plist (nth 1 link)))
  552. (when (-contains? org-ref-cite-types (plist-get plist ':type))
  553. (dolist
  554. (key
  555. (org-ref-split-and-strip-string (plist-get plist ':path)))
  556. (when (not (-contains? keys key))
  557. (setq keys (append keys (list key))))))))
  558. ;; set with-affiliated to get keys in captions
  559. nil nil nil t)
  560. (when sort
  561. ;; Sort keys alphabetically
  562. (setq keys (cl-sort keys 'string-lessp :key 'downcase)))
  563. keys))
  564. ;;;###autoload
  565. (defun org-ref-bibliography (&optional sort)
  566. "Create a new buffer with a bibliography.
  567. If SORT is non-nil it is alphabetically sorted by key
  568. This is mostly for convenience to see what has been cited.
  569. Entries are formatted according to the bibtex entry type in
  570. `org-ref-bibliography-entry-format', and the actual entries are
  571. generated by `org-ref-reftex-format-citation'."
  572. (interactive)
  573. (let ((bib (mapconcat
  574. 'identity
  575. (cl-loop for i from 1
  576. for citation in
  577. (mapcar
  578. (lambda (key)
  579. (let* ((results (org-ref-get-bibtex-key-and-file key))
  580. (key (car results))
  581. (bibfile (cdr results)))
  582. (format "cite:%s %s" key
  583. (if bibfile
  584. (save-excursion
  585. (with-temp-buffer
  586. (insert-file-contents bibfile)
  587. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  588. (bibtex-search-entry key)
  589. (org-ref-format-entry key)))
  590. "!!! No entry found !!!"))))
  591. (org-ref-get-bibtex-keys sort))
  592. collect (format "%3s. %s" i citation))
  593. "\n\n")))
  594. (switch-to-buffer-other-window (format "%s-bibliography" (buffer-file-name)))
  595. (erase-buffer)
  596. (insert bib)
  597. (org-mode)))
  598. (defun org-ref-get-bibtex-entry-html (key)
  599. "Return an html string for the bibliography entry corresponding to KEY."
  600. (let ((output))
  601. (setq output (concat (format "<a name=\"%s\"></a>" key)
  602. (org-ref-get-bibtex-entry-citation key)))
  603. (setq output (org-ref-clean-unused-entry-html output))
  604. (format "<li><a id=\"%s\">[%s]</a> %s</li>"
  605. key key output)))
  606. (defun org-ref-clean-unused-entry-html (entry-html)
  607. "Return from the html string ENTRY-HTML a cleaner version"
  608. ;; unescape the &
  609. (setq entry-html (replace-regexp-in-string "\\\\&" "&" entry-html))
  610. ;; hack to replace {} around text
  611. (setq entry-html (replace-regexp-in-string "{" "" entry-html))
  612. (setq entry-html (replace-regexp-in-string "}" "" entry-html))
  613. ;; get rid of empty parens
  614. (setq entry-html (replace-regexp-in-string "()" "" entry-html))
  615. ;; Remove empty volume, number field if empty
  616. (setq entry-html (replace-regexp-in-string "<b></b>," "" entry-html))
  617. ;; get rid of empty link and doi
  618. (setq entry-html (replace-regexp-in-string " <a href=\"\">link</a>\\." "" entry-html))
  619. ;; change double dash to single dash
  620. (setq entry-html (replace-regexp-in-string "--" "-" entry-html))
  621. (setq entry-html (replace-regexp-in-string " <a href=\"http://dx\\.doi\\.org/\">doi</a>\\." "" entry-html))
  622. entry-html)
  623. (defun org-ref-get-html-bibliography (&optional sort)
  624. "Create an html bibliography when there are keys.
  625. If one of SORT and `org-ref-bib-html-sorted' is non-nil,
  626. the bibliography is alphabetically sorted."
  627. (let ((keys (org-ref-get-bibtex-keys (or sort org-ref-bib-html-sorted))))
  628. (when keys
  629. (concat org-ref-bib-html "<ul class='org-ref-bib'>"
  630. (mapconcat (lambda (x) (org-ref-get-bibtex-entry-html x)) keys "\n")
  631. "\n</ul>"))))
  632. (defun org-ref-get-bibtex-entry-org (key)
  633. "Return an org string for the bibliography entry corresponding to KEY."
  634. (let ((org-ref-bibliography-files (org-ref-find-bibliography))
  635. file entry)
  636. (setq file (catch 'result
  637. (cl-loop for file in org-ref-bibliography-files do
  638. (if (org-ref-key-in-file-p key (file-truename file))
  639. (throw 'result file)
  640. (message "%s not found in %s" key
  641. (file-truename file))))))
  642. (with-temp-buffer
  643. (insert-file-contents file)
  644. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  645. (bibtex-search-entry key nil 0)
  646. (setq entry (bibtex-parse-entry))
  647. (format "** %s - %s
  648. :PROPERTIES:
  649. %s
  650. :END:
  651. " (org-ref-reftex-get-bib-field "author" entry)
  652. (org-ref-reftex-get-bib-field "title" entry)
  653. (concat " :CUSTOM_ID: " (org-ref-reftex-get-bib-field "=key=" entry) "\n"
  654. (mapconcat
  655. (lambda (element) (format " :%s: %s"
  656. (upcase (car element))
  657. (cdr element)))
  658. entry
  659. "\n"))))))
  660. (defun org-ref-get-org-bibliography (&optional sort)
  661. "Create an org bibliography when there are keys.
  662. If SORT is non-nil the bibliography is sorted alphabetically by key."
  663. (let ((keys (org-ref-get-bibtex-keys sort)))
  664. (when keys
  665. (concat "* Bibliography\n"
  666. (mapconcat (lambda (x)
  667. (org-ref-get-bibtex-entry-org x)) keys "\n")
  668. "\n"))))
  669. (defun org-ref-get-bibtex-entry-ascii (key)
  670. "Return an ascii string for the bibliography entry corresponding to KEY."
  671. (format "[%s] %s" key (org-ref-get-bibtex-entry-citation key)))
  672. (defun org-ref-get-bibtex-entry-md (key)
  673. "Return a md string for the bibliography entry corresponding to KEY."
  674. ;; We create an anchor to the key that we can jump to, and provide a jump back
  675. ;; link with the md5 of the key.
  676. (format "<a id=\"%s\"></a>[%s] %s%s [↩](#%s)"
  677. key key
  678. (org-ref-clean-unused-entry-html (org-ref-get-bibtex-entry-citation key))
  679. ""
  680. ;; Note: This is to temporarily resolve issue #558. This worked fine
  681. ;; for me earlier, so I don't know why it doesn't work in this issue.
  682. ;; (if (plist-get info :md-publish-bibtex)
  683. ;; (format
  684. ;; " <a href=\"data:text/plain;charset=US-ASCII;base64,%s\" title=\"%s\">[bib]</a>"
  685. ;; (base64-encode-string (org-ref-get-bibtex-entry key))
  686. ;; (concat "Right-click to open\n" (xml-escape-string
  687. ;; (org-ref-get-bibtex-entry key))))
  688. ;; "")
  689. (md5 key)))
  690. (defun org-ref-get-ascii-bibliography (&optional sort)
  691. "Create an ascii bibliography when there are keys.
  692. if SORT is non-nil the bibliography is sorted alphabetically by key."
  693. (let ((keys (org-ref-get-bibtex-keys sort)))
  694. (when keys
  695. (concat
  696. "\n\nBibliography\n=============\n\n"
  697. (mapconcat (lambda (x) (org-ref-get-bibtex-entry-ascii x)) keys "\n")
  698. "\n"))))
  699. (defun org-ref-get-md-bibliography (&optional sort)
  700. "Create an md bibliography when there are keys.
  701. if SORT is non-nil the bibliography is sorted alphabetically by key."
  702. (let ((keys (org-ref-get-bibtex-keys sort)))
  703. (when keys
  704. (concat
  705. "# Bibliography\n"
  706. (mapconcat (lambda (x) (org-ref-get-bibtex-entry-md x)) keys "\n\n")
  707. "\n"))))
  708. (defun org-ref-get-odt-bibliography (&optional sort)
  709. "Create an ascii bibliography ofr odt export when there are keys.
  710. if SORT is non-nil the bibliography is sorted alphabetically by
  711. key. This is a variant of `org-ref-get-ascii-bibliography' where
  712. some things are escaped since odt is an xml format."
  713. (let ((keys (org-ref-get-bibtex-keys sort)))
  714. (when keys
  715. (mapconcat (lambda (x)
  716. (xml-escape-string (org-ref-get-bibtex-entry-ascii x)))
  717. keys "\n"))))
  718. (defun org-ref-pdf-p (filename)
  719. "Check if FILENAME is PDF file.
  720. From the PDF specification 1.7:
  721. The first line of a PDF file shall be a header consisting of
  722. the 5 characters %PDF- followed by a version number of the
  723. form 1.N, where N is a digit between 0 and 7."
  724. (let ((header (with-temp-buffer
  725. (set-buffer-multibyte nil)
  726. (insert-file-contents-literally filename nil 0 5)
  727. (buffer-string))))
  728. (string-equal (encode-coding-string header 'utf-8) "%PDF-")))
  729. ;;;###autoload
  730. (defmacro org-ref-link-set-parameters (type &rest parameters)
  731. "Set link TYPE properties to PARAMETERS."
  732. (declare (indent 1))
  733. (if (fboundp 'org-link-set-parameters)
  734. `(org-link-set-parameters ,type ,@parameters)
  735. `(org-add-link-type ,type ,(plist-get parameters :follow) ,(plist-get parameters :export))))
  736. ;; This section creates some code that should speed up org-ref for large files.
  737. ;; I use org-element-parse-buffer a lot for getting information about labels
  738. ;; etc. However, it gets called a lot, and this is slow in large documents. Here
  739. ;; we try to use a cache that helps speed this up at least on loading. Some
  740. ;; notes for the future: on loading, it seems like fontification triggers buffer
  741. ;; changes, so here we only consider char changes. I am not sure this is the
  742. ;; best strategy overall. It is faster to use regexps for finding this
  743. ;; information, but those are substantially more difficult to debug in my
  744. ;; experience. There is an unfortunate number of ways to reference things in
  745. ;; org-mode, and so far this has been most reliable. An alternative might be to
  746. ;; leveralge what happens in font-lock somehow to update local variables
  747. ;; containing org-ref labels, refs, cites, etc. That would miss some #+names
  748. ;; though, and maybe some other things like custom-ids.
  749. (defvar-local org-ref-char-change-tick nil
  750. "Local variable to track character changes.")
  751. (defvar-local org-ref-parse-buffer-cache nil
  752. "Local variable to store parse buffer data.")
  753. (defun org-ref-parse-buffer (&optional force)
  754. "This is a thin wrapper around `org-element-parse-buffer'.
  755. The idea is to cache the data, and return it unless we can tell
  756. the buffer has been modified since the last time we ran it.
  757. if FORCE is non-nil reparse the buffer no matter what."
  758. (if force
  759. (progn
  760. (message "Forcing update.")
  761. (setq-local org-ref-char-change-tick (buffer-chars-modified-tick))
  762. (setq-local org-ref-parse-buffer-cache (org-element-parse-buffer)))
  763. (cond
  764. ((null org-ref-parse-buffer-cache)
  765. ;; (message "First parse.")
  766. (setq-local org-ref-char-change-tick (buffer-chars-modified-tick))
  767. (setq-local org-ref-parse-buffer-cache (org-element-parse-buffer)))
  768. ((not (eq org-ref-char-change-tick (buffer-chars-modified-tick)))
  769. ;; (message "Updating from a char change in the buffer.")
  770. (setq-local org-ref-char-change-tick (buffer-chars-modified-tick))
  771. (setq-local org-ref-parse-buffer-cache (org-element-parse-buffer)))
  772. (t
  773. ;; (message "Using cache.")
  774. org-ref-parse-buffer-cache))))
  775. (provide 'org-ref-utils)
  776. ;;; org-ref-utils.el ends here