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.

237 lines
9.2 KiB

5 years ago
  1. ;;; org-ref-arxiv.el --- arxiv utilities for org-mode -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2015 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. ;; this library creates a new org-link for Arxiv (http://arxiv.org/) entries,
  17. ;; and provides functions to retrieve bibtex entries from an Arxiv number.
  18. ;;
  19. ;; An Arxiv number might look like: cond-mat/0410285 or 1503.01742
  20. ;;; Code:
  21. (require 'bibtex)
  22. (require 'dash)
  23. (require 'f)
  24. (require 'org)
  25. (require 's)
  26. (require 'org-ref-utils)
  27. ;; This is a local variable defined in `url-http'. We need it to avoid
  28. ;; byte-compiler errors.
  29. (defvar url-http-end-of-headers)
  30. (defvar org-ref-default-bibliography)
  31. (defvar org-ref-pdf-directory)
  32. (declare-function parsebib-find-bibtex-dialect "parsebib")
  33. (declare-function org-ref-clean-bibtex-entry "org-ref-core")
  34. ;; this is a C function
  35. (declare-function libxml-parse-xml-region "xml")
  36. ;;* The org-mode link
  37. ;; this just makes a clickable link that opens the entry.
  38. ;; example: arxiv:cond-mat/0410285
  39. (org-ref-link-set-parameters "arxiv"
  40. :follow (lambda (link-string)
  41. (browse-url (format "http://arxiv.org/abs/%s" link-string)))
  42. :export (lambda (keyword desc format)
  43. (cond
  44. ((eq format 'html)
  45. (format "<a href=\"http://arxiv.org/abs/%s\">arxiv:%s</a>"
  46. keyword (or desc keyword)))
  47. ((eq format 'latex)
  48. ;; write out the latex command
  49. (format "\\url{http://arxiv.org/abs/%s}{%s}" keyword (or desc keyword))))))
  50. ;;* Getting a bibtex entry for an arXiv article using remote service:
  51. ;; For an arxiv article, there is a link to a NASA ADS page like this:
  52. ;; http://adsabs.harvard.edu/cgi-bin/bib_query?arXiv:1503.01742
  53. ;; On that page, there is a link to a bibtex entry:
  54. ;; http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=2015arXiv150301742H&data_type=BIBTEX&db_key=PRE&nocookieset=1
  55. ;;
  56. ;; It looks like you need to get a Bibliographic code from the arxiv number to
  57. ;; then get the bibtex entry.
  58. (defun arxiv-get-bibliographic-code (arxiv-number)
  59. "Get Bibliographic code for ARXIV-NUMBER."
  60. (with-current-buffer
  61. (url-retrieve-synchronously
  62. (concat
  63. "http://adsabs.harvard.edu/cgi-bin/bib_query?arXiv:"
  64. arxiv-number))
  65. (search-forward-regexp "name=\\\"bibcode\\\" value=\\\"\\(.*\\)\\\"")
  66. (match-string 1)))
  67. (defun arxiv-get-bibtex-entry (arxiv-bibliographic-code)
  68. "Get bibtex entry for ARXIV-BIBLIOGRAPHIC-CODE."
  69. (with-current-buffer
  70. (url-retrieve-synchronously
  71. (format
  72. "http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=%s&data_type=BIBTEX&db_key=PRE&nocookieset=1"
  73. arxiv-bibliographic-code))
  74. (goto-char url-http-end-of-headers)
  75. (if (search-forward "Retrieved 1 abstracts" (point-max) t)
  76. (progn
  77. (forward-line)
  78. (buffer-substring (point) (point-max)))
  79. (error "Did not get one entry: %s" (buffer-substring (point) (point-max))))))
  80. ;;* Getting a bibtex entry for an arXiv article using arXiv API:
  81. ;; Retrieves the meta data of an article view arXiv's http API,
  82. ;; extracts the necessary information, and formats a new BibTeX entry.
  83. (defvar arxiv-entry-format-string "@article{%s,
  84. journal = {CoRR},
  85. title = {%s},
  86. author = {%s},
  87. archivePrefix = {arXiv},
  88. year = {%s},
  89. eprint = {%s},
  90. primaryClass = {%s},
  91. abstract = {%s},
  92. url = {%s},
  93. }"
  94. "Template for BibTeX entries of arXiv articles.")
  95. (defun arxiv-get-bibtex-entry-via-arxiv-api (arxiv-number)
  96. "Retrieve meta data for ARXIV-NUMBER.
  97. Returns a formatted BibTeX entry."
  98. (with-current-buffer
  99. (url-retrieve-synchronously (format "http://export.arxiv.org/api/query?id_list=%s" arxiv-number) t)
  100. (let* ((parse-tree (libxml-parse-xml-region
  101. (progn (goto-char 0)
  102. (search-forward "<?xml ")
  103. (match-beginning 0))
  104. (point-max)))
  105. (entry (assq 'entry parse-tree))
  106. (authors (--map (nth 2 (nth 2 it))
  107. (--filter (and (listp it) (eq (car it) 'author)) entry)))
  108. (year (format-time-string "%Y" (date-to-time (nth 2 (assq 'published entry)))))
  109. (title (nth 2 (assq 'title entry)))
  110. (names (arxiv-bibtexify-authors authors))
  111. (category (cdar (nth 1 (assq 'primary_category entry))))
  112. (abstract (s-trim (nth 2 (assq 'summary entry))))
  113. (url (nth 2 (assq 'id entry)))
  114. (temp-bibtex (format arxiv-entry-format-string "" title names year arxiv-number category abstract url))
  115. (key (with-temp-buffer
  116. (insert temp-bibtex)
  117. (bibtex-mode)
  118. (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
  119. (bibtex-generate-autokey))))
  120. (format arxiv-entry-format-string key title names year arxiv-number category abstract url))))
  121. (defun arxiv-bibtexify-authors (authors)
  122. "Return names in 'SURNAME, FIRST NAME' format from AUTHORS list."
  123. (s-join " and "
  124. (--map (concat (-last-item it) ", " (s-join " " (-remove-last 'stringp it)))
  125. (--map (s-split " +" it) authors))))
  126. ;;;###autoload
  127. (defun arxiv-add-bibtex-entry (arxiv-number bibfile)
  128. "Add bibtex entry for ARXIV-NUMBER to BIBFILE."
  129. (interactive
  130. (list (read-string "arxiv: ")
  131. ;; now get the bibfile to add it to
  132. (completing-read
  133. "Bibfile: "
  134. (append (f-entries "." (lambda (f) (f-ext? f "bib")))
  135. org-ref-default-bibliography))))
  136. (save-window-excursion
  137. (find-file bibfile)
  138. (goto-char (point-max))
  139. (when (not (looking-at "^")) (insert "\n"))
  140. (insert (arxiv-get-bibtex-entry-via-arxiv-api arxiv-number))
  141. (org-ref-clean-bibtex-entry)
  142. (goto-char (point-max))
  143. (when (not (looking-at "^")) (insert "\n"))
  144. (save-buffer)))
  145. ;;;###autoload
  146. (defun arxiv-get-pdf (arxiv-number pdf)
  147. "Retrieve a pdf for ARXIV-NUMBER and save it to PDF."
  148. (interactive "sarxiv: \nsPDF: ")
  149. (let ((pdf-url (with-current-buffer
  150. (url-retrieve-synchronously
  151. (concat
  152. "http://arxiv.org/abs/" arxiv-number))
  153. ;; <meta name="citation_pdf_url" content="http://arxiv.org/pdf/0801.1144" />
  154. (goto-char (point-min))
  155. (search-forward-regexp
  156. "name=\\\"citation_pdf_url\\\" content=\\\"\\(.*\\)\\\"")
  157. (match-string 1))))
  158. (url-copy-file pdf-url pdf)
  159. ;; now check if we got a pdf
  160. (if (org-ref-pdf-p pdf)
  161. (org-open-file pdf)
  162. (delete-file pdf)
  163. (message "Error downloading arxiv pdf %s" pdf-url))))
  164. ;;;###autoload
  165. (defun arxiv-get-pdf-add-bibtex-entry (arxiv-number bibfile pdfdir)
  166. "Add bibtex entry for ARXIV-NUMBER to BIBFILE.
  167. Remove troublesome chars from the bibtex key, retrieve a pdf
  168. for ARXIV-NUMBER and save it to PDFDIR with the same name of the
  169. key."
  170. (interactive
  171. (list (read-string "arxiv: ")
  172. ;; now get the bibfile to add it to
  173. (completing-read
  174. "Bibfile: "
  175. (append (f-entries "." (lambda (f) (f-ext? f "bib")))
  176. org-ref-default-bibliography))
  177. (read-directory-name
  178. "PDF directory: "
  179. org-ref-pdf-directory)))
  180. (arxiv-add-bibtex-entry arxiv-number bibfile)
  181. (save-window-excursion
  182. (let ((key ""))
  183. (find-file bibfile)
  184. (goto-char (point-max))
  185. (bibtex-beginning-of-entry)
  186. (re-search-forward bibtex-entry-maybe-empty-head)
  187. (if (match-beginning bibtex-key-in-head)
  188. (progn
  189. (setq key (delete-and-extract-region
  190. (match-beginning bibtex-key-in-head)
  191. (match-end bibtex-key-in-head)))
  192. ;; remove potentially troublesome characters from key
  193. ;; as it will be used as a filename
  194. (setq key (replace-regexp-in-string "\"\\|\\*\\|/\\|:\\|<\\|>\\|\\?\\|\\\\\\||\\|\\+\\|,\\|\\.\\|;\\|=\\|\\[\\|]\\|!\\|@"
  195. "" key))
  196. ;; check if the key is in the buffer
  197. (when (save-excursion
  198. (bibtex-search-entry key))
  199. (save-excursion
  200. (bibtex-search-entry key)
  201. (bibtex-copy-entry-as-kill)
  202. (switch-to-buffer-other-window "*duplicate entry*")
  203. (bibtex-yank))
  204. (setq key (bibtex-read-key "Duplicate Key found, edit: " key))))
  205. (setq key (bibtex-read-key "Key not found, insert: ")))
  206. (insert key)
  207. (arxiv-get-pdf arxiv-number (concat pdfdir key ".pdf")))))
  208. (provide 'org-ref-arxiv)
  209. ;;; org-ref-arxiv.el ends here