-
Notifications
You must be signed in to change notification settings - Fork 9
/
citeproc-itemgetters.el
188 lines (169 loc) · 6.36 KB
/
citeproc-itemgetters.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
;; 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