update of packages
This commit is contained in:
@@ -54,6 +54,7 @@
|
||||
(require 'org-bibtex)) ; org-bibtex-yank
|
||||
|
||||
(require 'url-http)
|
||||
(require 'url-handlers)
|
||||
(require 'org-ref-utils)
|
||||
(require 'hydra)
|
||||
|
||||
@@ -213,10 +214,23 @@ must return a pdf-url, or nil.")
|
||||
;; http://onlinelibrary.wiley.com/doi/pdf/10.1002/anie.201402680
|
||||
;; Hence fewer steps are now required.
|
||||
|
||||
(defun wiley-pdf-url (*doi-utils-redirect*)
|
||||
"Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
;; https://onlinelibrary.wiley.com/doi/10.1002/adts.202200926
|
||||
;; https://onlinelibrary.wiley.com/doi/epdf/10.1002/adts.202200926
|
||||
|
||||
;; (defun wiley-pdf-url (*doi-utils-redirect*)
|
||||
;; "Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
;; (when (string-match "^http\\(s?\\)://onlinelibrary.wiley.com" *doi-utils-redirect*)
|
||||
;; (replace-regexp-in-string "doi/abs" "doi/pdf" *doi-utils-redirect*)))
|
||||
|
||||
|
||||
(defun wiley-pdf-url-2 (*doi-utils-redirect*)
|
||||
"Get url to the pdf from *DOI-UTILS-REDIRECT*.
|
||||
[2023-04-10 Mon] updated a new rule.
|
||||
https://onlinelibrary.wiley.com/doi/pdfdirect/10.1002/anie.201310461?download=true"
|
||||
(when (string-match "^http\\(s?\\)://onlinelibrary.wiley.com" *doi-utils-redirect*)
|
||||
(replace-regexp-in-string "doi/abs" "doi/pdf" *doi-utils-redirect*)))
|
||||
(concat
|
||||
(replace-regexp-in-string "doi/" "doi/pdfdirect/" *doi-utils-redirect*)
|
||||
"?download=true")))
|
||||
|
||||
|
||||
(defun agu-pdf-url (*doi-utils-redirect*)
|
||||
@@ -340,39 +354,66 @@ must return a pdf-url, or nil.")
|
||||
url)))
|
||||
|
||||
;;** Science Direct
|
||||
(defun doi-utils-get-science-direct-pdf-url (redirect-url)
|
||||
"Science direct hides the pdf url in html. We get it out here.
|
||||
REDIRECT-URL is where the pdf url will be in."
|
||||
(let ((first-url
|
||||
(with-current-buffer (url-retrieve-synchronously redirect-url)
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "pdf_url\" content=\"\\([^\"]*\\)\"" nil t)
|
||||
(match-string-no-properties 1)))))
|
||||
(and first-url
|
||||
(with-current-buffer (url-retrieve-synchronously first-url)
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "or click <a href=\"\\([^\"]*\\)\">" nil t)
|
||||
(match-string-no-properties 1))))))
|
||||
|
||||
;; https://www.sciencedirect.com/science/article/pii/S001085452200577X?via%3Dihub
|
||||
;; https://www.sciencedirect.com/science/article/pii/S001085452200577X/pdfft?isDTMRedir=true&download=true
|
||||
|
||||
(defun science-direct-pdf-url (*doi-utils-redirect*)
|
||||
"Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
(when (string-match "^http\\(s?\\)://www.sciencedirect.com" *doi-utils-redirect*)
|
||||
(doi-utils-get-science-direct-pdf-url *doi-utils-redirect*)))
|
||||
(replace-string "?via%3Dihub" "/pdfft?isDTMRedir=true&download=true" *doi-utils-redirect*)))
|
||||
|
||||
;; (defun doi-utils-get-science-direct-pdf-url (redirect-url)
|
||||
;; "Science direct hides the pdf url in html. We get it out here.
|
||||
;; REDIRECT-URL is where the pdf url will be in."
|
||||
;; (let ((first-url
|
||||
;; (with-current-buffer (url-retrieve-synchronously redirect-url)
|
||||
;; (goto-char (point-min))
|
||||
;; (when (re-search-forward "pdf_url\" content=\"\\([^\"]*\\)\"" nil t)
|
||||
;; (match-string-no-properties 1)))))
|
||||
;; (and first-url
|
||||
;; (with-current-buffer (url-retrieve-synchronously first-url)
|
||||
;; (goto-char (point-min))
|
||||
;; (when (re-search-forward "or click <a href=\"\\([^\"]*\\)\">" nil t)
|
||||
;; (match-string-no-properties 1))))))
|
||||
|
||||
;; (defun science-direct-pdf-url (*doi-utils-redirect*)
|
||||
;; "Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
;; (when (string-match "^http\\(s?\\)://www.sciencedirect.com" *doi-utils-redirect*)
|
||||
;; (doi-utils-get-science-direct-pdf-url *doi-utils-redirect*)))
|
||||
|
||||
;; sometimes I get
|
||||
;; http://linkinghub.elsevier.com/retrieve/pii/S0927025609004558
|
||||
;; which actually redirect to
|
||||
;; http://www.sciencedirect.com/science/article/pii/S0927025609004558
|
||||
|
||||
;; https://www.sciencedirect.com/science/article/pii/S001085452200577X?via%3Dihub
|
||||
;; https://www.sciencedirect.com/science/article/pii/S001085452200577X/pdfft?isDTMRedir=true&download=true
|
||||
|
||||
;; (defun linkinghub-elsevier-pdf-url (*doi-utils-redirect*)
|
||||
;; "Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
;; (when (string-match
|
||||
;; "^https://linkinghub.elsevier.com/retrieve" *doi-utils-redirect*)
|
||||
;; (science-direct-pdf-url
|
||||
;; (replace-regexp-in-string
|
||||
;; ;; change URL to science direct and use function to get pdf URL
|
||||
;; "https://linkinghub.elsevier.com/retrieve"
|
||||
;; "https://www.sciencedirect.com/science/article"
|
||||
;; *doi-utils-redirect*))))
|
||||
|
||||
;; https://www.sciencedirect.com/science/article/pii/S1385894723014973/pdfft?isDTMRedir=true&download=true
|
||||
|
||||
(defun linkinghub-elsevier-pdf-url (*doi-utils-redirect*)
|
||||
"Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
(when (string-match
|
||||
"^https://linkinghub.elsevier.com/retrieve" *doi-utils-redirect*)
|
||||
(doi-utils-get-science-direct-pdf-url
|
||||
(concat
|
||||
(replace-regexp-in-string
|
||||
;; change URL to science direct and use function to get pdf URL
|
||||
"https://linkinghub.elsevier.com/retrieve"
|
||||
"https://www.sciencedirect.com/science/article"
|
||||
*doi-utils-redirect*))))
|
||||
*doi-utils-redirect*)
|
||||
"/pdfft?isDTMRedir=true")))
|
||||
|
||||
;;** PNAS
|
||||
;; http://www.pnas.org/content/early/2014/05/08/1319030111
|
||||
@@ -550,9 +591,11 @@ REDIRECT-URL is where the pdf url will be in."
|
||||
|
||||
|
||||
|
||||
;;** ASME Biomechanical Journal
|
||||
;;** Publishers using Highwire Press metatags
|
||||
;; For context and details, see:
|
||||
;; https://webmasters.stackexchange.com/questions/72746/where-are-the-complete-set-of-highwire-press-metatags-defined
|
||||
|
||||
(defun asme-biomechanical-pdf-url (*doi-utils-redirect*)
|
||||
(defun highwire-pdf-url (*doi-utils-redirect*)
|
||||
"Typical URL: http://biomechanical.asmedigitalcollection.asme.org/article.aspx?articleid=1427237
|
||||
|
||||
On this page the pdf might be here: <meta name=\"citation_author\" content=\"Dalong Li\" /><meta name=\"citation_author_email\" content=\"dal40@pitt.edu\" /><meta name=\"citation_author\" content=\"Anne M. Robertson\" /><meta name=\"citation_author_email\" content=\"rbertson@pitt.edu\" /><meta name=\"citation_title\" content=\"A Structural Multi-Mechanism Damage Model for Cerebral Arterial Tissue\" /><meta name=\"citation_firstpage\" content=\"101013\" /><meta name=\"citation_doi\" content=\"10.1115/1.3202559\" /><meta name=\"citation_keyword\" content=\"Mechanisms\" /><meta name=\"citation_keyword\" content=\"Biological tissues\" /><meta name=\"citation_keyword\" content=\"Stress\" /><meta name=\"citation_keyword\" content=\"Fibers\" /><meta name=\"citation_journal_title\" content=\"Journal of Biomechanical Engineering\" /><meta name=\"citation_journal_abbrev\" content=\"J Biomech Eng\" /><meta name=\"citation_volume\" content=\"131\" /><meta name=\"citation_issue\" content=\"10\" /><meta name=\"citation_publication_date\" content=\"2009/10/01\" /><meta name=\"citation_issn\" content=\"0148-0731\" /><meta name=\"citation_publisher\" content=\"American Society of Mechanical Engineers\" /><meta name=\"citation_pdf_url\" content=\"http://biomechanical.asmedigitalcollection.asme.org/data/journals/jbendy/27048/101013_1.pdf\" />
|
||||
@@ -562,13 +605,17 @@ It is in the citation_pdf_url.
|
||||
It would be better to parse this, but here I just use a regexp.
|
||||
"
|
||||
|
||||
(when (string-match "^http\\(s?\\)://biomechanical.asmedigitalcollection.asme.org" *doi-utils-redirect*)
|
||||
(when (or (string-match "^http\\(s?\\)://biomechanical.asmedigitalcollection.asme.org" *doi-utils-redirect*)
|
||||
(string-match "^http\\(s?\\)://ojs.aaai.org" *doi-utils-redirect*)
|
||||
(string-match "^http\\(s?\\)://aclanthology.org" *doi-utils-redirect*))
|
||||
(setq *doi-utils-waiting* 0)
|
||||
(url-retrieve
|
||||
*doi-utils-redirect*
|
||||
(lambda (status)
|
||||
(goto-char (point-min))
|
||||
(re-search-forward "citation_pdf_url\" content=\"\\(.*\\)\"" nil t)
|
||||
(or (progn (goto-char (point-min))
|
||||
(re-search-forward "citation_pdf_url\"? content=\"\\(.*\\)\"" nil t))
|
||||
(progn (goto-char (point-min))
|
||||
(re-search-forward "\"\\([^\"]*\\)\" name=\"?citation_pdf_url" nil t)))
|
||||
;; (message-box (match-string 1))
|
||||
(setq *doi-utils-pdf-url* (match-string 1)
|
||||
*doi-utils-waiting* nil)))
|
||||
@@ -592,6 +639,47 @@ It would be better to parse this, but here I just use a regexp.
|
||||
(concat (replace-regexp-in-string (regexp-quote "/article?id=") "/article/file?id=" *doi-utils-redirect*) "&type=printable")))
|
||||
|
||||
|
||||
;; https://www.frontiersin.org/articles/10.3389/fchem.2022.1037997/full
|
||||
;; https://www.frontiersin.org/articles/10.3389/fchem.2022.1037997/pdf
|
||||
(defun frontiers-pdf-url (*doi-utils-redirect*)
|
||||
(when (string-match "^http\\(s*\\)://www.frontiersin.org" *doi-utils-redirect*)
|
||||
(replace-regexp-in-string "/full" "/pdf" *doi-utils-redirect*)))
|
||||
|
||||
|
||||
|
||||
|
||||
;; https://chemistry-europe.onlinelibrary.wiley.com/doi/10.1002/celc.201902035
|
||||
;; https://chemistry-europe.onlinelibrary.wiley.com/doi/epdf/10.1002/celc.201902035
|
||||
(defun chemistry-europe-pdf-url (*doi-utils-redirect*)
|
||||
(when (string-match "^http\\(s*\\)://chemistry-europe.onlinelibrary.wiley.com" *doi-utils-redirect*)
|
||||
(concat
|
||||
(replace-regexp-in-string "/doi" "/doi/pdfdirect" *doi-utils-redirect*)
|
||||
"?download=true")))
|
||||
|
||||
|
||||
;; ** from issue #1081
|
||||
|
||||
(defun arxiv-pdf-url (*doi-utils-redirect*)
|
||||
"Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
(when (string-match-p "^https?://arxiv\\.org" *doi-utils-redirect*)
|
||||
(concat (replace-regexp-in-string "/abs/" "/pdf/" *doi-utils-redirect*)
|
||||
".pdf")))
|
||||
|
||||
|
||||
(defun rss-pdf-url (*doi-utils-redirect*)
|
||||
"Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
(when (string-match-p "roboticsproceedings" *doi-utils-redirect*)
|
||||
(concat (replace-regexp-in-string "\\.html" ".pdf" *doi-utils-redirect*))))
|
||||
|
||||
|
||||
(defun ieeestamp-pdf-url (*doi-utils-redirect*)
|
||||
"Get url to the pdf from *DOI-UTILS-REDIRECT*."
|
||||
(when (string-match "^https?://ieeexplore\\.ieee\\.org/document/\\([0-9]+\\)"
|
||||
*doi-utils-redirect*)
|
||||
(concat "https://ieeexplore.ieee.org/stampPDF/getPDF.jsp?tp=&arnumber="
|
||||
(match-string 1 *doi-utils-redirect*))))
|
||||
|
||||
|
||||
;;** Add all functions
|
||||
|
||||
(setq doi-utils-pdf-url-functions
|
||||
@@ -599,7 +687,8 @@ It would be better to parse this, but here I just use a regexp.
|
||||
'aps-pdf-url
|
||||
'science-pdf-url
|
||||
'nature-pdf-url
|
||||
'wiley-pdf-url
|
||||
;; 'wiley-pdf-url
|
||||
'wiley-pdf-url-2
|
||||
'springer-chapter-pdf-url
|
||||
'springer-pdf-url
|
||||
'acs-pdf-url-1
|
||||
@@ -624,11 +713,16 @@ It would be better to parse this, but here I just use a regexp.
|
||||
'ieee3-pdf-url
|
||||
'acm-pdf-url
|
||||
'osa-pdf-url
|
||||
'asme-biomechanical-pdf-url
|
||||
'highwire-pdf-url
|
||||
'siam-pdf-url
|
||||
'agu-pdf-url
|
||||
'plos-pdf-url
|
||||
'generic-full-pdf-url))
|
||||
'frontiers-pdf-url
|
||||
'chemistry-europe-pdf-url
|
||||
'generic-full-pdf-url
|
||||
'arxiv-pdf-url
|
||||
'rss-pdf-url
|
||||
'ieeestamp-pdf-url))
|
||||
|
||||
;;** Get the pdf url for a doi
|
||||
|
||||
@@ -811,11 +905,10 @@ every field.")
|
||||
(json-object-type 'plist)
|
||||
(json-data)
|
||||
(url (concat doi-utils-dx-doi-org-url doi)))
|
||||
(with-current-buffer
|
||||
(url-retrieve-synchronously
|
||||
;; (concat "http://dx.doi.org/" doi)
|
||||
url)
|
||||
(setq json-data (buffer-substring url-http-end-of-headers (point-max)))
|
||||
(with-temp-buffer
|
||||
(url-insert
|
||||
(url-retrieve-synchronously url))
|
||||
(setq json-data (buffer-string))
|
||||
|
||||
(when (or (string-match "<title>Error: DOI Not Found</title>" json-data)
|
||||
(string-match "Resource not found" json-data)
|
||||
@@ -1011,7 +1104,8 @@ MATCHING-TYPES."
|
||||
(bibtex-set-field doi-utils-timestamp-field
|
||||
ts)))
|
||||
(org-ref-clean-bibtex-entry)
|
||||
(save-buffer))
|
||||
(when (buffer-file-name)
|
||||
(save-buffer)))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
@@ -1020,7 +1114,7 @@ MATCHING-TYPES."
|
||||
Pick the file ending with .bib or in . If you have an active region that
|
||||
starts like a DOI, that will be the initial prompt. If no region
|
||||
is selected and the first entry of the ‘kill-ring’ starts like a
|
||||
DOI, then that is the intial prompt. Otherwise, you have to type
|
||||
DOI, then that is the initial prompt. Otherwise, you have to type
|
||||
or paste in a DOI.
|
||||
Argument BIBFILE the bibliography to use."
|
||||
(interactive
|
||||
@@ -1478,10 +1572,11 @@ Get a list of possible matches. Choose one with completion."
|
||||
(let ((url-request-method "GET")
|
||||
(url-mime-accept-string "application/citeproc+json")
|
||||
(json-data))
|
||||
(with-current-buffer
|
||||
(url-retrieve-synchronously
|
||||
(concat doi-utils-dx-doi-org-url doi))
|
||||
(setq json-data (buffer-substring url-http-end-of-headers (point-max)))
|
||||
(with-temp-buffer
|
||||
(url-insert
|
||||
(url-retrieve-synchronously
|
||||
(concat doi-utils-dx-doi-org-url doi)))
|
||||
(setq json-data (buffer-string))
|
||||
(if (string-match "Resource not found" json-data)
|
||||
(progn
|
||||
(browse-url (concat doi-utils-dx-doi-org-url doi))
|
||||
@@ -1502,10 +1597,11 @@ Get a list of possible matches. Choose one with completion."
|
||||
(let ((url-request-method "GET")
|
||||
(url-mime-accept-string "application/citeproc+json"))
|
||||
(pp
|
||||
(json-read-from-string (with-current-buffer
|
||||
(url-retrieve-synchronously
|
||||
(concat doi-utils-dx-doi-org-url doi))
|
||||
(buffer-substring url-http-end-of-headers (point-max))))))
|
||||
(json-read-from-string (with-temp-buffer
|
||||
(url-insert
|
||||
(url-retrieve-synchronously
|
||||
(concat doi-utils-dx-doi-org-url doi)))
|
||||
(buffer-string)))))
|
||||
"\n\n")
|
||||
(goto-char (point-min)))
|
||||
|
||||
@@ -1536,48 +1632,40 @@ Get a list of possible matches. Choose one with completion."
|
||||
"Bibfile: "
|
||||
(append (f-entries "." (lambda (f) (f-ext? f "bib")))
|
||||
bibtex-completion-bibliography))))
|
||||
(let* ((raw-json-string)
|
||||
(json-string)
|
||||
(json-data)
|
||||
(doi))
|
||||
(let* ((json-data (with-temp-buffer
|
||||
(url-insert
|
||||
(url-retrieve-synchronously
|
||||
(concat
|
||||
"https://api.crossref.org/works?query="
|
||||
(url-hexify-string query))))
|
||||
|
||||
(json-read-from-string (buffer-string))))
|
||||
(name (format "Crossref hits for %s"
|
||||
;; remove carriage returns. They can make completion confusing.
|
||||
(replace-regexp-in-string "\n" " " query)))
|
||||
(candidates (let-alist json-data
|
||||
(cl-loop for item across .message.items
|
||||
collect (let-alist item
|
||||
(cons (format "%s, %s, %s, %s."
|
||||
(string-join .title " ")
|
||||
(string-join
|
||||
(cl-loop for author across .author collect
|
||||
(let-alist author
|
||||
(format "%s %s"
|
||||
.given .family)))
|
||||
", ")
|
||||
.publisher
|
||||
.created.date-parts)
|
||||
.DOI)))))
|
||||
(doi (cdr (assoc (completing-read "Choice: " candidates) candidates))))
|
||||
|
||||
(with-current-buffer
|
||||
(url-retrieve-synchronously
|
||||
(concat
|
||||
"http://search.crossref.org/dois?q="
|
||||
(url-hexify-string query)))
|
||||
;; replace html entities
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "<i>\\|</i>" nil t)
|
||||
(replace-match ""))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "&" nil t)
|
||||
(replace-match "&"))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward """ nil t)
|
||||
(replace-match "\\\"" nil t)))
|
||||
(setq raw-json-string (buffer-substring url-http-end-of-headers (point-max)))
|
||||
;; decode json string
|
||||
(setq json-string (decode-coding-string (encode-coding-string raw-json-string 'utf-8) 'utf-8))
|
||||
(setq json-data (json-read-from-string json-string)))
|
||||
(with-current-buffer (find-file-noselect bibtex-file)
|
||||
(doi-utils-add-bibtex-entry-from-doi
|
||||
(replace-regexp-in-string
|
||||
"^https?://\\(dx.\\)?doi.org/" "" doi)
|
||||
bibtex-file)
|
||||
(save-buffer))))
|
||||
|
||||
(let* ((name (format "Crossref hits for %s"
|
||||
;; remove carriage returns. They can make completion confusing.
|
||||
(replace-regexp-in-string "\n" " " query)))
|
||||
(candidates (mapcar (lambda (x)
|
||||
(cons
|
||||
(concat
|
||||
(cdr (assoc 'fullCitation x)))
|
||||
(cdr (assoc 'doi x))))
|
||||
json-data))
|
||||
(doi (cdr (assoc (completing-read "Choice: " candidates) candidates))))
|
||||
(with-current-buffer (find-file-noselect bibtex-file)
|
||||
(doi-utils-add-bibtex-entry-from-doi
|
||||
(replace-regexp-in-string
|
||||
"^https?://\\(dx.\\)?doi.org/" "" doi)
|
||||
bibtex-file)
|
||||
(save-buffer)))))
|
||||
|
||||
(defalias 'crossref-add-bibtex-entry 'doi-utils-add-entry-from-crossref-query
|
||||
"Alias function for convenience.")
|
||||
|
||||
459
lisp/org-ref/openalex.el
Normal file
459
lisp/org-ref/openalex.el
Normal file
@@ -0,0 +1,459 @@
|
||||
;;; openalex.el --- Org-ref interface to OpenAlex
|
||||
|
||||
;;; Commentary:
|
||||
;; This is an elisp interface to OpenAlex (https://docs.openalex.org/) for org-ref.
|
||||
;;
|
||||
;; This provides functionality for the Work and Author API
|
||||
;;
|
||||
;; See
|
||||
;; https://docs.openalex.org/how-to-use-the-api/rate-limits-and-authentication#the-polite-pool
|
||||
;; for why we add email to the request.
|
||||
|
||||
(require 'dash)
|
||||
(require 'request)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defun oa--response-parser ()
|
||||
"Parse the response from json to elisp."
|
||||
(let ((json-array-type 'list)
|
||||
(json-object-type 'plist)
|
||||
(json-key-type 'keyword)
|
||||
(json-false nil)
|
||||
(json-encoding-pretty-print nil))
|
||||
(json-read)))
|
||||
|
||||
|
||||
;; * Work object
|
||||
|
||||
(defun oa--work (entity-id &optional filter)
|
||||
"Retrieve json data for a Work object for ENTITY-ID.
|
||||
ENTITY-ID is an OpenAlex ID, DOI, Pubmed id,etc.
|
||||
|
||||
ENTITY-ID may also be a list of ids with a filter.
|
||||
|
||||
If FILTER is non-nil it should be a string like \"filter=openalex:\"
|
||||
|
||||
https://docs.openalex.org/api-entities/works"
|
||||
|
||||
(let* ((url (concat "https://api.openalex.org/works"
|
||||
(if filter
|
||||
(concat "?" filter entity-id)
|
||||
(concat "/" entity-id))
|
||||
(if user-mail-address
|
||||
(concat "?mailto=" user-mail-address)
|
||||
"")))
|
||||
(req (request url :sync t :parser 'oa--response-parser))
|
||||
(data (request-response-data req)))
|
||||
;; this is for convenience to inspect data in a browser.
|
||||
(plist-put data :oa-url url)
|
||||
data))
|
||||
|
||||
|
||||
;; * Viewing works
|
||||
;;
|
||||
;; This section provides a replacer and helper function to format org-entries
|
||||
;; from the results returned in OpenAlex.
|
||||
|
||||
(defun oa--replacer (query object)
|
||||
"Replacer function for `s-format'.
|
||||
QUERY is a string that is either a sexp for a function to
|
||||
evaluate or a dot notation path to data in OBJECT. If QUERY is a
|
||||
sexp, it is read and evaluated. Otherwise, the path is split, and
|
||||
looked up sequentially in object.
|
||||
|
||||
OBJECT is a plist, usually from a Work request."
|
||||
(if (s-starts-with? "(" query)
|
||||
;; this is a function
|
||||
(eval (read query))
|
||||
;; just get data
|
||||
(let ((fields (s-split "\\." query))
|
||||
result)
|
||||
(while fields
|
||||
(setq object (plist-get object (intern-soft (concat ":" (pop fields))))))
|
||||
(or (string-replace "\\n" "" (format "%s" object)) "Not found"))))
|
||||
|
||||
|
||||
;; ** help functions for complex data
|
||||
;;
|
||||
;; Some things like authors need to be constructed, and cannot just be looked
|
||||
;; up. In other cases, I want logic, e.g. if data is there provide something,
|
||||
;; and if not return an empty string. These functions do that work.
|
||||
(defun oa--authors (wrk)
|
||||
"Return an author string for WRK.
|
||||
The string is a comma-separated list of links to author pages in OpenAlex."
|
||||
(s-join ", " (cl-loop for author in (plist-get wrk :authorships)
|
||||
collect
|
||||
(format "[[elisp:(oa-author \"%s\")][%s]]"
|
||||
(plist-get
|
||||
(plist-get author :author)
|
||||
:id)
|
||||
(plist-get
|
||||
(plist-get author :author)
|
||||
:display_name)))))
|
||||
|
||||
|
||||
;; I want some links if they can be made so the buffer is interactive. It might
|
||||
;; be nice to integrate M-, navigation.
|
||||
(defun oa--elisp-get-bibtex (wrk)
|
||||
"Return a elisp link to get a bibtex entry for WRK if there is a doi."
|
||||
(if-let ((doi (plist-get wrk :doi)))
|
||||
(format "[[elisp:(doi-add-bibtex-entry \"%s\")][Get bibtex entry]]" doi)
|
||||
""))
|
||||
|
||||
|
||||
(defun oa--elisp-get-oa-related (wrk)
|
||||
"Return a elisp link to get related works for WRK."
|
||||
(format "[[elisp:(progn (xref--push-markers) (oa--related-works \"%s\"))][Get related work (%s)]]"
|
||||
(plist-get wrk :id)
|
||||
(length (plist-get wrk :related_works))))
|
||||
|
||||
|
||||
(defun oa--elisp-get-oa-refs (wrk)
|
||||
"Return a elisp link to get references for WRK."
|
||||
(format "[[elisp:(progn (xref--push-markers) (oa--referenced-works \"%s\"))][Get references (%s)]]"
|
||||
(plist-get wrk :id)
|
||||
(length (plist-get wrk :referenced_works))))
|
||||
|
||||
|
||||
(defun oa--elisp-get-oa-cited-by (wrk)
|
||||
"Return a elisp link to get works that cite WRK."
|
||||
(format "[[elisp:(progn (xref--push-markers) (oa--cited-by-works \"%s\"))][Get cited by (%s)]]"
|
||||
(plist-get wrk :id)
|
||||
(plist-get wrk :cited_by_count)))
|
||||
|
||||
|
||||
(defun oa--works-entries (works)
|
||||
"Return a list of org-formatted entries in WORKS.
|
||||
WORKS is a list of results from OpenAlex."
|
||||
(cl-loop for wrk in (plist-get works :results)
|
||||
collect
|
||||
(s-format "** ${title}
|
||||
:PROPERTIES:
|
||||
:HOST: ${host_venue.display_name}
|
||||
:YEAR: ${publication_year}
|
||||
:CITED_BY_COUNT: ${cited_by_count}
|
||||
:AUTHOR: ${(oa--authors wrk)}
|
||||
:DOI: ${doi}
|
||||
:OPENALEX: ${id}
|
||||
:END:
|
||||
|
||||
|
||||
${(oa--elisp-get-bibtex wrk)}
|
||||
|
||||
- ${(oa--elisp-get-oa-refs wrk)}
|
||||
- ${(oa--elisp-get-oa-related wrk)}
|
||||
- ${(oa--elisp-get-oa-cited-by wrk)}
|
||||
|
||||
"
|
||||
'oa--replacer wrk)))
|
||||
|
||||
|
||||
(defun oa--works-buffer (bufname header entries)
|
||||
"Create an org-buffer with BUFNAME representing the results in WORKS.
|
||||
HEADER is the first thing in the buffer
|
||||
WORKS is usually a list of results from OpenAlex.
|
||||
Argument ENTRIES A list of strings for each org entry."
|
||||
(let ((buf (get-buffer-create bufname)))
|
||||
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
(insert header)
|
||||
(insert "#+COLUMNS: %25ITEM %YEAR %CITED_BY_COUNT
|
||||
elisp:org-columns elisp:org-columns-quit
|
||||
|
||||
|
||||
#+caption: Sort
|
||||
| year | [[elisp:(oa-buffer-sort-year t)][old first]] | [[elisp:(oa-buffer-sort-year)][new first]] |
|
||||
| cited by | [[elisp:(oa-buffer-sort-cited-by-count t)][low first]] | [[elisp:(oa-buffer-sort-cited-by-count)][high first]] |
|
||||
|
||||
")
|
||||
(insert (s-join "\n" entries))
|
||||
(org-mode)
|
||||
(goto-char (point-min))
|
||||
(org-next-visible-heading 1))
|
||||
;; (display-buffer-in-side-window buf '((side . right)))
|
||||
(pop-to-buffer buf)))
|
||||
|
||||
|
||||
;; There is something funny about pages here, maybe 25 results per page?
|
||||
;; https://docs.openalex.org/how-to-use-the-api/get-lists-of-entities/paging I
|
||||
;; am not sure how to do pages in this approach, so I am just getting these 25
|
||||
;; at a time.
|
||||
(defun oa--related-works (entity-id)
|
||||
"Show the Related works buffer for ENTITY-ID."
|
||||
(let* ((wrk (oa--work entity-id))
|
||||
(related-work (plist-get wrk :related_works))
|
||||
split
|
||||
entries)
|
||||
(while related-work
|
||||
(setq split (-split-at 25 related-work)
|
||||
related-work (nth 1 split))
|
||||
|
||||
;; split is what we process now
|
||||
(setq entries (append entries
|
||||
(oa--works-entries
|
||||
(oa--work (s-join "|" (nth 0 split))
|
||||
"filter=openalex:")))))
|
||||
|
||||
(oa--works-buffer
|
||||
"*OpenAlex - Related works*"
|
||||
(format "* OpenAlex - Related works for %s ([[%s][json]])
|
||||
%s\n\n"
|
||||
entity-id
|
||||
(plist-get wrk :oa-url)
|
||||
(s-format ":PROPERTIES:
|
||||
:TITLE: ${title}
|
||||
:HOST: ${host_venue.display_name}
|
||||
:AUTHOR: ${(oa--authors wrk)}
|
||||
:DOI: ${doi}
|
||||
:YEAR: ${publication_year}
|
||||
:OPENALEX: ${id}
|
||||
:END:" 'oa--replacer wrk))
|
||||
entries)))
|
||||
|
||||
|
||||
(defun oa--referenced-works (entity-id)
|
||||
"Show the Referenced work for ENTITY-ID."
|
||||
(let* ((wrk (oa--work entity-id))
|
||||
(referenced-work (plist-get wrk :referenced_works))
|
||||
split
|
||||
(entries '()))
|
||||
(while referenced-work
|
||||
(setq split (-split-at 25 referenced-work)
|
||||
referenced-work (nth 1 split))
|
||||
;; split is what we process now
|
||||
(setq entries (append entries
|
||||
(oa--works-entries
|
||||
(oa--work (s-join "|" (nth 0 split))
|
||||
"filter=openalex:")))))
|
||||
(oa--works-buffer
|
||||
"*OpenAlex - References*"
|
||||
(format "* OpenAlex - References from %s ([[%s][json]])
|
||||
%s\n\n"
|
||||
entity-id
|
||||
(plist-get wrk :oa-url)
|
||||
(s-format ":PROPERTIES:
|
||||
:TITLE: ${title}
|
||||
:HOST: ${host_venue.display_name}
|
||||
:AUTHOR: ${(oa--authors wrk)}
|
||||
:DOI: ${doi}
|
||||
:YEAR: ${publication_year}
|
||||
:OPENALEX: ${id}
|
||||
:END:" 'oa--replacer wrk))
|
||||
entries)))
|
||||
|
||||
|
||||
;; This function is different than the previous two. First we follow a URL
|
||||
;; provided by the data, and second, here we do follow pages.
|
||||
(defun oa--cited-by-works (entity-id)
|
||||
"Show the Cited by buffer for ENTITY-ID."
|
||||
(let* ((wrk (oa--work entity-id))
|
||||
(url (plist-get wrk :cited_by_api_url))
|
||||
(cited-by-works (request-response-data
|
||||
(request url
|
||||
:sync t
|
||||
:parser 'oa--response-parser)))
|
||||
(count (plist-get (plist-get cited-by-works :meta) :count))
|
||||
(per-page (plist-get (plist-get cited-by-works :meta) :per_page))
|
||||
(entries '())
|
||||
(page 2))
|
||||
;; get first page
|
||||
(setq entries (oa--works-entries cited-by-works))
|
||||
(while (> count (* per-page (- page 1)))
|
||||
(setq cited-by-works (request-response-data
|
||||
(request (format "%s&page=%s" url page)
|
||||
:sync t
|
||||
:parser 'oa--response-parser)))
|
||||
(setq entries (append entries (oa--works-entries cited-by-works)))
|
||||
(cl-incf page))
|
||||
|
||||
(oa--works-buffer
|
||||
"*OpenAlex - Cited by*"
|
||||
(format "* OpenAlex - %s Cited by ([[%s][json]])
|
||||
%s"
|
||||
entity-id
|
||||
url
|
||||
(s-format ":PROPERTIES:
|
||||
:TITLE: ${title}
|
||||
:HOST: ${host_venue.display_name}
|
||||
:AUTHOR: ${(oa--authors wrk)}
|
||||
:DOI: ${doi}
|
||||
:YEAR: ${publication_year}
|
||||
:OPENALEX: ${id}
|
||||
:END:\n\n" 'oa--replacer wrk))
|
||||
entries)))
|
||||
|
||||
|
||||
;; ** buffer utilities for sorting entries
|
||||
|
||||
(defun oa-buffer-sort-year (&optional ascending)
|
||||
"Sort org headings by year in descending order (new to old).
|
||||
With prefix arg ASCENDING, sort in ascending order (old to new)"
|
||||
(interactive "P")
|
||||
(if ascending
|
||||
(org-sort-entries nil ?f
|
||||
(lambda () (string-to-number (or (org-entry-get (point) "YEAR") "0")))
|
||||
(lambda (y1 y2)
|
||||
(< y1 y2)))
|
||||
(org-sort-entries nil ?f
|
||||
(lambda () (string-to-number (or (org-entry-get (point) "YEAR") "0")))
|
||||
(lambda (y1 y2)
|
||||
(> y1 y2)))))
|
||||
|
||||
|
||||
(defun oa-buffer-sort-cited-by-count (&optional ascending)
|
||||
"Sort orgheadings by cited by count in descending order high to low.
|
||||
With prefix arg ASCENDING sort from low to high."
|
||||
(interactive "P")
|
||||
(if ascending
|
||||
(org-sort-entries nil ?f
|
||||
(lambda ()
|
||||
(string-to-number
|
||||
(or (org-entry-get (point) "CITED_BY_COUNT")
|
||||
"0")))
|
||||
#'<)
|
||||
(org-sort-entries nil ?f
|
||||
(lambda ()
|
||||
(string-to-number
|
||||
(or
|
||||
(org-entry-get (point) "CITED_BY_COUNT")
|
||||
"0")))
|
||||
#'>)))
|
||||
|
||||
|
||||
;; * Interactive versions for org-ref citations
|
||||
|
||||
(defun oa-related-works ()
|
||||
"Open the side window for Related works on cite at point."
|
||||
(interactive)
|
||||
(oa--related-works (concat "doi:" (org-ref-get-doi-at-point))))
|
||||
|
||||
|
||||
(defun oa-referenced-works ()
|
||||
"Open the side window for References from the cite at point."
|
||||
(interactive)
|
||||
(oa--referenced-works (concat "doi:" (org-ref-get-doi-at-point))))
|
||||
|
||||
|
||||
(defun oa-cited-by-works ()
|
||||
"Open the side window for Citing works for the cite at point."
|
||||
(interactive)
|
||||
(oa--cited-by-works (concat "doi:" (org-ref-get-doi-at-point))))
|
||||
|
||||
|
||||
(defhydra+ org-ref-citation-hydra () ("ar" oa-related-works "Related documents" :column "OpenAlex"))
|
||||
(defhydra+ org-ref-citation-hydra () ("ac" oa-cited-by-works "Cited by documents" :column "OpenAlex"))
|
||||
(defhydra+ org-ref-citation-hydra () ("af" oa-referenced-works "References from" :column "OpenAlex"))
|
||||
|
||||
|
||||
;; * utilities
|
||||
|
||||
(defun oa-kill-buffers ()
|
||||
"Kill OpenAlex buffers."
|
||||
(interactive)
|
||||
(cl-loop for buf in (buffer-list)
|
||||
do
|
||||
(when (s-starts-with? "*OpenAlex" (buffer-name buf))
|
||||
(kill-buffer buf))))
|
||||
|
||||
;; * Author object
|
||||
|
||||
(defun oa--author (entity-id &optional filter)
|
||||
"Get an Author object for entity-id"
|
||||
(let* ((url (concat "https://api.openalex.org/authors"
|
||||
(if filter
|
||||
(concat "?" filter entity-id)
|
||||
(concat "/" entity-id))
|
||||
(if user-mail-address
|
||||
(concat "?mailto=" user-mail-address)
|
||||
"")))
|
||||
(req (request url :sync t :parser 'oa--response-parser))
|
||||
(data (request-response-data req)))
|
||||
;; this is for convenience to inspect data in a browser.
|
||||
(plist-put data :oa-url url)
|
||||
data))
|
||||
|
||||
|
||||
(defun oa-author-entries (works-data url)
|
||||
"Get entries from WORKS-DATA."
|
||||
(let* ((meta (plist-get works-data :meta))
|
||||
(per-page (plist-get meta :per_page))
|
||||
(count (plist-get meta :count))
|
||||
(pages (/ count per-page))
|
||||
(entries '())
|
||||
purl)
|
||||
;; if there is a remainder we need to get the rest
|
||||
(when (> (mod count per-page) 0) (cl-incf pages))
|
||||
|
||||
;; Now we have to loop through the pages
|
||||
(cl-loop for i from 1 to pages
|
||||
do
|
||||
(setq purl (concat url (format "&page=%s" i))
|
||||
works-data (request-response-data
|
||||
(request purl
|
||||
:sync t
|
||||
:parser 'oa--response-parser))
|
||||
entries (append entries
|
||||
(cl-loop for result in (plist-get works-data :results)
|
||||
collect
|
||||
(s-format "** ${title}
|
||||
:PROPERTIES:
|
||||
:ID: ${id}
|
||||
:DOI: ${ids.doi}
|
||||
:YEAR: ${publication_year}
|
||||
:HOST_VENUE: ${host_venue.display_name}
|
||||
:AUTHORS: ${(oa--authors result)}
|
||||
:CITED_BY_COUNT: ${cited_by_count}
|
||||
:END:
|
||||
|
||||
${(oa--elisp-get-bibtex result)}
|
||||
|
||||
- ${(oa--elisp-get-oa-refs result)}
|
||||
- ${(oa--elisp-get-oa-related result)}
|
||||
- ${(oa--elisp-get-oa-cited-by result)}
|
||||
|
||||
" 'oa--replacer result)))))
|
||||
entries))
|
||||
|
||||
|
||||
(defun oa-author (entity-id)
|
||||
"View Author for ENTITY-ID in an org-buffer."
|
||||
(let* ((buf (get-buffer-create "*OpenAlex - Author*"))
|
||||
(data (oa--author entity-id))
|
||||
(works-count (plist-get data :works_count))
|
||||
(works-url (plist-get data :works_api_url))
|
||||
(works-data (request-response-data
|
||||
(request works-url
|
||||
:sync t
|
||||
:parser 'oa--response-parser))))
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
(insert (s-format "* ${display_name} ([[${oa-url}][json]])
|
||||
:PROPERTIES:
|
||||
:ORCID: ${orcid}
|
||||
:SCOPUS: ${ids.scopus}
|
||||
:WORKS_COUNT: ${works_count}
|
||||
:CITED_BY_COUNT: ${cited_by_count}
|
||||
:INSTITUTION: ${last_known_institution.display_name}, ${last_known_institution.country_code}
|
||||
:END:
|
||||
|
||||
#+COLUMNS: %25ITEM %YEAR %CITED_BY_COUNT
|
||||
elisp:org-columns elisp:org-columns-quit
|
||||
|
||||
#+caption: Sort
|
||||
| year | [[elisp:(oa-buffer-sort-year t)][old first]] | [[elisp:(oa-buffer-sort-year)][new first]] |
|
||||
| cited by | [[elisp:(oa-buffer-sort-cited-by-count t)][low first]] | [[elisp:(oa-buffer-sort-cited-by-count)][high first]] |
|
||||
|
||||
"
|
||||
'oa--replacer data))
|
||||
(insert (s-join "\n" (oa-author-entries works-data works-url)))
|
||||
(org-mode)
|
||||
(goto-char (point-min))
|
||||
(org-next-visible-heading 1))
|
||||
(pop-to-buffer buf)))
|
||||
|
||||
|
||||
(provide 'openalex)
|
||||
|
||||
;;; openalex.el ends here
|
||||
@@ -261,7 +261,7 @@ Returns `org-ref-bst-styles' or sets it and returns it."
|
||||
(mapcar (lambda (path)
|
||||
(setq path (replace-regexp-in-string "!" "" path))
|
||||
(when (file-directory-p path)
|
||||
(f-entries path (lambda (f) (f-ext? f "bst")) t)))
|
||||
(f-entries path (lambda (f) (f-ext? f "bst")))))
|
||||
(split-string
|
||||
;; https://tex.stackexchange.com/questions/431948/get-a-list-of-installed-bibliography-styles-with-kpsewhich?noredirect=1#comment1082436_431948
|
||||
(shell-command-to-string "kpsewhich -expand-path '$BSTINPUTS'")
|
||||
|
||||
@@ -1005,7 +1005,7 @@ keywords. Optional argument ARG prefix arg to replace keywords."
|
||||
(if (listp keywords)
|
||||
(mapconcat 'identity keywords ", ")
|
||||
keywords)
|
||||
;; else concatentate
|
||||
;; else concatenate
|
||||
(concat
|
||||
(if (listp keywords)
|
||||
(mapconcat 'identity keywords ", ")
|
||||
@@ -1209,13 +1209,13 @@ will clobber the file."
|
||||
;;** Clean a bibtex entry
|
||||
;; These functions operate on a bibtex entry and "clean" it in some way.
|
||||
|
||||
(defun orcb-clean-nil (arg)
|
||||
(defun orcb-clean-nil (&optional arg)
|
||||
"Remove nil from some article fields.
|
||||
The removal is conditional. Sometimes it is useful to have nil
|
||||
around, e.g. for ASAP articles where the fields are not defined
|
||||
yet but will be in the future.
|
||||
|
||||
With \\[univeral-argument], run `bibtex-clean-entry' after."
|
||||
With \\[universal-argument], run `bibtex-clean-entry' after."
|
||||
(interactive "P")
|
||||
(bibtex-beginning-of-entry)
|
||||
(let* ((entry (bibtex-parse-entry))
|
||||
@@ -1405,6 +1405,16 @@ If not, issue a warning."
|
||||
(doi-utils-get-bibtex-entry-pdf))))
|
||||
|
||||
|
||||
(defun orcb-clean-<>-tags ()
|
||||
"Try removing <tags> from the entry."
|
||||
(sgml-mode)
|
||||
(ignore-errors
|
||||
(while (sgml-skip-tag-forward 1)
|
||||
(sgml-skip-tag-backward 1)
|
||||
(sgml-delete-tag 1)))
|
||||
(bibtex-mode))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun org-ref-clean-bibtex-entry ()
|
||||
"Clean and replace the key in a bibtex entry.
|
||||
|
||||
@@ -158,7 +158,7 @@ Set this to nil to turn that off, which increase performance."
|
||||
("Smartcite" "like parencite in a footnote, and footcite in the body with capitalization")
|
||||
("cite*" "similar to cite, but prints the year or title")
|
||||
("parencite*" "similar to parencite, but prints the year or title")
|
||||
("supercite" "superscripted numeric citation (only in numberic styles)")
|
||||
("supercite" "superscripted numeric citation (only in numeric styles)")
|
||||
|
||||
("autocite" "handles some punctuation nuances")
|
||||
("Autocite" "handles some punctuation nuances with punctuation")
|
||||
@@ -296,7 +296,7 @@ Set this to nil to turn that off, which increase performance."
|
||||
(3 (let ((citation-references (split-string path ";"))
|
||||
(these-results '(:version 3)))
|
||||
;; if the first ref doesn't match a key, it must be a global prefix
|
||||
;; this pops the referenc off.
|
||||
;; this pops the reference off.
|
||||
(when (null (string-match org-ref-citation-key-re (cl-first citation-references)))
|
||||
(setq these-results (append these-results (list :prefix (cl-first citation-references)))
|
||||
citation-references (cdr citation-references)))
|
||||
@@ -543,6 +543,7 @@ PATH has the citations in it."
|
||||
(bibtex-copy-entry-as-kill)
|
||||
(kill-new (pop bibtex-entry-kill-ring))))
|
||||
"Copy bibtex" :column "Copy")
|
||||
("a" org-ref-add-pdf-at-point "add pdf to library" :column "Copy")
|
||||
("k" (kill-new (car (org-ref-get-bibtex-key-and-file))) "Copy key" :column "Copy")
|
||||
("f" (kill-new (bibtex-completion-apa-format-reference
|
||||
(org-ref-get-bibtex-key-under-cursor)))
|
||||
@@ -930,16 +931,20 @@ arg COMMON, edit the common prefixes instead."
|
||||
(setq prefix (concat
|
||||
(read-string "prenote: "
|
||||
(string-trim
|
||||
(plist-get
|
||||
(nth index (plist-get data :references))
|
||||
:prefix)))
|
||||
(or
|
||||
(plist-get
|
||||
(nth index (plist-get data :references))
|
||||
:prefix)
|
||||
"")))
|
||||
" ")
|
||||
suffix (concat " "
|
||||
(read-string "postnote: "
|
||||
(string-trim
|
||||
(plist-get
|
||||
(nth index (plist-get data :references))
|
||||
:suffix))))
|
||||
(or
|
||||
(plist-get
|
||||
(nth index (plist-get data :references))
|
||||
:suffix)
|
||||
""))))
|
||||
delta (- (length (plist-get
|
||||
(nth index (plist-get data :references))
|
||||
:prefix))
|
||||
@@ -955,8 +960,8 @@ arg COMMON, edit the common prefixes instead."
|
||||
nil suffix))))
|
||||
|
||||
|
||||
(setf (buffer-substring (org-element-property :begin cite) (org-element-property :end cite))
|
||||
(format "[[%s:%s]]" type (org-ref-interpret-cite-data data)))
|
||||
(cl--set-buffer-substring (org-element-property :begin cite) (org-element-property :end cite)
|
||||
(format "[[%s:%s]]" type (org-ref-interpret-cite-data data)))
|
||||
|
||||
;; This doesn't exactly save the point. I need a fancier calculation for
|
||||
;; that I think that accounts for the change due to the prefix change. e.g.
|
||||
@@ -995,41 +1000,79 @@ arg COMMON, edit the common prefixes instead."
|
||||
(defun org-ref-get-bibtex-key-under-cursor ()
|
||||
"Return key under the cursor in org-mode.
|
||||
If not on a key, but on a cite, prompt for key."
|
||||
(if-let ((key (get-text-property (point) 'cite-key)))
|
||||
;; Point is on a key, so we get it directly
|
||||
key
|
||||
;; point is not on a key, but may still be on a cite link
|
||||
(let ((el (org-element-context))
|
||||
data
|
||||
keys)
|
||||
(cond
|
||||
;; on a cite-link type
|
||||
((and
|
||||
(eq (org-element-type el) 'link)
|
||||
(assoc (org-element-property :type el) org-ref-cite-types))
|
||||
|
||||
(goto-char (org-element-property :begin el))
|
||||
(setq data (org-ref-parse-cite-path (org-element-property :path el))
|
||||
keys (cl-loop for ref in (plist-get data :references)
|
||||
collect (plist-get ref :key)))
|
||||
(cond
|
||||
(org-ref-activate-cite-links
|
||||
(if-let ((key (get-text-property (point) 'cite-key)))
|
||||
;; Point is on a key, so we get it directly
|
||||
key
|
||||
;; point is not on a key, but may still be on a cite link
|
||||
(let ((el (org-element-context))
|
||||
(cp (point))
|
||||
data
|
||||
keys)
|
||||
(cond
|
||||
((= 1 (length keys))
|
||||
(search-forward (car keys))
|
||||
(goto-char (match-beginning 0)))
|
||||
;; multiple keys
|
||||
(t
|
||||
(setq key (completing-read "Key: " keys))
|
||||
(search-forward key)
|
||||
(goto-char (match-beginning 0))))
|
||||
(get-text-property (point) 'cite-key))
|
||||
;; on a cite-link type
|
||||
((and
|
||||
(eq (org-element-type el) 'link)
|
||||
(assoc (org-element-property :type el) org-ref-cite-types))
|
||||
|
||||
;; somewhere else, but looking at a cite-type see issue #908. links in
|
||||
;; places like keywords are not parsed as links, but they seem to get
|
||||
;; activated, so we can just get onto the key, and then open it.
|
||||
((assoc (thing-at-point 'word) org-ref-cite-types)
|
||||
(save-excursion
|
||||
(when (re-search-forward ":" (line-end-position) t)
|
||||
(get-text-property (point) 'cite-key))))))))
|
||||
(goto-char (org-element-property :begin el))
|
||||
(setq data (org-ref-parse-cite-path (org-element-property :path el))
|
||||
keys (cl-loop for ref in (plist-get data :references)
|
||||
collect (plist-get ref :key)))
|
||||
(cond
|
||||
((= 1 (length keys))
|
||||
(search-forward (car keys))
|
||||
(goto-char (match-beginning 0)))
|
||||
;; multiple keys
|
||||
(t
|
||||
(setq key (completing-read "Key: " keys))
|
||||
(search-forward key)
|
||||
(goto-char (match-beginning 0))))
|
||||
(prog1
|
||||
(get-text-property (point) 'cite-key)
|
||||
(goto-char cp)))
|
||||
|
||||
;; somewhere else, but looking at a cite-type see issue #908. links in
|
||||
;; places like keywords are not parsed as links, but they seem to get
|
||||
;; activated, so we can just get onto the key, and then open it.
|
||||
((assoc (thing-at-point 'word) org-ref-cite-types)
|
||||
(save-excursion
|
||||
(when (re-search-forward ":" (line-end-position) t)
|
||||
(prog1
|
||||
(get-text-property (point) 'cite-key)
|
||||
(goto-char cp)))))))))
|
||||
|
||||
;; org-ref-activate-cite-links is nil so font-lock does not put
|
||||
;; text-properties on keys. We temporarily activate this
|
||||
|
||||
(t
|
||||
(let ((el (org-element-context))
|
||||
(cp (point))
|
||||
(org-ref-activate-cite-links t) ;; temporary
|
||||
data
|
||||
keys
|
||||
)
|
||||
(and
|
||||
(eq (org-element-type el) 'link)
|
||||
(assoc (org-element-property :type el) org-ref-cite-types))
|
||||
(save-excursion
|
||||
;; We activate just this one link
|
||||
(org-ref-cite-activate
|
||||
(org-element-property :begin el)
|
||||
(org-element-property :end el)
|
||||
(org-element-property :path el)
|
||||
nil))
|
||||
;; Now we have to handle some cases.
|
||||
(cond
|
||||
;; on a key, return a key
|
||||
((get-text-property (point) 'cite-key)
|
||||
(get-text-property (point) 'cite-key))
|
||||
;; not on a key, but on a cite. this is lazy, but we just search forward
|
||||
;; to the first key
|
||||
(t
|
||||
(search-forward ":")
|
||||
(get-text-property (point) 'cite-key)))))))
|
||||
|
||||
|
||||
;; ** Shift-arrow sorting of keys in a cite link
|
||||
@@ -1097,7 +1140,8 @@ If not on a key, but on a cite, prompt for key."
|
||||
(link-string (org-element-property :path object))
|
||||
(data (org-ref-parse-cite-path link-string))
|
||||
(references (plist-get data :references))
|
||||
(bibtex-completion-bibliography (org-ref-find-bibliography)))
|
||||
(bibtex-completion-bibliography (org-ref-find-bibliography))
|
||||
current-point)
|
||||
|
||||
(setq references (cl-sort (cl-loop for ref in references collect
|
||||
(append ref (list :year (bibtex-completion-get-value
|
||||
@@ -1107,11 +1151,12 @@ If not on a key, but on a cite, prompt for key."
|
||||
(lambda (x y)
|
||||
(< (string-to-number (plist-get x :year))
|
||||
(string-to-number (plist-get y :year))))))
|
||||
(setq data (plist-put data :references references))
|
||||
(save-excursion
|
||||
(goto-char begin)
|
||||
(re-search-forward link-string)
|
||||
(replace-match (org-ref-interpret-cite-data data)))))
|
||||
(setq data (plist-put data :references references)
|
||||
current-point (point))
|
||||
(goto-char begin)
|
||||
(re-search-forward link-string)
|
||||
(replace-match (org-ref-interpret-cite-data data))
|
||||
(goto-char current-point)))
|
||||
|
||||
|
||||
;;** C-arrow navigation of cite keys
|
||||
@@ -1369,10 +1414,10 @@ Here is an example use:
|
||||
(plist-put data :prefix (cl-first prefix-suffix))
|
||||
(plist-put data :suffix (cl-second prefix-suffix)))
|
||||
(plist-put data :version 3)
|
||||
(setf (buffer-substring (org-element-property :begin cite)
|
||||
(org-element-property :end cite))
|
||||
(format "[[%s:%s]]" (org-element-property :type cite)
|
||||
(org-ref-interpret-cite-data data))))))
|
||||
(cl--set-buffer-substring (org-element-property :begin cite)
|
||||
(org-element-property :end cite)
|
||||
(format "[[%s:%s]]" (org-element-property :type cite)
|
||||
(org-ref-interpret-cite-data data))))))
|
||||
|
||||
|
||||
(provide 'org-ref-citation-links)
|
||||
|
||||
94
lisp/org-ref/org-ref-compat.el
Normal file
94
lisp/org-ref/org-ref-compat.el
Normal file
@@ -0,0 +1,94 @@
|
||||
;;; org-ref-compat.el --- Compatibility functions for org-cite
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; The main function of this library is to provide compatibility functions for
|
||||
;; converting between org-ref and org-cite.
|
||||
|
||||
(require 'org-ref-export)
|
||||
|
||||
|
||||
(defcustom org-ref-to-org-cite-mapping
|
||||
'(("cite" . "")
|
||||
("citep" . "")
|
||||
("Citep" . "//caps-full")
|
||||
("citealp" . "//bare")
|
||||
("Citealp" . "//bare-caps")
|
||||
("Citealp*" . "//bare-caps-full")
|
||||
("citep*" . "//full")
|
||||
|
||||
("citet" . "/text")
|
||||
|
||||
("citeyear" . "/noauthor/bare")
|
||||
("citeyearpar" . "/noauthor")
|
||||
|
||||
("nocite" . "/nocite")
|
||||
|
||||
("citeauthor" . "/author")
|
||||
("citeauthor*" . "/author/full")
|
||||
("Citeauthor" . "/author/caps"))
|
||||
|
||||
"A-list of (org-ref-type . org-cite-style).
|
||||
This builds from
|
||||
https://blog.tecosaur.com/tmio/2021-07-31-citations.html#cite-syntax.
|
||||
There is no way to get them all though, there are conflicting
|
||||
translations with some biblatex and some natbib commands. This
|
||||
list maps the natbib commands. I have also opted to use the full
|
||||
names rather than the short names."
|
||||
:group 'org-ref)
|
||||
|
||||
|
||||
(defun org-ref-to-org-cite ()
|
||||
(interactive)
|
||||
(let ((ref-cites (reverse (org-ref-get-cite-links)))
|
||||
ref-type
|
||||
path
|
||||
beg end)
|
||||
;; This takes care of the cite links
|
||||
(cl-loop for rc in ref-cites do
|
||||
(setq
|
||||
type (org-element-property :type rc)
|
||||
path (org-element-property :path rc)
|
||||
beg (org-element-property :begin rc)
|
||||
end (org-element-property :end rc))
|
||||
(cl--set-buffer-substring
|
||||
beg end
|
||||
(format "[cite%s:%s]"
|
||||
(or (cdr (assoc type org-ref-to-org-cite-mapping)) "")
|
||||
;; This is not 100% correct, if someone has put an extra &
|
||||
;; anywhere in a note, this will be a little wrong. It
|
||||
;; would be a little more correct if I also look for a
|
||||
;; word next to it. The most correct would probably be to
|
||||
;; build the data and then use org-element interpret I
|
||||
;; think
|
||||
(replace-regexp-in-string "&" "@" path))))
|
||||
|
||||
;; Next replace bibliography links. I assume the paths are ok, and we just
|
||||
;; need to convert them to keywords.
|
||||
(cl-loop for bib-link in
|
||||
(reverse (org-element-map (org-element-parse-buffer) 'link
|
||||
(lambda (bl)
|
||||
(when (member (org-element-property :type bl)
|
||||
'("bibliography" "nobibliography"))
|
||||
bl))))
|
||||
do
|
||||
(cl--set-buffer-substring
|
||||
(org-element-property :begin bib-link)
|
||||
(org-element-property :end bib-link)
|
||||
(format "#+bibliography: %s%s"
|
||||
(org-element-property :path bib-link)
|
||||
(if (string= "bibliography"
|
||||
(org-element-property :type bib-link))
|
||||
"\n#+print_bibliography:"
|
||||
""))))
|
||||
;; Note it is a bit ambiguous what do do about where the bibliography is to
|
||||
;; be printed. This should be done via #+print_bibliography:. In org-ref the
|
||||
;; bibliography normally goes where the bibliography link was, and I sue
|
||||
;; that convention.
|
||||
|
||||
))
|
||||
|
||||
|
||||
(provide 'org-ref-compat)
|
||||
|
||||
;;; org-ref-compat.el ends here
|
||||
@@ -389,7 +389,7 @@ BACKEND is the org export backend."
|
||||
;;
|
||||
;; Here we add style css for html output.
|
||||
(cond
|
||||
((eq 'html backend)
|
||||
((or (eq 'html backend) (eq 'html csl-backend))
|
||||
(let ((s1 "")
|
||||
(s2 ""))
|
||||
(when (cdr (assq 'second-field-align bib-parameters))
|
||||
|
||||
190
lisp/org-ref/org-ref-extract.el
Normal file
190
lisp/org-ref/org-ref-extract.el
Normal file
@@ -0,0 +1,190 @@
|
||||
;;; org-ref-extract.el --- Extract BibTeX from HTML -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2023 Justus Piater
|
||||
|
||||
;; Author: Justus Piater <Justus-dev@Piater.name>
|
||||
;; 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:
|
||||
|
||||
;;
|
||||
|
||||
|
||||
(defun org-ref--extract (html-buffer rx num)
|
||||
"Return content matched within HTML-BUFFER by RX at parenthesized
|
||||
sub-expression NUM."
|
||||
(with-current-buffer html-buffer
|
||||
(goto-char (point-min))
|
||||
(if (re-search-forward rx nil t)
|
||||
(match-string num)
|
||||
nil)))
|
||||
|
||||
|
||||
(defun org-ref--get-pdf (pdf-url)
|
||||
"For BibTeX entry at point, if not already present, get PDF, place
|
||||
it in`bibtex-completion-library-path', and add a corresponding
|
||||
FILE field to the entry."
|
||||
(bibtex-beginning-of-entry)
|
||||
(let* ((key (cdr (assoc "=key=" (bibtex-parse-entry))))
|
||||
(pdf-file (concat (car bibtex-completion-library-path) key ".pdf")))
|
||||
(unless (file-exists-p pdf-file)
|
||||
(url-copy-file pdf-url pdf-file)
|
||||
(if (org-ref-pdf-p pdf-file)
|
||||
(message "%s saved" pdf-file)
|
||||
(delete-file pdf-file)
|
||||
(message "No pdf was downloaded.")
|
||||
(browse-url pdf-url)))
|
||||
(when (file-exists-p pdf-file)
|
||||
(bibtex-set-field "file" pdf-file)
|
||||
(when doi-utils-open-pdf-after-download
|
||||
(org-open-file pdf-file)))))
|
||||
|
||||
|
||||
(defun org-ref--extract-entry-from-html
|
||||
(html-buffer bibtex pdf-url &rest more-fields)
|
||||
"At point, create a BibTeX entry using information extracted
|
||||
from the HTML-BUFFER, and kill HTML-BUFFER."
|
||||
(bibtex-mode)
|
||||
(let ((bibtex (if (consp bibtex)
|
||||
(org-ref--extract html-buffer (car bibtex) (cdr bibtex))
|
||||
bibtex))
|
||||
(pdf-url (if (consp pdf-url)
|
||||
(org-ref--extract html-buffer (car pdf-url) (cdr pdf-url))
|
||||
pdf-url))
|
||||
(more-fields
|
||||
(mapcar
|
||||
(lambda (field)
|
||||
(cons (car field)
|
||||
(if (consp (cdr field))
|
||||
(org-ref--extract html-buffer (cadr field) (cddr field))
|
||||
(cdr field))))
|
||||
more-fields)))
|
||||
(insert bibtex)
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "{\\n" nil t)
|
||||
(replace-match "{"))
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "\\n" nil t)
|
||||
(replace-match "\n"))
|
||||
(org-ref-clean-bibtex-entry)
|
||||
(dolist (pair more-fields)
|
||||
(when (cdr pair)
|
||||
(bibtex-set-field (car pair) (cdr pair))))
|
||||
(org-ref--get-pdf pdf-url))
|
||||
(kill-buffer html-buffer))
|
||||
|
||||
|
||||
(defun org-ref--html-buffer (url)
|
||||
"Retrieve resource from URL, decode it, substitute XML entities,
|
||||
and return the buffer."
|
||||
(with-current-buffer (generate-new-buffer "org-ref--html")
|
||||
(let ((url-request-method "GET"))
|
||||
(url-insert (url-retrieve-synchronously url)))
|
||||
(goto-char (point-min))
|
||||
(insert (xml-substitute-special (buffer-string)))
|
||||
(delete-region (point) (point-max))
|
||||
(current-buffer)))
|
||||
|
||||
|
||||
(defun org-ref-extract-from-openreview (id)
|
||||
"At point, create a BibTeX entry for the given OpenReview ID."
|
||||
(interactive "MOpenReview ID: ")
|
||||
(let* ((url (concat "https://openreview.net/forum?id=" id))
|
||||
(html-buffer (org-ref--html-buffer url)))
|
||||
(org-ref--extract-entry-from-html
|
||||
html-buffer
|
||||
'("\"_bibtex\":\"\\(@.+?}\\)\"" . 1)
|
||||
(replace-regexp-in-string "forum" "pdf" url)
|
||||
'("abstract" .
|
||||
("<meta name=\"citation_abstract\" content=\"\\(.+?\\(\n.*?\\)*?\\)\"/>" . 1))
|
||||
'("area" .
|
||||
("\"Please_choose_the_closest_area_that_your_submission_falls_into\":\"\\(.+?\\)\"" . 1))
|
||||
'("keywords" . ("Keywords.*?\"note-content-value\">\\(.+?\\)</span>" . 1))
|
||||
'("summary" .
|
||||
("\\(Summary\\|TL;DR\\).*?\"note-content-value\">\\(.+?\\)</span>" . 2))
|
||||
;; Should we proactively download supplementary materials too?
|
||||
(cons "supp"
|
||||
(if-let ((supp (org-ref--extract
|
||||
html-buffer
|
||||
">Supplementary Material<.*?href=\"\\([^\"]+\\)" 1)))
|
||||
(concat "https://openreview.net" supp))))))
|
||||
|
||||
|
||||
(defun org-ref-extract-from-pmlr (url)
|
||||
"At point, create a BibTeX entry for the given PMLR URL."
|
||||
(interactive "MPMLR URL: ")
|
||||
(org-ref--extract-entry-from-html
|
||||
(org-ref--html-buffer url)
|
||||
'("id=\"bibtex\">\n\\(@.+\\(\n.*?\\)+?\\)\n</" . 1)
|
||||
'("{\\(http.+\\.pdf\\)}" . 1)
|
||||
;; Should we proactively download supplementary materials too?
|
||||
'("supp" . ("href=\"\\(https?://proceedings\\.mlr\\.press/[^\"]+?-supp[^\"]*?\\)\".*?>Supplementary PDF</" . 1))))
|
||||
|
||||
|
||||
(defun org-ref-extract-from-neurips (url)
|
||||
"At point, create a BibTeX entry for the given NeurIPS Abstract URL."
|
||||
(interactive "MNeurIPS Abstract URL: ")
|
||||
(let ((hash (progn (string-match "/\\([0-9a-f]+\\)-" url)
|
||||
(match-string 1 url)))
|
||||
(neurips-url "https://proceedings.neurips.cc")
|
||||
(html-buffer (org-ref--html-buffer url))
|
||||
(bibtex))
|
||||
(with-current-buffer html-buffer
|
||||
(goto-char (point-min))
|
||||
(re-search-forward "href=[\"']\\([^\"']+bibtex[^\"']*\\)[\"']")
|
||||
(let ((bibtex-url (match-string 1)))
|
||||
(with-temp-buffer
|
||||
(url-insert
|
||||
(url-retrieve-synchronously (concat neurips-url bibtex-url)))
|
||||
(setq bibtex (buffer-string)))))
|
||||
(org-ref--extract-entry-from-html
|
||||
html-buffer
|
||||
bibtex
|
||||
(concat neurips-url
|
||||
(org-ref--extract html-buffer
|
||||
"href=[\"']\\([^\"']+-Paper[^\"']*\\)[\"']" 1))
|
||||
(cons "url" url)
|
||||
'("abstract" . ("<h4>Abstract</h4>[ \n]*?\\(<p>\\)+\\(.+?\\)</p>" . 2))
|
||||
;; Should we proactively download supplementary materials too?
|
||||
(cons "supp"
|
||||
(if-let
|
||||
((supp (org-ref--extract
|
||||
html-buffer
|
||||
"href=[\"']\\([^\"']+-Supplemental[^\"']*\\)[\"']" 1)))
|
||||
(concat neurips-url supp))))))
|
||||
|
||||
|
||||
(defun org-ref-extract-from-cvf (url)
|
||||
"At point, create a BibTeX entry for the given CVF HTML URL."
|
||||
(interactive "MCVF HTML URL: ")
|
||||
(let ((cvf-url "https://openaccess.thecvf.com")
|
||||
(html-buffer (org-ref--html-buffer url)))
|
||||
(org-ref--extract-entry-from-html
|
||||
html-buffer
|
||||
'("class=\"bibref[^\"]*\">[ \n]*\\(@.+?\\(\n.*?\\)+?\\)[ \n]*</" . 1)
|
||||
(concat cvf-url (org-ref--extract
|
||||
html-buffer "<a href=[\"']\\([^\"']+\\)[\"']>pdf</a>" 1))
|
||||
(cons "url" url)
|
||||
'("abstract" . ("id=\"abstract\">[ \n]*\\([^<]+\\)[ \n]*</" . 1))
|
||||
;; Should we proactively download supplementary materials too?
|
||||
(cons "supp" (concat cvf-url
|
||||
(org-ref--extract html-buffer
|
||||
"href=[\"']\\([^\"']+\\)[\"']>supp</"
|
||||
1))))))
|
||||
|
||||
|
||||
(provide 'org-ref-extract)
|
||||
;;; org-ref-extract.el ends here
|
||||
@@ -429,13 +429,13 @@ This is intended to be run in `org-export-before-parsing-hook'."
|
||||
(nthcdr 2 (org-babel-read-table))))))))))
|
||||
;; Delete the table
|
||||
(when entries
|
||||
(setf (buffer-substring begin end) "")
|
||||
(cl--set-buffer-substring begin end ""))
|
||||
|
||||
(goto-char (point-min))
|
||||
(cl-loop for (label name description) in entries
|
||||
do
|
||||
(insert (format "#+latex_header_extra: \\newglossaryentry{%s}{name=%s,description={{%s}}}\n"
|
||||
label name description)))))))
|
||||
(goto-char (point-min))
|
||||
(cl-loop for (label name description) in entries
|
||||
do
|
||||
(insert (format "#+latex_header_extra: \\newglossaryentry{%s}{name=%s,description={{%s}}}\n"
|
||||
label name description))))))
|
||||
|
||||
|
||||
;;* Acronyms
|
||||
@@ -447,7 +447,7 @@ This is intended to be run in `org-export-before-parsing-hook'."
|
||||
FULL is the expanded acronym.
|
||||
|
||||
This is not the preferred way to add acronyms, you should add
|
||||
them manually to the acroynms table."
|
||||
them manually to the acronyms table."
|
||||
(interactive "sLabel: \nsAcronym: \nsFull name: ")
|
||||
(save-excursion
|
||||
(re-search-backward "#\\+latex_header" nil t)
|
||||
@@ -668,13 +668,13 @@ This will run in `org-export-before-parsing-hook'."
|
||||
(nthcdr 2 (org-babel-read-table))))))))))
|
||||
(when entries
|
||||
;; Delete the table
|
||||
(setf (buffer-substring begin end) "")
|
||||
(cl--set-buffer-substring begin end ""))
|
||||
|
||||
(goto-char (point-min))
|
||||
(cl-loop for (label name description) in entries
|
||||
do
|
||||
(insert (format "#+latex_header_extra: \\newacronym{%s}{%s}{%s}\n"
|
||||
label name description)))))))
|
||||
(goto-char (point-min))
|
||||
(cl-loop for (label name description) in entries
|
||||
do
|
||||
(insert (format "#+latex_header_extra: \\newacronym{%s}{%s}{%s}\n"
|
||||
label name description))))))
|
||||
|
||||
|
||||
;; * Interactive command to insert acroynm/glossary links
|
||||
@@ -907,9 +907,9 @@ Meant for non-LaTeX exports."
|
||||
;; skip header and hline
|
||||
(nthcdr 2 (org-babel-read-table))
|
||||
;; delete the table
|
||||
(setf (buffer-substring (org-element-property :begin el)
|
||||
(org-element-property :end el))
|
||||
""))))
|
||||
(cl--set-buffer-substring (org-element-property :begin el)
|
||||
(org-element-property :end el)
|
||||
""))))
|
||||
nil t))
|
||||
(setq acronyms (org-element-map
|
||||
(org-element-parse-buffer)
|
||||
@@ -922,9 +922,9 @@ Meant for non-LaTeX exports."
|
||||
(prog1
|
||||
(nthcdr 2 (org-babel-read-table))
|
||||
;; delete the table
|
||||
(setf (buffer-substring (org-element-property :begin el)
|
||||
(org-element-property :end el))
|
||||
""))))
|
||||
(cl--set-buffer-substring (org-element-property :begin el)
|
||||
(org-element-property :end el)
|
||||
""))))
|
||||
nil t))
|
||||
|
||||
;; Replace printglossary link
|
||||
@@ -939,20 +939,20 @@ Meant for non-LaTeX exports."
|
||||
lnk))
|
||||
nil t))
|
||||
(when printglossary-link
|
||||
(setf (buffer-substring (org-element-property :begin printglossary-link)
|
||||
(org-element-property :end printglossary-link))
|
||||
|
||||
(concat "*Glossary*\n"
|
||||
(string-join
|
||||
(cl-loop for (label name description) in glossary collect
|
||||
(format "<<%s>>\n- %s :: %s" label name description))
|
||||
"\n")
|
||||
(cl--set-buffer-substring (org-element-property :begin printglossary-link)
|
||||
(org-element-property :end printglossary-link)
|
||||
|
||||
(concat "*Glossary*\n"
|
||||
(string-join
|
||||
(cl-loop for (label name description) in glossary collect
|
||||
(format "<<%s>>\n- %s :: %s" label name description))
|
||||
"\n")
|
||||
|
||||
"\n*Acronyms*\n"
|
||||
(string-join
|
||||
(cl-loop for (label name description) in acronyms collect
|
||||
(format "<<%s>>\n- %s :: %s " label name description))
|
||||
"\n"))))
|
||||
"\n*Acronyms*\n"
|
||||
(string-join
|
||||
(cl-loop for (label name description) in acronyms collect
|
||||
(format "<<%s>>\n- %s :: %s " label name description))
|
||||
"\n"))))
|
||||
|
||||
|
||||
;; Replace links
|
||||
@@ -967,13 +967,13 @@ Meant for non-LaTeX exports."
|
||||
lnk))))
|
||||
;; For each link, replace with [[label][link description]]
|
||||
(cl-loop for lnk in (reverse links) do
|
||||
(setf (buffer-substring (org-element-property :begin lnk)
|
||||
(org-element-property :end lnk))
|
||||
(format "[[%s][%s]]%s"
|
||||
(org-element-property :path lnk)
|
||||
(buffer-substring (org-element-property :contents-begin lnk)
|
||||
(org-element-property :contents-end lnk))
|
||||
(make-string (org-element-property :post-blank lnk) ? )))))))
|
||||
(cl--set-buffer-substring (org-element-property :begin lnk)
|
||||
(org-element-property :end lnk)
|
||||
(format "[[%s][%s]]%s"
|
||||
(org-element-property :path lnk)
|
||||
(buffer-substring (org-element-property :contents-begin lnk)
|
||||
(org-element-property :contents-end lnk))
|
||||
(make-string (org-element-property :post-blank lnk) ? )))))))
|
||||
|
||||
|
||||
(provide 'org-ref-glossary)
|
||||
|
||||
@@ -191,5 +191,69 @@ in the file. Data comes from www.ebook.de."
|
||||
(s-trim (buffer-string))))
|
||||
(save-buffer))))
|
||||
|
||||
|
||||
(defun isbn-to-bibtex-open-library (isbn bibfile)
|
||||
"Retrieve bibtex entry for a book with ISBN using openlibrary.org.
|
||||
|
||||
API: https://openlibrary.org/developers/api
|
||||
"
|
||||
(interactive
|
||||
(list
|
||||
(read-string
|
||||
"ISBN: "
|
||||
;; now set initial input
|
||||
(cond
|
||||
;; If region is active and it starts with a number, we use it
|
||||
((and (region-active-p)
|
||||
(s-match "^[0-9]" (buffer-substring (region-beginning) (region-end))))
|
||||
(buffer-substring (region-beginning) (region-end)))
|
||||
;; if first entry in kill ring starts with a number assume it is an isbn
|
||||
;; and use it as the guess
|
||||
((stringp (car kill-ring))
|
||||
(when (s-match "^[0-9]" (car kill-ring))
|
||||
(car kill-ring)))
|
||||
;; type or paste it in
|
||||
(t
|
||||
nil)))
|
||||
(completing-read "Bibfile: " (org-ref-possible-bibfiles))))
|
||||
|
||||
(let* ((url (format "https://openlibrary.org/isbn/%s.json" isbn))
|
||||
(json (with-current-buffer (url-retrieve-synchronously url)
|
||||
(json-read-from-string (string-trim (buffer-substring url-http-end-of-headers (point-max))))))
|
||||
(title (cdr (assoc 'title json)))
|
||||
(publisher (s-join ", " (cdr (assoc 'publishers json))))
|
||||
(year (cdr (assoc 'publish_date json)))
|
||||
;; this is a list of urls
|
||||
(author-urls (cdr (assoc 'authors json)))
|
||||
(authors (s-join " and "
|
||||
(cl-loop for aurl across author-urls
|
||||
collect
|
||||
(with-current-buffer (url-retrieve-synchronously
|
||||
(format "https://openlibrary.org%s.json"
|
||||
(cdr (assoc 'key aurl))))
|
||||
(cdr (assoc 'personal_name
|
||||
(json-read-from-string
|
||||
(string-trim (buffer-substring url-http-end-of-headers (point-max))))))))))
|
||||
(burl (format "https://openlibrary.org%s" (cdr (assoc 'key json))))
|
||||
(bibtex (format "@Book{,
|
||||
author = {%s},
|
||||
title = {%s},
|
||||
publisher = {%s},
|
||||
year = {%s},
|
||||
url = {%s}
|
||||
}"
|
||||
authors
|
||||
title
|
||||
publisher
|
||||
year
|
||||
burl)))
|
||||
|
||||
(with-current-buffer (find-file-noselect bibfile)
|
||||
(goto-char (point-max))
|
||||
(insert "\n\n")
|
||||
(insert bibtex)
|
||||
(org-ref-clean-bibtex-entry)
|
||||
(save-buffer))))
|
||||
|
||||
(provide 'org-ref-isbn)
|
||||
;;; org-ref-isbn.el ends here
|
||||
|
||||
@@ -58,7 +58,17 @@
|
||||
(insert (bibtex-completion-apa-format-reference
|
||||
(cdr (assoc "=key=" candidate)))))
|
||||
"Insert formatted citation")
|
||||
("f" (lambda (_candidate) (ivy-bibtex-fallback ivy-text)) "Fallback options"))
|
||||
("f" (lambda (_candidate) (ivy-bibtex-fallback ivy-text)) "Fallback options")
|
||||
("d" (lambda (_)
|
||||
"Add a bibtex entry from doi and insert cite to it at point."
|
||||
(funcall-interactively 'doi-utils-add-bibtex-entry-from-doi
|
||||
(read-string
|
||||
"DOI: "
|
||||
;; now set initial input
|
||||
(doi-utils-maybe-doi-from-region-or-current-kill)))
|
||||
(org-ref-insert-cite-key
|
||||
(current-kill 0 t)))
|
||||
"Insert from a DOI"))
|
||||
"Alternate actions to do instead of inserting."
|
||||
:type '(list (repeat (string function string)))
|
||||
:group 'org-ref)
|
||||
|
||||
@@ -270,33 +270,34 @@ replaced by links to them."
|
||||
link-replacements)))
|
||||
|
||||
(cl-loop for il in index-links collect
|
||||
(setf (buffer-substring (org-element-property :begin il)
|
||||
(org-element-property :end il))
|
||||
(cdr (assoc (org-element-property :begin il) link-replacements))))
|
||||
(cl--set-buffer-substring
|
||||
(org-element-property :begin il)
|
||||
(org-element-property :end il)
|
||||
(cdr (assoc (org-element-property :begin il) link-replacements))))
|
||||
|
||||
;; Now we replace the printindex link
|
||||
(org-element-map (org-element-parse-buffer) 'link
|
||||
(lambda (lnk)
|
||||
(when (string= "printindex" (org-element-property :type lnk))
|
||||
(setf (buffer-substring (org-element-property :begin lnk)
|
||||
(org-element-property :end lnk))
|
||||
;; If sorted-groups is empty, we should do nothing I think.
|
||||
(if sorted-groups
|
||||
(format "*Index*\n\n%s"
|
||||
(string-join
|
||||
(cl-loop for (key . links) in sorted-groups collect
|
||||
(format "%s: %s"
|
||||
key
|
||||
(string-join
|
||||
(cl-loop for i from 0 for lnk in links collect
|
||||
(format "[[%s-%s][%s-%s]] "
|
||||
(org-element-property :path lnk)
|
||||
i
|
||||
(org-element-property :path lnk)
|
||||
i))
|
||||
", ")))
|
||||
"\n\n"))
|
||||
"")))))))
|
||||
(cl--set-buffer-substring (org-element-property :begin lnk)
|
||||
(org-element-property :end lnk)
|
||||
;; If sorted-groups is empty, we should do nothing I think.
|
||||
(if sorted-groups
|
||||
(format "*Index*\n\n%s"
|
||||
(string-join
|
||||
(cl-loop for (key . links) in sorted-groups collect
|
||||
(format "%s: %s"
|
||||
key
|
||||
(string-join
|
||||
(cl-loop for i from 0 for lnk in links collect
|
||||
(format "[[%s-%s][%s-%s]] "
|
||||
(org-element-property :path lnk)
|
||||
i
|
||||
(org-element-property :path lnk)
|
||||
i))
|
||||
", ")))
|
||||
"\n\n"))
|
||||
"")))))))
|
||||
|
||||
|
||||
(provide 'org-ref-misc-links)
|
||||
|
||||
@@ -140,15 +140,7 @@ should be open in Emacs using the `pdf-tools' package."
|
||||
(let ((key (org-ref-bibtex-key-from-doi doi)))
|
||||
(funcall org-ref-pdf-to-bibtex-function
|
||||
(buffer-file-name)
|
||||
(expand-file-name (format "%s.pdf" key)
|
||||
(cond
|
||||
((stringp bibtex-completion-library-path)
|
||||
bibtex-completion-library-path)
|
||||
((and (listp bibtex-completion-library-path)
|
||||
(= 1 (length bibtex-completion-library-path)))
|
||||
(car bibtex-completion-library-path))
|
||||
(t
|
||||
(completing-read "Dir: " bibtex-completion-library-path))))))))
|
||||
(expand-file-name (format "%s.pdf" key) (org-ref-library-path))))))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(define-package "org-ref" "20221129.1925" "citations, cross-references and bibliographies in org-mode"
|
||||
(define-package "org-ref" "20231101.2355" "citations, cross-references and bibliographies in org-mode"
|
||||
'((org "9.4")
|
||||
(dash "0")
|
||||
(s "0")
|
||||
@@ -10,7 +10,9 @@
|
||||
(bibtex-completion "0")
|
||||
(citeproc "0")
|
||||
(ox-pandoc "0"))
|
||||
:commit "26735e914f09559c7b9753462a596e62595b135e" :authors
|
||||
:commit "195b8d3209aff956ecdd755422700e8517a34d11" :authors
|
||||
'(("John Kitchin" . "jkitchin@andrew.cmu.edu"))
|
||||
:maintainers
|
||||
'(("John Kitchin" . "jkitchin@andrew.cmu.edu"))
|
||||
:maintainer
|
||||
'("John Kitchin" . "jkitchin@andrew.cmu.edu")
|
||||
|
||||
107
lisp/org-ref/org-ref-publish.el
Normal file
107
lisp/org-ref/org-ref-publish.el
Normal file
@@ -0,0 +1,107 @@
|
||||
;;; org-ref-publish.el --- org-publish with org-ref
|
||||
|
||||
;;; Commentary:
|
||||
;; First draft proposed by madhu 230826 (Madhu <enometh@meer.net>)
|
||||
;; This code provides publishing capability that leverages
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; modified from org-publish-org-to to call org-ref-process-buffer before
|
||||
;; calling org-export-to-file
|
||||
(defun org-ref-publish-org-to (backend filename extension plist &optional pub-dir)
|
||||
"Publish an Org file to a specified backend using org-ref.
|
||||
|
||||
BACKEND is a symbol representing the backend used for
|
||||
transcoding. FILENAME is the filename of the Org file to be
|
||||
published. EXTENSION is the extension used for the output
|
||||
string, with the leading dot. PLIST is the property list for the
|
||||
given project.
|
||||
|
||||
Optional argument PUB-DIR, when non-nil is the publishing
|
||||
directory.
|
||||
|
||||
Return output file name."
|
||||
(unless (or (not pub-dir) (file-exists-p pub-dir))
|
||||
(make-directory pub-dir t))
|
||||
;; Check if a buffer visiting FILENAME is already open.
|
||||
(let* ((org-inhibit-startup t)
|
||||
(visiting (find-buffer-visiting filename))
|
||||
(work-buffer (or visiting (find-file-noselect filename))))
|
||||
(unwind-protect
|
||||
(with-current-buffer work-buffer
|
||||
(let* ((output (org-export-output-file-name extension nil pub-dir)))
|
||||
(org-export-with-buffer-copy
|
||||
(org-export-expand-include-keyword)
|
||||
(goto-char (point-min))
|
||||
(org-ref-process-buffer backend nil) ;no subtreep
|
||||
(goto-char (point-min))
|
||||
(org-export-to-file backend output
|
||||
nil nil nil (plist-get plist :body-only)
|
||||
;; Add `org-publish--store-crossrefs' and
|
||||
;; `org-publish-collect-index' to final output filters.
|
||||
;; The latter isn't dependent on `:makeindex', since we
|
||||
;; want to keep it up-to-date in cache anyway.
|
||||
(org-combine-plists
|
||||
plist
|
||||
`(:crossrefs
|
||||
,(org-publish-cache-get-file-property
|
||||
;; Normalize file names in cache.
|
||||
(file-truename filename) :crossrefs nil t)
|
||||
:filter-final-output
|
||||
(org-publish--store-crossrefs
|
||||
org-publish-collect-index
|
||||
,@(plist-get plist :filter-final-output))))))))
|
||||
;; Remove opened buffer in the process.
|
||||
(unless visiting (kill-buffer work-buffer)))))
|
||||
|
||||
;; modified from org-html-publish-to-html to call org-ref-publish-org-to instead
|
||||
;; of org-publish-org-to
|
||||
(defun org-ref-publish-to-html (plist filename pub-dir)
|
||||
"Publish an org file to HTML through org-ref.
|
||||
|
||||
FILENAME is the filename of the Org file to be published. PLIST
|
||||
is the property list for the given project. PUB-DIR is the
|
||||
publishing directory.
|
||||
|
||||
Return output file name."
|
||||
(org-ref-publish-org-to 'html filename
|
||||
(concat (when (> (length org-html-extension) 0) ".")
|
||||
(or (plist-get plist :html-extension)
|
||||
org-html-extension
|
||||
"html"))
|
||||
plist pub-dir))
|
||||
|
||||
|
||||
;; modified from org-latex-publish-to-latex to call org-ref-publish-org-to
|
||||
;; instead of org-publish-org-to
|
||||
(defun org-ref-publish-to-latex (plist filename pub-dir)
|
||||
"Publish an Org file to LaTeX using org-ref.
|
||||
|
||||
FILENAME is the filename of the Org file to be published. PLIST
|
||||
is the property list for the given project. PUB-DIR is the
|
||||
publishing directory.
|
||||
|
||||
Return output file name."
|
||||
(org-ref-publish-org-to 'latex filename ".tex" plist pub-dir))
|
||||
|
||||
;; modified from org-latex-publish-to-pdf to call org-ref-publish-org-to instead of org-publish-org-to
|
||||
(defun org-ref-publish-to-pdf (plist filename pub-dir)
|
||||
"Publish an Org file to PDF (via LaTeX) using org-ref.
|
||||
|
||||
FILENAME is the filename of the Org file to be published. PLIST
|
||||
is the property list for the given project. PUB-DIR is the
|
||||
publishing directory.
|
||||
|
||||
Return output file name."
|
||||
(org-publish-attachment
|
||||
plist
|
||||
(let ((default-directory (file-name-directory filename)))
|
||||
(org-latex-compile
|
||||
(org-ref-publish-org-to
|
||||
'latex filename ".tex" plist (file-name-directory filename))))
|
||||
pub-dir))
|
||||
|
||||
(provide 'org-ref-publish)
|
||||
|
||||
;;; org-ref-publish.el ends here
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
;;; Code:
|
||||
(eval-and-compile (require 'org-macs))
|
||||
(eval-and-compile (require 'ol))
|
||||
(require 'hydra)
|
||||
|
||||
(defcustom org-ref-default-ref-type "ref"
|
||||
@@ -83,6 +84,7 @@ The label should always be in group 1.")
|
||||
("pageref" "to the page number a label is on")
|
||||
("nameref" "to the name associated with a label (e.g. a caption)")
|
||||
("autoref" "from hyperref, adds automatic prefixes")
|
||||
("Autoref" "from hyperref, capitalized version of autoref")
|
||||
("cref" "from cleveref, adds automatic prefixes, and condenses multiple refs")
|
||||
("Cref" "from cleveref, capitalized version of cref")
|
||||
("crefrange" "from cleveref, makes a range of refs from two refs with a prefix")
|
||||
@@ -113,11 +115,11 @@ The label should always be in group 1.")
|
||||
(path (org-element-property :path cite-link))
|
||||
(deltap (- (point) begin)))
|
||||
;; note this does not respect brackets
|
||||
(setf (buffer-substring begin end)
|
||||
(concat
|
||||
(if bracketp "[[" "")
|
||||
new-type ":" path
|
||||
(if bracketp "]]" "")))
|
||||
(cl--set-buffer-substring begin end
|
||||
(concat
|
||||
(if bracketp "[[" "")
|
||||
new-type ":" path
|
||||
(if bracketp "]]" "")))
|
||||
;; try to preserve the character the point is on.
|
||||
(goto-char (+ begin deltap (- (length new-type) (length old-type))))))
|
||||
|
||||
@@ -275,9 +277,10 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
(concat refstyle ":" (completing-read "Label: " (org-ref-get-labels))))
|
||||
|
||||
|
||||
(defun org-ref-store-ref ()
|
||||
(defun org-ref-store-ref-link (&optional reftype)
|
||||
"Store a ref link to a label. The output will be a ref to that label."
|
||||
;; First we have to make sure we are on a label link.
|
||||
(unless reftype (setq reftype "ref"))
|
||||
(let* ((object (and (eq major-mode 'org-mode) (org-element-context)))
|
||||
(label (cond
|
||||
;; here literally on a label link.
|
||||
@@ -357,17 +360,16 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
nil))))
|
||||
|
||||
(when label
|
||||
(cl-loop for (reftype _) in org-ref-ref-types do
|
||||
(org-link-store-props
|
||||
:type reftype
|
||||
:link (concat reftype ":" label)))
|
||||
(format (concat org-ref-default-ref-type ":" label)))))
|
||||
(org-link-store-props
|
||||
:type reftype
|
||||
:link (concat reftype ":" label))
|
||||
t)))
|
||||
|
||||
|
||||
;; ** ref link
|
||||
|
||||
(org-link-set-parameters "ref"
|
||||
:store #'org-ref-store-ref
|
||||
:store (defun org-ref-store-ref () (org-ref-store-ref-link "ref"))
|
||||
:complete (apply-partially #'org-ref-complete-link "ref")
|
||||
:activate-func #'org-ref-ref-activate
|
||||
:follow #'org-ref-ref-jump-to
|
||||
@@ -379,7 +381,7 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
;;** pageref link
|
||||
|
||||
(org-link-set-parameters "pageref"
|
||||
:store #'org-ref-store-ref
|
||||
:store (defun org-ref-store-pageref () (org-ref-store-ref-link "pageref"))
|
||||
:complete (apply-partially #'org-ref-complete-link "pageref")
|
||||
:activate-func #'org-ref-ref-activate
|
||||
:follow #'org-ref-ref-jump-to
|
||||
@@ -392,7 +394,7 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
;;** nameref link
|
||||
|
||||
(org-link-set-parameters "nameref"
|
||||
:store #'org-ref-store-ref
|
||||
:store (defun org-ref-store-nameref () (org-ref-store-ref-link "nameref"))
|
||||
:complete (apply-partially #'org-ref-complete-link "nameref")
|
||||
:activate-func #'org-ref-ref-activate
|
||||
:follow #'org-ref-ref-jump-to
|
||||
@@ -403,7 +405,7 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
;;** eqref link
|
||||
|
||||
(org-link-set-parameters "eqref"
|
||||
:store #'org-ref-store-ref
|
||||
:store (defun org-ref-store-eqref () (org-ref-store-ref-link "eqref"))
|
||||
:complete (apply-partially #'org-ref-complete-link "eqref")
|
||||
:activate-func #'org-ref-ref-activate
|
||||
:follow #'org-ref-ref-jump-to
|
||||
@@ -414,7 +416,7 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
;;** autoref link
|
||||
|
||||
(org-link-set-parameters "autoref"
|
||||
:store #'org-ref-store-ref
|
||||
:store (defun org-ref-store-autoref () (org-ref-store-ref-link "autoref"))
|
||||
:complete (apply-partially #'org-ref-complete-link "autoref")
|
||||
:activate-func #'org-ref-ref-activate
|
||||
:follow #'org-ref-ref-jump-to
|
||||
@@ -422,13 +424,23 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
:face 'org-ref-ref-face
|
||||
:help-echo #'org-ref-ref-help-echo)
|
||||
|
||||
|
||||
(org-link-set-parameters "Autoref"
|
||||
:store (defun org-ref-store-Autoref () (org-ref-store-ref-link "Autoref"))
|
||||
:complete (apply-partially #'org-ref-complete-link "Autoref")
|
||||
:activate-func #'org-ref-ref-activate
|
||||
:follow #'org-ref-ref-jump-to
|
||||
:export (apply-partially #'org-ref-ref-export "Autoref")
|
||||
:face 'org-ref-ref-face
|
||||
:help-echo #'org-ref-ref-help-echo)
|
||||
|
||||
;;** cref link
|
||||
;; for LaTeX cleveref package:
|
||||
;; https://www.ctan.org/tex-archive/macros/latex/contrib/cleveref
|
||||
|
||||
|
||||
(org-link-set-parameters "cref"
|
||||
:store #'org-ref-store-ref
|
||||
:store (defun org-ref-store-cref () (org-ref-store-ref-link "cref"))
|
||||
:complete (apply-partially #'org-ref-complete-link "cref")
|
||||
:activate-func #'org-ref-ref-activate
|
||||
:follow #'org-ref-ref-jump-to
|
||||
@@ -438,7 +450,7 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
|
||||
|
||||
(org-link-set-parameters "Cref"
|
||||
:store #'org-ref-store-ref
|
||||
:store (defun org-ref-store-Cref () (org-ref-store-ref-link "Cref"))
|
||||
:complete (apply-partially #'org-ref-complete-link "Cref")
|
||||
:activate-func #'org-ref-ref-activate
|
||||
:follow #'org-ref-ref-jump-to
|
||||
@@ -458,7 +470,7 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
(pcase backend
|
||||
('latex
|
||||
(let ((labels (split-string path ",")))
|
||||
(format "\\crefrange{%s}{%s}" (cl-first labels) (cl-second labels))))))
|
||||
(format "\\Crefrange{%s}{%s}" (cl-first labels) (cl-second labels))))))
|
||||
|
||||
|
||||
(defun org-ref-crefrange-complete (cmd &optional _arg)
|
||||
@@ -487,6 +499,19 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
:help-echo #'org-ref-ref-help-echo)
|
||||
|
||||
|
||||
;; ** remove store functions
|
||||
(defun org-ref-ref-remove-store ()
|
||||
"Remove the store functions from ref links.
|
||||
These tend to clobber the org store links. You can use C-u C-u
|
||||
C-c C-l to not use them, but if you prefer not to use them, this
|
||||
function removes the store functions from the links."
|
||||
(interactive)
|
||||
(cl-loop for reflink in '("ref" "pageref" "nameref" "eqref" "autoref" "Autoref"
|
||||
"cref" "Cref" "crefrange" "Crefrange")
|
||||
do
|
||||
(setf (cdr (assoc reflink org-link-parameters))
|
||||
(org-plist-delete (cdr (assoc reflink org-link-parameters)) :store))))
|
||||
|
||||
;; * Insert link
|
||||
(defvar org-ref-equation-environments
|
||||
'("equation"
|
||||
|
||||
@@ -134,6 +134,9 @@ environments)."
|
||||
(when (or (and (eq type 'equation)
|
||||
(string-match "\\\\begin{equation}"
|
||||
(org-element-property :value e)))
|
||||
(and (eq type 'equation)
|
||||
(string-match "\\\\begin{align}"
|
||||
(org-element-property :value e)))
|
||||
(and (eq type 'proof) (string-match "\\\\begin{proof}"
|
||||
(org-element-property :value e))))
|
||||
|
||||
@@ -144,7 +147,13 @@ environments)."
|
||||
|
||||
;; latex label in the value
|
||||
((string-match "\\\\label{\\(.*\\)}" (org-element-property :value e))
|
||||
(match-string 1 (org-element-property :value e))))))
|
||||
(save-match-data
|
||||
(let ((pos 1)
|
||||
matches)
|
||||
(while (string-match "\\\\label{\\(.*\\)}" (org-element-property :value e) pos)
|
||||
(push (match-string 1 (org-element-property :value e)) matches)
|
||||
(setq pos (match-end 0)))
|
||||
matches))))))
|
||||
|
||||
;; special blocks
|
||||
('special-block
|
||||
@@ -169,7 +178,9 @@ environments)."
|
||||
('src-block
|
||||
(when-let (name (org-element-property :name e))
|
||||
name)))))))))
|
||||
referencables))
|
||||
;; the align equation environment needs to be flattened
|
||||
(cl-loop for type in referencables
|
||||
collect (cons (car type) (-flatten (cdr type))))))
|
||||
|
||||
|
||||
(defun org-ref-refproc-get-type (label referenceables)
|
||||
@@ -340,9 +351,7 @@ REFERENCEABLES comes from `org-ref-refproc-referenceables'.
|
||||
If CAPITALIZE is non-nil, capitalize the first entry (this is for
|
||||
Cref) and is different than the capitalize option in #+refproc:
|
||||
which capitalizes each prefix."
|
||||
(let* ((options (org-ref-refproc-get-options))
|
||||
;; I guess I know this will be cref or Cref here.
|
||||
;; (ref-type (org-element-property :type ref-link))
|
||||
(let* ((options (org-ref-refproc-get-options))
|
||||
(labels (split-string (org-element-property :path ref-link) ","))
|
||||
(post-blanks (org-element-property :post-blank ref-link))
|
||||
(data (cl-loop for label in labels collect (org-ref-refproc-get-type label referenceables)))
|
||||
@@ -371,12 +380,17 @@ which capitalizes each prefix."
|
||||
:full)))
|
||||
(when (plist-get options :capitalize)
|
||||
(setq prefix (capitalize prefix)))
|
||||
(format "%s [[%s]]"
|
||||
(format "%s %s"
|
||||
;; prefix
|
||||
prefix
|
||||
(concat
|
||||
(if (eq 'section (plist-get collection :type)) "#" "")
|
||||
(plist-get collection :label))))
|
||||
(cond
|
||||
((eq 'section (plist-get collection :type))
|
||||
(format "[[#%s]]" (plist-get collection :label)))
|
||||
((eq 'equation (plist-get collection :type))
|
||||
(format "\\ref{%s}" (plist-get collection :label)))
|
||||
(t
|
||||
(format "[[%s]]" (plist-get collection :label)))))))
|
||||
(2
|
||||
;; the prefix can be found from the first label, but we have to make it plural.
|
||||
(setq prefix-data (cdr (assoc (plist-get (cl-first collection) :type)
|
||||
|
||||
@@ -190,6 +190,16 @@ You set =pdftotext-executable= to ${pdftotext-executable} (exists: ${pdftotext-e
|
||||
(bibtex-copy-entry-as-kill)
|
||||
(pop bibtex-entry-kill-ring)))
|
||||
|
||||
(defun org-ref-library-path ()
|
||||
"return the library path"
|
||||
(cond
|
||||
((stringp bibtex-completion-library-path)
|
||||
bibtex-completion-library-path)
|
||||
((and (listp bibtex-completion-library-path)
|
||||
(= 1 (length bibtex-completion-library-path)))
|
||||
(car bibtex-completion-library-path))
|
||||
(t
|
||||
(completing-read "Dir: " bibtex-completion-library-path))))
|
||||
|
||||
;;*** key at point functions
|
||||
(defun org-ref-get-pdf-filename (key)
|
||||
@@ -261,6 +271,36 @@ Jabref, Mendeley and Zotero. See `bibtex-completion-find-pdf'."
|
||||
(completing-read "pdf: " pdf-file))))))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun org-ref-add-pdf-at-point (&optional prefix)
|
||||
"Add the pdf for bibtex key under point if it exists.
|
||||
|
||||
Similar to org-ref-bibtex-assoc-pdf-with-entry prompt for pdf
|
||||
associated with bibtex key at point and rename it. Check whether a
|
||||
pdf already exists in `bibtex-completion-library' with the name
|
||||
'[bibtexkey].pdf'. If the file does not exist, rename it to
|
||||
'[bibtexkey].pdf' using
|
||||
`org-ref-bibtex-assoc-pdf-with-entry-move-function' and place it
|
||||
in a directory. Optional PREFIX argument toggles between
|
||||
`rename-file' and `copy-file'."
|
||||
|
||||
(interactive)
|
||||
(let* ((bibtex-completion-bibliography (org-ref-find-bibliography))
|
||||
(results (org-ref-get-bibtex-key-and-file))
|
||||
(key (car results))
|
||||
(pdf-file (bibtex-completion-find-pdf-in-library key)))
|
||||
(if pdf-file
|
||||
(message "PDF for key [%s] already exists %s" key pdf-file)
|
||||
(let* (
|
||||
(source-file-name (read-file-name (format "Select pdf file associated with key [%s]: " key)
|
||||
org-ref-bibtex-pdf-download-dir))
|
||||
(dest-file-name (expand-file-name (format "%s.pdf" key) (org-ref-library-path)))
|
||||
(file-move-func (org-ref-bibtex-get-file-move-func prefix))
|
||||
)
|
||||
(progn
|
||||
(funcall file-move-func source-file-name dest-file-name)
|
||||
(message "added file %s to key %s" dest-file-name key))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-ref-open-url-at-point ()
|
||||
"Open the url for bibtex key under point."
|
||||
@@ -1131,13 +1171,18 @@ if FORCE is non-nil reparse the buffer no matter what."
|
||||
|
||||
|
||||
|
||||
;;** Find non-ascii charaters
|
||||
;;** Find non-ascii characters
|
||||
;;;###autoload
|
||||
(defun org-ref-find-non-ascii-characters ()
|
||||
"Find non-ascii characters in the buffer. Useful for cleaning up bibtex files."
|
||||
(interactive)
|
||||
(occur "[^[:ascii:]]"))
|
||||
|
||||
|
||||
;;* Utilities
|
||||
|
||||
;;** Extract bibtex entries in org-file
|
||||
|
||||
;;;###autoload
|
||||
(defun org-ref-extract-bibtex-to-file (bibfile &optional clobber)
|
||||
"Extract all bibtex entries for citations buffer to BIBFILE.
|
||||
@@ -1176,10 +1221,6 @@ which will CLOBBER the file."
|
||||
"\n\n")))))
|
||||
|
||||
|
||||
;;* Utilities
|
||||
|
||||
;;** Extract bibtex entries in org-file
|
||||
|
||||
;;;###autoload
|
||||
(defun org-ref-extract-bibtex-entries ()
|
||||
"Extract the bibtex entries in the current buffer into a bibtex src block."
|
||||
@@ -1216,6 +1257,22 @@ which will CLOBBER the file."
|
||||
"\n\n")))))
|
||||
|
||||
|
||||
;;** Extract cited pdfs
|
||||
;;;###autoload
|
||||
(defun org-ref-extract-cited-pdfs (newdir)
|
||||
"Copy PDFs in citations in current buffer to NEWDIR."
|
||||
(interactive (list (read-directory-name "Copy to: ")))
|
||||
;; Make sure newdir exists
|
||||
(unless (file-directory-p newdir)
|
||||
(mkdir newdir t))
|
||||
|
||||
(cl-loop for key in (org-ref-get-bibtex-keys) do
|
||||
(let ((pdf (org-ref-get-pdf-filename key)))
|
||||
(if (file-exists-p pdf)
|
||||
(progn
|
||||
(message "Copying %s to %s." pdf newdir)
|
||||
(copy-file pdf newdir t))
|
||||
(message "%s not found" pdf)))))
|
||||
|
||||
|
||||
(provide 'org-ref-utils)
|
||||
|
||||
Reference in New Issue
Block a user