Files
emacs/lisp/citeproc/citeproc-itemgetters.el
Daniel Weschke 82f05baffe pkg update and first config fix
org-brain not working, add org-roam
2022-12-19 23:02:34 +01:00

189 lines
6.4 KiB
EmacsLisp

;; citeproc-itemgetters.el --- functions for constructing itemgetters -*- lexical-binding: t; -*-
;; Copyright (C) 2017-2021 András Simonyi
;; Author: András Simonyi <andras.simonyi@gmail.com>
;; 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/>.
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Functions for constructing various types of bibliographic itemgetter
;; functions. The returned itemgetter functions can, in turn, be used to create
;; `citeproc-style' and `citeproc-proc' structures.
;;; Code:
(require 'dash)
(require 'org)
;; Handle the fact that org-bibtex has been renamed to ol-bibtex -- for the time
;; being we support both feature names.
(or (require 'ol-bibtex nil t)
(require 'org-bibtex))
(require 'json)
(require 'bibtex)
(require 'parsebib)
(require 'citeproc-bibtex)
(require 'citeproc-biblatex)
(defun citeproc-itemgetters--parsebib-buffer (entries strings)
"Parse a BibTeX/biblatex buffer with Parsebib."
;; Note: this is needed to support different Parsebib versions in use.
(cond ((fboundp 'parsebib-parse-buffer)
(parsebib-parse-buffer entries strings t t))
((fboundp 'parsebib-parse-bib-buffer)
(parsebib-parse-bib-buffer :entries entries :strings strings
:expand-strings t :inheritance t))
(t (error "No Parsebib buffer parsing function is available"))))
(defun citeproc-hash-itemgetter-from-csl-json (file)
"Return a hash-based getter for csl json bibliography FILE."
(let* ((json-array-type 'list)
(json-key-type 'symbol)
(item-list (json-read-file file))
(hash (make-hash-table :test 'equal)))
(--each item-list
(puthash (alist-get 'id it) it hash))
(lambda (itemids) (--map (cons it (gethash it hash))
itemids))))
(defun citeproc-itemgetter-from-csl-json (file)
"Return an item-getter for csl json bibliography FILE."
(lambda (itemids)
(let* ((json-array-type 'list)
(json-key-type 'symbol)
(item-list (json-read-file file))
result)
(dolist (item item-list result)
(let ((id (alist-get 'id item)))
(when (member id itemids)
(push (cons id item) result)))))))
(defun citeproc-itemgetter-from-bibtex (file-or-files)
"Return a getter for BibTeX bibliography FILE-OR-FILES."
(if (listp file-or-files)
(lambda (itemids)
(let (result
(remaining-ids (cl-copy-list itemids))
(remaining-files file-or-files))
(while (and remaining-ids remaining-files)
(let ((file (pop remaining-files)))
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(bibtex-set-dialect 'BibTeX t)
(bibtex-map-entries
(lambda (key _beg _end)
(when (member key itemids)
(push (cons key (citeproc-bt-entry-to-csl (bibtex-parse-entry)))
result)
(setq remaining-ids (delete key remaining-ids))))))))
result))
(lambda (itemids)
(let (result)
(with-temp-buffer
(insert-file-contents file-or-files)
(goto-char (point-min))
(bibtex-set-dialect 'BibTeX t)
(bibtex-map-entries
(lambda (key _beg _end)
(when (member key itemids)
(push (cons key (citeproc-bt-entry-to-csl (bibtex-parse-entry)))
result)))))
result))))
(defun citeproc-itemgetter-from-org-bibtex (file-or-files)
"Return a getter for org-bibtex bibliography FILE-OR-FILES."
(let ((files (if (listp file-or-files)
file-or-files
(list file-or-files))))
(lambda (itemids)
(let (result)
(org-map-entries
(lambda ()
(-when-let (key-w-entry (citeproc-bt-from-org-headline itemids))
(push (cons (car key-w-entry)
(citeproc-bt-entry-to-csl (cdr key-w-entry)))
result)))
t files)
result))))
(defun citeproc-hash-itemgetter-from-any (file-or-files &optional no-sentcase-wo-langid)
"Return a getter for FILE-OR-FILES in any supported format.
The format is determined on the basis of file extensions.
Supported formats:
- CSL-JSON (.json extension) the recommended native format;
- BibTeX/biblatex (.bib or .bibtex extension),
- org-bibtex (.org extension).
If NO-SENTCASE-WO-LANGID is non-nil then title fields in items
without a `langid' field are not converted to sentence-case."
(let ((files (if (listp file-or-files)
file-or-files
(list file-or-files)))
(cache (make-hash-table :test #'equal))
(bt-entries (make-hash-table :test #'equal))
(bt-strings (make-hash-table :test #'equal)))
(dolist (file files)
(pcase (file-name-extension file)
("json"
(let ((json-array-type 'list)
(json-key-type 'symbol))
(dolist (item (json-read-file file))
(puthash (cdr (assq 'id item)) item cache))))
((and (or "bib" "bibtex") ext)
(with-temp-buffer
(insert-file-contents file)
(bibtex-set-dialect (if (string= ext "bib") 'biblatex 'BibTeX) t)
(citeproc-itemgetters--parsebib-buffer bt-entries bt-strings)))
("org"
(org-map-entries
(lambda ()
(-when-let (key-w-entry (citeproc-bt-from-org-headline))
(condition-case err
(puthash (car key-w-entry) (citeproc-blt-entry-to-csl
(cdr key-w-entry))
cache)
(error
(user-error
"Couldn't parse the bib(la)tex entry with key '%s', the error was: %s"
(car key-w-entry) err)))))
t (list file)))
(ext
(user-error "Unknown bibliography extension: %S" ext))))
(maphash
(lambda (key entry)
(condition-case err
(puthash key (citeproc-blt-entry-to-csl entry nil no-sentcase-wo-langid)
cache)
(error
(user-error
"Couldn't parse the bib(la)tex entry with key '%s', the error was: %s"
key err))))
bt-entries)
(lambda (x)
(pcase x
('itemids
(hash-table-keys cache))
((pred listp) (mapcar (lambda (id)
(cons id (gethash id cache)))
x))
(_ (error "Unsupported citeproc itemgetter retrieval method"))))))
(provide 'citeproc-itemgetters)
;;; citeproc-itemgetters.el ends here