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.

147 lines
5.1 KiB

4 years ago
  1. ;;; biblio-arxiv.el --- Lookup and import bibliographic entries from arXiv -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2016 Clément Pit-Claudel
  3. ;; Author: Clément Pit-Claudel <clement.pitclaudel@live.com>
  4. ;; URL: http://github.com/cpitclaudel/biblio.el
  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. ;;
  10. ;; This program is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;;
  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. ;;
  19. ;; Lookup and download bibliographic records from arXiv using `arxiv-lookup'.
  20. ;; When a DOI is available, the metadata is fetched from the DOI's issuer;
  21. ;; otherwise, this package uses arXiv's metadata to generate an entry.
  22. ;;
  23. ;; This file implements a backend for the for the `biblio' package (which see for more
  24. ;; documentation).
  25. ;;; Code:
  26. (require 'biblio-core)
  27. (require 'biblio-doi)
  28. (require 'timezone)
  29. (defgroup biblio-arxiv nil
  30. "arXiv support in biblio.el"
  31. :group 'biblio)
  32. (defcustom biblio-arxiv-bibtex-header "online"
  33. "Which header to use for BibTeX entries generated from arXiv metadata."
  34. :group 'biblio
  35. :type 'string)
  36. (defun biblio-arxiv--build-bibtex-1 (metadata)
  37. "Create an unformated BibTeX record for METADATA."
  38. (let-alist metadata
  39. (format "@%s{NO_KEY,
  40. author = {%s},
  41. title = {{%s}},
  42. year = {%s},
  43. archivePrefix = {arXiv},
  44. eprint = {%s},
  45. primaryClass = {%s}}"
  46. biblio-arxiv-bibtex-header
  47. (biblio-join-1 " AND " .authors)
  48. .title .year .identifier .category)))
  49. (defun biblio-arxiv--build-bibtex (metadata)
  50. "Create a BibTeX record for METADATA."
  51. (let-alist metadata
  52. (message "Auto-generating a BibTeX entry for %S." .id)
  53. (biblio-format-bibtex (biblio-arxiv--build-bibtex-1 metadata) t)))
  54. (defun biblio-arxiv--forward-bibtex (metadata forward-to)
  55. "Forward BibTeX for arXiv entry METADATA to FORWARD-TO."
  56. (let-alist metadata
  57. (if (seq-empty-p .doi)
  58. (funcall forward-to (biblio-arxiv--build-bibtex metadata))
  59. (biblio-doi-forward-bibtex .doi forward-to))))
  60. (defun biblio-arxiv--format-author (author)
  61. "Format AUTHOR for arXiv search results."
  62. (when (eq (car-safe author) 'author)
  63. (let-alist (cdr author)
  64. (biblio-join " "
  65. (cadr .name)
  66. (biblio-parenthesize (cadr .arxiv:affiliation))))))
  67. (defun biblio-arxiv--extract-id (id)
  68. "Extract identifier from ID, the URL of an arXiv abstract."
  69. (replace-regexp-in-string "https?://arxiv.org/abs/" "" id))
  70. (defun biblio-arxiv--pdf-url (id)
  71. "Extract PDF url from ID of an arXiv entry."
  72. (when id
  73. (concat "http://arxiv.org/pdf/" id)))
  74. (defun biblio-arxiv--extract-interesting-fields (entry)
  75. "Prepare an arXiv search result ENTRY for display."
  76. (let-alist entry
  77. (let ((id (biblio-arxiv--extract-id (cadr .id))))
  78. (list (cons 'doi (cadr .arxiv:doi))
  79. (cons 'identifier id)
  80. (cons 'year (aref (timezone-parse-date (cadr .published)) 0))
  81. (cons 'title (cadr .title))
  82. (cons 'authors (seq-map #'biblio-arxiv--format-author entry))
  83. (cons 'container (cadr .arxiv:journal_ref))
  84. (cons 'category
  85. (biblio-alist-get 'term (car .arxiv:primary_category)))
  86. (cons 'references (list (cadr .arxiv:doi) id))
  87. (cons 'type "eprint")
  88. (cons 'url (biblio-alist-get 'href (car .link)))
  89. (cons 'direct-url (biblio-arxiv--pdf-url id))))))
  90. (defun biblio-arxiv--entryp (entry)
  91. "Check if ENTRY is an arXiv entry."
  92. (eq (car-safe entry) 'entry))
  93. (defun biblio-arxiv--parse-search-results ()
  94. "Extract search results from arXiv response."
  95. (biblio-decode-url-buffer 'utf-8)
  96. (let-alist (xml-parse-region (point-min) (point-max))
  97. (seq-map #'biblio-arxiv--extract-interesting-fields
  98. (seq-filter #'biblio-arxiv--entryp .feed))))
  99. (defun biblio-arxiv--url (query)
  100. "Create an arXiv url to look up QUERY."
  101. (format "http://export.arxiv.org/api/query?search_query=%s"
  102. (url-encode-url query)))
  103. ;;;###autoload
  104. (defun biblio-arxiv-backend (command &optional arg &rest more)
  105. "A arXiv backend for biblio.el.
  106. COMMAND, ARG, MORE: See `biblio-backends'."
  107. (pcase command
  108. (`name "arXiv")
  109. (`prompt "arXiv query: ")
  110. (`url (biblio-arxiv--url arg))
  111. (`parse-buffer (biblio-arxiv--parse-search-results))
  112. (`forward-bibtex (biblio-arxiv--forward-bibtex arg (car more)))
  113. (`register (add-to-list 'biblio-backends #'biblio-arxiv-backend))))
  114. ;;;###autoload
  115. (add-hook 'biblio-init-hook #'biblio-arxiv-backend)
  116. ;;;###autoload
  117. (defun biblio-arxiv-lookup (&optional query)
  118. "Start an arXiv search for QUERY, prompting if needed."
  119. (interactive)
  120. (biblio-lookup #'biblio-arxiv-backend query))
  121. ;;;###autoload
  122. (defalias 'arxiv-lookup 'biblio-arxiv-lookup)
  123. (provide 'biblio-arxiv)
  124. ;;; biblio-arxiv.el ends here