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

;;; org-ref-arxiv.el --- arxiv utilities for org-mode -*- lexical-binding: t; -*-
;; Copyright (C) 2015 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; this library creates a new org-link for Arxiv (http://arxiv.org/) entries,
;; and provides functions to retrieve bibtex entries from an Arxiv number.
;;
;; An Arxiv number might look like: cond-mat/0410285 or 1503.01742
;;; Code:
(require 'bibtex)
(require 'dash)
(require 'f)
(require 'org)
(require 's)
(require 'org-ref-utils)
;; This is a local variable defined in `url-http'. We need it to avoid
;; byte-compiler errors.
(defvar url-http-end-of-headers)
(defvar org-ref-default-bibliography)
(defvar org-ref-pdf-directory)
(declare-function parsebib-find-bibtex-dialect "parsebib")
(declare-function org-ref-clean-bibtex-entry "org-ref-core")
;; this is a C function
(declare-function libxml-parse-xml-region "xml")
;;* The org-mode link
;; this just makes a clickable link that opens the entry.
;; example: arxiv:cond-mat/0410285
(org-ref-link-set-parameters "arxiv"
:follow (lambda (link-string)
(browse-url (format "http://arxiv.org/abs/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://arxiv.org/abs/%s\">arxiv:%s</a>"
keyword (or desc keyword)))
((eq format 'latex)
;; write out the latex command
(format "\\url{http://arxiv.org/abs/%s}{%s}" keyword (or desc keyword))))))
;;* Getting a bibtex entry for an arXiv article using remote service:
;; For an arxiv article, there is a link to a NASA ADS page like this:
;; http://adsabs.harvard.edu/cgi-bin/bib_query?arXiv:1503.01742
;; On that page, there is a link to a bibtex entry:
;; http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=2015arXiv150301742H&data_type=BIBTEX&db_key=PRE&nocookieset=1
;;
;; It looks like you need to get a Bibliographic code from the arxiv number to
;; then get the bibtex entry.
(defun arxiv-get-bibliographic-code (arxiv-number)
"Get Bibliographic code for ARXIV-NUMBER."
(with-current-buffer
(url-retrieve-synchronously
(concat
"http://adsabs.harvard.edu/cgi-bin/bib_query?arXiv:"
arxiv-number))
(search-forward-regexp "name=\\\"bibcode\\\" value=\\\"\\(.*\\)\\\"")
(match-string 1)))
(defun arxiv-get-bibtex-entry (arxiv-bibliographic-code)
"Get bibtex entry for ARXIV-BIBLIOGRAPHIC-CODE."
(with-current-buffer
(url-retrieve-synchronously
(format
"http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=%s&data_type=BIBTEX&db_key=PRE&nocookieset=1"
arxiv-bibliographic-code))
(goto-char url-http-end-of-headers)
(if (search-forward "Retrieved 1 abstracts" (point-max) t)
(progn
(forward-line)
(buffer-substring (point) (point-max)))
(error "Did not get one entry: %s" (buffer-substring (point) (point-max))))))
;;* Getting a bibtex entry for an arXiv article using arXiv API:
;; Retrieves the meta data of an article view arXiv's http API,
;; extracts the necessary information, and formats a new BibTeX entry.
(defvar arxiv-entry-format-string "@article{%s,
journal = {CoRR},
title = {%s},
author = {%s},
archivePrefix = {arXiv},
year = {%s},
eprint = {%s},
primaryClass = {%s},
abstract = {%s},
url = {%s},
}"
"Template for BibTeX entries of arXiv articles.")
(defun arxiv-get-bibtex-entry-via-arxiv-api (arxiv-number)
"Retrieve meta data for ARXIV-NUMBER.
Returns a formatted BibTeX entry."
(with-current-buffer
(url-retrieve-synchronously (format "http://export.arxiv.org/api/query?id_list=%s" arxiv-number) t)
(let* ((parse-tree (libxml-parse-xml-region
(progn (goto-char 0)
(search-forward "<?xml ")
(match-beginning 0))
(point-max)))
(entry (assq 'entry parse-tree))
(authors (--map (nth 2 (nth 2 it))
(--filter (and (listp it) (eq (car it) 'author)) entry)))
(year (format-time-string "%Y" (date-to-time (nth 2 (assq 'published entry)))))
(title (nth 2 (assq 'title entry)))
(names (arxiv-bibtexify-authors authors))
(category (cdar (nth 1 (assq 'primary_category entry))))
(abstract (s-trim (nth 2 (assq 'summary entry))))
(url (nth 2 (assq 'id entry)))
(temp-bibtex (format arxiv-entry-format-string "" title names year arxiv-number category abstract url))
(key (with-temp-buffer
(insert temp-bibtex)
(bibtex-mode)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-generate-autokey))))
(format arxiv-entry-format-string key title names year arxiv-number category abstract url))))
(defun arxiv-bibtexify-authors (authors)
"Return names in 'SURNAME, FIRST NAME' format from AUTHORS list."
(s-join " and "
(--map (concat (-last-item it) ", " (s-join " " (-remove-last 'stringp it)))
(--map (s-split " +" it) authors))))
;;;###autoload
(defun arxiv-add-bibtex-entry (arxiv-number bibfile)
"Add bibtex entry for ARXIV-NUMBER to BIBFILE."
(interactive
(list (read-string "arxiv: ")
;; now get the bibfile to add it to
(completing-read
"Bibfile: "
(append (f-entries "." (lambda (f) (f-ext? f "bib")))
org-ref-default-bibliography))))
(save-window-excursion
(find-file bibfile)
(goto-char (point-max))
(when (not (looking-at "^")) (insert "\n"))
(insert (arxiv-get-bibtex-entry-via-arxiv-api arxiv-number))
(org-ref-clean-bibtex-entry)
(goto-char (point-max))
(when (not (looking-at "^")) (insert "\n"))
(save-buffer)))
;;;###autoload
(defun arxiv-get-pdf (arxiv-number pdf)
"Retrieve a pdf for ARXIV-NUMBER and save it to PDF."
(interactive "sarxiv: \nsPDF: ")
(let ((pdf-url (with-current-buffer
(url-retrieve-synchronously
(concat
"http://arxiv.org/abs/" arxiv-number))
;; <meta name="citation_pdf_url" content="http://arxiv.org/pdf/0801.1144" />
(goto-char (point-min))
(search-forward-regexp
"name=\\\"citation_pdf_url\\\" content=\\\"\\(.*\\)\\\"")
(match-string 1))))
(url-copy-file pdf-url pdf)
;; now check if we got a pdf
(if (org-ref-pdf-p pdf)
(org-open-file pdf)
(delete-file pdf)
(message "Error downloading arxiv pdf %s" pdf-url))))
;;;###autoload
(defun arxiv-get-pdf-add-bibtex-entry (arxiv-number bibfile pdfdir)
"Add bibtex entry for ARXIV-NUMBER to BIBFILE.
Remove troublesome chars from the bibtex key, retrieve a pdf
for ARXIV-NUMBER and save it to PDFDIR with the same name of the
key."
(interactive
(list (read-string "arxiv: ")
;; now get the bibfile to add it to
(completing-read
"Bibfile: "
(append (f-entries "." (lambda (f) (f-ext? f "bib")))
org-ref-default-bibliography))
(read-directory-name
"PDF directory: "
org-ref-pdf-directory)))
(arxiv-add-bibtex-entry arxiv-number bibfile)
(save-window-excursion
(let ((key ""))
(find-file bibfile)
(goto-char (point-max))
(bibtex-beginning-of-entry)
(re-search-forward bibtex-entry-maybe-empty-head)
(if (match-beginning bibtex-key-in-head)
(progn
(setq key (delete-and-extract-region
(match-beginning bibtex-key-in-head)
(match-end bibtex-key-in-head)))
;; remove potentially troublesome characters from key
;; as it will be used as a filename
(setq key (replace-regexp-in-string "\"\\|\\*\\|/\\|:\\|<\\|>\\|\\?\\|\\\\\\||\\|\\+\\|,\\|\\.\\|;\\|=\\|\\[\\|]\\|!\\|@"
"" key))
;; check if the key is in the buffer
(when (save-excursion
(bibtex-search-entry key))
(save-excursion
(bibtex-search-entry key)
(bibtex-copy-entry-as-kill)
(switch-to-buffer-other-window "*duplicate entry*")
(bibtex-yank))
(setq key (bibtex-read-key "Duplicate Key found, edit: " key))))
(setq key (bibtex-read-key "Key not found, insert: ")))
(insert key)
(arxiv-get-pdf arxiv-number (concat pdfdir key ".pdf")))))
(provide 'org-ref-arxiv)
;;; org-ref-arxiv.el ends here