Commit | Line | Data |
---|---|---|
a2a25d24 | 1 | ;;; bibtex.el --- BibTeX mode for GNU Emacs -*- lexical-binding: t -*- |
c0274f38 | 2 | |
ab422c4d PE |
3 | ;; Copyright (C) 1992, 1994-1999, 2001-2013 Free Software Foundation, |
4 | ;; Inc. | |
9750e079 | 5 | |
31bc4210 | 6 | ;; Author: Stefan Schoef <schoef@offis.uni-oldenburg.de> |
7fbf4804 | 7 | ;; Bengt Martensson <bengt@mathematik.uni-Bremen.de> |
f021dbca | 8 | ;; Marc Shapiro <marc.shapiro@acm.org> |
7fbf4804 SM |
9 | ;; Mike Newton <newton@gumby.cs.caltech.edu> |
10 | ;; Aaron Larson <alarson@src.honeywell.com> | |
11 | ;; Dirk Herrmann <D.Herrmann@tu-bs.de> | |
1e05f387 | 12 | ;; Maintainer: Roland Winkler <winkler@gnu.org> |
cb4ad359 | 13 | ;; Keywords: BibTeX, LaTeX, TeX |
f961a17c | 14 | |
745bc783 JB |
15 | ;; This file is part of GNU Emacs. |
16 | ||
1fecc8fe | 17 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
745bc783 | 18 | ;; it under the terms of the GNU General Public License as published by |
1fecc8fe GM |
19 | ;; the Free Software Foundation, either version 3 of the License, or |
20 | ;; (at your option) any later version. | |
745bc783 JB |
21 | |
22 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | ;; GNU General Public License for more details. | |
26 | ||
27 | ;; You should have received a copy of the GNU General Public License | |
1fecc8fe | 28 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
745bc783 | 29 | |
5c69dbfc | 30 | ;;; Commentary: |
b578f267 | 31 | |
cb4ad359 | 32 | ;; Major mode for editing and validating BibTeX files. |
e5167999 | 33 | |
5c69dbfc | 34 | ;; Usage: |
f2dfa899 | 35 | ;; See documentation for `bibtex-mode' or type "M-x describe-mode" |
02c8032e | 36 | ;; when you are in BibTeX mode. |
e5167999 | 37 | |
5c69dbfc RS |
38 | ;; Todo: |
39 | ;; Distribute texinfo file. | |
9ae11a89 | 40 | |
5c69dbfc | 41 | ;;; Code: |
b578f267 | 42 | |
e0dc0c55 SM |
43 | (require 'button) |
44 | ||
28f2ee66 | 45 | \f |
5c69dbfc | 46 | ;; User Options: |
e5167999 | 47 | |
f754fb7b | 48 | (defgroup bibtex nil |
ffe68348 | 49 | "BibTeX mode." |
f754fb7b RS |
50 | :group 'tex |
51 | :prefix "bibtex-") | |
52 | ||
53 | (defgroup bibtex-autokey nil | |
ffe68348 | 54 | "Generate automatically a key from the author/editor and the title field." |
f754fb7b | 55 | :group 'bibtex |
ab2d0cdb | 56 | :prefix "bibtex-autokey-") |
f754fb7b RS |
57 | |
58 | (defcustom bibtex-mode-hook nil | |
59 | "List of functions to call on entry to BibTeX mode." | |
60 | :group 'bibtex | |
ab2d0cdb | 61 | :type 'hook) |
f754fb7b RS |
62 | |
63 | (defcustom bibtex-field-delimiters 'braces | |
02c8032e | 64 | "Type of field delimiters. Allowed values are `braces' or `double-quotes'." |
f754fb7b RS |
65 | :group 'bibtex |
66 | :type '(choice (const braces) | |
7fbf4804 | 67 | (const double-quotes))) |
50e4b39e | 68 | |
f754fb7b | 69 | (defcustom bibtex-entry-delimiters 'braces |
02c8032e | 70 | "Type of entry delimiters. Allowed values are `braces' or `parentheses'." |
f754fb7b RS |
71 | :group 'bibtex |
72 | :type '(choice (const braces) | |
7fbf4804 | 73 | (const parentheses))) |
cb4ad359 | 74 | |
f754fb7b | 75 | (defcustom bibtex-include-OPTcrossref '("InProceedings" "InCollection") |
02c8032e | 76 | "List of BibTeX entries that get an OPTcrossref field." |
f754fb7b RS |
77 | :group 'bibtex |
78 | :type '(repeat string)) | |
e5167999 | 79 | |
f754fb7b | 80 | (defcustom bibtex-include-OPTkey t |
d10e87a2 SM |
81 | "If non-nil, all newly created entries get an OPTkey field. |
82 | If this is a string, use it as the initial field text. | |
83 | If this is a function, call it to generate the initial field text." | |
f754fb7b RS |
84 | :group 'bibtex |
85 | :type '(choice (const :tag "None" nil) | |
7fbf4804 | 86 | (string :tag "Initial text") |
27a61fcd | 87 | (function :tag "Initialize Function") |
eab10abb | 88 | (const :tag "Default" t))) |
8a51a318 | 89 | (put 'bibtex-include-OPTkey 'risky-local-variable t) |
f754fb7b RS |
90 | |
91 | (defcustom bibtex-user-optional-fields | |
50e4b39e | 92 | '(("annote" "Personal annotation (ignored)")) |
02c8032e | 93 | "List of optional fields the user wants to have always present. |
2de69e00 RW |
94 | Entries should be of the same form as the OPTIONAL list |
95 | in `bibtex-BibTeX-entry-alist' (which see)." | |
f754fb7b | 96 | :group 'bibtex |
7fbf4804 SM |
97 | :type '(repeat (group (string :tag "Field") |
98 | (string :tag "Comment") | |
27a61fcd RW |
99 | (option (choice :tag "Init" |
100 | (const nil) string function))))) | |
90ce8c2a | 101 | (put 'bibtex-user-optional-fields 'risky-local-variable t) |
7fbf4804 SM |
102 | |
103 | (defcustom bibtex-entry-format | |
104 | '(opts-or-alts required-fields numerical-fields) | |
02c8032e | 105 | "Type of formatting performed by `bibtex-clean-entry'. |
f0cb6034 | 106 | It may be t, nil, or a list of symbols out of the following: |
d0388eac RS |
107 | opts-or-alts Delete empty optional and alternative fields and |
108 | remove OPT and ALT prefixes from used fields. | |
7fbf4804 | 109 | required-fields Signal an error if a required field is missing. |
d0388eac RS |
110 | numerical-fields Delete delimiters around numeral fields. |
111 | page-dashes Change double dashes in page field to single dash | |
112 | (for scribe compatibility). | |
f2dfa899 | 113 | whitespace Delete whitespace at the beginning and end of fields. |
d10e87a2 SM |
114 | inherit-booktitle If entry contains a crossref field and the booktitle |
115 | field is empty, set the booktitle field to the content | |
116 | of the title field of the crossreferenced entry. | |
d0388eac | 117 | realign Realign entries, so that field texts and perhaps equal |
50e4b39e | 118 | signs (depending on the value of |
f0cb6034 | 119 | `bibtex-align-at-equal-sign') begin in the same column. |
65e10478 | 120 | Also fill fields. |
d0388eac RS |
121 | last-comma Add or delete comma on end of last field in entry, |
122 | according to value of `bibtex-comma-after-last-field'. | |
123 | delimiters Change delimiters according to variables | |
124 | `bibtex-field-delimiters' and `bibtex-entry-delimiters'. | |
c48f463b | 125 | unify-case Change case of entry types and field names. |
f2dfa899 RW |
126 | braces Enclose parts of field entries by braces according to |
127 | `bibtex-field-braces-alist'. | |
128 | strings Replace parts of field entries by string constants | |
129 | according to `bibtex-field-strings-alist'. | |
b7c3692a | 130 | sort-fields Sort fields to match the field order in |
2de69e00 | 131 | `bibtex-BibTeX-entry-alist'. |
d0388eac RS |
132 | |
133 | The value t means do all of the above formatting actions. | |
134 | The value nil means do no formatting at all." | |
f754fb7b RS |
135 | :group 'bibtex |
136 | :type '(choice (const :tag "None" nil) | |
7fbf4804 SM |
137 | (const :tag "All" t) |
138 | (set :menu-tag "Some" | |
139 | (const opts-or-alts) | |
140 | (const required-fields) | |
141 | (const numerical-fields) | |
142 | (const page-dashes) | |
f2dfa899 | 143 | (const whitespace) |
7fbf4804 SM |
144 | (const inherit-booktitle) |
145 | (const realign) | |
146 | (const last-comma) | |
147 | (const delimiters) | |
f2dfa899 RW |
148 | (const unify-case) |
149 | (const braces) | |
b7c3692a RW |
150 | (const strings) |
151 | (const sort-fields)))) | |
e56d3af5 RW |
152 | (put 'bibtex-entry-format 'safe-local-variable |
153 | (lambda (x) | |
154 | (or (eq x t) | |
155 | (let ((OK t)) | |
156 | (while (consp x) | |
157 | (unless (memq (pop x) | |
158 | '(opts-or-alts required-fields numerical-fields | |
159 | page-dashes whitespace inherit-booktitle realign | |
b7c3692a RW |
160 | last-comma delimiters unify-case braces strings |
161 | sort-fields)) | |
e56d3af5 RW |
162 | (setq OK nil))) |
163 | (unless (null x) (setq OK nil)) | |
164 | OK)))) | |
f2dfa899 RW |
165 | |
166 | (defcustom bibtex-field-braces-alist nil | |
167 | "Alist of field regexps that \\[bibtex-clean-entry] encloses by braces. | |
168 | Each element has the form (FIELDS REGEXP), where FIELDS is a list | |
169 | of BibTeX field names and REGEXP is a regexp. | |
403111a8 | 170 | Space characters in REGEXP will be replaced by \"[ \\t\\n]+\"." |
f2dfa899 RW |
171 | :group 'bibtex |
172 | :type '(repeat (list (repeat (string :tag "field name")) | |
173 | (choice (regexp :tag "regexp") | |
174 | (sexp :tag "sexp"))))) | |
175 | ||
176 | (defcustom bibtex-field-strings-alist nil | |
177 | "Alist of regexps that \\[bibtex-clean-entry] replaces by string constants. | |
178 | Each element has the form (FIELDS REGEXP TO-STR), where FIELDS is a list | |
179 | of BibTeX field names. In FIELDS search for REGEXP, which are replaced | |
180 | by the BibTeX string constant TO-STR. | |
403111a8 | 181 | Space characters in REGEXP will be replaced by \"[ \\t\\n]+\"." |
f2dfa899 RW |
182 | :group 'bibtex |
183 | :type '(repeat (list (repeat (string :tag "field name")) | |
184 | (regexp :tag "From regexp") | |
185 | (regexp :tag "To string constant")))) | |
50e4b39e | 186 | |
f754fb7b | 187 | (defcustom bibtex-clean-entry-hook nil |
02c8032e | 188 | "List of functions to call when entry has been cleaned. |
d0388eac | 189 | Functions are called with point inside the cleaned entry, and the buffer |
f754fb7b RS |
190 | narrowed to just the entry." |
191 | :group 'bibtex | |
ab2d0cdb | 192 | :type 'hook) |
cb4ad359 | 193 | |
f754fb7b | 194 | (defcustom bibtex-maintain-sorted-entries nil |
d10e87a2 | 195 | "If non-nil, BibTeX mode maintains all entries in sorted order. |
d715b065 | 196 | Allowed non-nil values are: |
eab10abb | 197 | plain or t All entries are sorted alphabetically. |
7fbf4804 | 198 | crossref All entries are sorted alphabetically unless an entry has a |
a9d77f1f | 199 | crossref field. These crossrefed entries are placed in |
7fbf4804 SM |
200 | alphabetical order immediately preceding the main entry. |
201 | entry-class The entries are divided into classes according to their | |
c48f463b | 202 | entry type, see `bibtex-sort-entry-class'. Within each class |
7fbf4804 SM |
203 | the entries are sorted alphabetically. |
204 | See also `bibtex-sort-ignore-string-entries'." | |
205 | :group 'bibtex | |
206 | :type '(choice (const nil) | |
207 | (const plain) | |
208 | (const crossref) | |
eab10abb RW |
209 | (const entry-class) |
210 | (const t))) | |
211 | (put 'bibtex-maintain-sorted-entries 'safe-local-variable | |
a2a25d24 | 212 | (lambda (a) (memq a '(nil t plain crossref entry-class)))) |
7fbf4804 | 213 | |
02c8032e | 214 | (defcustom bibtex-sort-entry-class |
7fbf4804 | 215 | '(("String") |
d715b065 KG |
216 | (catch-all) |
217 | ("Book" "Proceedings")) | |
c48f463b | 218 | "List of classes of BibTeX entry types, used for sorting entries. |
d715b065 | 219 | If value of `bibtex-maintain-sorted-entries' is `entry-class' |
a9d77f1f | 220 | entries are ordered according to the classes they belong to. Each |
c48f463b | 221 | class contains a list of entry types. An entry `catch-all' applies |
31df23f5 | 222 | to all entries not explicitly mentioned." |
5a0c3f56 | 223 | :group 'bibtex |
02c8032e SM |
224 | :type '(repeat (choice :tag "Class" |
225 | (const :tag "catch-all" (catch-all)) | |
c48f463b | 226 | (repeat :tag "Entry type" string)))) |
7a0574f3 SM |
227 | (put 'bibtex-sort-entry-class 'safe-local-variable |
228 | (lambda (x) (let ((OK t)) | |
229 | (while (consp x) | |
230 | (let ((y (pop x))) | |
231 | (while (consp y) | |
232 | (let ((z (pop y))) | |
233 | (unless (or (stringp z) (eq z 'catch-all)) | |
234 | (setq OK nil)))) | |
235 | (unless (null y) (setq OK nil)))) | |
236 | (unless (null x) (setq OK nil)) | |
237 | OK))) | |
7fbf4804 | 238 | |
d715b065 | 239 | (defcustom bibtex-sort-ignore-string-entries t |
d10e87a2 | 240 | "If non-nil, BibTeX @String entries are not sort-significant. |
7fbf4804 SM |
241 | That means they are ignored when determining ordering of the buffer |
242 | \(e.g., sorting, locating alphabetical position for new entries, etc.)." | |
f754fb7b RS |
243 | :group 'bibtex |
244 | :type 'boolean) | |
9ae11a89 | 245 | |
f754fb7b | 246 | (defcustom bibtex-field-kill-ring-max 20 |
d10e87a2 | 247 | "Max length of `bibtex-field-kill-ring' before discarding oldest elements." |
f754fb7b RS |
248 | :group 'bibtex |
249 | :type 'integer) | |
50e4b39e | 250 | |
d715b065 | 251 | (defcustom bibtex-entry-kill-ring-max 20 |
d10e87a2 | 252 | "Max length of `bibtex-entry-kill-ring' before discarding oldest elements." |
d715b065 KG |
253 | :group 'bibtex |
254 | :type 'integer) | |
255 | ||
f754fb7b | 256 | (defcustom bibtex-parse-keys-timeout 60 |
d10e87a2 | 257 | "Time interval in seconds for parsing BibTeX buffers during idle time. |
02c8032e | 258 | Parsing initializes `bibtex-reference-keys' and `bibtex-strings'." |
f754fb7b RS |
259 | :group 'bibtex |
260 | :type 'integer) | |
af6fb89d | 261 | |
d715b065 | 262 | (defcustom bibtex-parse-keys-fast t |
d10e87a2 | 263 | "If non-nil, use fast but simplified algorithm for parsing BibTeX keys. |
d715b065 KG |
264 | If parsing fails, try to set this variable to nil." |
265 | :group 'bibtex | |
266 | :type 'boolean) | |
267 | ||
2de69e00 RW |
268 | (define-widget 'bibtex-entry-alist 'lazy |
269 | "Format of `bibtex-BibTeX-entry-alist' and friends." | |
270 | :type '(repeat (group (string :tag "Entry type") | |
271 | (string :tag "Documentation") | |
272 | (repeat :tag "Required fields" | |
273 | (group (string :tag "Field") | |
274 | (option (choice :tag "Comment" :value nil | |
275 | (const nil) string)) | |
276 | (option (choice :tag "Init" :value nil | |
277 | (const nil) string function)) | |
278 | (option (choice :tag "Alternative" :value nil | |
279 | (const nil) integer)))) | |
280 | (repeat :tag "Crossref fields" | |
281 | (group (string :tag "Field") | |
282 | (option (choice :tag "Comment" :value nil | |
283 | (const nil) string)) | |
284 | (option (choice :tag "Init" :value nil | |
285 | (const nil) string function)) | |
286 | (option (choice :tag "Alternative" :value nil | |
287 | (const nil) integer)))) | |
288 | (repeat :tag "Optional fields" | |
289 | (group (string :tag "Field") | |
290 | (option (choice :tag "Comment" :value nil | |
291 | (const nil) string)) | |
292 | (option (choice :tag "Init" :value nil | |
293 | (const nil) string function))))))) | |
294 | ||
295 | (define-obsolete-variable-alias 'bibtex-entry-field-alist | |
296 | 'bibtex-BibTeX-entry-alist "24.1") | |
297 | (defcustom bibtex-BibTeX-entry-alist | |
298 | '(("Article" "Article in Journal" | |
299 | (("author") | |
300 | ("title" "Title of the article (BibTeX converts it to lowercase)")) | |
301 | (("journal") ("year")) | |
302 | (("volume" "Volume of the journal") | |
303 | ("number" "Number of the journal (only allowed if entry contains volume)") | |
304 | ("pages" "Pages in the journal") | |
305 | ("month") ("note"))) | |
306 | ("InProceedings" "Article in Conference Proceedings" | |
307 | (("author") | |
308 | ("title" "Title of the article in proceedings (BibTeX converts it to lowercase)")) | |
309 | (("booktitle" "Name of the conference proceedings") | |
310 | ("year")) | |
311 | (("editor") | |
312 | ("volume" "Volume of the conference proceedings in the series") | |
313 | ("number" "Number of the conference proceedings in a small series (overwritten by volume)") | |
314 | ("series" "Series in which the conference proceedings appeared") | |
315 | ("pages" "Pages in the conference proceedings") | |
316 | ("month") ("address") | |
317 | ("organization" "Sponsoring organization of the conference") | |
318 | ("publisher" "Publishing company, its location") | |
319 | ("note"))) | |
320 | ("InCollection" "Article in a Collection" | |
321 | (("author") | |
322 | ("title" "Title of the article in book (BibTeX converts it to lowercase)") | |
323 | ("booktitle" "Name of the book")) | |
324 | (("publisher") ("year")) | |
325 | (("editor") | |
326 | ("volume" "Volume of the book in the series") | |
327 | ("number" "Number of the book in a small series (overwritten by volume)") | |
328 | ("series" "Series in which the book appeared") | |
329 | ("type" "Word to use instead of \"chapter\"") | |
330 | ("chapter" "Chapter in the book") | |
331 | ("pages" "Pages in the book") | |
332 | ("edition" "Edition of the book as a capitalized English word") | |
333 | ("month") ("address") ("note"))) | |
334 | ("InBook" "Chapter or Pages in a Book" | |
335 | (("author" nil nil 0) | |
336 | ("editor" nil nil 0) | |
337 | ("title" "Title of the book") | |
338 | ("chapter" "Chapter in the book")) | |
339 | (("publisher") ("year")) | |
340 | (("volume" "Volume of the book in the series") | |
341 | ("number" "Number of the book in a small series (overwritten by volume)") | |
342 | ("series" "Series in which the book appeared") | |
343 | ("type" "Word to use instead of \"chapter\"") | |
344 | ("address") | |
345 | ("edition" "Edition of the book as a capitalized English word") | |
346 | ("month") | |
347 | ("pages" "Pages in the book") | |
348 | ("note"))) | |
349 | ("Proceedings" "Conference Proceedings" | |
350 | (("title" "Title of the conference proceedings") | |
351 | ("year")) | |
352 | nil | |
353 | (("booktitle" "Title of the proceedings for cross references") | |
354 | ("editor") | |
355 | ("volume" "Volume of the conference proceedings in the series") | |
356 | ("number" "Number of the conference proceedings in a small series (overwritten by volume)") | |
357 | ("series" "Series in which the conference proceedings appeared") | |
358 | ("address") | |
359 | ("month") | |
360 | ("organization" "Sponsoring organization of the conference") | |
361 | ("publisher" "Publishing company, its location") | |
362 | ("note"))) | |
363 | ("Book" "Book" | |
364 | (("author" nil nil 0) | |
365 | ("editor" nil nil 0) | |
366 | ("title" "Title of the book")) | |
367 | (("publisher") ("year")) | |
368 | (("volume" "Volume of the book in the series") | |
369 | ("number" "Number of the book in a small series (overwritten by volume)") | |
370 | ("series" "Series in which the book appeared") | |
371 | ("address") | |
372 | ("edition" "Edition of the book as a capitalized English word") | |
373 | ("month") ("note"))) | |
374 | ("Booklet" "Booklet (Bound, but no Publisher)" | |
375 | (("title" "Title of the booklet (BibTeX converts it to lowercase)")) | |
376 | nil | |
377 | (("author") | |
378 | ("howpublished" "The way in which the booklet was published") | |
379 | ("address") ("month") ("year") ("note"))) | |
380 | ("PhdThesis" "PhD. Thesis" | |
381 | (("author") | |
382 | ("title" "Title of the PhD. thesis") | |
383 | ("school" "School where the PhD. thesis was written") | |
384 | ("year")) | |
385 | nil | |
386 | (("type" "Type of the PhD. thesis") | |
387 | ("address" "Address of the school (if not part of field \"school\") or country") | |
388 | ("month") ("note"))) | |
389 | ("MastersThesis" "Master's Thesis" | |
390 | (("author") | |
391 | ("title" "Title of the master's thesis (BibTeX converts it to lowercase)") | |
392 | ("school" "School where the master's thesis was written") | |
393 | ("year")) | |
394 | nil | |
395 | (("type" "Type of the master's thesis (if other than \"Master's thesis\")") | |
396 | ("address" "Address of the school (if not part of field \"school\") or country") | |
397 | ("month") ("note"))) | |
398 | ("TechReport" "Technical Report" | |
399 | (("author") | |
400 | ("title" "Title of the technical report (BibTeX converts it to lowercase)") | |
401 | ("institution" "Sponsoring institution of the report") | |
402 | ("year")) | |
403 | nil | |
404 | (("type" "Type of the report (if other than \"technical report\")") | |
405 | ("number" "Number of the technical report") | |
406 | ("address") ("month") ("note"))) | |
407 | ("Manual" "Technical Manual" | |
408 | (("title" "Title of the manual")) | |
409 | nil | |
410 | (("author") | |
411 | ("organization" "Publishing organization of the manual") | |
412 | ("address") | |
413 | ("edition" "Edition of the manual as a capitalized English word") | |
414 | ("month") ("year") ("note"))) | |
415 | ("Unpublished" "Unpublished" | |
416 | (("author") | |
417 | ("title" "Title of the unpublished work (BibTeX converts it to lowercase)") | |
418 | ("note")) | |
419 | nil | |
420 | (("month") ("year"))) | |
421 | ("Misc" "Miscellaneous" nil nil | |
422 | (("author") | |
423 | ("title" "Title of the work (BibTeX converts it to lowercase)") | |
424 | ("howpublished" "The way in which the work was published") | |
425 | ("month") ("year") ("note")))) | |
426 | "Alist of BibTeX entry types and their associated fields. | |
427 | Elements are lists (ENTRY-TYPE DOC REQUIRED CROSSREF OPTIONAL). | |
428 | ENTRY-TYPE is the type of a BibTeX entry. | |
429 | DOC is a brief doc string used for menus. If nil ENTRY-TYPE is used. | |
430 | REQUIRED is a list of required fields. | |
431 | CROSSREF is a list of fields that are optional if a crossref field | |
432 | is present; but these fields are required otherwise. | |
433 | OPTIONAL is a list of optional fields. | |
434 | ||
50e4b39e | 435 | Each element of these lists is a list of the form |
2de69e00 RW |
436 | \(FIELD COMMENT INIT ALTERNATIVE). |
437 | COMMENT, INIT, and ALTERNATIVE are optional. | |
438 | ||
439 | FIELD is the name of the field. | |
440 | COMMENT is the comment string that appears in the echo area. | |
441 | If COMMENT is nil use `bibtex-BibTeX-field-alist' if possible. | |
442 | INIT is either the initial content of the field or a function, | |
443 | which is called to determine the initial content of the field. | |
444 | ALTERNATIVE if non-nil is an integer that numbers sets of | |
445 | alternatives, starting from zero." | |
446 | :group 'BibTeX | |
b2096d72 | 447 | :version "24.1" |
2de69e00 RW |
448 | :type 'bibtex-entry-alist) |
449 | (put 'bibtex-BibTeX-entry-alist 'risky-local-variable t) | |
450 | ||
451 | (defcustom bibtex-biblatex-entry-alist | |
452 | ;; Compare in biblatex documentation: | |
453 | ;; Sec. 2.1.1 Regular types (required and optional fields) | |
454 | ;; Appendix A Default Crossref setup | |
455 | '(("Article" "Article in Journal" | |
456 | (("author") ("title") ("journaltitle") | |
457 | ("year" nil nil 0) ("date" nil nil 0)) | |
458 | nil | |
459 | (("translator") ("annotator") ("commentator") ("subtitle") ("titleaddon") | |
460 | ("editor") ("editora") ("editorb") ("editorc") | |
461 | ("journalsubtitle") ("issuetitle") ("issuesubtitle") | |
462 | ("language") ("origlanguage") ("series") ("volume") ("number") ("eid") | |
463 | ("issue") ("month") ("pages") ("version") ("note") ("issn") | |
464 | ("addendum") ("pubstate") ("doi") ("eprint") ("eprintclass") | |
465 | ("eprinttype") ("url") ("urldate"))) | |
466 | ("Book" "Single-Volume Book" | |
467 | (("author") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
468 | nil | |
469 | (("editor") ("editora") ("editorb") ("editorc") | |
470 | ("translator") ("annotator") ("commentator") | |
471 | ("introduction") ("foreword") ("afterword") ("titleaddon") | |
472 | ("maintitle") ("mainsubtitle") ("maintitleaddon") | |
473 | ("language") ("origlanguage") ("volume") ("part") ("edition") ("volumes") | |
474 | ("series") ("number") ("note") ("publisher") ("location") ("isbn") | |
475 | ("chapter") ("pages") ("pagetotal") ("addendum") ("pubstate") ("doi") | |
476 | ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
477 | ("MVBook" "Multi-Volume Book" | |
478 | (("author") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
479 | nil | |
480 | (("editor") ("editora") ("editorb") ("editorc") | |
481 | ("translator") ("annotator") ("commentator") | |
482 | ("introduction") ("foreword") ("afterword") ("subtitle") | |
483 | ("titleaddon") ("language") ("origlanguage") ("edition") ("volumes") | |
484 | ("series") ("number") ("note") ("publisher") | |
485 | ("location") ("isbn") ("pagetotal") ("addendum") ("pubstate") ("doi") | |
486 | ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
487 | ("InBook" "Chapter or Pages in a Book" | |
488 | (("title") ("year" nil nil 0) ("date" nil nil 0)) | |
489 | (("author") ("booktitle")) | |
490 | (("bookauthor") ("editor") ("editora") ("editorb") ("editorc") | |
491 | ("translator") ("annotator") ("commentator") ("introduction") ("foreword") | |
492 | ("afterword") ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
493 | ("maintitleaddon") ("booksubtitle") ("booktitleaddon") | |
494 | ("language") ("origlanguage") ("volume") ("part") ("edition") ("volumes") | |
495 | ("series") ("number") ("note") ("publisher") ("location") ("isbn") | |
496 | ("chapter") ("pages") ("addendum") ("pubstate") | |
497 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
498 | ("BookInBook" "Book in Collection" ; same as @inbook | |
499 | (("title") ("year" nil nil 0) ("date" nil nil 0)) | |
500 | (("author") ("booktitle")) | |
501 | (("bookauthor") ("editor") ("editora") ("editorb") ("editorc") | |
502 | ("translator") ("annotator") ("commentator") ("introduction") ("foreword") | |
503 | ("afterword") ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
504 | ("maintitleaddon") ("booksubtitle") ("booktitleaddon") | |
505 | ("language") ("origlanguage") ("volume") ("part") ("edition") ("volumes") | |
506 | ("series") ("number") ("note") ("publisher") ("location") ("isbn") | |
507 | ("chapter") ("pages") ("addendum") ("pubstate") | |
508 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
509 | ("SuppBook" "Supplemental Material in a Book" ; same as @inbook | |
510 | (("title") ("year" nil nil 0) ("date" nil nil 0)) | |
511 | (("author") ("booktitle")) | |
512 | (("bookauthor") ("editor") ("editora") ("editorb") ("editorc") | |
513 | ("translator") ("annotator") ("commentator") ("introduction") ("foreword") | |
514 | ("afterword") ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
515 | ("maintitleaddon") ("booksubtitle") ("booktitleaddon") | |
516 | ("language") ("origlanguage") ("volume") ("part") ("edition") ("volumes") | |
517 | ("series") ("number") ("note") ("publisher") ("location") ("isbn") | |
518 | ("chapter") ("pages") ("addendum") ("pubstate") | |
519 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
520 | ("Booklet" "Booklet (Bound, but no Publisher)" | |
521 | (("author" nil nil 0) ("editor" nil nil 0) ("title") | |
522 | ("year" nil nil 1) ("date" nil nil 1)) | |
523 | nil | |
524 | (("subtitle") ("titleaddon") ("language") ("howpublished") ("type") | |
525 | ("note") ("location") ("chapter") ("pages") ("pagetotal") ("addendum") | |
526 | ("pubstate") ("doi") ("eprint") ("eprintclass") ("eprinttype") | |
527 | ("url") ("urldate"))) | |
528 | ("Collection" "Single-Volume Collection" | |
529 | (("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
530 | nil | |
531 | (("editora") ("editorb") ("editorc") ("translator") ("annotator") | |
532 | ("commentator") ("introduction") ("foreword") ("afterword") | |
533 | ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
534 | ("maintitleaddon") ("language") ("origlanguage") ("volume") | |
535 | ("part") ("edition") ("volumes") ("series") ("number") ("note") | |
536 | ("publisher") ("location") ("isbn") ("chapter") ("pages") ("pagetotal") | |
537 | ("addendum") ("pubstate") ("doi") ("eprint") ("eprintclass") | |
538 | ("eprinttype") ("url") ("urldate"))) | |
539 | ("MVCollection" "Multi-Volume Collection" | |
540 | (("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
541 | nil | |
542 | (("editora") ("editorb") ("editorc") ("translator") ("annotator") | |
543 | ("commentator") ("introduction") ("foreword") ("afterword") | |
544 | ("subtitle") ("titleaddon") ("language") ("origlanguage") ("edition") | |
545 | ("volumes") ("series") ("number") ("note") ("publisher") | |
546 | ("location") ("isbn") ("pagetotal") ("addendum") ("pubstate") ("doi") | |
547 | ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
548 | ("InCollection" "Article in a Collection" | |
549 | (("author") ("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
550 | (("booktitle")) | |
551 | (("editora") ("editorb") ("editorc") ("translator") ("annotator") | |
552 | ("commentator") ("introduction") ("foreword") ("afterword") | |
553 | ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
554 | ("maintitleaddon") ("booksubtitle") ("booktitleaddon") | |
555 | ("language") ("origlanguage") ("volume") ("part") ("edition") | |
556 | ("volumes") ("series") ("number") ("note") ("publisher") ("location") | |
557 | ("isbn") ("chapter") ("pages") ("addendum") ("pubstate") ("doi") | |
558 | ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
559 | ("SuppCollection" "Supplemental Material in a Collection" ; same as @incollection | |
560 | (("author") ("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
561 | (("booktitle")) | |
562 | (("editora") ("editorb") ("editorc") ("translator") ("annotator") | |
563 | ("commentator") ("introduction") ("foreword") ("afterword") | |
564 | ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
565 | ("maintitleaddon") ("booksubtitle") ("booktitleaddon") | |
566 | ("language") ("origlanguage") ("volume") ("part") ("edition") | |
567 | ("volumes") ("series") ("number") ("note") ("publisher") ("location") | |
568 | ("isbn") ("chapter") ("pages") ("addendum") ("pubstate") ("doi") | |
569 | ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
570 | ("Manual" "Technical Manual" | |
571 | (("author" nil nil 0) ("editor" nil nil 0) ("title") | |
572 | ("year" nil nil 1) ("date" nil nil 1)) | |
573 | nil | |
574 | (("subtitle") ("titleaddon") ("language") ("edition") | |
575 | ("type") ("series") ("number") ("version") ("note") | |
576 | ("organization") ("publisher") ("location") ("isbn") ("chapter") | |
577 | ("pages") ("pagetotal") ("addendum") ("pubstate") | |
578 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
579 | ("Misc" "Miscellaneous" | |
580 | (("author" nil nil 0) ("editor" nil nil 0) ("title") | |
581 | ("year" nil nil 1) ("date" nil nil 1)) | |
582 | nil | |
583 | (("subtitle") ("titleaddon") ("language") ("howpublished") ("type") | |
584 | ("version") ("note") ("organization") ("location") | |
585 | ("date") ("month") ("year") ("addendum") ("pubstate") | |
586 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
587 | ("Online" "Online Resource" | |
588 | (("author" nil nil 0) ("editor" nil nil 0) ("title") | |
589 | ("year" nil nil 1) ("date" nil nil 1) ("url")) | |
590 | nil | |
591 | (("subtitle") ("titleaddon") ("language") ("version") ("note") | |
592 | ("organization") ("date") ("month") ("year") ("addendum") | |
593 | ("pubstate") ("urldate"))) | |
594 | ("Patent" "Patent" | |
595 | (("author") ("title") ("number") ("year" nil nil 0) ("date" nil nil 0)) | |
596 | nil | |
597 | (("holder") ("subtitle") ("titleaddon") ("type") ("version") ("location") | |
598 | ("note") ("date") ("month") ("year") ("addendum") ("pubstate") | |
599 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
600 | ("Periodical" "Complete Issue of a Periodical" | |
601 | (("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
602 | nil | |
603 | (("editora") ("editorb") ("editorc") ("subtitle") ("issuetitle") | |
604 | ("issuesubtitle") ("language") ("series") ("volume") ("number") ("issue") | |
605 | ("date") ("month") ("year") ("note") ("issn") ("addendum") ("pubstate") | |
606 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
607 | ("SuppPeriodical" "Supplemental Material in a Periodical" ; same as @article | |
608 | (("author") ("title") ("journaltitle") | |
609 | ("year" nil nil 0) ("date" nil nil 0)) | |
610 | nil | |
611 | (("translator") ("annotator") ("commentator") ("subtitle") ("titleaddon") | |
612 | ("editor") ("editora") ("editorb") ("editorc") | |
613 | ("journalsubtitle") ("issuetitle") ("issuesubtitle") | |
614 | ("language") ("origlanguage") ("series") ("volume") ("number") ("eid") | |
615 | ("issue") ("month") ("pages") ("version") ("note") ("issn") | |
616 | ("addendum") ("pubstate") ("doi") ("eprint") ("eprintclass") | |
617 | ("eprinttype") ("url") ("urldate"))) | |
618 | ("Proceedings" "Single-Volume Conference Proceedings" | |
619 | (("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
620 | nil | |
621 | (("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
622 | ("maintitleaddon") ("eventtitle") ("eventdate") ("venue") ("language") | |
623 | ("volume") ("part") ("volumes") ("series") ("number") ("note") | |
624 | ("organization") ("publisher") ("location") ("month") | |
625 | ("isbn") ("chapter") ("pages") ("pagetotal") ("addendum") ("pubstate") | |
626 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
627 | ("MVProceedings" "Multi-Volume Conference Proceedings" | |
628 | (("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
629 | nil | |
630 | (("subtitle") ("titleaddon") ("eventtitle") ("eventdate") ("venue") | |
631 | ("language") ("volumes") ("series") ("number") ("note") | |
632 | ("organization") ("publisher") ("location") ("month") | |
633 | ("isbn") ("pagetotal") ("addendum") ("pubstate") | |
634 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
635 | ("InProceedings" "Article in Conference Proceedings" | |
636 | (("author") ("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
637 | (("booktitle")) | |
638 | (("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
639 | ("maintitleaddon") ("booksubtitle") ("booktitleaddon") | |
640 | ("eventtitle") ("eventdate") ("venue") ("language") | |
641 | ("volume") ("part") ("volumes") ("series") ("number") ("note") | |
642 | ("organization") ("publisher") ("location") ("month") ("isbn") | |
643 | ("chapter") ("pages") ("addendum") ("pubstate") | |
644 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
645 | ("Reference" "Single-Volume Work of Reference" ; same as @collection | |
646 | (("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
647 | nil | |
648 | (("editora") ("editorb") ("editorc") ("translator") ("annotator") | |
649 | ("commentator") ("introduction") ("foreword") ("afterword") | |
650 | ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
651 | ("maintitleaddon") ("language") ("origlanguage") ("volume") | |
652 | ("part") ("edition") ("volumes") ("series") ("number") ("note") | |
653 | ("publisher") ("location") ("isbn") ("chapter") ("pages") ("pagetotal") | |
654 | ("addendum") ("pubstate") ("doi") ("eprint") ("eprintclass") | |
655 | ("eprinttype") ("url") ("urldate"))) | |
656 | ("MVReference" "Multi-Volume Work of Reference" ; same as @mvcollection | |
657 | (("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
658 | nil | |
659 | (("editora") ("editorb") ("editorc") ("translator") ("annotator") | |
660 | ("commentator") ("introduction") ("foreword") ("afterword") | |
661 | ("subtitle") ("titleaddon") ("language") ("origlanguage") ("edition") | |
662 | ("volumes") ("series") ("number") ("note") ("publisher") | |
663 | ("location") ("isbn") ("pagetotal") ("addendum") ("pubstate") ("doi") | |
664 | ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
665 | ("InReference" "Article in a Work of Reference" ; same as @incollection | |
666 | (("author") ("editor") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
667 | (("booktitle")) | |
668 | (("editora") ("editorb") ("editorc") ("translator") ("annotator") | |
669 | ("commentator") ("introduction") ("foreword") ("afterword") | |
670 | ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle") | |
671 | ("maintitleaddon") ("booksubtitle") ("booktitleaddon") | |
672 | ("language") ("origlanguage") ("volume") ("part") ("edition") | |
673 | ("volumes") ("series") ("number") ("note") ("publisher") ("location") | |
674 | ("isbn") ("chapter") ("pages") ("addendum") ("pubstate") ("doi") | |
675 | ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
676 | ("Report" "Technical or Research Report" | |
677 | (("author") ("title") ("type") ("institution") | |
678 | ("year" nil nil 0) ("date" nil nil 0)) | |
679 | nil | |
680 | (("subtitle") ("titleaddon") ("language") ("number") ("version") ("note") | |
681 | ("location") ("month") ("isrn") ("chapter") ("pages") ("pagetotal") | |
682 | ("addendum") ("pubstate") | |
683 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
684 | ("Thesis" "PhD. or Master's Thesis" | |
685 | (("author") ("title") ("type") ("institution") | |
686 | ("year" nil nil 0) ("date" nil nil 0)) | |
687 | nil | |
688 | (("subtitle") ("titleaddon") ("language") ("note") ("location") | |
689 | ("month") ("isbn") ("chapter") ("pages") ("pagetotal") | |
690 | ("addendum") ("pubstate") | |
691 | ("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate"))) | |
692 | ("Unpublished" "Unpublished" | |
693 | (("author") ("title") ("year" nil nil 0) ("date" nil nil 0)) | |
694 | nil | |
695 | (("subtitle") ("titleaddon") ("language") ("howpublished") | |
696 | ("note") ("location") ("isbn") ("date") ("month") ("year") | |
697 | ("addendum") ("pubstate") ("url") ("urldate")))) | |
698 | "Alist of biblatex entry types and their associated fields. | |
699 | It has the same format as `bibtex-BibTeX-entry-alist'." | |
0dcfda42 | 700 | :group 'bibtex |
b2096d72 | 701 | :version "24.1" |
2de69e00 RW |
702 | :type 'bibtex-entry-alist) |
703 | (put 'bibtex-biblatex-entry-alist 'risky-local-variable t) | |
704 | ||
705 | (define-widget 'bibtex-field-alist 'lazy | |
706 | "Format of `bibtex-BibTeX-entry-alist' and friends." | |
707 | :type '(repeat (group (string :tag "Field type") | |
708 | (string :tag "Comment")))) | |
709 | ||
710 | (defcustom bibtex-BibTeX-field-alist | |
711 | '(("author" "Author1 [and Author2 ...] [and others]") | |
712 | ("editor" "Editor1 [and Editor2 ...] [and others]") | |
713 | ("journal" "Name of the journal (use string, remove braces)") | |
714 | ("year" "Year of publication") | |
715 | ("month" "Month of the publication as a string (remove braces)") | |
716 | ("note" "Remarks to be put at the end of the \\bibitem") | |
717 | ("publisher" "Publishing company") | |
718 | ("address" "Address of the publisher")) | |
719 | "Alist of BibTeX fields. | |
720 | Each element is a list (FIELD COMMENT). COMMENT is used as a default | |
721 | if `bibtex-BibTeX-entry-alist' does not define a comment for FIELD." | |
722 | :group 'bibtex | |
b2096d72 | 723 | :version "24.1" |
2de69e00 RW |
724 | :type 'bibtex-field-alist) |
725 | ||
726 | (defcustom bibtex-biblatex-field-alist | |
727 | ;; See 2.2.2 Data Fields | |
728 | '(("abstract" "Abstract of the work") | |
729 | ("addendum" "Miscellaneous bibliographic data") | |
730 | ("afterword" "Author(s) of an afterword to the work") | |
731 | ("annotation" "Annotation") | |
732 | ("annotator" "Author(s) of annotations to the work") | |
733 | ("author" "Author(s) of the title") | |
734 | ("bookauthor" "Author(s) of the booktitle.") | |
735 | ("bookpagination" "Pagination scheme of the enclosing work") | |
736 | ("booksubtitle" "Subtitle related to the booktitle") | |
737 | ("booktitle" "Title of the book") | |
738 | ("booktitleaddon" "Annex to the booktitle") | |
739 | ("chapter" "Chapter, section, or any other unit of a work") | |
740 | ("commentator" "Author(s) of a commentary to the work") | |
741 | ("date" "Publication date") | |
742 | ("doi" "Digital Object Identifier") | |
743 | ("edition" "Edition of a printed publication") | |
744 | ("editor" "Editor(s) of the title, booktitle, or maintitle") | |
745 | ("editora" "Secondary editor") | |
746 | ("editorb" "Secondary editor") | |
747 | ("editorc" "Secondary editor") | |
748 | ("editortype" "Type of editorial role performed by the editor") | |
749 | ("editoratype" "Type of editorial role performed by editora") | |
750 | ("editorbtype" "Type of editorial role performed by editorb") | |
751 | ("editorctype" "Type of editorial role performed by editorc") | |
752 | ("eid" "Electronic identifier of an article") | |
753 | ("eprint" "Electronic identifier of an online publication") | |
754 | ("eprintclass" "Additional information related to the eprinttype") | |
755 | ("eprinttype" "Type of eprint identifier") | |
756 | ("eventdate" "Date of a conference or some other event") | |
757 | ("eventtitle" "Title of a conference or some other event") | |
758 | ("file" "Local link to an electronic version of the work") | |
759 | ("foreword" "Author(s) of a foreword to the work") | |
760 | ("holder" "Holder(s) of a patent") | |
761 | ("howpublished" "Publication notice for unusual publications") | |
762 | ("indextitle" "Title to use for indexing instead of the regular title") | |
763 | ("institution" "Name of a university or some other institution") | |
764 | ("introduction" "Author(s) of an introduction to the work") | |
765 | ("isan" "International Standard Audiovisual Number of an audiovisual work") | |
766 | ("isbn" "International Standard Book Number of a book.") | |
767 | ("ismn" "International Standard Music Number for printed music") | |
768 | ("isrn" "International Standard Technical Report Number") | |
769 | ("issn" "International Standard Serial Number of a periodical.") | |
770 | ("issue" "Issue of a journal") | |
771 | ("issuesubtitle" "Subtitle of a specific issue of a journal or other periodical.") | |
772 | ("issuetitle" "Title of a specific issue of a journal or other periodical.") | |
773 | ("iswc" "International Standard Work Code of a musical work") | |
774 | ("journalsubtitle" "Subtitle of a journal, a newspaper, or some other periodical.") | |
775 | ("journaltitle" "Name of a journal, a newspaper, or some other periodical.") | |
776 | ("label" "Substitute for the regular label to be used by the citation style") | |
777 | ("language" "Language(s) of the work") | |
778 | ("library" "Library name and a call number") | |
779 | ("location" "Place(s) of publication") | |
780 | ("mainsubtitle" "Subtitle related to the maintitle") | |
781 | ("maintitle" "Main title of a multi-volume book, such as Collected Works") | |
782 | ("maintitleaddon" "Annex to the maintitle") | |
783 | ("month" "Publication month") | |
784 | ("nameaddon" "Addon to be printed immediately after the author name") | |
785 | ("note" "Miscellaneous bibliographic data") | |
786 | ("number" "Number of a journal or the volume/number of a book in a series") | |
787 | ("organization" "Organization(s) that published a work") | |
788 | ("origdate" "Publication date of the original edition") | |
789 | ("origlanguage" "Original publication language of a translated edition") | |
790 | ("origlocation" "Location of the original edition") | |
791 | ("origpublisher" "Publisher of the original edition") | |
792 | ("origtitle" "Title of the original work") | |
793 | ("pages" "Page number(s) or page range(s)") | |
794 | ("pagetotal" "Total number of pages of the work.") | |
795 | ("pagination" "Pagination of the work") | |
796 | ("part" "Number of a partial volume") | |
797 | ("publisher" "Name(s) of the publisher(s)") | |
798 | ("pubstate" "Publication state of the work, e. g.,'in press'") | |
799 | ("reprinttitle" "Title of a reprint of the work") | |
800 | ("series" "Name of a publication series") | |
801 | ("shortauthor" "Author(s) of the work, given in an abbreviated form") | |
802 | ("shorteditor" "Editor(s) of the work, given in an abbreviated form") | |
803 | ("shortjournal" "Short version or an acronym of the journal title") | |
804 | ("shortseries" "Short version or an acronym of the series field") | |
805 | ("shorttitle" "Title in an abridged form") | |
806 | ("subtitle" "Subtitle of the work") | |
807 | ("title" "Title of the work") | |
808 | ("titleaddon" "Annex to the title") | |
809 | ("translator" "Translator(s) of the work") | |
810 | ("type" "Type of a manual, patent, report, or thesis") | |
811 | ("url" " URL of an online publication.") | |
812 | ("urldate" "Access date of the address specified in the url field") | |
813 | ("venue" "Location of a conference, a symposium, or some other event") | |
814 | ("version" "Revision number of a piece of software, a manual, etc.") | |
815 | ("volume" "Volume of a multi-volume book or a periodical") | |
816 | ("volumes" "Total number of volumes of a multi-volume work") | |
817 | ("year" "Year of publication")) | |
818 | "Alist of biblatex fields. | |
819 | It has the same format as `bibtex-BibTeX-entry-alist'." | |
820 | :group 'bibtex | |
b2096d72 | 821 | :version "24.1" |
2de69e00 RW |
822 | :type 'bibtex-field-alist) |
823 | ||
824 | (defcustom bibtex-dialect-list '(BibTeX biblatex) | |
825 | "List of BibTeX dialects known to BibTeX mode. | |
826 | For each DIALECT (a symbol) a variable bibtex-DIALECT-entry-alist defines | |
827 | the allowed entries and bibtex-DIALECT-field-alist defines known field types. | |
828 | Predefined dialects include BibTeX and biblatex." | |
829 | :group 'bibtex | |
b2096d72 | 830 | :version "24.1" |
2de69e00 RW |
831 | :type '(repeat (symbol :tag "Dialect"))) |
832 | ||
833 | (defcustom bibtex-dialect 'BibTeX | |
834 | "Current BibTeX dialect. For allowed values see `bibtex-dialect-list'. | |
ace88aa2 | 835 | To interactively change the dialect use the command `bibtex-set-dialect'." |
2de69e00 | 836 | :group 'bibtex |
b2096d72 | 837 | :version "24.1" |
2de69e00 RW |
838 | :set '(lambda (symbol value) |
839 | (set-default symbol value) | |
840 | ;; `bibtex-set-dialect' is undefined during loading (no problem) | |
841 | (if (fboundp 'bibtex-set-dialect) | |
842 | (bibtex-set-dialect value))) | |
843 | :type '(choice (const BibTeX) | |
844 | (const biblatex) | |
845 | (symbol :tag "Custom"))) | |
ace88aa2 | 846 | (put 'bibtex-dialect 'safe-local-variable 'symbolp) |
2de69e00 RW |
847 | |
848 | (defcustom bibtex-no-opt-remove-re "\\`option" | |
849 | "If a field name matches this regexp, the prefix OPT is not removed. | |
850 | If nil prefix OPT is always removed" | |
851 | :group 'bibtex | |
b2096d72 | 852 | :version "24.1" |
2de69e00 | 853 | :type '(choice (regexp) (const nil))) |
50e4b39e | 854 | |
02c8032e SM |
855 | (defcustom bibtex-comment-start "@Comment" |
856 | "String starting a BibTeX comment." | |
857 | :group 'bibtex | |
858 | :type 'string) | |
ab2d0cdb | 859 | |
f754fb7b | 860 | (defcustom bibtex-add-entry-hook nil |
02c8032e | 861 | "List of functions to call when BibTeX entry has been inserted." |
f754fb7b | 862 | :group 'bibtex |
ab2d0cdb | 863 | :type 'hook) |
50e4b39e | 864 | |
f754fb7b | 865 | (defcustom bibtex-predefined-month-strings |
7fbf4804 SM |
866 | '(("jan" . "January") |
867 | ("feb" . "February") | |
868 | ("mar" . "March") | |
869 | ("apr" . "April") | |
870 | ("may" . "May") | |
871 | ("jun" . "June") | |
872 | ("jul" . "July") | |
873 | ("aug" . "August") | |
874 | ("sep" . "September") | |
875 | ("oct" . "October") | |
876 | ("nov" . "November") | |
877 | ("dec" . "December")) | |
878 | "Alist of month string definitions used in the BibTeX style files. | |
d715b065 | 879 | Each element is a pair of strings (ABBREVIATION . EXPANSION)." |
f754fb7b | 880 | :group 'bibtex |
7fbf4804 SM |
881 | :type '(repeat (cons (string :tag "Month abbreviation") |
882 | (string :tag "Month expansion")))) | |
50e4b39e | 883 | |
f754fb7b | 884 | (defcustom bibtex-predefined-strings |
50e4b39e RS |
885 | (append |
886 | bibtex-predefined-month-strings | |
7fbf4804 SM |
887 | '(("acmcs" . "ACM Computing Surveys") |
888 | ("acta" . "Acta Informatica") | |
889 | ("cacm" . "Communications of the ACM") | |
890 | ("ibmjrd" . "IBM Journal of Research and Development") | |
891 | ("ibmsj" . "IBM Systems Journal") | |
892 | ("ieeese" . "IEEE Transactions on Software Engineering") | |
893 | ("ieeetc" . "IEEE Transactions on Computers") | |
894 | ("ieeetcad" . "IEEE Transactions on Computer-Aided Design of Integrated Circuits") | |
895 | ("ipl" . "Information Processing Letters") | |
896 | ("jacm" . "Journal of the ACM") | |
897 | ("jcss" . "Journal of Computer and System Sciences") | |
898 | ("scp" . "Science of Computer Programming") | |
899 | ("sicomp" . "SIAM Journal on Computing") | |
900 | ("tcs" . "Theoretical Computer Science") | |
901 | ("tocs" . "ACM Transactions on Computer Systems") | |
902 | ("tods" . "ACM Transactions on Database Systems") | |
903 | ("tog" . "ACM Transactions on Graphics") | |
904 | ("toms" . "ACM Transactions on Mathematical Software") | |
905 | ("toois" . "ACM Transactions on Office Information Systems") | |
906 | ("toplas" . "ACM Transactions on Programming Languages and Systems"))) | |
907 | "Alist of string definitions used in the BibTeX style files. | |
d715b065 | 908 | Each element is a pair of strings (ABBREVIATION . EXPANSION)." |
f754fb7b | 909 | :group 'bibtex |
7fbf4804 SM |
910 | :type '(repeat (cons (string :tag "String") |
911 | (string :tag "String expansion")))) | |
cb4ad359 | 912 | |
f754fb7b | 913 | (defcustom bibtex-string-files nil |
d10e87a2 | 914 | "List of BibTeX files containing string definitions. |
02c8032e SM |
915 | List elements can be absolute file names or file names relative |
916 | to the directories specified in `bibtex-string-file-path'." | |
f754fb7b RS |
917 | :group 'bibtex |
918 | :type '(repeat file)) | |
50e4b39e | 919 | |
f1a4e679 CY |
920 | (defcustom bibtex-string-file-path (getenv "BIBINPUTS") |
921 | "Colon-separated list of paths to search for `bibtex-string-files'." | |
922 | :group 'bibtex | |
923 | :type 'string) | |
cb4ad359 | 924 | |
e0dc0c55 | 925 | (defcustom bibtex-files nil |
02c8032e | 926 | "List of BibTeX files that are searched for entry keys. |
e0dc0c55 SM |
927 | List elements can be absolute file names or file names relative to the |
928 | directories specified in `bibtex-file-path'. If an element is a directory, | |
929 | check all BibTeX files in this directory. If an element is the symbol | |
022fe7ce RW |
930 | `bibtex-file-path', check all BibTeX files in `bibtex-file-path'. |
931 | See also `bibtex-search-entry-globally'." | |
e0dc0c55 | 932 | :group 'bibtex |
238a5d6d RW |
933 | :type '(repeat (choice (const :tag "bibtex-file-path" bibtex-file-path) |
934 | directory file))) | |
e0dc0c55 | 935 | |
f1a4e679 CY |
936 | (defcustom bibtex-file-path (getenv "BIBINPUTS") |
937 | "Colon separated list of paths to search for `bibtex-files'." | |
938 | :group 'bibtex | |
939 | :type 'string) | |
e0dc0c55 | 940 | |
022fe7ce RW |
941 | (defcustom bibtex-search-entry-globally nil |
942 | "If non-nil, interactive calls of `bibtex-search-entry' search globally. | |
943 | A global search includes all files in `bibtex-files'." | |
944 | :group 'bibtex | |
b2096d72 | 945 | :version "24.1" |
022fe7ce RW |
946 | :type 'boolean) |
947 | ||
f754fb7b | 948 | (defcustom bibtex-help-message t |
d10e87a2 | 949 | "If non-nil print help messages in the echo area on entering a new field." |
f754fb7b RS |
950 | :group 'bibtex |
951 | :type 'boolean) | |
cb4ad359 | 952 | |
f754fb7b | 953 | (defcustom bibtex-autokey-prefix-string "" |
02c8032e | 954 | "String prefix for automatically generated reference keys. |
d715b065 | 955 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
956 | :group 'bibtex-autokey |
957 | :type 'string) | |
50e4b39e | 958 | |
f754fb7b | 959 | (defcustom bibtex-autokey-names 1 |
d10e87a2 | 960 | "Number of names to use for the automatically generated reference key. |
d0388eac | 961 | Possibly more names are used according to `bibtex-autokey-names-stretch'. |
d715b065 KG |
962 | If this variable is nil, all names are used. |
963 | See `bibtex-generate-autokey' for details." | |
f754fb7b | 964 | :group 'bibtex-autokey |
ab2d0cdb | 965 | :type '(choice (const :tag "All" infty) |
7fbf4804 | 966 | integer)) |
cb4ad359 | 967 | |
f754fb7b | 968 | (defcustom bibtex-autokey-names-stretch 0 |
02c8032e | 969 | "Number of names that can additionally be used for reference keys. |
50e4b39e | 970 | These names are used only, if all names are used then. |
d715b065 | 971 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
972 | :group 'bibtex-autokey |
973 | :type 'integer) | |
50e4b39e | 974 | |
f754fb7b | 975 | (defcustom bibtex-autokey-additional-names "" |
02c8032e | 976 | "String to append to the generated key if not all names could be used. |
d715b065 | 977 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
978 | :group 'bibtex-autokey |
979 | :type 'string) | |
50e4b39e | 980 | |
cdc61d35 SM |
981 | (defcustom bibtex-autokey-expand-strings nil |
982 | "If non-nil, expand strings when extracting the content of a BibTeX field. | |
983 | See `bibtex-generate-autokey' for details." | |
984 | :group 'bibtex-autokey | |
985 | :type 'boolean) | |
986 | ||
50e4b39e | 987 | (defvar bibtex-autokey-transcriptions |
7fbf4804 SM |
988 | '(;; language specific characters |
989 | ("\\\\aa" . "a") ; \aa -> a | |
990 | ("\\\\AA" . "A") ; \AA -> A | |
991 | ("\\\"a\\|\\\\\\\"a\\|\\\\ae" . "ae") ; "a,\"a,\ae -> ae | |
992 | ("\\\"A\\|\\\\\\\"A\\|\\\\AE" . "Ae") ; "A,\"A,\AE -> Ae | |
993 | ("\\\\i" . "i") ; \i -> i | |
994 | ("\\\\j" . "j") ; \j -> j | |
995 | ("\\\\l" . "l") ; \l -> l | |
996 | ("\\\\L" . "L") ; \L -> L | |
997 | ("\\\"o\\|\\\\\\\"o\\|\\\\o\\|\\\\oe" . "oe") ; "o,\"o,\o,\oe -> oe | |
998 | ("\\\"O\\|\\\\\\\"O\\|\\\\O\\|\\\\OE" . "Oe") ; "O,\"O,\O,\OE -> Oe | |
999 | ("\\\"s\\|\\\\\\\"s\\|\\\\3" . "ss") ; "s,\"s,\3 -> ss | |
1000 | ("\\\"u\\|\\\\\\\"u" . "ue") ; "u,\"u -> ue | |
1001 | ("\\\"U\\|\\\\\\\"U" . "Ue") ; "U,\"U -> Ue | |
50e4b39e | 1002 | ;; accents |
7fbf4804 | 1003 | ("\\\\`\\|\\\\'\\|\\\\\\^\\|\\\\~\\|\\\\=\\|\\\\\\.\\|\\\\u\\|\\\\v\\|\\\\H\\|\\\\t\\|\\\\c\\|\\\\d\\|\\\\b" . "") |
d715b065 KG |
1004 | ;; braces, quotes, concatenation. |
1005 | ("[`'\"{}#]" . "") | |
2f438239 | 1006 | ("\\\\-" . "") ; \- -> |
7fbf4804 | 1007 | ;; spaces |
e0dc0c55 | 1008 | ("\\\\?[ \t\n]+\\|~" . " ")) |
d715b065 | 1009 | "Alist of (OLD-REGEXP . NEW-STRING) pairs. |
d0388eac RS |
1010 | Used by the default values of `bibtex-autokey-name-change-strings' and |
1011 | `bibtex-autokey-titleword-change-strings'. Defaults to translating some | |
1012 | language specific characters to their ASCII transcriptions, and | |
50e4b39e RS |
1013 | removing any character accents.") |
1014 | ||
f754fb7b | 1015 | (defcustom bibtex-autokey-name-change-strings |
50e4b39e | 1016 | bibtex-autokey-transcriptions |
d715b065 | 1017 | "Alist of (OLD-REGEXP . NEW-STRING) pairs. |
02c8032e | 1018 | Any part of a name matching OLD-REGEXP is replaced by NEW-STRING. |
d0388eac | 1019 | Case is significant in OLD-REGEXP. All regexps are tried in the |
7fbf4804 | 1020 | order in which they appear in the list. |
d715b065 | 1021 | See `bibtex-generate-autokey' for details." |
f754fb7b | 1022 | :group 'bibtex-autokey |
7fbf4804 SM |
1023 | :type '(repeat (cons (regexp :tag "Old") |
1024 | (string :tag "New")))) | |
cb4ad359 | 1025 | |
8a51a318 | 1026 | (defcustom bibtex-autokey-name-case-convert-function 'downcase |
d10e87a2 | 1027 | "Function called for each name to perform case conversion. |
d715b065 | 1028 | See `bibtex-generate-autokey' for details." |
ab2d0cdb RS |
1029 | :group 'bibtex-autokey |
1030 | :type '(choice (const :tag "Preserve case" identity) | |
7fbf4804 SM |
1031 | (const :tag "Downcase" downcase) |
1032 | (const :tag "Capitalize" capitalize) | |
1033 | (const :tag "Upcase" upcase) | |
1034 | (function :tag "Conversion function"))) | |
7a0574f3 SM |
1035 | (put 'bibtex-autokey-name-case-convert-function 'safe-local-variable |
1036 | (lambda (x) (memq x '(upcase downcase capitalize identity)))) | |
8a51a318 RW |
1037 | (defvaralias 'bibtex-autokey-name-case-convert |
1038 | 'bibtex-autokey-name-case-convert-function) | |
ab2d0cdb | 1039 | |
f754fb7b | 1040 | (defcustom bibtex-autokey-name-length 'infty |
d10e87a2 | 1041 | "Number of characters from name to incorporate into key. |
cb4ad359 | 1042 | If this is set to anything but a number, all characters are used. |
d715b065 | 1043 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1044 | :group 'bibtex-autokey |
1045 | :type '(choice (const :tag "All" infty) | |
7fbf4804 | 1046 | integer)) |
cb4ad359 | 1047 | |
f754fb7b | 1048 | (defcustom bibtex-autokey-name-separator "" |
d10e87a2 | 1049 | "String that comes between any two names in the key. |
d715b065 | 1050 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1051 | :group 'bibtex-autokey |
1052 | :type 'string) | |
cb4ad359 | 1053 | |
f754fb7b | 1054 | (defcustom bibtex-autokey-year-length 2 |
d10e87a2 | 1055 | "Number of rightmost digits from the year field to incorporate into key. |
d715b065 | 1056 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1057 | :group 'bibtex-autokey |
1058 | :type 'integer) | |
50e4b39e | 1059 | |
7fbf4804 | 1060 | (defcustom bibtex-autokey-use-crossref t |
d10e87a2 | 1061 | "If non-nil use fields from crossreferenced entry if necessary. |
7fbf4804 SM |
1062 | If this variable is non-nil and some field has no entry, but a |
1063 | valid crossref entry, the field from the crossreferenced entry is used. | |
d715b065 | 1064 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1065 | :group 'bibtex-autokey |
1066 | :type 'boolean) | |
cb4ad359 | 1067 | |
f754fb7b | 1068 | (defcustom bibtex-autokey-titlewords 5 |
d10e87a2 | 1069 | "Number of title words to use for the automatically generated reference key. |
cb4ad359 | 1070 | If this is set to anything but a number, all title words are used. |
50e4b39e | 1071 | Possibly more words from the title are used according to |
d0388eac | 1072 | `bibtex-autokey-titlewords-stretch'. |
d715b065 | 1073 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1074 | :group 'bibtex-autokey |
1075 | :type '(choice (const :tag "All" infty) | |
7fbf4804 | 1076 | integer)) |
cb4ad359 | 1077 | |
02c8032e SM |
1078 | (defcustom bibtex-autokey-title-terminators "[.!?:;]\\|--" |
1079 | "Regexp defining the termination of the main part of the title. | |
1080 | Case of the regexps is ignored. See `bibtex-generate-autokey' for details." | |
f754fb7b | 1081 | :group 'bibtex-autokey |
02c8032e | 1082 | :type 'regexp) |
cb4ad359 | 1083 | |
f754fb7b | 1084 | (defcustom bibtex-autokey-titlewords-stretch 2 |
d10e87a2 | 1085 | "Number of words that can additionally be used from the title. |
cb4ad359 | 1086 | These words are used only, if a sentence from the title can be ended then. |
d715b065 | 1087 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1088 | :group 'bibtex-autokey |
1089 | :type 'integer) | |
cb4ad359 | 1090 | |
ab2d0cdb RS |
1091 | (defcustom bibtex-autokey-titleword-ignore |
1092 | '("A" "An" "On" "The" "Eine?" "Der" "Die" "Das" | |
6801feef | 1093 | "[^[:upper:]].*" ".*[^[:upper:][:lower:]0-9].*") |
d10e87a2 | 1094 | "Determines words from the title that are not to be used in the key. |
31df23f5 | 1095 | Each item of the list is a regexp. If a word of the title matches a |
ab2d0cdb | 1096 | regexp from that list, it is not included in the title part of the key. |
6801feef | 1097 | Case is significant. See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1098 | :group 'bibtex-autokey |
1099 | :type '(repeat regexp)) | |
cb4ad359 | 1100 | |
8a51a318 | 1101 | (defcustom bibtex-autokey-titleword-case-convert-function 'downcase |
d10e87a2 | 1102 | "Function called for each titleword to perform case conversion. |
d715b065 | 1103 | See `bibtex-generate-autokey' for details." |
ab2d0cdb RS |
1104 | :group 'bibtex-autokey |
1105 | :type '(choice (const :tag "Preserve case" identity) | |
7fbf4804 SM |
1106 | (const :tag "Downcase" downcase) |
1107 | (const :tag "Capitalize" capitalize) | |
1108 | (const :tag "Upcase" upcase) | |
1109 | (function :tag "Conversion function"))) | |
8a51a318 RW |
1110 | (defvaralias 'bibtex-autokey-titleword-case-convert |
1111 | 'bibtex-autokey-titleword-case-convert-function) | |
ab2d0cdb | 1112 | |
f754fb7b | 1113 | (defcustom bibtex-autokey-titleword-abbrevs nil |
d10e87a2 | 1114 | "Determines exceptions to the usual abbreviation mechanism. |
d715b065 | 1115 | An alist of (OLD-REGEXP . NEW-STRING) pairs. Case is ignored |
d0388eac | 1116 | in matching against OLD-REGEXP, and the first matching pair is used. |
d715b065 | 1117 | See `bibtex-generate-autokey' for details." |
7fbf4804 SM |
1118 | :group 'bibtex-autokey |
1119 | :type '(repeat (cons (regexp :tag "Old") | |
1120 | (string :tag "New")))) | |
cb4ad359 | 1121 | |
f754fb7b | 1122 | (defcustom bibtex-autokey-titleword-change-strings |
50e4b39e | 1123 | bibtex-autokey-transcriptions |
d715b065 | 1124 | "Alist of (OLD-REGEXP . NEW-STRING) pairs. |
d0388eac RS |
1125 | Any part of title word matching a OLD-REGEXP is replaced by NEW-STRING. |
1126 | Case is significant in OLD-REGEXP. All regexps are tried in the | |
7fbf4804 | 1127 | order in which they appear in the list. |
d715b065 | 1128 | See `bibtex-generate-autokey' for details." |
f754fb7b | 1129 | :group 'bibtex-autokey |
7fbf4804 SM |
1130 | :type '(repeat (cons (regexp :tag "Old") |
1131 | (string :tag "New")))) | |
cb4ad359 | 1132 | |
f754fb7b | 1133 | (defcustom bibtex-autokey-titleword-length 5 |
d10e87a2 | 1134 | "Number of characters from title words to incorporate into key. |
cb4ad359 | 1135 | If this is set to anything but a number, all characters are used. |
d715b065 | 1136 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1137 | :group 'bibtex-autokey |
1138 | :type '(choice (const :tag "All" infty) | |
7fbf4804 | 1139 | integer)) |
cb4ad359 | 1140 | |
f754fb7b | 1141 | (defcustom bibtex-autokey-titleword-separator "_" |
d10e87a2 | 1142 | "String to be put between the title words. |
d715b065 | 1143 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1144 | :group 'bibtex-autokey |
1145 | :type 'string) | |
cb4ad359 | 1146 | |
f754fb7b | 1147 | (defcustom bibtex-autokey-name-year-separator "" |
d10e87a2 | 1148 | "String to be put between name part and year part of key. |
d715b065 | 1149 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1150 | :group 'bibtex-autokey |
1151 | :type 'string) | |
cb4ad359 | 1152 | |
f754fb7b | 1153 | (defcustom bibtex-autokey-year-title-separator ":_" |
e56d3af5 | 1154 | "String to be put between year part and title part of key. |
d715b065 | 1155 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
1156 | :group 'bibtex-autokey |
1157 | :type 'string) | |
50e4b39e | 1158 | |
f754fb7b | 1159 | (defcustom bibtex-autokey-edit-before-use t |
d10e87a2 | 1160 | "If non-nil, user is allowed to edit the generated key before it is used." |
f754fb7b RS |
1161 | :group 'bibtex-autokey |
1162 | :type 'boolean) | |
cb4ad359 | 1163 | |
ab2d0cdb | 1164 | (defcustom bibtex-autokey-before-presentation-function nil |
02c8032e SM |
1165 | "If non-nil, function to call before generated key is presented. |
1166 | The function must take one argument (the automatically generated key), | |
1167 | and must return a string (the key to use)." | |
f754fb7b | 1168 | :group 'bibtex-autokey |
b4a64de4 | 1169 | :type '(choice (const nil) function)) |
50e4b39e | 1170 | |
f754fb7b | 1171 | (defcustom bibtex-entry-offset 0 |
d10e87a2 | 1172 | "Offset for BibTeX entries. |
31df23f5 | 1173 | Added to the value of all other variables which determine columns." |
f754fb7b RS |
1174 | :group 'bibtex |
1175 | :type 'integer) | |
50e4b39e | 1176 | |
f754fb7b | 1177 | (defcustom bibtex-field-indentation 2 |
d10e87a2 | 1178 | "Starting column for the name part in BibTeX fields." |
f754fb7b RS |
1179 | :group 'bibtex |
1180 | :type 'integer) | |
50e4b39e | 1181 | |
f754fb7b | 1182 | (defcustom bibtex-text-indentation |
7fbf4804 SM |
1183 | (+ bibtex-field-indentation |
1184 | (length "organization = ")) | |
d10e87a2 | 1185 | "Starting column for the text part in BibTeX fields. |
f754fb7b RS |
1186 | Should be equal to the space needed for the longest name part." |
1187 | :group 'bibtex | |
1188 | :type 'integer) | |
50e4b39e | 1189 | |
f754fb7b | 1190 | (defcustom bibtex-contline-indentation |
50e4b39e | 1191 | (+ bibtex-text-indentation 1) |
d10e87a2 | 1192 | "Starting column for continuation lines of BibTeX fields." |
f754fb7b RS |
1193 | :group 'bibtex |
1194 | :type 'integer) | |
50e4b39e | 1195 | |
f754fb7b | 1196 | (defcustom bibtex-align-at-equal-sign nil |
d10e87a2 | 1197 | "If non-nil, align fields at equal sign instead of field text. |
7fbf4804 SM |
1198 | If non-nil, the column for the equal sign is the value of |
1199 | `bibtex-text-indentation', minus 2." | |
f754fb7b RS |
1200 | :group 'bibtex |
1201 | :type 'boolean) | |
1202 | ||
1203 | (defcustom bibtex-comma-after-last-field nil | |
d10e87a2 | 1204 | "If non-nil, a comma is put at end of last field in the entry template." |
f754fb7b RS |
1205 | :group 'bibtex |
1206 | :type 'boolean) | |
50e4b39e | 1207 | |
d715b065 KG |
1208 | (defcustom bibtex-autoadd-commas t |
1209 | "If non-nil automatically add missing commas at end of BibTeX fields." | |
e0dc0c55 | 1210 | :group 'bibtex |
d715b065 KG |
1211 | :type 'boolean) |
1212 | ||
1213 | (defcustom bibtex-autofill-types '("Proceedings") | |
1214 | "Automatically fill fields if possible for those BibTeX entry types." | |
e0dc0c55 | 1215 | :group 'bibtex |
d715b065 KG |
1216 | :type '(repeat string)) |
1217 | ||
e0dc0c55 | 1218 | (defcustom bibtex-summary-function 'bibtex-summary |
921a9483 SM |
1219 | "Function to call for generating a summary of current BibTeX entry. |
1220 | It takes no arguments. Point must be at beginning of entry. | |
02c8032e | 1221 | Used by `bibtex-complete-crossref-cleanup' and `bibtex-copy-summary-as-kill'." |
e0dc0c55 SM |
1222 | :group 'bibtex |
1223 | :type '(choice (const :tag "Default" bibtex-summary) | |
1224 | (function :tag "Personalized function"))) | |
1225 | ||
d528bff7 | 1226 | (defcustom bibtex-generate-url-list |
bceff189 RW |
1227 | '((("url" . ".*:.*")) |
1228 | (("doi" . "10\\.[0-9]+/.+") | |
1229 | "http://dx.doi.org/%s" | |
1230 | ("doi" ".*" 0))) | |
d528bff7 SM |
1231 | "List of schemes for generating the URL of a BibTeX entry. |
1232 | These schemes are used by `bibtex-url'. | |
1233 | ||
63d516ce | 1234 | Each scheme should have one of these forms: |
d528bff7 | 1235 | |
63d516ce SM |
1236 | ((FIELD . REGEXP)) |
1237 | ((FIELD . REGEXP) STEP...) | |
1238 | ((FIELD . REGEXP) STRING STEP...) | |
a9d77f1f | 1239 | |
63d516ce SM |
1240 | FIELD is a field name as returned by `bibtex-parse-entry'. |
1241 | REGEXP is matched against the text of FIELD. If the match succeeds, | |
1242 | then this scheme is used. If no STRING and STEPs are specified | |
1243 | the matched text is used as the URL, otherwise the URL is built | |
1244 | by evaluating STEPs. If no STRING is specified the STEPs must result | |
1245 | in strings which are concatenated. Otherwise the resulting objects | |
1246 | are passed through `format' using STRING as format control string. | |
1247 | ||
1248 | A STEP is a list (FIELD REGEXP REPLACE). The text of FIELD | |
1249 | is matched against REGEXP, and is replaced with REPLACE. | |
1250 | REPLACE can be a string, or a number (which selects the corresponding | |
1251 | submatch), or a function called with the field's text as argument | |
1252 | and with the `match-data' properly set. | |
1253 | ||
1254 | Case is always ignored. Always remove the field delimiters. | |
cdc61d35 SM |
1255 | If `bibtex-expand-strings' is non-nil, BibTeX strings are expanded |
1256 | for generating the URL. | |
403111a8 | 1257 | Set this variable before loading BibTeX mode. |
63d516ce | 1258 | |
4106334c | 1259 | The following is a complex example, see URL `http://link.aps.org/'. |
63d516ce SM |
1260 | |
1261 | (((\"journal\" . \"\\\\=<\\(PR[ABCDEL]?\\|RMP\\)\\\\=>\") | |
1262 | \"http://link.aps.org/abstract/%s/v%s/p%s\" | |
004dedd3 | 1263 | (\"journal\" \".*\" upcase) |
63d516ce SM |
1264 | (\"volume\" \".*\" 0) |
1265 | (\"pages\" \"\\`[A-Z]?[0-9]+\" 0)))" | |
d528bff7 | 1266 | :group 'bibtex |
bceff189 | 1267 | :version "24.4" |
d528bff7 | 1268 | :type '(repeat |
63d516ce | 1269 | (cons :tag "Scheme" |
d528bff7 SM |
1270 | (cons :tag "Matcher" :extra-offset 4 |
1271 | (string :tag "BibTeX field") | |
a9d77f1f | 1272 | (regexp :tag "Regexp")) |
63d516ce SM |
1273 | (choice |
1274 | (const :tag "Take match as is" nil) | |
1275 | (cons :tag "Formatted" | |
1276 | (string :tag "Format control string") | |
1277 | (repeat :tag "Steps to generate URL" | |
1278 | (list (string :tag "BibTeX field") | |
1279 | (regexp :tag "Regexp") | |
1280 | (choice (string :tag "Replacement") | |
1281 | (integer :tag "Sub-match") | |
1282 | (function :tag "Filter"))))) | |
1283 | (repeat :tag "Concatenated" | |
d528bff7 | 1284 | (list (string :tag "BibTeX field") |
a9d77f1f SM |
1285 | (regexp :tag "Regexp") |
1286 | (choice (string :tag "Replacement") | |
1287 | (integer :tag "Sub-match") | |
1288 | (function :tag "Filter")))))))) | |
8a51a318 | 1289 | (put 'bibtex-generate-url-list 'risky-local-variable t) |
7fbf4804 | 1290 | |
f2dfa899 RW |
1291 | (defcustom bibtex-cite-matcher-alist |
1292 | '(("\\\\cite[ \t\n]*{\\([^}]+\\)}" . 1)) | |
1293 | "Alist of rules to identify cited keys in a BibTeX entry. | |
1294 | Each rule should be of the form (REGEXP . SUBEXP), where SUBEXP | |
1295 | specifies which parenthesized expression in REGEXP is a cited key. | |
1296 | Case is significant. | |
403111a8 RW |
1297 | Used by `bibtex-search-crossref' and for font-locking. |
1298 | Set this variable before loading BibTeX mode." | |
f2dfa899 RW |
1299 | :group 'bibtex |
1300 | :type '(repeat (cons (regexp :tag "Regexp") | |
af09cfd7 JB |
1301 | (integer :tag "Number"))) |
1302 | :version "23.1") | |
f2dfa899 | 1303 | |
cdc61d35 SM |
1304 | (defcustom bibtex-expand-strings nil |
1305 | "If non-nil, expand strings when extracting the content of a BibTeX field." | |
1306 | :group 'bibtex | |
1307 | :type 'boolean) | |
1308 | ||
34699b85 RW |
1309 | (defcustom bibtex-search-buffer "*BibTeX Search*" |
1310 | "Buffer for BibTeX search results." | |
1311 | :group 'bibtex | |
b2096d72 | 1312 | :version "24.1" |
34699b85 RW |
1313 | :type 'string) |
1314 | ||
ffc1e1db | 1315 | ;; `bibtex-font-lock-keywords' is a user option, too. But since the |
31bc4210 | 1316 | ;; patterns used to define this variable are defined in a later |
50e4b39e | 1317 | ;; section of this file, it is defined later. |
28f2ee66 GM |
1318 | |
1319 | \f | |
cdc61d35 | 1320 | ;; Syntax Table and Keybindings |
9ae11a89 ER |
1321 | (defvar bibtex-mode-syntax-table |
1322 | (let ((st (make-syntax-table))) | |
50e4b39e | 1323 | (modify-syntax-entry ?\" "\"" st) |
9ae11a89 ER |
1324 | (modify-syntax-entry ?$ "$$ " st) |
1325 | (modify-syntax-entry ?% "< " st) | |
a2a25d24 | 1326 | (modify-syntax-entry ?' "w " st) ;FIXME: Not allowed in @string keys. |
50e4b39e | 1327 | (modify-syntax-entry ?@ "w " st) |
9ae11a89 ER |
1328 | (modify-syntax-entry ?\\ "\\" st) |
1329 | (modify-syntax-entry ?\f "> " st) | |
1330 | (modify-syntax-entry ?\n "> " st) | |
7fbf4804 SM |
1331 | ;; Keys cannot have = in them (wrong font-lock of @string{foo=bar}). |
1332 | (modify-syntax-entry ?= "." st) | |
9ae11a89 | 1333 | (modify-syntax-entry ?~ " " st) |
7fbf4804 SM |
1334 | st) |
1335 | "Syntax table used in BibTeX mode buffers.") | |
9ae11a89 | 1336 | |
9ae11a89 ER |
1337 | (defvar bibtex-mode-map |
1338 | (let ((km (make-sparse-keymap))) | |
28f2ee66 | 1339 | ;; The Key `C-c&' is reserved for reftex.el |
9ae11a89 ER |
1340 | (define-key km "\t" 'bibtex-find-text) |
1341 | (define-key km "\n" 'bibtex-next-field) | |
a2a25d24 | 1342 | (define-key km "\M-\t" 'completion-at-point) |
50e4b39e RS |
1343 | (define-key km "\C-c\"" 'bibtex-remove-delimiters) |
1344 | (define-key km "\C-c{" 'bibtex-remove-delimiters) | |
1345 | (define-key km "\C-c}" 'bibtex-remove-delimiters) | |
9ae11a89 | 1346 | (define-key km "\C-c\C-c" 'bibtex-clean-entry) |
50e4b39e | 1347 | (define-key km "\C-c\C-q" 'bibtex-fill-entry) |
7af32e66 RW |
1348 | (define-key km "\C-c\C-s" 'bibtex-search-entry) |
1349 | (define-key km "\C-c\C-x" 'bibtex-search-crossref) | |
e0dc0c55 | 1350 | (define-key km "\C-c\C-t" 'bibtex-copy-summary-as-kill) |
cb4ad359 | 1351 | (define-key km "\C-c?" 'bibtex-print-help-message) |
9ae11a89 ER |
1352 | (define-key km "\C-c\C-p" 'bibtex-pop-previous) |
1353 | (define-key km "\C-c\C-n" 'bibtex-pop-next) | |
50e4b39e RS |
1354 | (define-key km "\C-c\C-k" 'bibtex-kill-field) |
1355 | (define-key km "\C-c\M-k" 'bibtex-copy-field-as-kill) | |
1356 | (define-key km "\C-c\C-w" 'bibtex-kill-entry) | |
1357 | (define-key km "\C-c\M-w" 'bibtex-copy-entry-as-kill) | |
1358 | (define-key km "\C-c\C-y" 'bibtex-yank) | |
1359 | (define-key km "\C-c\M-y" 'bibtex-yank-pop) | |
9ae11a89 | 1360 | (define-key km "\C-c\C-d" 'bibtex-empty-field) |
50e4b39e | 1361 | (define-key km "\C-c\C-f" 'bibtex-make-field) |
8bf38a9b | 1362 | (define-key km "\C-c\C-u" 'bibtex-entry-update) |
50e4b39e RS |
1363 | (define-key km "\C-c$" 'bibtex-ispell-abstract) |
1364 | (define-key km "\M-\C-a" 'bibtex-beginning-of-entry) | |
1365 | (define-key km "\M-\C-e" 'bibtex-end-of-entry) | |
1366 | (define-key km "\C-\M-l" 'bibtex-reposition-window) | |
1367 | (define-key km "\C-\M-h" 'bibtex-mark-entry) | |
1368 | (define-key km "\C-c\C-b" 'bibtex-entry) | |
cb4ad359 RS |
1369 | (define-key km "\C-c\C-rn" 'bibtex-narrow-to-entry) |
1370 | (define-key km "\C-c\C-rw" 'widen) | |
d528bff7 | 1371 | (define-key km "\C-c\C-l" 'bibtex-url) |
34699b85 | 1372 | (define-key km "\C-c\C-a" 'bibtex-search-entries) |
50e4b39e | 1373 | (define-key km "\C-c\C-o" 'bibtex-remove-OPT-or-ALT) |
cb4ad359 | 1374 | (define-key km "\C-c\C-e\C-i" 'bibtex-InProceedings) |
9ae11a89 | 1375 | (define-key km "\C-c\C-ei" 'bibtex-InCollection) |
cb4ad359 RS |
1376 | (define-key km "\C-c\C-eI" 'bibtex-InBook) |
1377 | (define-key km "\C-c\C-e\C-a" 'bibtex-Article) | |
1378 | (define-key km "\C-c\C-e\C-b" 'bibtex-InBook) | |
1379 | (define-key km "\C-c\C-eb" 'bibtex-Book) | |
1380 | (define-key km "\C-c\C-eB" 'bibtex-Booklet) | |
1381 | (define-key km "\C-c\C-e\C-c" 'bibtex-InCollection) | |
9ae11a89 ER |
1382 | (define-key km "\C-c\C-e\C-m" 'bibtex-Manual) |
1383 | (define-key km "\C-c\C-em" 'bibtex-MastersThesis) | |
1384 | (define-key km "\C-c\C-eM" 'bibtex-Misc) | |
cb4ad359 | 1385 | (define-key km "\C-c\C-e\C-p" 'bibtex-InProceedings) |
9ae11a89 | 1386 | (define-key km "\C-c\C-ep" 'bibtex-Proceedings) |
cb4ad359 | 1387 | (define-key km "\C-c\C-eP" 'bibtex-PhdThesis) |
50e4b39e RS |
1388 | (define-key km "\C-c\C-e\M-p" 'bibtex-Preamble) |
1389 | (define-key km "\C-c\C-e\C-s" 'bibtex-String) | |
cb4ad359 | 1390 | (define-key km "\C-c\C-e\C-t" 'bibtex-TechReport) |
9ae11a89 | 1391 | (define-key km "\C-c\C-e\C-u" 'bibtex-Unpublished) |
7fbf4804 SM |
1392 | km) |
1393 | "Keymap used in BibTeX mode.") | |
9ae11a89 | 1394 | |
50e4b39e | 1395 | (easy-menu-define |
7fbf4804 SM |
1396 | bibtex-edit-menu bibtex-mode-map "BibTeX-Edit Menu in BibTeX mode" |
1397 | '("BibTeX-Edit" | |
1398 | ("Moving inside an Entry" | |
1399 | ["End of Field" bibtex-find-text t] | |
1400 | ["Next Field" bibtex-next-field t] | |
1401 | ["Beginning of Entry" bibtex-beginning-of-entry t] | |
d10e87a2 SM |
1402 | ["End of Entry" bibtex-end-of-entry t] |
1403 | "--" | |
1404 | ["Make Entry Visible" bibtex-reposition-window t]) | |
02c8032e | 1405 | ("Moving in BibTeX Buffers" |
7af32e66 RW |
1406 | ["Search Entry" bibtex-search-entry t] |
1407 | ["Search Crossref Entry" bibtex-search-crossref t]) | |
e0dc0c55 | 1408 | "--" |
7fbf4804 | 1409 | ("Operating on Current Field" |
d715b065 | 1410 | ["Fill Field" fill-paragraph t] |
7fbf4804 SM |
1411 | ["Remove Delimiters" bibtex-remove-delimiters t] |
1412 | ["Remove OPT or ALT Prefix" bibtex-remove-OPT-or-ALT t] | |
1413 | ["Clear Field" bibtex-empty-field t] | |
1414 | "--" | |
1415 | ["Kill Field" bibtex-kill-field t] | |
1416 | ["Copy Field to Kill Ring" bibtex-copy-field-as-kill t] | |
1417 | ["Paste Most Recently Killed Field" bibtex-yank t] | |
1418 | ["Paste Previously Killed Field" bibtex-yank-pop t] | |
1419 | "--" | |
1420 | ["Make New Field" bibtex-make-field t] | |
1421 | "--" | |
1422 | ["Snatch from Similar Following Field" bibtex-pop-next t] | |
1423 | ["Snatch from Similar Preceding Field" bibtex-pop-previous t] | |
1424 | "--" | |
1425 | ["String or Key Complete" bibtex-complete t] | |
1426 | "--" | |
1427 | ["Help about Current Field" bibtex-print-help-message t]) | |
d528bff7 SM |
1428 | ("Operating on Current Entry" |
1429 | ["Fill Entry" bibtex-fill-entry t] | |
1430 | ["Clean Entry" bibtex-clean-entry t] | |
1431 | ["Update Entry" bibtex-entry-update t] | |
1432 | "--" | |
1433 | ["Kill Entry" bibtex-kill-entry t] | |
1434 | ["Copy Entry to Kill Ring" bibtex-copy-entry-as-kill t] | |
1435 | ["Paste Most Recently Killed Entry" bibtex-yank t] | |
1436 | ["Paste Previously Killed Entry" bibtex-yank-pop t] | |
1437 | "--" | |
e0dc0c55 | 1438 | ["Copy Summary to Kill Ring" bibtex-copy-summary-as-kill t] |
02c8032e | 1439 | ["Browse URL" bibtex-url t] |
e0dc0c55 | 1440 | "--" |
d528bff7 SM |
1441 | ["Ispell Entry" bibtex-ispell-entry t] |
1442 | ["Ispell Entry Abstract" bibtex-ispell-abstract t] | |
02c8032e | 1443 | "--" |
d528bff7 | 1444 | ["Narrow to Entry" bibtex-narrow-to-entry t] |
02c8032e | 1445 | ["Mark Entry" bibtex-mark-entry t] |
d528bff7 SM |
1446 | "--" |
1447 | ["View Cite Locations (RefTeX)" reftex-view-crossref-from-bibtex | |
1448 | (fboundp 'reftex-view-crossref-from-bibtex)]) | |
7fbf4804 | 1449 | ("Operating on Buffer or Region" |
34699b85 RW |
1450 | ["Search Entries" bibtex-search-entries t] |
1451 | "--" | |
7fbf4804 SM |
1452 | ["Validate Entries" bibtex-validate t] |
1453 | ["Sort Entries" bibtex-sort-buffer t] | |
1454 | ["Reformat Entries" bibtex-reformat t] | |
d528bff7 SM |
1455 | ["Count Entries" bibtex-count-entries t] |
1456 | "--" | |
e0dc0c55 SM |
1457 | ["Convert Alien Buffer" bibtex-convert-alien t]) |
1458 | ("Operating on Multiple Buffers" | |
65e10478 | 1459 | ["(Re)Initialize BibTeX Buffers" bibtex-initialize t] |
e0dc0c55 | 1460 | ["Validate Entries" bibtex-validate-globally t]))) |
50e4b39e | 1461 | |
31bc4210 | 1462 | \f |
5c69dbfc | 1463 | ;; Internal Variables |
9ae11a89 | 1464 | |
ace88aa2 RW |
1465 | (defvar bibtex-entry-alist nil |
1466 | "Alist of currently active entry types. | |
1467 | Initialized by `bibtex-set-dialect'.") | |
2de69e00 | 1468 | |
ace88aa2 RW |
1469 | (defvar bibtex-field-alist nil |
1470 | "Alist of currently active field types. | |
1471 | Initialized by `bibtex-set-dialect'.") | |
2de69e00 | 1472 | |
f2dfa899 RW |
1473 | (defvar bibtex-field-braces-opt nil |
1474 | "Optimized value of `bibtex-field-braces-alist'. | |
1475 | Created by `bibtex-field-re-init'. | |
20db1522 | 1476 | It is an alist with elements (FIELD . REGEXP).") |
f2dfa899 RW |
1477 | |
1478 | (defvar bibtex-field-strings-opt nil | |
1479 | "Optimized value of `bibtex-field-strings-alist'. | |
1480 | Created by `bibtex-field-re-init'. | |
20db1522 | 1481 | It is an alist with elements (FIELD RULE1 RULE2 ...), |
f2dfa899 RW |
1482 | where each RULE is (REGEXP . TO-STR).") |
1483 | ||
7fbf4804 SM |
1484 | (defvar bibtex-pop-previous-search-point nil |
1485 | "Next point where `bibtex-pop-previous' starts looking for a similar entry.") | |
1486 | ||
1487 | (defvar bibtex-pop-next-search-point nil | |
1488 | "Next point where `bibtex-pop-next' starts looking for a similar entry.") | |
1489 | ||
1490 | (defvar bibtex-field-kill-ring nil | |
1491 | "Ring of least recently killed fields. | |
1492 | At most `bibtex-field-kill-ring-max' items are kept here.") | |
9ae11a89 | 1493 | |
7fbf4804 SM |
1494 | (defvar bibtex-field-kill-ring-yank-pointer nil |
1495 | "The tail of `bibtex-field-kill-ring' whose car is the last item yanked.") | |
745bc783 | 1496 | |
7fbf4804 SM |
1497 | (defvar bibtex-entry-kill-ring nil |
1498 | "Ring of least recently killed entries. | |
1499 | At most `bibtex-entry-kill-ring-max' items are kept here.") | |
50e4b39e | 1500 | |
7fbf4804 SM |
1501 | (defvar bibtex-entry-kill-ring-yank-pointer nil |
1502 | "The tail of `bibtex-entry-kill-ring' whose car is the last item yanked.") | |
50e4b39e | 1503 | |
7fbf4804 SM |
1504 | (defvar bibtex-last-kill-command nil |
1505 | "Type of the last kill command (either 'field or 'entry).") | |
50e4b39e | 1506 | |
d715b065 KG |
1507 | (defvar bibtex-strings |
1508 | (lazy-completion-table bibtex-strings | |
2784fcc9 SM |
1509 | (lambda () |
1510 | (bibtex-parse-strings (bibtex-string-files-init)))) | |
d715b065 | 1511 | "Completion table for BibTeX string keys. |
7fbf4804 | 1512 | Initialized from `bibtex-predefined-strings' and `bibtex-string-files'.") |
d715b065 | 1513 | (make-variable-buffer-local 'bibtex-strings) |
964a8b47 | 1514 | (put 'bibtex-strings 'risky-local-variable t) |
50e4b39e | 1515 | |
d715b065 | 1516 | (defvar bibtex-reference-keys |
2784fcc9 SM |
1517 | (lazy-completion-table bibtex-reference-keys |
1518 | (lambda () (bibtex-parse-keys nil t))) | |
e0dc0c55 SM |
1519 | "Completion table for BibTeX reference keys. |
1520 | The CDRs of the elements are t for header keys and nil for crossref keys.") | |
d715b065 | 1521 | (make-variable-buffer-local 'bibtex-reference-keys) |
964a8b47 | 1522 | (put 'bibtex-reference-keys 'risky-local-variable t) |
50e4b39e | 1523 | |
7fbf4804 | 1524 | (defvar bibtex-buffer-last-parsed-tick nil |
a9d77f1f | 1525 | "Value of `buffer-modified-tick' last time buffer was parsed for keys.") |
745bc783 | 1526 | |
7fbf4804 SM |
1527 | (defvar bibtex-parse-idle-timer nil |
1528 | "Stores if timer is already installed.") | |
0640d7bf | 1529 | |
7fbf4804 SM |
1530 | (defvar bibtex-progress-lastperc nil |
1531 | "Last reported percentage for the progress message.") | |
50e4b39e | 1532 | |
7fbf4804 SM |
1533 | (defvar bibtex-progress-lastmes nil |
1534 | "Last reported progress message.") | |
50e4b39e | 1535 | |
7fbf4804 SM |
1536 | (defvar bibtex-progress-interval nil |
1537 | "Interval for progress messages.") | |
50e4b39e | 1538 | |
7fbf4804 SM |
1539 | (defvar bibtex-key-history nil |
1540 | "History list for reading keys.") | |
50e4b39e | 1541 | |
7fbf4804 | 1542 | (defvar bibtex-entry-type-history nil |
d715b065 | 1543 | "History list for reading entry types.") |
50e4b39e | 1544 | |
7fbf4804 SM |
1545 | (defvar bibtex-field-history nil |
1546 | "History list for reading field names.") | |
50e4b39e | 1547 | |
7fbf4804 SM |
1548 | (defvar bibtex-reformat-previous-options nil |
1549 | "Last reformat options given.") | |
50e4b39e | 1550 | |
7fbf4804 SM |
1551 | (defvar bibtex-reformat-previous-reference-keys nil |
1552 | "Last reformat reference keys option given.") | |
50e4b39e | 1553 | |
7fbf4804 | 1554 | (defconst bibtex-field-name "[^\"#%'(),={} \t\n0-9][^\"#%'(),={} \t\n]*" |
cdc61d35 | 1555 | "Regexp matching the name of a BibTeX field.") |
50e4b39e | 1556 | |
cdc61d35 | 1557 | (defconst bibtex-name-part |
ffc1e1db | 1558 | (concat ",[ \t\n]*\\(" bibtex-field-name "\\)") |
cdc61d35 | 1559 | "Regexp matching the name part of a BibTeX field.") |
7fbf4804 | 1560 | |
a172852f | 1561 | (defconst bibtex-reference-key "[][[:alnum:].:;?!`'/*@+|()<>&_^$-]+" |
7fbf4804 SM |
1562 | "Regexp matching the reference key part of a BibTeX entry.") |
1563 | ||
a172852f | 1564 | (defconst bibtex-field-const "[][[:alnum:].:;?!`'/*@+=|<>&_^$-]+" |
7fbf4804 SM |
1565 | "Regexp matching a BibTeX field constant.") |
1566 | ||
2de69e00 RW |
1567 | (defvar bibtex-entry-type nil |
1568 | "Regexp matching the type of a BibTeX entry. | |
1569 | Initialized by `bibtex-set-dialect'.") | |
cdc61d35 | 1570 | |
2de69e00 RW |
1571 | (defvar bibtex-entry-head nil |
1572 | "Regexp matching the header line of a BibTeX entry (including key). | |
1573 | Initialized by `bibtex-set-dialect'.") | |
7fbf4804 | 1574 | |
2de69e00 RW |
1575 | (defvar bibtex-entry-maybe-empty-head nil |
1576 | "Regexp matching the header line of a BibTeX entry (possibly without key). | |
1577 | Initialized by `bibtex-set-dialect'.") | |
7fbf4804 | 1578 | |
cdc61d35 SM |
1579 | (defconst bibtex-any-entry-maybe-empty-head |
1580 | (concat "^[ \t]*\\(@[ \t]*" bibtex-field-name "\\)[ \t]*[({][ \t\n]*\\(" | |
1581 | bibtex-reference-key "\\)?") | |
1582 | "Regexp matching the header line of any BibTeX entry (possibly without key).") | |
1583 | ||
2de69e00 RW |
1584 | (defvar bibtex-any-valid-entry-type nil |
1585 | "Regexp matching any valid BibTeX entry (including String and Preamble). | |
1586 | Initialized by `bibtex-set-dialect'.") | |
ffc1e1db | 1587 | |
7fbf4804 SM |
1588 | (defconst bibtex-type-in-head 1 |
1589 | "Regexp subexpression number of the type part in `bibtex-entry-head'.") | |
1590 | ||
1591 | (defconst bibtex-key-in-head 2 | |
1592 | "Regexp subexpression number of the key part in `bibtex-entry-head'.") | |
1593 | ||
cdc61d35 SM |
1594 | (defconst bibtex-string-type "^[ \t]*\\(@[ \t]*String\\)[ \t]*[({][ \t\n]*" |
1595 | "Regexp matching the name of a BibTeX String entry.") | |
7fbf4804 | 1596 | |
cdc61d35 SM |
1597 | (defconst bibtex-string-maybe-empty-head |
1598 | (concat bibtex-string-type "\\(" bibtex-reference-key "\\)?") | |
1599 | "Regexp matching the header line of a BibTeX String entry.") | |
7fbf4804 | 1600 | |
ffc1e1db RW |
1601 | (defconst bibtex-preamble-prefix |
1602 | "[ \t]*\\(@[ \t]*Preamble\\)[ \t]*[({][ \t\n]*" | |
1603 | "Regexp matching the prefix part of a BibTeX Preamble entry.") | |
7fbf4804 | 1604 | |
7fbf4804 SM |
1605 | (defconst bibtex-font-lock-syntactic-keywords |
1606 | `((,(concat "^[ \t]*\\(" (substring bibtex-comment-start 0 1) "\\)" | |
1607 | (substring bibtex-comment-start 1) "\\>") | |
1608 | 1 '(11)))) | |
1609 | ||
1610 | (defvar bibtex-font-lock-keywords | |
d528bff7 | 1611 | ;; entry type and reference key |
cdc61d35 | 1612 | `((,bibtex-any-entry-maybe-empty-head |
d528bff7 SM |
1613 | (,bibtex-type-in-head font-lock-function-name-face) |
1614 | (,bibtex-key-in-head font-lock-constant-face nil t)) | |
1615 | ;; optional field names (treated as comments) | |
1616 | (,(concat "^[ \t]*\\(OPT" bibtex-field-name "\\)[ \t]*=") | |
1617 | 1 font-lock-comment-face) | |
1618 | ;; field names | |
1619 | (,(concat "^[ \t]*\\(" bibtex-field-name "\\)[ \t]*=") | |
1620 | 1 font-lock-variable-name-face) | |
1621 | ;; url | |
f2dfa899 RW |
1622 | (bibtex-font-lock-url) (bibtex-font-lock-crossref) |
1623 | ;; cite | |
1624 | ,@(mapcar (lambda (matcher) | |
1625 | `((lambda (bound) (bibtex-font-lock-cite ',matcher bound)))) | |
1626 | bibtex-cite-matcher-alist)) | |
fb7ada5f | 1627 | "Default expressions to highlight in BibTeX mode.") |
7fbf4804 | 1628 | |
d528bff7 | 1629 | (defvar bibtex-font-lock-url-regexp |
e0dc0c55 | 1630 | ;; Assume that field names begin at the beginning of a line. |
d10e87a2 SM |
1631 | (concat "^[ \t]*" |
1632 | (regexp-opt (delete-dups (mapcar 'caar bibtex-generate-url-list)) t) | |
e0dc0c55 | 1633 | "[ \t]*=[ \t]*") |
f2dfa899 | 1634 | "Regexp for `bibtex-font-lock-url' derived from `bibtex-generate-url-list'.") |
d528bff7 | 1635 | |
cdc61d35 SM |
1636 | (defvar bibtex-string-empty-key nil |
1637 | "If non-nil, `bibtex-parse-string' accepts empty key.") | |
7fbf4804 | 1638 | |
7a0574f3 | 1639 | (defvar bibtex-sort-entry-class-alist nil |
a9d77f1f SM |
1640 | "Alist mapping entry types to their sorting index. |
1641 | Auto-generated from `bibtex-sort-entry-class'. | |
1642 | Used when `bibtex-maintain-sorted-entries' is `entry-class'.") | |
0640d7bf | 1643 | |
cb4ad359 | 1644 | \f |
f9bd4abe | 1645 | (defun bibtex-parse-association (parse-lhs parse-rhs) |
7fbf4804 | 1646 | "Parse a string of the format <left-hand-side = right-hand-side>. |
f9bd4abe GM |
1647 | The functions PARSE-LHS and PARSE-RHS are used to parse the corresponding |
1648 | substrings. These functions are expected to return nil if parsing is not | |
cdc61d35 SM |
1649 | successful. If the returned values of both functions are non-nil, |
1650 | return a cons pair of these values. Do not move point." | |
f9bd4abe | 1651 | (save-match-data |
7fbf4804 | 1652 | (save-excursion |
d715b065 KG |
1653 | (let ((left (funcall parse-lhs)) |
1654 | right) | |
1655 | (if (and left | |
7fbf4804 SM |
1656 | (looking-at "[ \t\n]*=[ \t\n]*") |
1657 | (goto-char (match-end 0)) | |
1658 | (setq right (funcall parse-rhs))) | |
1659 | (cons left right)))))) | |
f9bd4abe GM |
1660 | |
1661 | (defun bibtex-parse-field-name () | |
cdc61d35 | 1662 | "Parse the name part of a BibTeX field. |
f9bd4abe GM |
1663 | If the field name is found, return a triple consisting of the position of the |
1664 | very first character of the match, the actual starting position of the name | |
a9d77f1f | 1665 | part and end position of the match. Move point to end of field name. |
31df23f5 | 1666 | If `bibtex-autoadd-commas' is non-nil add missing comma at end of preceding |
d715b065 | 1667 | BibTeX field as necessary." |
ffc1e1db RW |
1668 | (cond ((looking-at bibtex-name-part) |
1669 | (goto-char (match-end 0)) | |
1670 | (list (match-beginning 0) (match-beginning 1) (match-end 0))) | |
d715b065 KG |
1671 | ;; Maybe add a missing comma. |
1672 | ((and bibtex-autoadd-commas | |
cdc61d35 | 1673 | (looking-at (concat "[ \t\n]*\\(?:" bibtex-field-name |
d715b065 KG |
1674 | "\\)[ \t\n]*="))) |
1675 | (skip-chars-backward " \t\n") | |
cdc61d35 SM |
1676 | ;; It can be confusing if non-editing commands try to |
1677 | ;; modify the buffer. | |
1678 | (if buffer-read-only | |
1679 | (error "Comma missing at buffer position %s" (point))) | |
d715b065 KG |
1680 | (insert ",") |
1681 | (forward-char -1) | |
1682 | ;; Now try again. | |
1683 | (bibtex-parse-field-name)))) | |
d30bfc76 | 1684 | |
8bf38a9b SM |
1685 | (defconst bibtex-braced-string-syntax-table |
1686 | (let ((st (make-syntax-table))) | |
1687 | (modify-syntax-entry ?\{ "(}" st) | |
1688 | (modify-syntax-entry ?\} "){" st) | |
1689 | (modify-syntax-entry ?\[ "." st) | |
1690 | (modify-syntax-entry ?\] "." st) | |
1691 | (modify-syntax-entry ?\( "." st) | |
1692 | (modify-syntax-entry ?\) "." st) | |
1693 | (modify-syntax-entry ?\\ "." st) | |
1694 | (modify-syntax-entry ?\" "." st) | |
1695 | st) | |
1696 | "Syntax-table to parse matched braces.") | |
1697 | ||
1698 | (defconst bibtex-quoted-string-syntax-table | |
1699 | (let ((st (make-syntax-table))) | |
1700 | (modify-syntax-entry ?\\ "\\" st) | |
1701 | (modify-syntax-entry ?\" "\"" st) | |
1702 | st) | |
1703 | "Syntax-table to parse matched quotes.") | |
1704 | ||
1705 | (defun bibtex-parse-field-string () | |
02c8032e | 1706 | "Parse a BibTeX field string enclosed by braces or quotes. |
8bf38a9b | 1707 | If a syntactically correct string is found, a pair containing the start and |
cdc61d35 SM |
1708 | end position of the field string is returned, nil otherwise. |
1709 | Do not move point." | |
8bf38a9b SM |
1710 | (let ((end-point |
1711 | (or (and (eq (following-char) ?\") | |
1712 | (save-excursion | |
1713 | (with-syntax-table bibtex-quoted-string-syntax-table | |
1714 | (forward-sexp 1)) | |
1715 | (point))) | |
1716 | (and (eq (following-char) ?\{) | |
1717 | (save-excursion | |
1718 | (with-syntax-table bibtex-braced-string-syntax-table | |
1719 | (forward-sexp 1)) | |
1720 | (point)))))) | |
1721 | (if end-point | |
1722 | (cons (point) end-point)))) | |
1723 | ||
f9bd4abe | 1724 | (defun bibtex-parse-field-text () |
7fbf4804 | 1725 | "Parse the text part of a BibTeX field. |
f9bd4abe GM |
1726 | The text part is either a string, or an empty string, or a constant followed |
1727 | by one or more <# (string|constant)> pairs. If a syntactically correct text | |
1728 | is found, a pair containing the start and end position of the text is | |
a9d77f1f | 1729 | returned, nil otherwise. Move point to end of field text." |
f9bd4abe | 1730 | (let ((starting-point (point)) |
7fbf4804 | 1731 | end-point failure boundaries) |
d715b065 | 1732 | (while (not (or end-point failure)) |
7fbf4804 SM |
1733 | (cond ((looking-at bibtex-field-const) |
1734 | (goto-char (match-end 0))) | |
1735 | ((setq boundaries (bibtex-parse-field-string)) | |
1736 | (goto-char (cdr boundaries))) | |
1737 | ((setq failure t))) | |
d528bff7 SM |
1738 | (if (looking-at "[ \t\n]*#[ \t\n]*") |
1739 | (goto-char (match-end 0)) | |
1740 | (setq end-point (point)))) | |
cdc61d35 | 1741 | (skip-chars-forward " \t\n") |
7fbf4804 SM |
1742 | (if (and (not failure) |
1743 | end-point) | |
cdc61d35 SM |
1744 | (list starting-point end-point (point))))) |
1745 | ||
1746 | (defun bibtex-parse-field () | |
1747 | "Parse the BibTeX field beginning at the position of point. | |
1748 | If a syntactically correct field is found, return a cons pair containing | |
1749 | the boundaries of the name and text parts of the field. Do not move point." | |
1750 | (bibtex-parse-association 'bibtex-parse-field-name | |
1751 | 'bibtex-parse-field-text)) | |
f9bd4abe | 1752 | |
cdc61d35 SM |
1753 | (defsubst bibtex-start-of-field (bounds) |
1754 | (nth 0 (car bounds))) | |
1755 | (defsubst bibtex-start-of-name-in-field (bounds) | |
1756 | (nth 1 (car bounds))) | |
1757 | (defsubst bibtex-end-of-name-in-field (bounds) | |
1758 | (nth 2 (car bounds))) | |
1759 | (defsubst bibtex-start-of-text-in-field (bounds) | |
1760 | (nth 1 bounds)) | |
1761 | (defsubst bibtex-end-of-text-in-field (bounds) | |
1762 | (nth 2 bounds)) | |
1763 | (defsubst bibtex-end-of-field (bounds) | |
1764 | (nth 3 bounds)) | |
f9bd4abe | 1765 | |
7fbf4804 | 1766 | (defun bibtex-search-forward-field (name &optional bound) |
02c8032e | 1767 | "Search forward to find a BibTeX field of name NAME. |
cdc61d35 SM |
1768 | If a syntactically correct field is found, return a pair containing |
1769 | the boundaries of the name and text parts of the field. The search | |
ffc1e1db RW |
1770 | is limited by optional arg BOUND. If BOUND is t the search is limited |
1771 | by the end of the current entry. Do not move point." | |
f9bd4abe | 1772 | (save-match-data |
7fbf4804 | 1773 | (save-excursion |
ffc1e1db RW |
1774 | (if (eq bound t) |
1775 | (let ((regexp (concat bibtex-name-part "[ \t\n]*=\\|" | |
1776 | bibtex-any-entry-maybe-empty-head)) | |
1777 | (case-fold-search t) bounds) | |
1778 | (catch 'done | |
1779 | (if (looking-at "[ \t]*@") (goto-char (match-end 0))) | |
1780 | (while (and (not bounds) | |
1781 | (re-search-forward regexp nil t)) | |
1782 | (if (match-beginning 2) | |
1783 | ;; We found a new entry | |
1784 | (throw 'done nil) | |
1785 | ;; We found a field | |
1786 | (goto-char (match-beginning 0)) | |
1787 | (setq bounds (bibtex-parse-field)))) | |
1788 | ;; Step through all fields so that we cannot overshoot. | |
1789 | (while bounds | |
1790 | (goto-char (bibtex-start-of-name-in-field bounds)) | |
1791 | (if (looking-at name) (throw 'done bounds)) | |
1792 | (goto-char (bibtex-end-of-field bounds)) | |
1793 | (setq bounds (bibtex-parse-field))))) | |
1794 | ;; Bounded search or bound is nil (i.e. we cannot overshoot). | |
1795 | ;; Indeed, the search is bounded when `bibtex-search-forward-field' | |
1796 | ;; is called many times. So we optimize this part of this function. | |
1797 | (let ((name-part (concat ",[ \t\n]*\\(" name "\\)[ \t\n]*=[ \t\n]*")) | |
1798 | (case-fold-search t) left right) | |
1799 | (while (and (not right) | |
1800 | (re-search-forward name-part bound t)) | |
1801 | (setq left (list (match-beginning 0) (match-beginning 1) | |
1802 | (match-end 1)) | |
1803 | ;; Don't worry that the field text could be past bound. | |
1804 | right (bibtex-parse-field-text))) | |
1805 | (if right (cons left right))))))) | |
7fbf4804 SM |
1806 | |
1807 | (defun bibtex-search-backward-field (name &optional bound) | |
02c8032e | 1808 | "Search backward to find a BibTeX field of name NAME. |
cdc61d35 SM |
1809 | If a syntactically correct field is found, return a pair containing |
1810 | the boundaries of the name and text parts of the field. The search | |
ffc1e1db | 1811 | is limited by the optional arg BOUND. If BOUND is t the search is |
cdc61d35 | 1812 | limited by the beginning of the current entry. Do not move point." |
f9bd4abe | 1813 | (save-match-data |
ffc1e1db RW |
1814 | (if (eq bound t) |
1815 | (setq bound (save-excursion (bibtex-beginning-of-entry)))) | |
1816 | (let ((name-part (concat ",[ \t\n]*\\(" name "\\)[ \t\n]*=[ \t\n]*")) | |
1817 | (case-fold-search t) left right) | |
1818 | (save-excursion | |
1819 | ;; the parsing functions are not designed for parsing backwards :-( | |
1820 | (when (search-backward "," bound t) | |
1821 | (or (save-excursion | |
1822 | (when (looking-at name-part) | |
1823 | (setq left (list (match-beginning 0) (match-beginning 1) | |
1824 | (match-end 1))) | |
1825 | (goto-char (match-end 0)) | |
1826 | (setq right (bibtex-parse-field-text)))) | |
1827 | (while (and (not right) | |
1828 | (re-search-backward name-part bound t)) | |
1829 | (setq left (list (match-beginning 0) (match-beginning 1) | |
1830 | (match-end 1))) | |
1831 | (save-excursion | |
1832 | (goto-char (match-end 0)) | |
1833 | (setq right (bibtex-parse-field-text))))) | |
1834 | (if right (cons left right))))))) | |
7fbf4804 | 1835 | |
d528bff7 SM |
1836 | (defun bibtex-name-in-field (bounds &optional remove-opt-alt) |
1837 | "Get content of name in BibTeX field defined via BOUNDS. | |
1838 | If optional arg REMOVE-OPT-ALT is non-nil remove \"OPT\" and \"ALT\"." | |
cdc61d35 SM |
1839 | (let ((name (buffer-substring-no-properties |
1840 | (bibtex-start-of-name-in-field bounds) | |
1841 | (bibtex-end-of-name-in-field bounds)))) | |
d528bff7 | 1842 | (if (and remove-opt-alt |
2de69e00 RW |
1843 | (string-match "\\`\\(OPT\\|ALT\\)" name) |
1844 | (not (and bibtex-no-opt-remove-re | |
1845 | (string-match bibtex-no-opt-remove-re name)))) | |
d528bff7 SM |
1846 | (substring name 3) |
1847 | name))) | |
7fbf4804 | 1848 | |
cdc61d35 SM |
1849 | (defun bibtex-text-in-field-bounds (bounds &optional content) |
1850 | "Get text in BibTeX field defined via BOUNDS. | |
1851 | If optional arg CONTENT is non-nil extract content of field | |
1852 | by removing field delimiters and concatenating the resulting string. | |
1853 | If `bibtex-expand-strings' is non-nil, also expand BibTeX strings." | |
1854 | (if content | |
1855 | (save-excursion | |
ffc1e1db | 1856 | (goto-char (bibtex-start-of-text-in-field bounds)) |
cdc61d35 | 1857 | (let ((epoint (bibtex-end-of-text-in-field bounds)) |
842d73a1 SM |
1858 | content) |
1859 | (while (< (point) epoint) | |
ffc1e1db RW |
1860 | (if (looking-at bibtex-field-const) |
1861 | (let ((mtch (match-string-no-properties 0))) | |
e8606202 RW |
1862 | (push (or (if bibtex-expand-strings |
1863 | (cdr (assoc-string mtch (bibtex-strings) t))) | |
1864 | mtch) content) | |
ffc1e1db RW |
1865 | (goto-char (match-end 0))) |
1866 | (let ((bounds (bibtex-parse-field-string))) | |
1867 | (push (buffer-substring-no-properties | |
1868 | (1+ (car bounds)) (1- (cdr bounds))) content) | |
1869 | (goto-char (cdr bounds)))) | |
cdc61d35 | 1870 | (re-search-forward "\\=[ \t\n]*#[ \t\n]*" nil t)) |
ffc1e1db | 1871 | (apply 'concat (nreverse content)))) |
cdc61d35 SM |
1872 | (buffer-substring-no-properties (bibtex-start-of-text-in-field bounds) |
1873 | (bibtex-end-of-text-in-field bounds)))) | |
7fbf4804 SM |
1874 | |
1875 | (defun bibtex-text-in-field (field &optional follow-crossref) | |
02c8032e SM |
1876 | "Get content of field FIELD of current BibTeX entry. |
1877 | Return nil if not found. | |
7fbf4804 SM |
1878 | If optional arg FOLLOW-CROSSREF is non-nil, follow crossref." |
1879 | (save-excursion | |
ffc1e1db RW |
1880 | (let* ((end (if follow-crossref (bibtex-end-of-entry) t)) |
1881 | (beg (bibtex-beginning-of-entry)) ; move point | |
1882 | (bounds (bibtex-search-forward-field field end))) | |
1883 | (cond (bounds (bibtex-text-in-field-bounds bounds t)) | |
1884 | ((and follow-crossref | |
1885 | (progn (goto-char beg) | |
1886 | (setq bounds (bibtex-search-forward-field | |
1887 | "\\(OPT\\)?crossref" end)))) | |
1888 | (let ((crossref-field (bibtex-text-in-field-bounds bounds t))) | |
7af32e66 | 1889 | (if (bibtex-search-crossref crossref-field) |
7fbf4804 SM |
1890 | ;; Do not pass FOLLOW-CROSSREF because we want |
1891 | ;; to follow crossrefs only one level of recursion. | |
1892 | (bibtex-text-in-field field)))))))) | |
f9bd4abe GM |
1893 | |
1894 | (defun bibtex-parse-string-prefix () | |
7fbf4804 | 1895 | "Parse the prefix part of a BibTeX string entry, including reference key. |
f9bd4abe GM |
1896 | If the string prefix is found, return a triple consisting of the position of |
1897 | the very first character of the match, the actual starting position of the | |
cdc61d35 SM |
1898 | reference key and the end position of the match. |
1899 | If `bibtex-string-empty-key' is non-nil accept empty string key." | |
7fbf4804 | 1900 | (let ((case-fold-search t)) |
cdc61d35 | 1901 | (if (looking-at bibtex-string-type) |
7fbf4804 SM |
1902 | (let ((start (point))) |
1903 | (goto-char (match-end 0)) | |
cdc61d35 SM |
1904 | (cond ((looking-at bibtex-reference-key) |
1905 | (goto-char (match-end 0)) | |
1906 | (list start | |
1907 | (match-beginning 0) | |
1908 | (match-end 0))) | |
1909 | ((and bibtex-string-empty-key | |
1910 | (looking-at "=")) | |
1911 | (skip-chars-backward " \t\n") | |
1912 | (list start (point) (point)))))))) | |
f9bd4abe GM |
1913 | |
1914 | (defun bibtex-parse-string-postfix () | |
7fbf4804 | 1915 | "Parse the postfix part of a BibTeX string entry, including the text. |
f9bd4abe GM |
1916 | If the string postfix is found, return a triple consisting of the position of |
1917 | the actual starting and ending position of the text and the very last | |
a9d77f1f | 1918 | character of the string entry. Move point past BibTeX string entry." |
f9bd4abe | 1919 | (let* ((case-fold-search t) |
d715b065 KG |
1920 | (bounds (bibtex-parse-field-text))) |
1921 | (when bounds | |
cdc61d35 | 1922 | (goto-char (nth 1 bounds)) |
7fbf4804 SM |
1923 | (when (looking-at "[ \t\n]*[})]") |
1924 | (goto-char (match-end 0)) | |
d715b065 | 1925 | (list (car bounds) |
cdc61d35 | 1926 | (nth 1 bounds) |
7fbf4804 | 1927 | (match-end 0)))))) |
f9bd4abe | 1928 | |
ffc1e1db | 1929 | (defun bibtex-parse-string (&optional empty-key) |
cdc61d35 SM |
1930 | "Parse a BibTeX string entry beginning at the position of point. |
1931 | If a syntactically correct entry is found, return a cons pair containing | |
1932 | the boundaries of the reference key and text parts of the entry. | |
ffc1e1db RW |
1933 | If EMPTY-KEY is non-nil, key may be empty. Do not move point." |
1934 | (let ((bibtex-string-empty-key empty-key)) | |
1935 | (bibtex-parse-association 'bibtex-parse-string-prefix | |
1936 | 'bibtex-parse-string-postfix))) | |
f9bd4abe | 1937 | |
ffc1e1db | 1938 | (defun bibtex-search-forward-string (&optional empty-key) |
7fbf4804 | 1939 | "Search forward to find a BibTeX string entry. |
f9bd4abe | 1940 | If a syntactically correct entry is found, a pair containing the boundaries of |
ffc1e1db RW |
1941 | the reference key and text parts of the string is returned. |
1942 | If EMPTY-KEY is non-nil, key may be empty. Do not move point." | |
7fbf4804 SM |
1943 | (save-excursion |
1944 | (save-match-data | |
ffc1e1db RW |
1945 | (let ((case-fold-search t) bounds) |
1946 | (while (and (not bounds) | |
cdc61d35 | 1947 | (search-forward-regexp bibtex-string-type nil t)) |
ffc1e1db RW |
1948 | (save-excursion (goto-char (match-beginning 0)) |
1949 | (setq bounds (bibtex-parse-string empty-key)))) | |
1950 | bounds)))) | |
7fbf4804 SM |
1951 | |
1952 | (defun bibtex-reference-key-in-string (bounds) | |
f2dfa899 | 1953 | "Return the key part of a BibTeX string defined via BOUNDS." |
7fbf4804 SM |
1954 | (buffer-substring-no-properties (nth 1 (car bounds)) |
1955 | (nth 2 (car bounds)))) | |
1956 | ||
cdc61d35 SM |
1957 | (defun bibtex-text-in-string (bounds &optional content) |
1958 | "Get text in BibTeX string field defined via BOUNDS. | |
1959 | If optional arg CONTENT is non-nil extract content | |
1960 | by removing field delimiters and concatenating the resulting string. | |
1961 | If `bibtex-expand-strings' is non-nil, also expand BibTeX strings." | |
1962 | (bibtex-text-in-field-bounds bounds content)) | |
f9bd4abe | 1963 | |
d715b065 | 1964 | (defsubst bibtex-start-of-text-in-string (bounds) |
7fbf4804 | 1965 | (nth 0 (cdr bounds))) |
d715b065 | 1966 | (defsubst bibtex-end-of-text-in-string (bounds) |
7fbf4804 | 1967 | (nth 1 (cdr bounds))) |
d715b065 | 1968 | (defsubst bibtex-end-of-string (bounds) |
7fbf4804 | 1969 | (nth 2 (cdr bounds))) |
745bc783 | 1970 | |
d715b065 | 1971 | (defsubst bibtex-type-in-head () |
7fbf4804 SM |
1972 | "Extract BibTeX type in head." |
1973 | ;; ignore @ | |
1974 | (buffer-substring-no-properties (1+ (match-beginning bibtex-type-in-head)) | |
1975 | (match-end bibtex-type-in-head))) | |
31bc4210 | 1976 | |
e0dc0c55 | 1977 | (defsubst bibtex-key-in-head (&optional empty) |
a9d77f1f | 1978 | "Extract BibTeX key in head. Return optional arg EMPTY if key is empty." |
e0dc0c55 SM |
1979 | (or (match-string-no-properties bibtex-key-in-head) |
1980 | empty)) | |
f9bd4abe | 1981 | |
ffc1e1db RW |
1982 | (defun bibtex-parse-preamble () |
1983 | "Parse BibTeX preamble. | |
1984 | Point must be at beginning of preamble. Do not move point." | |
cdc61d35 | 1985 | (let ((case-fold-search t)) |
ffc1e1db RW |
1986 | (when (looking-at bibtex-preamble-prefix) |
1987 | (let ((start (match-beginning 0)) (pref-start (match-beginning 1)) | |
1988 | (bounds (save-excursion (goto-char (match-end 0)) | |
1989 | (bibtex-parse-string-postfix)))) | |
1990 | (if bounds (cons (list start pref-start) bounds)))))) | |
e5167999 | 1991 | |
cdc61d35 | 1992 | ;; Helper Functions |
d10e87a2 | 1993 | |
d528bff7 | 1994 | (defsubst bibtex-string= (str1 str2) |
a9d77f1f | 1995 | "Return t if STR1 and STR2 are equal, ignoring case." |
d528bff7 SM |
1996 | (eq t (compare-strings str1 0 nil str2 0 nil t))) |
1997 | ||
55fe21fc | 1998 | (defun bibtex-delete-whitespace () |
7fbf4804 | 1999 | "Delete all whitespace starting at point." |
50e4b39e RS |
2000 | (if (looking-at "[ \t\n]+") |
2001 | (delete-region (point) (match-end 0)))) | |
2002 | ||
55fe21fc | 2003 | (defun bibtex-current-line () |
7fbf4804 | 2004 | "Compute line number of point regardless whether the buffer is narrowed." |
50e4b39e | 2005 | (+ (count-lines 1 (point)) |
e0dc0c55 | 2006 | (if (bolp) 1 0))) |
50e4b39e | 2007 | |
ffc1e1db RW |
2008 | (defun bibtex-valid-entry (&optional empty-key) |
2009 | "Parse a valid BibTeX entry (maybe without key if EMPTY-KEY is t). | |
2010 | A valid entry is a syntactical correct one with type contained in | |
2de69e00 | 2011 | `bibtex-BibTeX-entry-alist'. Ignore @String and @Preamble entries. |
ffc1e1db RW |
2012 | Return a cons pair with buffer positions of beginning and end of entry |
2013 | if a valid entry is found, nil otherwise. Do not move point. | |
2014 | After a call to this function `match-data' corresponds to the header | |
2015 | of the entry, see regexp `bibtex-entry-head'." | |
2016 | (let ((case-fold-search t) end) | |
2017 | (if (looking-at (if empty-key bibtex-entry-maybe-empty-head | |
2018 | bibtex-entry-head)) | |
2019 | (save-excursion | |
2020 | (save-match-data | |
2021 | (goto-char (match-end 0)) | |
2022 | (let ((entry-closer | |
2023 | (if (save-excursion | |
2024 | (goto-char (match-end bibtex-type-in-head)) | |
2025 | (looking-at "[ \t]*(")) | |
f2dfa899 RW |
2026 | ",?[ \t\n]*)" ; entry opened with `(' |
2027 | ",?[ \t\n]*}")) ; entry opened with `{' | |
ffc1e1db RW |
2028 | bounds) |
2029 | (skip-chars-forward " \t\n") | |
2030 | ;; loop over all BibTeX fields | |
2031 | (while (setq bounds (bibtex-parse-field)) | |
2032 | (goto-char (bibtex-end-of-field bounds))) | |
2033 | ;; This matches the infix* part. | |
2034 | (if (looking-at entry-closer) (setq end (match-end 0))))) | |
2035 | (if end (cons (match-beginning 0) end)))))) | |
2036 | ||
55fe21fc | 2037 | (defun bibtex-skip-to-valid-entry (&optional backward) |
a9d77f1f SM |
2038 | "Move point to beginning of the next valid BibTeX entry. |
2039 | Do not move if we are already at beginning of a valid BibTeX entry. | |
2040 | With optional argument BACKWARD non-nil, move backward to | |
2041 | beginning of previous valid one. A valid entry is a syntactical correct one | |
2de69e00 | 2042 | with type contained in `bibtex-BibTeX-entry-alist' or, if |
7fbf4804 | 2043 | `bibtex-sort-ignore-string-entries' is nil, a syntactical correct string |
cdc61d35 | 2044 | entry. Return buffer position of beginning and end of entry if a valid |
d715b065 KG |
2045 | entry is found, nil otherwise." |
2046 | (interactive "P") | |
7fbf4804 | 2047 | (let ((case-fold-search t) |
ffc1e1db | 2048 | found bounds) |
cdc61d35 SM |
2049 | (beginning-of-line) |
2050 | ;; Loop till we look at a valid entry. | |
d715b065 | 2051 | (while (not (or found (if backward (bobp) (eobp)))) |
ffc1e1db RW |
2052 | (cond ((setq found (or (bibtex-valid-entry) |
2053 | (and (not bibtex-sort-ignore-string-entries) | |
2054 | (setq bounds (bibtex-parse-string)) | |
2055 | (cons (bibtex-start-of-field bounds) | |
2056 | (bibtex-end-of-string bounds)))))) | |
2057 | (backward (re-search-backward "^[ \t]*@" nil 'move)) | |
2058 | (t (if (re-search-forward "\n\\([ \t]*@\\)" nil 'move) | |
2059 | (goto-char (match-beginning 1)))))) | |
7fbf4804 | 2060 | found)) |
9ae11a89 | 2061 | |
55fe21fc | 2062 | (defun bibtex-map-entries (fun) |
e0dc0c55 SM |
2063 | "Call FUN for each BibTeX entry in buffer (possibly narrowed). |
2064 | FUN is called with three arguments, the key of the entry and the buffer | |
ffc1e1db RW |
2065 | positions of beginning and end of entry. Also, point is at beginning of |
2066 | entry and `match-data' corresponds to the header of the entry, | |
2067 | see regexp `bibtex-entry-head'. If `bibtex-sort-ignore-string-entries' | |
2068 | is non-nil, FUN is not called for @String entries." | |
cdc61d35 | 2069 | (let ((case-fold-search t) |
403111a8 | 2070 | (end-marker (make-marker)) |
cdc61d35 | 2071 | found) |
403111a8 RW |
2072 | ;; Use marker to keep track of the buffer position of the end of |
2073 | ;; a BibTeX entry as this position may change during reformatting. | |
2074 | (set-marker-insertion-type end-marker t) | |
e0dc0c55 SM |
2075 | (save-excursion |
2076 | (goto-char (point-min)) | |
cdc61d35 | 2077 | (while (setq found (bibtex-skip-to-valid-entry)) |
403111a8 | 2078 | (set-marker end-marker (cdr found)) |
cdc61d35 | 2079 | (looking-at bibtex-any-entry-maybe-empty-head) |
403111a8 RW |
2080 | (funcall fun (bibtex-key-in-head "") (car found) end-marker) |
2081 | (goto-char end-marker))))) | |
50e4b39e RS |
2082 | |
2083 | (defun bibtex-progress-message (&optional flag interval) | |
7fbf4804 SM |
2084 | "Echo a message about progress of current buffer. |
2085 | If FLAG is a string, the message is initialized (in this case a | |
2086 | value for INTERVAL may be given as well (if not this is set to 5)). | |
02c8032e | 2087 | If FLAG is `done', the message is deinitialized. |
8bf38a9b SM |
2088 | If FLAG is nil, a message is echoed if point was incremented at least |
2089 | `bibtex-progress-interval' percent since last message was echoed." | |
7fbf4804 | 2090 | (cond ((stringp flag) |
02c8032e SM |
2091 | (setq bibtex-progress-lastmes flag |
2092 | bibtex-progress-interval (or interval 5) | |
7fbf4804 | 2093 | bibtex-progress-lastperc 0)) |
02c8032e | 2094 | ((eq flag 'done) |
7fbf4804 SM |
2095 | (message "%s (done)" bibtex-progress-lastmes) |
2096 | (setq bibtex-progress-lastmes nil)) | |
2097 | (t | |
2098 | (let* ((size (- (point-max) (point-min))) | |
2099 | (perc (if (= size 0) | |
2100 | 100 | |
2101 | (/ (* 100 (- (point) (point-min))) size)))) | |
2102 | (when (>= perc (+ bibtex-progress-lastperc | |
2103 | bibtex-progress-interval)) | |
2104 | (setq bibtex-progress-lastperc perc) | |
2105 | (message "%s (%d%%)" bibtex-progress-lastmes perc)))))) | |
50e4b39e RS |
2106 | |
2107 | (defun bibtex-field-left-delimiter () | |
7fbf4804 | 2108 | "Return a string dependent on `bibtex-field-delimiters'." |
02c8032e | 2109 | (if (eq bibtex-field-delimiters 'braces) |
50e4b39e RS |
2110 | "{" |
2111 | "\"")) | |
2112 | ||
2113 | (defun bibtex-field-right-delimiter () | |
7fbf4804 | 2114 | "Return a string dependent on `bibtex-field-delimiters'." |
02c8032e | 2115 | (if (eq bibtex-field-delimiters 'braces) |
50e4b39e RS |
2116 | "}" |
2117 | "\"")) | |
2118 | ||
2119 | (defun bibtex-entry-left-delimiter () | |
e0dc0c55 | 2120 | "Return a string dependent on `bibtex-entry-delimiters'." |
02c8032e | 2121 | (if (eq bibtex-entry-delimiters 'braces) |
50e4b39e RS |
2122 | "{" |
2123 | "(")) | |
2124 | ||
2125 | (defun bibtex-entry-right-delimiter () | |
e0dc0c55 | 2126 | "Return a string dependent on `bibtex-entry-delimiters'." |
02c8032e | 2127 | (if (eq bibtex-entry-delimiters 'braces) |
50e4b39e RS |
2128 | "}" |
2129 | ")")) | |
2130 | ||
ffc1e1db | 2131 | (defun bibtex-flash-head (prompt) |
65e10478 | 2132 | "Flash at BibTeX entry head before point, if it exists." |
7fbf4804 | 2133 | (let ((case-fold-search t) |
ffc1e1db | 2134 | (pnt (point))) |
cdc61d35 SM |
2135 | (save-excursion |
2136 | (bibtex-beginning-of-entry) | |
2137 | (when (and (looking-at bibtex-any-entry-maybe-empty-head) | |
2138 | (< (point) pnt)) | |
2139 | (goto-char (match-beginning bibtex-type-in-head)) | |
65e10478 RW |
2140 | (if (and (< 0 blink-matching-delay) |
2141 | (pos-visible-in-window-p (point))) | |
f2dfa899 | 2142 | (sit-for blink-matching-delay) |
ffc1e1db RW |
2143 | (message "%s%s" prompt (buffer-substring-no-properties |
2144 | (point) (match-end bibtex-key-in-head)))))))) | |
e5167999 | 2145 | |
d715b065 KG |
2146 | (defun bibtex-make-optional-field (field) |
2147 | "Make an optional field named FIELD in current BibTeX entry." | |
2148 | (if (consp field) | |
2149 | (bibtex-make-field (cons (concat "OPT" (car field)) (cdr field))) | |
2150 | (bibtex-make-field (concat "OPT" field)))) | |
50e4b39e | 2151 | |
cb4ad359 | 2152 | (defun bibtex-move-outside-of-entry () |
7fbf4804 | 2153 | "Make sure point is outside of a BibTeX entry." |
f0cb6034 | 2154 | (let ((orig-point (point))) |
28f2ee66 | 2155 | (bibtex-end-of-entry) |
0640e91a | 2156 | (when (< (point) orig-point) |
7fbf4804 SM |
2157 | ;; We moved backward, so we weren't inside an entry to begin with. |
2158 | ;; Leave point at the beginning of a line, and preferably | |
2159 | ;; at the beginning of a paragraph. | |
2160 | (goto-char orig-point) | |
2161 | (beginning-of-line 1) | |
0640e91a RS |
2162 | (unless (= ?\n (char-before (1- (point)))) |
2163 | (re-search-forward "^[ \t]*[@\n]" nil 'move) | |
2164 | (backward-char 1))) | |
f0cb6034 | 2165 | (skip-chars-forward " \t\n"))) |
50e4b39e RS |
2166 | |
2167 | (defun bibtex-beginning-of-first-entry () | |
cdc61d35 SM |
2168 | "Go to beginning of line of first BibTeX entry in buffer. |
2169 | If `bibtex-sort-ignore-string-entries' is non-nil, @String entries | |
2170 | are ignored. Return point" | |
e5167999 | 2171 | (goto-char (point-min)) |
cdc61d35 | 2172 | (bibtex-skip-to-valid-entry) |
50e4b39e | 2173 | (point)) |
e5167999 | 2174 | |
ffc1e1db | 2175 | (defun bibtex-enclosing-field (&optional comma noerr) |
d528bff7 | 2176 | "Search for BibTeX field enclosing point. |
ffc1e1db RW |
2177 | For `bibtex-mode''s internal algorithms, a field begins at the comma |
2178 | following the preceding field. Usually, this is not what the user expects. | |
4106334c RW |
2179 | Thus if COMMA is non-nil, the \"current field\" includes the terminating comma |
2180 | as well as the entry delimiter if it appears on the same line. | |
02c8032e SM |
2181 | Unless NOERR is non-nil, signal an error if no enclosing field is found. |
2182 | On success return bounds, nil otherwise. Do not move point." | |
ffc1e1db RW |
2183 | (save-excursion |
2184 | (when comma | |
2185 | (end-of-line) | |
2186 | (skip-chars-backward " \t") | |
4106334c RW |
2187 | ;; Ignore entry delimiter and comma at end of line. |
2188 | (if (memq (preceding-char) '(?} ?\))) (forward-char -1)) | |
ffc1e1db RW |
2189 | (if (= (preceding-char) ?,) (forward-char -1))) |
2190 | ||
2191 | (let ((bounds (bibtex-search-backward-field bibtex-field-name t))) | |
2192 | (cond ((and bounds | |
2193 | (<= (bibtex-start-of-field bounds) (point)) | |
2194 | (>= (bibtex-end-of-field bounds) (point))) | |
2195 | bounds) | |
2196 | ((not noerr) | |
2197 | (error "Can't find enclosing BibTeX field")))))) | |
2198 | ||
2199 | (defun bibtex-beginning-first-field (&optional beg) | |
2200 | "Move point to beginning of first field. | |
2201 | Optional arg BEG is beginning of entry." | |
2202 | (if beg (goto-char beg) (bibtex-beginning-of-entry)) | |
2203 | (looking-at bibtex-any-entry-maybe-empty-head) | |
2204 | (goto-char (match-end 0))) | |
2205 | ||
2206 | (defun bibtex-insert-kill (n &optional comma) | |
2207 | "Reinsert the Nth stretch of killed BibTeX text (field or entry). | |
2208 | Optional arg COMMA is as in `bibtex-enclosing-field'." | |
2209 | (unless bibtex-last-kill-command (error "BibTeX kill ring is empty")) | |
f2dfa899 | 2210 | (let ((fun (lambda (kryp kr) ; adapted from `current-kill' |
ffc1e1db RW |
2211 | (car (set kryp (nthcdr (mod (- n (length (eval kryp))) |
2212 | (length kr)) kr)))))) | |
e70ee681 RW |
2213 | ;; We put the mark at the beginning of the inserted field or entry |
2214 | ;; and point at its end - a behavior similar to what `yank' does. | |
2215 | ;; The mark is then used by `bibtex-yank-pop', which needs to know | |
2216 | ;; what we have inserted. | |
ffc1e1db RW |
2217 | (if (eq bibtex-last-kill-command 'field) |
2218 | (progn | |
2219 | ;; insert past the current field | |
2220 | (goto-char (bibtex-end-of-field (bibtex-enclosing-field comma))) | |
f2dfa899 | 2221 | (push-mark) |
ffc1e1db | 2222 | (bibtex-make-field (funcall fun 'bibtex-field-kill-ring-yank-pointer |
84aa4fc6 | 2223 | bibtex-field-kill-ring) t nil t)) |
ffc1e1db RW |
2224 | ;; insert past the current entry |
2225 | (bibtex-skip-to-valid-entry) | |
f2dfa899 | 2226 | (push-mark) |
ffc1e1db | 2227 | (insert (funcall fun 'bibtex-entry-kill-ring-yank-pointer |
403111a8 | 2228 | bibtex-entry-kill-ring)) |
004dedd3 RW |
2229 | ;; If we copied an entry from a buffer containing only this one entry, |
2230 | ;; it can be missing the second "\n". | |
2231 | (unless (looking-back "\n\n") (insert "\n")) | |
403111a8 RW |
2232 | (unless (functionp bibtex-reference-keys) |
2233 | ;; update `bibtex-reference-keys' | |
2234 | (save-excursion | |
2235 | (goto-char (mark t)) | |
2236 | (looking-at bibtex-any-entry-maybe-empty-head) | |
2237 | (let ((key (bibtex-key-in-head))) | |
2238 | (if key (push (cons key t) bibtex-reference-keys)))))))) | |
f9bd4abe | 2239 | |
2de69e00 RW |
2240 | (defsubst bibtex-vec-push (vec idx newelt) |
2241 | "Add NEWELT to the list stored in VEC at index IDX." | |
2242 | (aset vec idx (cons newelt (aref vec idx)))) | |
2243 | ||
2244 | (defsubst bibtex-vec-incr (vec idx) | |
e70ee681 | 2245 | "Increment by 1 the counter which is stored in VEC at index IDX." |
2de69e00 RW |
2246 | (aset vec idx (1+ (aref vec idx)))) |
2247 | ||
50e4b39e | 2248 | (defun bibtex-format-entry () |
7fbf4804 SM |
2249 | "Helper function for `bibtex-clean-entry'. |
2250 | Formats current entry according to variable `bibtex-entry-format'." | |
65e10478 RW |
2251 | ;; initialize `bibtex-field-braces-opt' if necessary |
2252 | (if (and bibtex-field-braces-alist (not bibtex-field-braces-opt)) | |
2253 | (setq bibtex-field-braces-opt | |
2254 | (bibtex-field-re-init bibtex-field-braces-alist 'braces))) | |
2255 | ;; initialize `bibtex-field-strings-opt' if necessary | |
2256 | (if (and bibtex-field-strings-alist (not bibtex-field-strings-opt)) | |
2257 | (setq bibtex-field-strings-opt | |
2258 | (bibtex-field-re-init bibtex-field-strings-alist 'strings))) | |
2259 | ||
7af32e66 RW |
2260 | (let ((case-fold-search t) |
2261 | (format (if (eq bibtex-entry-format t) | |
2262 | '(realign opts-or-alts required-fields numerical-fields | |
2263 | page-dashes whitespace inherit-booktitle | |
2264 | last-comma delimiters unify-case braces | |
b7c3692a | 2265 | strings sort-fields) |
7af32e66 | 2266 | bibtex-entry-format)) |
a51cfa58 | 2267 | (left-delim-re (regexp-quote (bibtex-field-left-delimiter))) |
7af32e66 | 2268 | bounds crossref-key req-field-list default-field-list field-list |
2de69e00 | 2269 | num-alt alt-fields idx error-field-name) |
7af32e66 RW |
2270 | (unwind-protect |
2271 | ;; formatting (undone if error occurs) | |
2272 | (atomic-change-group | |
2273 | (save-excursion | |
2274 | (save-restriction | |
2275 | (bibtex-narrow-to-entry) | |
2276 | ||
2277 | ;; There are more elegant high-level functions for several tasks | |
2278 | ;; done by `bibtex-format-entry'. However, they contain some | |
2279 | ;; redundancy compared with what we need to do anyway. | |
2280 | ;; So for speed-up we avoid using them. | |
2281 | ;; (`bibtex-format-entry' is called often by `bibtex-reformat'.) | |
2282 | ||
2283 | ;; identify entry type | |
2284 | (goto-char (point-min)) | |
2285 | (or (re-search-forward bibtex-entry-type nil t) | |
2286 | (error "Not inside a BibTeX entry")) | |
2287 | (let* ((beg-type (1+ (match-beginning 0))) | |
2288 | (end-type (match-end 0)) | |
2289 | (entry-list (assoc-string (buffer-substring-no-properties | |
2290 | beg-type end-type) | |
2de69e00 | 2291 | bibtex-entry-alist t))) |
7af32e66 | 2292 | |
c48f463b | 2293 | ;; unify case of entry type |
7af32e66 RW |
2294 | (when (memq 'unify-case format) |
2295 | (delete-region beg-type end-type) | |
2296 | (insert (car entry-list))) | |
2297 | ||
2298 | ;; update left entry delimiter | |
2299 | (when (memq 'delimiters format) | |
2300 | (goto-char end-type) | |
2301 | (skip-chars-forward " \t\n") | |
7fbf4804 | 2302 | (delete-char 1) |
7af32e66 RW |
2303 | (insert (bibtex-entry-left-delimiter))) |
2304 | ||
2305 | ;; Do we have a crossref key? | |
2306 | (goto-char (point-min)) | |
45cb4eb4 RW |
2307 | (if (setq bounds (bibtex-search-forward-field |
2308 | "\\(OPT\\)?crossref")) | |
7af32e66 RW |
2309 | (let ((text (bibtex-text-in-field-bounds bounds t))) |
2310 | (unless (equal "" text) | |
2311 | (setq crossref-key text)))) | |
2312 | ||
2313 | ;; list of required fields appropriate for an entry with | |
2314 | ;; or without crossref key. | |
2de69e00 RW |
2315 | (setq req-field-list (if crossref-key (nth 2 entry-list) |
2316 | (append (nth 2 entry-list) (nth 3 entry-list))) | |
7af32e66 | 2317 | ;; default list of fields that may appear in this entry |
2de69e00 RW |
2318 | default-field-list (append (nth 2 entry-list) (nth 3 entry-list) |
2319 | (nth 4 entry-list) | |
2320 | bibtex-user-optional-fields) | |
2321 | ;; number of ALT fields we expect to find | |
2322 | num-alt (length (delq nil (delete-dups | |
2323 | (mapcar (lambda (x) (nth 3 x)) | |
2324 | req-field-list)))) | |
2325 | ;; ALT fields of respective groups | |
2326 | alt-fields (make-vector num-alt nil)) | |
b7c3692a RW |
2327 | |
2328 | (when (memq 'sort-fields format) | |
2329 | (goto-char (point-min)) | |
2330 | (let ((beg-fields (save-excursion (bibtex-beginning-first-field))) | |
2331 | (fields-alist (bibtex-parse-entry)) | |
2332 | bibtex-help-message elt) | |
2333 | (delete-region beg-fields (point)) | |
2334 | (dolist (field default-field-list) | |
2335 | (when (setq elt (assoc-string (car field) fields-alist t)) | |
2336 | (setq fields-alist (delete elt fields-alist)) | |
2de69e00 | 2337 | (bibtex-make-field (list (car elt) nil (cdr elt)) nil nil t))) |
b7c3692a RW |
2338 | (dolist (field fields-alist) |
2339 | (unless (member (car field) '("=key=" "=type=")) | |
2de69e00 | 2340 | (bibtex-make-field (list (car field) nil (cdr field)) nil nil t)))))) |
7af32e66 RW |
2341 | |
2342 | ;; process all fields | |
2343 | (bibtex-beginning-first-field (point-min)) | |
2344 | (while (setq bounds (bibtex-parse-field)) | |
2345 | (let* ((beg-field (copy-marker (bibtex-start-of-field bounds))) | |
2346 | (end-field (copy-marker (bibtex-end-of-field bounds) t)) | |
2347 | (beg-name (copy-marker (bibtex-start-of-name-in-field bounds))) | |
2348 | (end-name (copy-marker (bibtex-end-of-name-in-field bounds))) | |
2349 | (beg-text (copy-marker (bibtex-start-of-text-in-field bounds))) | |
2350 | (end-text (copy-marker (bibtex-end-of-text-in-field bounds) t)) | |
7af32e66 | 2351 | (empty-field (equal "" (bibtex-text-in-field-bounds bounds t))) |
2de69e00 RW |
2352 | (field-name (buffer-substring-no-properties beg-name end-name)) |
2353 | (opt-alt (and (string-match "\\`\\(OPT\\|ALT\\)" field-name) | |
2354 | (not (and bibtex-no-opt-remove-re | |
2355 | (string-match bibtex-no-opt-remove-re | |
2356 | field-name))))) | |
7af32e66 | 2357 | deleted) |
2de69e00 | 2358 | (if opt-alt (setq field-name (substring field-name 3))) |
7af32e66 RW |
2359 | |
2360 | ;; keep track of alternatives | |
2de69e00 RW |
2361 | (if (setq idx (nth 3 (assoc-string field-name req-field-list t))) |
2362 | (bibtex-vec-push alt-fields idx field-name)) | |
7af32e66 RW |
2363 | |
2364 | (if (memq 'opts-or-alts format) | |
2365 | ;; delete empty optional and alternative fields | |
2366 | ;; (but keep empty required fields) | |
2367 | (cond ((and empty-field | |
2368 | (or opt-alt | |
2369 | (let ((field (assoc-string | |
2370 | field-name req-field-list t))) | |
2371 | (or (not field) ; OPT field | |
2372 | (nth 3 field))))) ; ALT field | |
2373 | (delete-region beg-field end-field) | |
2374 | (setq deleted t)) | |
2375 | ;; otherwise nonempty field: delete "OPT" or "ALT" | |
2376 | (opt-alt | |
2377 | (goto-char beg-name) | |
2378 | (delete-char 3)))) | |
2379 | ||
2380 | (unless deleted | |
2381 | (push field-name field-list) | |
2382 | ||
403111a8 RW |
2383 | ;; Remove whitespace at beginning and end of field. |
2384 | ;; We do not look at individual parts of the field | |
2385 | ;; as {foo } # bar # { baz} is a fine field. | |
2386 | (when (memq 'whitespace format) | |
2387 | (goto-char beg-text) | |
2388 | (if (looking-at "\\([{\"]\\)[ \t\n]+") | |
2389 | (replace-match "\\1")) | |
2390 | (goto-char end-text) | |
2391 | (if (looking-back "[ \t\n]+\\([}\"]\\)" beg-text t) | |
2392 | (replace-match "\\1"))) | |
2393 | ||
7af32e66 RW |
2394 | ;; remove delimiters from purely numerical fields |
2395 | (when (and (memq 'numerical-fields format) | |
2396 | (progn (goto-char beg-text) | |
a2a25d24 | 2397 | (looking-at "\"[0-9]+\"\\|{[0-9]+}"))) |
7af32e66 RW |
2398 | (goto-char end-text) |
2399 | (delete-char -1) | |
2400 | (goto-char beg-text) | |
2401 | (delete-char 1)) | |
2402 | ||
2403 | ;; update delimiters | |
2404 | (when (memq 'delimiters format) | |
2405 | (goto-char beg-text) | |
a51cfa58 RW |
2406 | ;; simplified from `bibtex-parse-field-text', as we |
2407 | ;; already checked that the field format is correct | |
2408 | (while (< (point) end-text) | |
2409 | (if (looking-at bibtex-field-const) | |
2410 | (goto-char (match-end 0)) | |
2411 | (let ((boundaries (bibtex-parse-field-string))) | |
635618a4 RW |
2412 | (if (looking-at left-delim-re) |
2413 | (goto-char (cdr boundaries)) | |
a51cfa58 | 2414 | (delete-char 1) |
635618a4 RW |
2415 | (insert (bibtex-field-left-delimiter)) |
2416 | (goto-char (1- (cdr boundaries))) | |
a51cfa58 RW |
2417 | (delete-char 1) |
2418 | (insert (bibtex-field-right-delimiter))))) | |
2419 | (if (looking-at "[ \t\n]*#[ \t\n]*") | |
2420 | (goto-char (match-end 0))))) | |
7af32e66 RW |
2421 | |
2422 | ;; update page dashes | |
2423 | (if (and (memq 'page-dashes format) | |
2424 | (bibtex-string= field-name "pages") | |
2425 | (progn (goto-char beg-text) | |
2426 | (looking-at | |
2427 | "\\([\"{][0-9]+\\)[ \t\n]*--?[ \t\n]*\\([0-9]+[\"}]\\)"))) | |
2428 | (replace-match "\\1-\\2")) | |
2429 | ||
7af32e66 RW |
2430 | ;; enclose field text by braces according to |
2431 | ;; `bibtex-field-braces-alist'. | |
2432 | (let (case-fold-search temp) ; Case-sensitive search | |
2433 | (when (and (memq 'braces format) | |
2434 | (setq temp (cdr (assoc-string field-name | |
2435 | bibtex-field-braces-opt t)))) | |
2436 | (goto-char beg-text) | |
2437 | (while (re-search-forward temp end-text t) | |
2438 | (let ((beg (match-beginning 0)) | |
2439 | (bounds (bibtex-find-text-internal nil t))) | |
2440 | (unless (or (nth 4 bounds) ; string constant | |
2441 | ;; match already surrounded by braces | |
2442 | ;; (braces are inside field delimiters) | |
2443 | (and (< (point) (1- (nth 2 bounds))) | |
2444 | (< (1+ (nth 1 bounds)) beg) | |
2445 | (looking-at "}") | |
2446 | (save-excursion (goto-char (1- beg)) | |
2447 | (looking-at "{")))) | |
2448 | (insert "}") | |
2449 | (goto-char beg) | |
2450 | (insert "{"))))) | |
2451 | ||
2452 | ;; replace field text by BibTeX string constants | |
2453 | ;; according to `bibtex-field-strings-alist'. | |
2454 | (when (and (memq 'strings format) | |
2455 | (setq temp (cdr (assoc-string field-name | |
2456 | bibtex-field-strings-opt t)))) | |
2457 | (goto-char beg-text) | |
2458 | (dolist (re temp) | |
2459 | (while (re-search-forward (car re) end-text t) | |
2460 | (let ((bounds (save-match-data | |
2461 | (bibtex-find-text-internal nil t)))) | |
2462 | (unless (nth 4 bounds) | |
2463 | ;; if match not at right subfield boundary... | |
2464 | (if (< (match-end 0) (1- (nth 2 bounds))) | |
2465 | (insert " # " (bibtex-field-left-delimiter)) | |
2466 | (delete-char 1)) | |
2467 | (replace-match (cdr re)) | |
2468 | (goto-char (match-beginning 0)) | |
2469 | ;; if match not at left subfield boundary... | |
2470 | (if (< (1+ (nth 1 bounds)) (match-beginning 0)) | |
2471 | (insert (bibtex-field-right-delimiter) " # ") | |
d355a0b7 | 2472 | (delete-char -1)))))))) |
7af32e66 RW |
2473 | |
2474 | ;; use book title of crossref'd entry | |
2475 | (if (and (memq 'inherit-booktitle format) | |
2476 | empty-field | |
2477 | (bibtex-string= field-name "booktitle") | |
2478 | crossref-key) | |
2479 | (let ((title (save-excursion | |
2480 | (save-restriction | |
2481 | (widen) | |
2482 | (if (bibtex-search-entry crossref-key t) | |
2483 | (bibtex-text-in-field "title")))))) | |
2484 | (when title | |
2485 | (setq empty-field nil) | |
2486 | (goto-char (1+ beg-text)) | |
2487 | (insert title)))) | |
2488 | ||
2489 | ;; if empty field is a required field, complain | |
2490 | (when (and empty-field | |
2491 | (memq 'required-fields format) | |
2492 | (assoc-string field-name req-field-list t)) | |
2493 | (setq error-field-name field-name) | |
2494 | (error "Mandatory field `%s' is empty" field-name)) | |
2495 | ||
2496 | ;; unify case of field name | |
2497 | (if (memq 'unify-case format) | |
2498 | (let ((fname (car (assoc-string field-name | |
2499 | default-field-list t)))) | |
2500 | (if fname | |
2501 | (progn | |
2502 | (delete-region beg-name end-name) | |
2503 | (goto-char beg-name) | |
2504 | (insert fname)) | |
2505 | ;; there are no rules we could follow | |
2506 | (downcase-region beg-name end-name)))) | |
2507 | ||
2508 | ;; update point | |
2509 | (goto-char end-field)))) | |
2510 | ||
2511 | ;; check whether all required fields are present | |
2512 | (if (memq 'required-fields format) | |
2de69e00 RW |
2513 | (let ((alt-expect (make-vector num-alt nil)) |
2514 | (alt-found (make-vector num-alt 0))) | |
7af32e66 | 2515 | (dolist (fname req-field-list) |
2de69e00 RW |
2516 | (cond ((setq idx (nth 3 fname)) |
2517 | ;; t if field has alternative flag | |
2518 | (bibtex-vec-push alt-expect idx (car fname)) | |
7af32e66 | 2519 | (if (member-ignore-case (car fname) field-list) |
2de69e00 | 2520 | (bibtex-vec-incr alt-found idx))) |
7af32e66 | 2521 | ((not (member-ignore-case (car fname) field-list)) |
c48f463b RW |
2522 | ;; If we use the crossref field, a required field |
2523 | ;; can have the OPT prefix. So if it was empty, | |
2524 | ;; we have deleted by now. Nonetheless we can | |
2525 | ;; move point on this empty field. | |
2526 | (setq error-field-name (car fname)) | |
7af32e66 | 2527 | (error "Mandatory field `%s' is missing" (car fname))))) |
2de69e00 RW |
2528 | (dotimes (idx num-alt) |
2529 | (cond ((= 0 (aref alt-found idx)) | |
2530 | (setq error-field-name (car (last (aref alt-fields idx)))) | |
2531 | (error "Alternative mandatory field `%s' is missing" | |
2532 | (aref alt-expect idx))) | |
2533 | ((< 1 (aref alt-found idx)) | |
2534 | (setq error-field-name (car (last (aref alt-fields idx)))) | |
2535 | (error "Alternative fields `%s' are defined %s times" | |
2536 | (aref alt-expect idx) | |
2537 | (length (aref alt-fields idx)))))))) | |
7af32e66 RW |
2538 | |
2539 | ;; update comma after last field | |
2540 | (if (memq 'last-comma format) | |
2541 | (cond ((and bibtex-comma-after-last-field | |
2542 | (not (looking-at ","))) | |
2543 | (insert ",")) | |
2544 | ((and (not bibtex-comma-after-last-field) | |
2545 | (looking-at ",")) | |
2546 | (delete-char 1)))) | |
2547 | ||
2548 | ;; update right entry delimiter | |
2549 | (if (looking-at ",") | |
2550 | (forward-char)) | |
2551 | (when (memq 'delimiters format) | |
2552 | (skip-chars-forward " \t\n") | |
2553 | (delete-char 1) | |
2554 | (insert (bibtex-entry-right-delimiter))) | |
2555 | ||
2556 | ;; realign and fill entry | |
2557 | (if (memq 'realign format) | |
2558 | (bibtex-fill-entry))))) | |
2559 | ||
5a89f0a7 | 2560 | ;; Unwindform: move point to location where error occurred if possible |
c48f463b RW |
2561 | (if error-field-name |
2562 | (let (bounds) | |
2563 | (when (save-excursion | |
2564 | (bibtex-beginning-of-entry) | |
2565 | (setq bounds | |
2566 | (bibtex-search-forward-field | |
2567 | ;; If we use the crossref field, a required field | |
2568 | ;; can have the OPT prefix | |
2569 | (concat "\\(OPT\\|ALT\\)?" error-field-name) t))) | |
2570 | (goto-char (bibtex-start-of-text-in-field bounds)) | |
2571 | (bibtex-find-text))))))) | |
cb4ad359 | 2572 | |
f2dfa899 RW |
2573 | (defun bibtex-field-re-init (regexp-alist type) |
2574 | "Calculate optimized value for bibtex-regexp-TYPE-opt. | |
2575 | This value is based on bibtex-regexp-TYPE-alist. TYPE is 'braces or 'strings. | |
2576 | Return optimized value to be used by `bibtex-format-entry'." | |
2577 | (setq regexp-alist | |
2578 | (mapcar (lambda (e) | |
2579 | (list (car e) | |
403111a8 | 2580 | (replace-regexp-in-string " +" "[ \t\n]+" (nth 1 e)) |
f2dfa899 RW |
2581 | (nth 2 e))) ; nil for 'braces'. |
2582 | regexp-alist)) | |
2583 | (let (opt-list) | |
2584 | ;; Loop over field names | |
2585 | (dolist (field (delete-dups (apply 'append (mapcar 'car regexp-alist)))) | |
2586 | (let (rules) | |
2587 | ;; Collect all matches we have for this field name | |
2588 | (dolist (e regexp-alist) | |
2589 | (if (assoc-string field (car e) t) | |
2590 | (push (cons (nth 1 e) (nth 2 e)) rules))) | |
2591 | (if (eq type 'braces) | |
2592 | ;; concatenate all regexps to a single regexp | |
2593 | (setq rules (concat "\\(?:" (mapconcat 'car rules "\\|") "\\)"))) | |
2594 | ;; create list of replacement rules. | |
2595 | (push (cons field rules) opt-list))) | |
2596 | opt-list)) | |
2597 | ||
7fbf4804 | 2598 | \f |
cb4ad359 | 2599 | (defun bibtex-autokey-abbrev (string len) |
7fbf4804 SM |
2600 | "Return an abbreviation of STRING with at least LEN characters. |
2601 | If LEN is positive the abbreviation is terminated only after a consonant | |
a9d77f1f SM |
2602 | or at the word end. If LEN is negative the abbreviation is strictly |
2603 | enforced using abs (LEN) characters. If LEN is not a number, STRING | |
7fbf4804 SM |
2604 | is returned unchanged." |
2605 | (cond ((or (not (numberp len)) | |
2606 | (<= (length string) (abs len))) | |
50e4b39e RS |
2607 | string) |
2608 | ((equal len 0) | |
2609 | "") | |
7fbf4804 SM |
2610 | ((< len 0) |
2611 | (substring string 0 (abs len))) | |
2612 | (t (let* ((case-fold-search t) | |
2613 | (abort-char (string-match "[^aeiou]" string (1- len)))) | |
2614 | (if abort-char | |
2615 | (substring string 0 (1+ abort-char)) | |
2616 | string))))) | |
2617 | ||
2618 | (defun bibtex-autokey-get-field (field &optional change-list) | |
a9d77f1f | 2619 | "Get content of BibTeX field FIELD. Return empty string if not found. |
7fbf4804 | 2620 | Optional arg CHANGE-LIST is a list of substitution patterns that is |
a9d77f1f | 2621 | applied to the content of FIELD. It is an alist with pairs |
7fbf4804 | 2622 | \(OLD-REGEXP . NEW-STRING\)." |
cdc61d35 SM |
2623 | (let* ((bibtex-expand-strings bibtex-autokey-expand-strings) |
2624 | (content (bibtex-text-in-field field bibtex-autokey-use-crossref)) | |
7fbf4804 SM |
2625 | case-fold-search) |
2626 | (unless content (setq content "")) | |
a2a25d24 | 2627 | (dolist (pattern change-list) |
7fbf4804 SM |
2628 | (setq content (replace-regexp-in-string (car pattern) |
2629 | (cdr pattern) | |
a2a25d24 SM |
2630 | content t))) |
2631 | content)) | |
7fbf4804 SM |
2632 | |
2633 | (defun bibtex-autokey-get-names () | |
2634 | "Get contents of the name field of the current entry. | |
e0dc0c55 SM |
2635 | Do some modifications based on `bibtex-autokey-name-change-strings'. |
2636 | Return the names as a concatenated string obeying `bibtex-autokey-names' | |
2637 | and `bibtex-autokey-names-stretch'." | |
2638 | (let ((names (bibtex-autokey-get-field "author\\|editor" | |
d528bff7 SM |
2639 | bibtex-autokey-name-change-strings))) |
2640 | ;; Some entries do not have a name field. | |
02c8032e SM |
2641 | (if (string= "" names) |
2642 | names | |
e0dc0c55 SM |
2643 | (let* ((case-fold-search t) |
2644 | (name-list (mapcar 'bibtex-autokey-demangle-name | |
2645 | (split-string names "[ \t\n]+and[ \t\n]+"))) | |
2646 | additional-names) | |
2647 | (unless (or (not (numberp bibtex-autokey-names)) | |
2648 | (<= (length name-list) | |
2649 | (+ bibtex-autokey-names | |
2650 | bibtex-autokey-names-stretch))) | |
f2dfa899 | 2651 | ;; Take `bibtex-autokey-names' elements from beginning of name-list |
e0dc0c55 SM |
2652 | (setq name-list (nreverse (nthcdr (- (length name-list) |
2653 | bibtex-autokey-names) | |
2654 | (nreverse name-list))) | |
2655 | additional-names bibtex-autokey-additional-names)) | |
2656 | (concat (mapconcat 'identity name-list | |
2657 | bibtex-autokey-name-separator) | |
2658 | additional-names))))) | |
50e4b39e RS |
2659 | |
2660 | (defun bibtex-autokey-demangle-name (fullname) | |
a9d77f1f | 2661 | "Get the last part from a well-formed FULLNAME and perform abbreviations." |
f9bd4abe | 2662 | (let* (case-fold-search |
a172852f | 2663 | (name (cond ((string-match "\\([[:upper:]][^, ]*\\)[^,]*," fullname) |
7fbf4804 SM |
2664 | ;; Name is of the form "von Last, First" or |
2665 | ;; "von Last, Jr, First" | |
2666 | ;; --> Take the first capital part before the comma | |
dd310c45 | 2667 | (match-string 1 fullname)) |
7fbf4804 SM |
2668 | ((string-match "\\([^, ]*\\)," fullname) |
2669 | ;; Strange name: we have a comma, but nothing capital | |
2670 | ;; So we accept even lowercase names | |
dd310c45 | 2671 | (match-string 1 fullname)) |
a172852f | 2672 | ((string-match "\\(\\<[[:lower:]][^ ]* +\\)+\\([[:upper:]][^ ]*\\)" |
7fbf4804 SM |
2673 | fullname) |
2674 | ;; name is of the form "First von Last", "von Last", | |
2675 | ;; "First von von Last", or "d'Last" | |
2676 | ;; --> take the first capital part after the "von" parts | |
dd310c45 SM |
2677 | (match-string 2 fullname)) |
2678 | ((string-match "\\([^ ]+\\) *\\'" fullname) | |
7fbf4804 SM |
2679 | ;; name is of the form "First Middle Last" or "Last" |
2680 | ;; --> take the last token | |
dd310c45 | 2681 | (match-string 1 fullname)) |
7fbf4804 | 2682 | (t (error "Name `%s' is incorrectly formed" fullname))))) |
8a51a318 | 2683 | (funcall bibtex-autokey-name-case-convert-function |
02c8032e | 2684 | (bibtex-autokey-abbrev name bibtex-autokey-name-length)))) |
7fbf4804 | 2685 | |
e0dc0c55 SM |
2686 | (defun bibtex-autokey-get-year () |
2687 | "Return year field contents as a string obeying `bibtex-autokey-year-length'." | |
2688 | (let ((yearfield (bibtex-autokey-get-field "year"))) | |
2689 | (substring yearfield (max 0 (- (length yearfield) | |
2690 | bibtex-autokey-year-length))))) | |
2691 | ||
7fbf4804 | 2692 | (defun bibtex-autokey-get-title () |
e0dc0c55 SM |
2693 | "Get title field contents up to a terminator. |
2694 | Return the result as a string" | |
d528bff7 SM |
2695 | (let ((case-fold-search t) |
2696 | (titlestring | |
7fbf4804 SM |
2697 | (bibtex-autokey-get-field "title" |
2698 | bibtex-autokey-titleword-change-strings))) | |
2699 | ;; ignore everything past a terminator | |
02c8032e SM |
2700 | (if (string-match bibtex-autokey-title-terminators titlestring) |
2701 | (setq titlestring (substring titlestring 0 (match-beginning 0)))) | |
e0dc0c55 | 2702 | ;; gather words from titlestring into a list. Ignore |
7fbf4804 | 2703 | ;; specific words and use only a specific amount of words. |
8bf38a9b | 2704 | (let ((counter 0) |
6801feef RW |
2705 | (ignore-re (concat "\\`\\(?:" |
2706 | (mapconcat 'identity | |
2707 | bibtex-autokey-titleword-ignore "\\|") | |
2708 | "\\)\\'")) | |
e0dc0c55 | 2709 | titlewords titlewords-extra word) |
7fbf4804 SM |
2710 | (while (and (or (not (numberp bibtex-autokey-titlewords)) |
2711 | (< counter (+ bibtex-autokey-titlewords | |
2712 | bibtex-autokey-titlewords-stretch))) | |
2713 | (string-match "\\b\\w+" titlestring)) | |
e0dc0c55 SM |
2714 | (setq word (match-string 0 titlestring) |
2715 | titlestring (substring titlestring (match-end 0))) | |
2716 | ;; Ignore words matched by one of the elements of | |
6801feef RW |
2717 | ;; `bibtex-autokey-titleword-ignore'. Case is significant. |
2718 | (unless (let (case-fold-search) | |
2719 | (string-match ignore-re word)) | |
02c8032e | 2720 | (setq counter (1+ counter)) |
7fbf4804 | 2721 | (if (or (not (numberp bibtex-autokey-titlewords)) |
d10e87a2 | 2722 | (<= counter bibtex-autokey-titlewords)) |
e0dc0c55 SM |
2723 | (push word titlewords) |
2724 | (push word titlewords-extra)))) | |
f2dfa899 | 2725 | ;; Obey `bibtex-autokey-titlewords-stretch': |
e0dc0c55 | 2726 | ;; If by now we have processed all words in titlestring, we include |
f2dfa899 | 2727 | ;; titlewords-extra in titlewords. Otherwise, we ignore titlewords-extra. |
7fbf4804 | 2728 | (unless (string-match "\\b\\w+" titlestring) |
e0dc0c55 SM |
2729 | (setq titlewords (append titlewords-extra titlewords))) |
2730 | (mapconcat 'bibtex-autokey-demangle-title (nreverse titlewords) | |
2731 | bibtex-autokey-titleword-separator)))) | |
7fbf4804 SM |
2732 | |
2733 | (defun bibtex-autokey-demangle-title (titleword) | |
2734 | "Do some abbreviations on TITLEWORD. | |
2735 | The rules are defined in `bibtex-autokey-titleword-abbrevs' | |
2736 | and `bibtex-autokey-titleword-length'." | |
d528bff7 | 2737 | (let ((case-fold-search t) |
8bf38a9b SM |
2738 | (alist bibtex-autokey-titleword-abbrevs)) |
2739 | (while (and alist | |
2740 | (not (string-match (concat "\\`\\(?:" (caar alist) "\\)\\'") | |
2741 | titleword))) | |
2742 | (setq alist (cdr alist))) | |
2743 | (if alist | |
2744 | (cdar alist) | |
8a51a318 | 2745 | (funcall bibtex-autokey-titleword-case-convert-function |
02c8032e | 2746 | (bibtex-autokey-abbrev titleword bibtex-autokey-titleword-length))))) |
cb4ad359 RS |
2747 | |
2748 | (defun bibtex-generate-autokey () | |
02c8032e SM |
2749 | "Generate automatically a key for a BibTeX entry. |
2750 | Use the author/editor, the year and the title field. | |
2751 | The algorithm works as follows. | |
2752 | ||
2753 | The name part: | |
2754 | 1. Use the author or editor field to generate the name part of the key. | |
cdc61d35 | 2755 | Expand BibTeX strings if `bibtex-autokey-expand-strings' is non-nil. |
02c8032e SM |
2756 | 2. Change the content of the name field according to |
2757 | `bibtex-autokey-name-change-strings' (see there for further detail). | |
2758 | 3. Use the first `bibtex-autokey-names' names in the name field. If there | |
2759 | are up to `bibtex-autokey-names' + `bibtex-autokey-names-stretch' names, | |
2760 | use all names. | |
2761 | 4. Use only the last names to form the name part. From these last names, | |
2762 | take at least `bibtex-autokey-name-length' characters (truncate only | |
2763 | after a consonant or at a word end). | |
2764 | 5. Convert all last names using the function | |
8a51a318 | 2765 | `bibtex-autokey-name-case-convert-function'. |
02c8032e SM |
2766 | 6. Build the name part of the key by concatenating all abbreviated last |
2767 | names with the string `bibtex-autokey-name-separator' between any two. | |
2768 | If there are more names in the name field than names used in the name | |
2769 | part, append the string `bibtex-autokey-additional-names'. | |
2770 | ||
2771 | The year part: | |
2772 | 1. Build the year part of the key by truncating the content of the year | |
2773 | field to the rightmost `bibtex-autokey-year-length' digits (useful | |
2774 | values are 2 and 4). | |
2775 | 2. If the year field (or any other field required to generate the key) | |
2776 | is absent, but the entry has a valid crossref field and | |
7fbf4804 SM |
2777 | `bibtex-autokey-use-crossref' is non-nil, use the field of the |
2778 | crossreferenced entry instead. | |
02c8032e SM |
2779 | |
2780 | The title part | |
2781 | 1. Change the content of the title field according to | |
2782 | `bibtex-autokey-titleword-change-strings' (see there for further detail). | |
2783 | 2. Truncate the title before the first match of | |
2784 | `bibtex-autokey-title-terminators' and delete those words which appear | |
2785 | in `bibtex-autokey-titleword-ignore'. Build the title part using the | |
2786 | first `bibtex-autokey-titlewords' words from this truncated title. | |
2787 | If the truncated title ends after up to `bibtex-autokey-titlewords' + | |
2788 | `bibtex-autokey-titlewords-stretch' words, use all words from the | |
2789 | truncated title. | |
2790 | 3. For every title word that appears in `bibtex-autokey-titleword-abbrevs' | |
2791 | use the corresponding abbreviation (see documentation of this variable | |
2792 | for further detail). | |
2793 | 4. From every title word not generated by an abbreviation, take at least | |
2794 | `bibtex-autokey-titleword-length' characters (truncate only after | |
2795 | a consonant or at a word end). | |
2796 | 5. Convert all title words using the function | |
8a51a318 | 2797 | `bibtex-autokey-titleword-case-convert-function'. |
02c8032e SM |
2798 | 6. Build the title part by concatenating all abbreviated title words with |
2799 | the string `bibtex-autokey-titleword-separator' between any two. | |
2800 | ||
2801 | Concatenate the key: | |
2802 | 1. Concatenate `bibtex-autokey-prefix-string', the name part, the year | |
2803 | part and the title part. If the name part and the year part are both | |
2804 | non-empty insert `bibtex-autokey-name-year-separator' between the two. | |
2805 | If the title part and the year (or name) part are non-empty, insert | |
2806 | `bibtex-autokey-year-title-separator' between the two. | |
2807 | 2. If `bibtex-autokey-before-presentation-function' is non-nil, it must be | |
2808 | a function taking one argument. Call this function with the generated | |
2809 | key as the argument. Use the return value of this function (a string) | |
2810 | as the key. | |
2811 | 3. If `bibtex-autokey-edit-before-use' is non-nil, present the key in the | |
2812 | minibuffer to the user for editing. Insert the key given by the user." | |
e0dc0c55 SM |
2813 | (let* ((names (bibtex-autokey-get-names)) |
2814 | (year (bibtex-autokey-get-year)) | |
2815 | (title (bibtex-autokey-get-title)) | |
7fbf4804 | 2816 | (autokey (concat bibtex-autokey-prefix-string |
e0dc0c55 SM |
2817 | names |
2818 | (unless (or (equal names "") | |
2819 | (equal year "")) | |
7fbf4804 | 2820 | bibtex-autokey-name-year-separator) |
e0dc0c55 SM |
2821 | year |
2822 | (unless (or (and (equal names "") | |
2823 | (equal year "")) | |
2824 | (equal title "")) | |
7fbf4804 | 2825 | bibtex-autokey-year-title-separator) |
e0dc0c55 | 2826 | title))) |
ab2d0cdb | 2827 | (if bibtex-autokey-before-presentation-function |
7fbf4804 SM |
2828 | (funcall bibtex-autokey-before-presentation-function autokey) |
2829 | autokey))) | |
e5167999 | 2830 | |
7fbf4804 | 2831 | \f |
02c8032e SM |
2832 | (defun bibtex-global-key-alist () |
2833 | "Return global key alist based on `bibtex-files'." | |
2834 | (if bibtex-files | |
2835 | (apply 'append | |
2836 | (mapcar (lambda (buf) | |
2837 | (with-current-buffer buf bibtex-reference-keys)) | |
03db5e5f RW |
2838 | ;; include current buffer only if it uses `bibtex-mode' |
2839 | (bibtex-initialize (eq major-mode 'bibtex-mode)))) | |
2840 | (if (eq major-mode 'bibtex-mode) | |
2841 | bibtex-reference-keys))) | |
02c8032e SM |
2842 | |
2843 | (defun bibtex-read-key (prompt &optional key global) | |
2844 | "Read BibTeX key from minibuffer using PROMPT and default KEY. | |
2845 | If optional arg GLOBAL is non-nil, completion is based on the keys in | |
2846 | `bibtex-reference-keys' of `bibtex-files'," | |
2847 | (let (completion-ignore-case) | |
2848 | (completing-read prompt (if global (bibtex-global-key-alist) | |
2849 | bibtex-reference-keys) | |
2850 | nil nil key 'bibtex-key-history))) | |
2851 | ||
2852 | (defun bibtex-read-string-key (&optional key) | |
2853 | "Read BibTeX string key from minibuffer using default KEY." | |
2854 | (let ((completion-ignore-case t)) | |
2855 | (completing-read "String key: " bibtex-strings | |
2856 | nil nil key 'bibtex-key-history))) | |
e0dc0c55 SM |
2857 | |
2858 | (defun bibtex-parse-keys (&optional abortable verbose) | |
7fbf4804 | 2859 | "Set `bibtex-reference-keys' to the keys used in the whole buffer. |
02c8032e SM |
2860 | Find both entry keys and crossref entries. If ABORTABLE is non-nil abort |
2861 | on user input. If VERBOSE is non-nil give messages about progress. | |
cdc61d35 SM |
2862 | Return alist of keys if parsing was completed, `aborted' otherwise. |
2863 | If `bibtex-parse-keys-fast' is non-nil, use fast but simplified algorithm | |
2864 | for parsing BibTeX keys. If parsing fails, try to set this variable to nil." | |
7af32e66 RW |
2865 | (if (eq major-mode 'bibtex-mode) |
2866 | (let (ref-keys crossref-keys) | |
2867 | (save-excursion | |
2868 | (save-match-data | |
2869 | (if verbose | |
2870 | (bibtex-progress-message | |
2871 | (concat (buffer-name) ": parsing reference keys"))) | |
2872 | (catch 'userkey | |
2873 | (goto-char (point-min)) | |
2874 | (if bibtex-parse-keys-fast | |
2875 | (let ((case-fold-search t) | |
2876 | (re (concat bibtex-entry-head "\\|" | |
2877 | ",[ \t\n]*crossref[ \t\n]*=[ \t\n]*" | |
2878 | "\\(\"[^\"]*\"\\|{[^}]*}\\)[ \t\n]*[,})]"))) | |
2879 | (while (re-search-forward re nil t) | |
2880 | (if (and abortable (input-pending-p)) | |
2881 | ;; user has aborted by typing a key: return `aborted' | |
2882 | (throw 'userkey 'aborted)) | |
2883 | (cond ((match-end 3) | |
2884 | ;; This is a crossref. | |
2885 | (let ((key (buffer-substring-no-properties | |
2886 | (1+ (match-beginning 3)) (1- (match-end 3))))) | |
e0dc0c55 SM |
2887 | (unless (assoc key crossref-keys) |
2888 | (push (list key) crossref-keys)))) | |
7af32e66 RW |
2889 | ;; only keys of known entries |
2890 | ((assoc-string (bibtex-type-in-head) | |
2de69e00 | 2891 | bibtex-entry-alist t) |
7af32e66 RW |
2892 | ;; This is an entry. |
2893 | (let ((key (bibtex-key-in-head))) | |
2894 | (unless (assoc key ref-keys) | |
2895 | (push (cons key t) ref-keys))))))) | |
2896 | ||
2897 | (let (;; ignore @String entries because they are handled | |
2898 | ;; separately by `bibtex-parse-strings' | |
2899 | (bibtex-sort-ignore-string-entries t) | |
2900 | bounds) | |
2901 | (bibtex-map-entries | |
a2a25d24 | 2902 | (lambda (key _beg end) |
7af32e66 RW |
2903 | (if (and abortable |
2904 | (input-pending-p)) | |
2905 | ;; user has aborted by typing a key: return `aborted' | |
2906 | (throw 'userkey 'aborted)) | |
2907 | (if verbose (bibtex-progress-message)) | |
2908 | (unless (assoc key ref-keys) | |
2909 | (push (cons key t) ref-keys)) | |
2910 | (if (and (setq bounds (bibtex-search-forward-field "crossref" end)) | |
2911 | (setq key (bibtex-text-in-field-bounds bounds t)) | |
2912 | (not (assoc key crossref-keys))) | |
2913 | (push (list key) crossref-keys)))))) | |
2914 | ||
2915 | (dolist (key crossref-keys) | |
2916 | (unless (assoc (car key) ref-keys) (push key ref-keys))) | |
2917 | (if verbose | |
2918 | (bibtex-progress-message 'done)) | |
2919 | ;; successful operation --> return `bibtex-reference-keys' | |
2920 | (setq bibtex-reference-keys ref-keys))))))) | |
7fbf4804 | 2921 | |
d715b065 | 2922 | (defun bibtex-parse-strings (&optional add abortable) |
7fbf4804 | 2923 | "Set `bibtex-strings' to the string definitions in the whole buffer. |
d715b065 | 2924 | If ADD is non-nil add the new strings to `bibtex-strings' instead of |
a9d77f1f SM |
2925 | simply resetting it. If ADD is an alist of strings, also add ADD to |
2926 | `bibtex-strings'. If ABORTABLE is non-nil abort on user input. | |
d715b065 | 2927 | Return alist of strings if parsing was completed, `aborted' otherwise." |
7fbf4804 SM |
2928 | (save-excursion |
2929 | (save-match-data | |
2930 | (goto-char (point-min)) | |
03db5e5f | 2931 | (let ((strings (if (and add (not (functionp bibtex-strings))) |
d715b065 | 2932 | bibtex-strings)) |
7fbf4804 | 2933 | bounds key) |
d715b065 KG |
2934 | (if (listp add) |
2935 | (dolist (string add) | |
d528bff7 | 2936 | (unless (assoc-string (car string) strings t) |
d715b065 KG |
2937 | (push string strings)))) |
2938 | (catch 'userkey | |
2939 | (while (setq bounds (bibtex-search-forward-string)) | |
2940 | (if (and abortable | |
2941 | (input-pending-p)) | |
2942 | ;; user has aborted by typing a key --> return `aborted' | |
2943 | (throw 'userkey 'aborted)) | |
2944 | (setq key (bibtex-reference-key-in-string bounds)) | |
d528bff7 SM |
2945 | (unless (assoc-string key strings t) |
2946 | (push (cons key (bibtex-text-in-string bounds t)) | |
2947 | strings)) | |
d715b065 KG |
2948 | (goto-char (bibtex-end-of-text-in-string bounds))) |
2949 | ;; successful operation --> return `bibtex-strings' | |
2950 | (setq bibtex-strings strings)))))) | |
7fbf4804 | 2951 | |
cdc61d35 | 2952 | (defun bibtex-strings () |
f2dfa899 | 2953 | "Return `bibtex-strings'. Initialize this variable if necessary." |
03db5e5f RW |
2954 | (if (functionp bibtex-strings) |
2955 | (bibtex-parse-strings (bibtex-string-files-init)) | |
2956 | bibtex-strings)) | |
cdc61d35 | 2957 | |
7fbf4804 SM |
2958 | (defun bibtex-string-files-init () |
2959 | "Return initialization for `bibtex-strings'. | |
e0dc0c55 | 2960 | Use `bibtex-predefined-strings' and BibTeX files `bibtex-string-files'." |
7fbf4804 | 2961 | (save-match-data |
e0dc0c55 | 2962 | (let ((dirlist (split-string (or bibtex-string-file-path default-directory) |
7fbf4804 SM |
2963 | ":+")) |
2964 | (case-fold-search) | |
e0dc0c55 SM |
2965 | string-files fullfilename compl bounds found) |
2966 | ;; collect absolute file names of valid string files | |
7fbf4804 | 2967 | (dolist (filename bibtex-string-files) |
dd310c45 | 2968 | (unless (string-match "\\.bib\\'" filename) |
7fbf4804 SM |
2969 | (setq filename (concat filename ".bib"))) |
2970 | ;; test filenames | |
e0dc0c55 SM |
2971 | (if (file-name-absolute-p filename) |
2972 | (if (file-readable-p filename) | |
2973 | (push filename string-files) | |
2974 | (error "BibTeX strings file %s not found" filename)) | |
7fbf4804 SM |
2975 | (dolist (dir dirlist) |
2976 | (when (file-readable-p | |
2977 | (setq fullfilename (expand-file-name filename dir))) | |
e0dc0c55 | 2978 | (push fullfilename string-files) |
7fbf4804 SM |
2979 | (setq found t))) |
2980 | (unless found | |
d715b065 | 2981 | (error "File %s not in paths defined via bibtex-string-file-path" |
7fbf4804 | 2982 | filename)))) |
e0dc0c55 SM |
2983 | ;; parse string files |
2984 | (dolist (filename string-files) | |
2985 | (with-temp-buffer | |
2986 | (insert-file-contents filename) | |
2987 | (goto-char (point-min)) | |
2988 | (while (setq bounds (bibtex-search-forward-string)) | |
2989 | (push (cons (bibtex-reference-key-in-string bounds) | |
2990 | (bibtex-text-in-string bounds t)) | |
2991 | compl) | |
2992 | (goto-char (bibtex-end-of-string bounds))))) | |
7fbf4804 | 2993 | (append bibtex-predefined-strings (nreverse compl))))) |
50e4b39e RS |
2994 | |
2995 | (defun bibtex-parse-buffers-stealthily () | |
a9d77f1f | 2996 | "Parse buffer in the background during idle time. |
e0dc0c55 | 2997 | Called by `run-with-idle-timer'. Whenever Emacs has been idle |
02c8032e SM |
2998 | for `bibtex-parse-keys-timeout' seconds, parse all BibTeX buffers |
2999 | which have been modified after last parsing. | |
3000 | Parsing initializes `bibtex-reference-keys' and `bibtex-strings'." | |
7fbf4804 SM |
3001 | (save-excursion |
3002 | (let ((buffers (buffer-list)) | |
3003 | (strings-init (bibtex-string-files-init))) | |
50e4b39e RS |
3004 | (while (and buffers (not (input-pending-p))) |
3005 | (set-buffer (car buffers)) | |
7fbf4804 SM |
3006 | (if (and (eq major-mode 'bibtex-mode) |
3007 | (not (eq (buffer-modified-tick) | |
3008 | bibtex-buffer-last-parsed-tick))) | |
3009 | (save-restriction | |
3010 | (widen) | |
f2dfa899 RW |
3011 | ;; Output no progress messages in `bibtex-parse-keys' |
3012 | ;; because when in `y-or-n-p' that can hide the question. | |
e0dc0c55 | 3013 | (if (and (listp (bibtex-parse-keys t)) |
f2dfa899 | 3014 | ;; update `bibtex-strings' |
d715b065 | 3015 | (listp (bibtex-parse-strings strings-init t))) |
7fbf4804 SM |
3016 | |
3017 | ;; remember that parsing was successful | |
3018 | (setq bibtex-buffer-last-parsed-tick (buffer-modified-tick))))) | |
3019 | (setq buffers (cdr buffers)))))) | |
3020 | ||
65e10478 RW |
3021 | ;;;###autoload |
3022 | (defun bibtex-initialize (&optional current force select) | |
3023 | "(Re)Initialize BibTeX buffers. | |
3024 | Visit the BibTeX files defined by `bibtex-files' and return a list | |
3025 | of corresponding buffers. | |
e0dc0c55 | 3026 | Initialize in these buffers `bibtex-reference-keys' if not yet set. |
23a0e159 RW |
3027 | List of BibTeX buffers includes current buffer if CURRENT is non-nil |
3028 | and the current buffer visits a file using `bibtex-mode'. | |
02c8032e | 3029 | If FORCE is non-nil, (re)initialize `bibtex-reference-keys' even if |
65e10478 | 3030 | already set. If SELECT is non-nil interactively select a BibTeX buffer. |
23a0e159 RW |
3031 | |
3032 | When called interactively, FORCE is t, CURRENT is t if current buffer | |
3033 | visits a file using `bibtex-mode', and SELECT is t if current buffer | |
3034 | does not use `bibtex-mode'," | |
65e10478 RW |
3035 | (interactive (list (eq major-mode 'bibtex-mode) t |
3036 | (not (eq major-mode 'bibtex-mode)))) | |
e0dc0c55 SM |
3037 | (let ((file-path (split-string (or bibtex-file-path default-directory) ":+")) |
3038 | file-list dir-list buffer-list) | |
65e10478 | 3039 | ;; generate list of BibTeX files |
e0dc0c55 SM |
3040 | (dolist (file bibtex-files) |
3041 | (cond ((eq file 'bibtex-file-path) | |
3042 | (setq dir-list (append dir-list file-path))) | |
3043 | ((file-accessible-directory-p file) | |
3044 | (push file dir-list)) | |
3045 | ((progn (unless (string-match "\\.bib\\'" file) | |
3046 | (setq file (concat file ".bib"))) | |
3047 | (file-name-absolute-p file)) | |
3048 | (push file file-list)) | |
3049 | (t | |
65e10478 | 3050 | (let (expanded-file-name found) |
e0dc0c55 SM |
3051 | (dolist (dir file-path) |
3052 | (when (file-readable-p | |
65e10478 RW |
3053 | (setq expanded-file-name (expand-file-name file dir))) |
3054 | (push expanded-file-name file-list) | |
e0dc0c55 SM |
3055 | (setq found t))) |
3056 | (unless found | |
65e10478 | 3057 | (error "File `%s' not in paths defined via bibtex-file-path" |
e0dc0c55 SM |
3058 | file)))))) |
3059 | (dolist (file file-list) | |
3060 | (unless (file-readable-p file) | |
65e10478 | 3061 | (error "BibTeX file `%s' not found" file))) |
e0dc0c55 SM |
3062 | ;; expand dir-list |
3063 | (dolist (dir dir-list) | |
3064 | (setq file-list | |
3065 | (append file-list (directory-files dir t "\\.bib\\'" t)))) | |
3066 | (delete-dups file-list) | |
65e10478 | 3067 | ;; visit files in FILE-LIST |
e0dc0c55 | 3068 | (dolist (file file-list) |
65e10478 RW |
3069 | (if (file-readable-p file) |
3070 | (push (find-file-noselect file) buffer-list))) | |
03db5e5f | 3071 | ;; Include current buffer iff we want it. |
23a0e159 RW |
3072 | ;; Exclude current buffer if it does not visit a file using `bibtex-mode'. |
3073 | ;; This way we exclude BibTeX buffers such as `bibtex-search-buffer' | |
3074 | ;; that are not visiting a BibTeX file. Also, calling `bibtex-initialize' | |
3075 | ;; gives meaningful results for any current buffer. | |
3076 | (unless (and current (eq major-mode 'bibtex-mode) buffer-file-name) | |
3077 | (setq current nil)) | |
e0dc0c55 | 3078 | (cond ((and current (not (memq (current-buffer) buffer-list))) |
65e10478 | 3079 | (push (current-buffer) buffer-list)) |
e0dc0c55 SM |
3080 | ((and (not current) (memq (current-buffer) buffer-list)) |
3081 | (setq buffer-list (delq (current-buffer) buffer-list)))) | |
65e10478 | 3082 | ;; parse keys |
004dedd3 RW |
3083 | (let (string-init) |
3084 | (dolist (buffer buffer-list) | |
3085 | (with-current-buffer buffer | |
3086 | (if (or force (functionp bibtex-reference-keys)) | |
3087 | (bibtex-parse-keys)) | |
3088 | (when (or force (functionp bibtex-strings)) | |
3089 | (unless string-init (setq string-init (bibtex-string-files-init))) | |
3090 | (bibtex-parse-strings string-init))))) | |
65e10478 RW |
3091 | ;; select BibTeX buffer |
3092 | (if select | |
3093 | (if buffer-list | |
c3313451 | 3094 | (switch-to-buffer |
65e10478 RW |
3095 | (completing-read "Switch to BibTeX buffer: " |
3096 | (mapcar 'buffer-name buffer-list) | |
3097 | nil t | |
3098 | (if current (buffer-name (current-buffer))))) | |
3099 | (message "No BibTeX buffers defined"))) | |
e0dc0c55 SM |
3100 | buffer-list)) |
3101 | ||
3fe48822 | 3102 | (defun bibtex-complete-string-cleanup (compl) (lambda (str status) ;Curried. |
d715b065 | 3103 | "Cleanup after inserting string STR. |
02c8032e SM |
3104 | Remove enclosing field delimiters for STR. Display message with |
3105 | expansion of STR using expansion list COMPL." | |
3fe48822 SM |
3106 | (when (memq status '(exact finished sole)) |
3107 | (let ((abbr (cdr (assoc-string str compl t)))) | |
3108 | (when abbr | |
3109 | (message "%s = abbreviation for `%s'" str abbr))) | |
3110 | (when (eq status 'finished) | |
3111 | (save-excursion (bibtex-remove-delimiters)))))) | |
3112 | ||
3113 | (defun bibtex-complete-crossref-cleanup (buf) (lambda (key status) ;Curried. | |
e0dc0c55 SM |
3114 | "Display summary message on entry KEY after completion of a crossref key. |
3115 | Use `bibtex-summary-function' to generate summary." | |
3fe48822 SM |
3116 | (when (memq status '(exact sole finished)) |
3117 | (let ((summary | |
3118 | (with-current-buffer buf | |
3119 | (save-excursion | |
3120 | (if (bibtex-search-entry key t) | |
3121 | (funcall bibtex-summary-function)))))) | |
3122 | (when summary | |
3123 | (message "%s %s" key summary)))))) | |
02c8032e | 3124 | |
f2dfa899 | 3125 | (defun bibtex-copy-summary-as-kill (&optional arg) |
02c8032e | 3126 | "Push summery of current BibTeX entry to kill ring. |
f2dfa899 RW |
3127 | Use `bibtex-summary-function' to generate summary. |
3128 | If prefix ARG is non-nil push BibTeX entry's URL to kill ring | |
3129 | that is generated by calling `bibtex-url'." | |
3130 | (interactive "P") | |
3131 | (if arg (let ((url (bibtex-url nil t))) | |
3132 | (if url (kill-new (message "%s" url)) | |
3133 | (message "No URL known"))) | |
3134 | (save-excursion | |
3135 | (bibtex-beginning-of-entry) | |
3136 | (if (looking-at bibtex-entry-maybe-empty-head) | |
3137 | (kill-new (message "%s" (funcall bibtex-summary-function))) | |
3138 | (error "No entry found"))))) | |
921a9483 SM |
3139 | |
3140 | (defun bibtex-summary () | |
3141 | "Return summary of current BibTeX entry. | |
e0dc0c55 | 3142 | Used as default value of `bibtex-summary-function'." |
f2dfa899 | 3143 | ;; It would be neat to make this function customizable. How? |
1fdecd0c | 3144 | (if (looking-at bibtex-entry-maybe-empty-head) |
8a51a318 | 3145 | (let* ((bibtex-autokey-name-case-convert-function 'identity) |
1fdecd0c RF |
3146 | (bibtex-autokey-name-length 'infty) |
3147 | (bibtex-autokey-names 1) | |
3148 | (bibtex-autokey-names-stretch 0) | |
3149 | (bibtex-autokey-name-separator " ") | |
3150 | (bibtex-autokey-additional-names " etal") | |
3151 | (names (bibtex-autokey-get-names)) | |
3152 | (bibtex-autokey-year-length 4) | |
3153 | (year (bibtex-autokey-get-year)) | |
3154 | (bibtex-autokey-titlewords 5) | |
3155 | (bibtex-autokey-titlewords-stretch 2) | |
8a51a318 | 3156 | (bibtex-autokey-titleword-case-convert-function 'identity) |
1fdecd0c RF |
3157 | (bibtex-autokey-titleword-length 5) |
3158 | (bibtex-autokey-titleword-separator " ") | |
3159 | (title (bibtex-autokey-get-title)) | |
3160 | (journal (bibtex-autokey-get-field | |
3161 | "journal" bibtex-autokey-transcriptions)) | |
3162 | (volume (bibtex-autokey-get-field "volume")) | |
3163 | (pages (bibtex-autokey-get-field "pages" '(("-.*\\'" . ""))))) | |
3164 | (mapconcat (lambda (arg) | |
3165 | (if (not (string= "" (cdr arg))) | |
3166 | (concat (car arg) (cdr arg)))) | |
3167 | `((" " . ,names) (" " . ,year) (": " . ,title) | |
3168 | (", " . ,journal) (" " . ,volume) (":" . ,pages)) | |
3169 | "")) | |
3170 | (error "Entry not found"))) | |
cb4ad359 | 3171 | |
50e4b39e | 3172 | (defun bibtex-pop (arg direction) |
02c8032e | 3173 | "Fill current field from the ARGth same field's text in DIRECTION. |
a9d77f1f | 3174 | Generic function used by `bibtex-pop-previous' and `bibtex-pop-next'." |
ffc1e1db RW |
3175 | ;; parse current field |
3176 | (let* ((bounds (bibtex-enclosing-field t)) | |
3177 | (start-old-field (bibtex-start-of-field bounds)) | |
3178 | (start-old-text (bibtex-start-of-text-in-field bounds)) | |
3179 | (end-old-text (bibtex-end-of-text-in-field bounds)) | |
3180 | (field-name (bibtex-name-in-field bounds t)) | |
3181 | failure) | |
3182 | (save-excursion | |
7fbf4804 SM |
3183 | ;; if executed several times in a row, start each search where |
3184 | ;; the last one was finished | |
ffc1e1db RW |
3185 | (cond ((eq last-command 'bibtex-pop) |
3186 | (goto-char (if (eq direction 'previous) | |
3187 | bibtex-pop-previous-search-point | |
3188 | bibtex-pop-next-search-point))) | |
3189 | ((eq direction 'previous) | |
3190 | (bibtex-beginning-of-entry)) | |
3191 | (t (bibtex-end-of-entry))) | |
3192 | ;; Search for arg'th previous/next similar field | |
3193 | (while (and (not failure) | |
3194 | (>= (setq arg (1- arg)) 0)) | |
3195 | ;; The search of BibTeX fields is not bounded by entry boundaries | |
3196 | (if (eq direction 'previous) | |
3197 | (if (setq bounds (bibtex-search-backward-field field-name)) | |
3198 | (goto-char (bibtex-start-of-field bounds)) | |
3199 | (setq failure t)) | |
3200 | (if (setq bounds (bibtex-search-forward-field field-name)) | |
3201 | (goto-char (bibtex-end-of-field bounds)) | |
3202 | (setq failure t)))) | |
3203 | (if failure | |
3204 | (error "No %s matching BibTeX field" | |
3205 | (if (eq direction 'previous) "previous" "next")) | |
3206 | ;; Found a matching field. Remember boundaries. | |
3207 | (let ((new-text (bibtex-text-in-field-bounds bounds)) | |
3208 | (nbeg (copy-marker (bibtex-start-of-field bounds))) | |
3209 | (nend (copy-marker (bibtex-end-of-field bounds)))) | |
3210 | (bibtex-flash-head "From: ") | |
7fbf4804 | 3211 | ;; Go back to where we started, delete old text, and pop new. |
ffc1e1db RW |
3212 | (goto-char end-old-text) |
3213 | (delete-region start-old-text end-old-text) | |
3214 | (if (= nbeg start-old-field) | |
3215 | (insert (bibtex-field-left-delimiter) | |
3216 | (bibtex-field-right-delimiter)) | |
3217 | (insert new-text)) | |
3218 | (setq bibtex-pop-previous-search-point (marker-position nbeg) | |
3219 | bibtex-pop-next-search-point (marker-position nend)))))) | |
3220 | (bibtex-find-text nil nil nil t) | |
50e4b39e RS |
3221 | (setq this-command 'bibtex-pop)) |
3222 | ||
e0dc0c55 SM |
3223 | (defun bibtex-beginning-of-field () |
3224 | "Move point backward to beginning of field. | |
3225 | This function uses a simple, fast algorithm assuming that the field | |
3226 | begins at the beginning of a line. We use this function for font-locking." | |
3227 | (let ((field-reg (concat "^[ \t]*" bibtex-field-name "[ \t]*="))) | |
3228 | (beginning-of-line) | |
3229 | (unless (looking-at field-reg) | |
3230 | (re-search-backward field-reg nil t)))) | |
3231 | ||
f2dfa899 RW |
3232 | (defun bibtex-font-lock-url (bound &optional no-button) |
3233 | "Font-lock for URLs. BOUND limits the search. | |
3234 | If NO-BUTTON is non-nil do not generate buttons." | |
e0dc0c55 SM |
3235 | (let ((case-fold-search t) |
3236 | (pnt (point)) | |
f2dfa899 | 3237 | name bounds start end found) |
e0dc0c55 SM |
3238 | (bibtex-beginning-of-field) |
3239 | (while (and (not found) | |
9cee7d84 | 3240 | (<= (point) bound) |
e0dc0c55 | 3241 | (prog1 (re-search-forward bibtex-font-lock-url-regexp bound t) |
f2dfa899 | 3242 | (setq name (match-string-no-properties 1))) |
e0dc0c55 SM |
3243 | (setq bounds (bibtex-parse-field-text)) |
3244 | (progn | |
cdc61d35 | 3245 | (setq start (car bounds) end (nth 1 bounds)) |
e0dc0c55 SM |
3246 | ;; Always ignore field delimiters |
3247 | (if (memq (char-before end) '(?\} ?\")) | |
3248 | (setq end (1- end))) | |
3249 | (if (memq (char-after start) '(?\{ ?\")) | |
3250 | (setq start (1+ start))) | |
f2dfa899 RW |
3251 | (if (< start pnt) (setq start (min pnt end))) |
3252 | (<= start bound))) | |
3253 | (if (<= pnt start) | |
3254 | (let ((lst bibtex-generate-url-list) url) | |
3255 | (while (and (not found) (setq url (car (pop lst)))) | |
3256 | (goto-char start) | |
3257 | (setq found (and (bibtex-string= name (car url)) | |
3258 | (re-search-forward (cdr url) end t)))))) | |
3259 | (unless found (goto-char end))) | |
3260 | (if (and found (not no-button)) | |
3261 | (bibtex-button (match-beginning 0) (match-end 0) | |
3262 | 'bibtex-url (match-beginning 0))) | |
e0dc0c55 SM |
3263 | found)) |
3264 | ||
3265 | (defun bibtex-font-lock-crossref (bound) | |
02c8032e | 3266 | "Font-lock for crossref fields. BOUND limits the search." |
e0dc0c55 SM |
3267 | (let ((case-fold-search t) |
3268 | (pnt (point)) | |
3269 | (crossref-reg (concat "^[ \t]*crossref[ \t]*=[ \t\n]*" | |
3270 | "\\(\"[^\"]*\"\\|{[^}]*}\\)[ \t\n]*[,})]")) | |
3271 | start end found) | |
3272 | (bibtex-beginning-of-field) | |
3273 | (while (and (not found) | |
3274 | (re-search-forward crossref-reg bound t)) | |
3275 | (setq start (1+ (match-beginning 1)) | |
3276 | end (1- (match-end 1)) | |
3277 | found (>= start pnt))) | |
7af32e66 | 3278 | (if found (bibtex-button start end 'bibtex-search-crossref |
e0dc0c55 SM |
3279 | (buffer-substring-no-properties start end) |
3280 | start t)) | |
3281 | found)) | |
3282 | ||
f2dfa899 RW |
3283 | (defun bibtex-font-lock-cite (matcher bound) |
3284 | "Font-lock for cited keys. | |
3285 | MATCHER identifies the cited key, see `bibtex-cite-matcher-alist'. | |
3286 | BOUND limits the search." | |
3287 | (let (case-fold-search) | |
3288 | (if (re-search-forward (car matcher) bound t) | |
3289 | (let ((start (match-beginning (cdr matcher))) | |
3290 | (end (match-end (cdr matcher)))) | |
7af32e66 | 3291 | (bibtex-button start end 'bibtex-search-crossref |
f2dfa899 RW |
3292 | (buffer-substring-no-properties start end) |
3293 | start t t) | |
3294 | t)))) | |
3295 | ||
e0dc0c55 SM |
3296 | (defun bibtex-button-action (button) |
3297 | "Call BUTTON's BibTeX function." | |
3298 | (apply (button-get button 'bibtex-function) | |
3299 | (button-get button 'bibtex-args))) | |
3300 | ||
3301 | (define-button-type 'bibtex-url | |
3302 | 'action 'bibtex-button-action | |
3303 | 'bibtex-function 'bibtex-url | |
3304 | 'help-echo (purecopy "mouse-2, RET: follow URL")) | |
3305 | ||
7af32e66 | 3306 | (define-button-type 'bibtex-search-crossref |
e0dc0c55 | 3307 | 'action 'bibtex-button-action |
7af32e66 | 3308 | 'bibtex-function 'bibtex-search-crossref |
e0dc0c55 SM |
3309 | 'help-echo (purecopy "mouse-2, RET: follow crossref")) |
3310 | ||
3311 | (defun bibtex-button (beg end type &rest args) | |
02c8032e | 3312 | "Make a BibTeX button from BEG to END of type TYPE in the current buffer." |
e0dc0c55 SM |
3313 | (make-text-button beg end 'type type 'bibtex-args args)) |
3314 | ||
50e4b39e RS |
3315 | \f |
3316 | ;; Interactive Functions: | |
3317 | ||
3318 | ;;;###autoload | |
a2a25d24 | 3319 | (define-derived-mode bibtex-mode nil "BibTeX" |
50e4b39e RS |
3320 | "Major mode for editing BibTeX files. |
3321 | ||
50e4b39e RS |
3322 | General information on working with BibTeX mode: |
3323 | ||
a51cfa58 | 3324 | Use commands such as \\<bibtex-mode-map>\\[bibtex-Book] to get a template for a specific entry. |
02c8032e SM |
3325 | Then fill in all desired fields using \\[bibtex-next-field] to jump from field |
3326 | to field. After having filled in all desired fields in the entry, clean the | |
3327 | new entry with the command \\[bibtex-clean-entry]. | |
cb4ad359 | 3328 | |
d715b065 | 3329 | Some features of BibTeX mode are available only by setting the variable |
d10e87a2 | 3330 | `bibtex-maintain-sorted-entries' to non-nil. However, then BibTeX mode |
a2a25d24 | 3331 | works only with buffers containing valid (syntactically correct) and sorted |
d10e87a2 SM |
3332 | entries. This is usually the case, if you have created a buffer completely |
3333 | with BibTeX mode and finished every new entry with \\[bibtex-clean-entry]. | |
50e4b39e | 3334 | |
921a9483 | 3335 | For third party BibTeX files, call the command \\[bibtex-convert-alien] |
d715b065 | 3336 | to fully take advantage of all features of BibTeX mode. |
50e4b39e RS |
3337 | |
3338 | ||
3339 | Special information: | |
3340 | ||
d10e87a2 | 3341 | A command such as \\[bibtex-Book] outlines the fields for a BibTeX book entry. |
cb4ad359 | 3342 | |
02c8032e SM |
3343 | The names of optional fields start with the string OPT, and are thus ignored |
3344 | by BibTeX. The names of alternative fields from which only one is required | |
3345 | start with the string ALT. The OPT or ALT string may be removed from | |
3346 | the name of a field with \\[bibtex-remove-OPT-or-ALT]. | |
50e4b39e RS |
3347 | \\[bibtex-make-field] inserts a new field after the current one. |
3348 | \\[bibtex-kill-field] kills the current field entirely. | |
d715b065 | 3349 | \\[bibtex-yank] yanks the last recently killed field after the current field. |
50e4b39e | 3350 | \\[bibtex-remove-delimiters] removes the double-quotes or braces around the text of the current field. |
02c8032e SM |
3351 | \\[bibtex-empty-field] replaces the text of the current field with the default \"\" or {}. |
3352 | \\[bibtex-find-text] moves point to the end of the current field. | |
a2a25d24 | 3353 | \\[completion-at-point] completes word fragment before point according to context. |
50e4b39e RS |
3354 | |
3355 | The command \\[bibtex-clean-entry] cleans the current entry, i.e. it removes OPT/ALT | |
02c8032e SM |
3356 | from the names of all non-empty optional or alternative fields, checks that |
3357 | no required fields are empty, and does some formatting dependent on the value | |
3358 | of `bibtex-entry-format'. Furthermore, it can automatically generate a key | |
3359 | for the BibTeX entry, see `bibtex-generate-autokey'. | |
f0cb6034 RS |
3360 | Note: some functions in BibTeX mode depend on entries being in a special |
3361 | format (all fields beginning on separate lines), so it is usually a bad | |
7fbf4804 | 3362 | idea to remove `realign' from `bibtex-entry-format'. |
cb4ad359 | 3363 | |
02c8032e SM |
3364 | BibTeX mode supports Imenu and hideshow minor mode (`hs-minor-mode'). |
3365 | ||
3366 | ---------------------------------------------------------- | |
3367 | Entry to BibTeX mode calls the value of `bibtex-mode-hook' | |
3368 | if that value is non-nil. | |
50e4b39e | 3369 | |
f0cb6034 | 3370 | \\{bibtex-mode-map}" |
a2a25d24 SM |
3371 | (add-hook 'completion-at-point-functions |
3372 | 'bibtex-completion-at-point-function nil 'local) | |
7fbf4804 | 3373 | (make-local-variable 'bibtex-buffer-last-parsed-tick) |
50e4b39e | 3374 | ;; Install stealthy parse function if not already installed |
7fbf4804 | 3375 | (unless bibtex-parse-idle-timer |
e0dc0c55 | 3376 | (setq bibtex-parse-idle-timer (run-with-idle-timer |
7fbf4804 SM |
3377 | bibtex-parse-keys-timeout t |
3378 | 'bibtex-parse-buffers-stealthily))) | |
3379 | (set (make-local-variable 'paragraph-start) "[ \f\n\t]*$") | |
3380 | (set (make-local-variable 'comment-start) bibtex-comment-start) | |
3381 | (set (make-local-variable 'comment-start-skip) | |
3382 | (concat (regexp-quote bibtex-comment-start) "\\>[ \t]*")) | |
3383 | (set (make-local-variable 'comment-column) 0) | |
a172852f | 3384 | (set (make-local-variable 'defun-prompt-regexp) "^[ \t]*@[[:alnum:]]+[ \t]*") |
7fbf4804 | 3385 | (set (make-local-variable 'outline-regexp) "[ \t]*@") |
d715b065 | 3386 | (set (make-local-variable 'fill-paragraph-function) 'bibtex-fill-field) |
a2a25d24 SM |
3387 | (set (make-local-variable 'fill-prefix) |
3388 | (make-string (+ bibtex-entry-offset bibtex-contline-indentation) ?\s)) | |
7fbf4804 SM |
3389 | (set (make-local-variable 'font-lock-defaults) |
3390 | '(bibtex-font-lock-keywords | |
3391 | nil t ((?$ . "\"") | |
3392 | ;; Mathematical expressions should be fontified as strings | |
3393 | (?\" . ".") | |
3394 | ;; Quotes are field delimiters and quote-delimited | |
3395 | ;; entries should be fontified in the same way as | |
3396 | ;; brace-delimited ones | |
3397 | ) | |
3398 | nil | |
e0dc0c55 | 3399 | (font-lock-extra-managed-props . (category)) |
d715b065 KG |
3400 | (font-lock-mark-block-function |
3401 | . (lambda () | |
d528bff7 | 3402 | (set-mark (bibtex-end-of-entry)) |
d715b065 | 3403 | (bibtex-beginning-of-entry))))) |
cf38dd42 SM |
3404 | (set (make-local-variable 'syntax-propertize-function) |
3405 | (syntax-propertize-via-font-lock | |
3406 | bibtex-font-lock-syntactic-keywords)) | |
ace88aa2 RW |
3407 | ;; Allow `bibtex-dialect' as a file-local variable. |
3408 | (add-hook 'hack-local-variables-hook 'bibtex-set-dialect nil t)) | |
3409 | ||
3410 | (defun bibtex-entry-alist (dialect) | |
3411 | "Return entry-alist for DIALECT." | |
3412 | (let ((var (intern (format "bibtex-%s-entry-alist" dialect))) | |
3413 | entry-alist) | |
3414 | (if (boundp var) | |
3415 | (setq entry-alist (symbol-value var)) | |
3416 | (error "BibTeX dialect `%s' undefined" dialect)) | |
3417 | (if (not (consp (nth 1 (car entry-alist)))) | |
3418 | ;; new format | |
3419 | entry-alist | |
3420 | ;; Convert old format of `bibtex-entry-field-alist' | |
3421 | (unless (get var 'entry-list-format) | |
3422 | (put var 'entry-list-format "pre-24") | |
3423 | (message "Old format of `%s' (pre GNU Emacs 24). | |
3424 | Please convert to the new format." | |
3425 | (if (eq (indirect-variable 'bibtex-entry-field-alist) var) | |
3426 | 'bibtex-entry-field-alist var)) | |
3427 | (sit-for 3)) | |
3428 | (let (lst) | |
3429 | (dolist (entry entry-alist) | |
3430 | (let ((fl (nth 1 entry)) req xref opt) | |
3431 | (dolist (field (copy-tree (car fl))) | |
3432 | (if (nth 3 field) (setcar (nthcdr 3 field) 0)) | |
3433 | (if (or (not (nth 2 entry)) | |
3434 | (assoc-string (car field) (car (nth 2 entry)) t)) | |
3435 | (push field req) | |
3436 | (push field xref))) | |
3437 | (dolist (field (nth 1 fl)) | |
3438 | (push field opt)) | |
3439 | (push (list (car entry) nil (nreverse req) | |
3440 | (nreverse xref) (nreverse opt)) | |
3441 | lst))) | |
3442 | (nreverse lst))))) | |
3443 | ||
3444 | (defun bibtex-set-dialect (&optional dialect local) | |
3445 | "Select BibTeX DIALECT for editing BibTeX files. | |
3446 | This sets the user variable `bibtex-dialect' as well as the dialect-dependent | |
3447 | internal variables. Allowed dialects are listed in `bibtex-dialect-list'. | |
3448 | If DIALECT is nil use current value of `bibtex-dialect'. | |
3449 | If LOCAL is non-nil make buffer-local bindings for these variables rather than | |
3450 | setting the global values. The dialect-dependent internal variables | |
3451 | are also bound buffer-locally if `bibtex-dialect' is already buffer-local | |
3452 | in the current buffer (for example, as a file-local variable). | |
3453 | LOCAL is t for interactive calls." | |
2de69e00 RW |
3454 | (interactive (list (intern (completing-read "Dialect: " |
3455 | (mapcar 'list bibtex-dialect-list) | |
ace88aa2 RW |
3456 | nil t)) t)) |
3457 | (let ((setfun (if (or local (local-variable-p 'bibtex-dialect)) | |
3458 | (lambda (var val) (set (make-local-variable var) val)) | |
3459 | 'set))) | |
3460 | (if dialect (funcall setfun 'bibtex-dialect dialect)) | |
3461 | ||
3462 | ;; Set internal variables | |
3463 | (funcall setfun 'bibtex-entry-alist (bibtex-entry-alist bibtex-dialect)) | |
3464 | (funcall setfun 'bibtex-field-alist | |
3465 | (let ((var (intern (format "bibtex-%s-field-alist" | |
3466 | bibtex-dialect)))) | |
3467 | (if (boundp var) | |
3468 | (symbol-value var) | |
3469 | (error "Field types for BibTeX dialect `%s' undefined" | |
3470 | bibtex-dialect)))) | |
3471 | (funcall setfun 'bibtex-entry-type | |
3472 | (concat "@[ \t]*\\(?:" | |
3473 | (regexp-opt (mapcar 'car bibtex-entry-alist)) "\\)")) | |
3474 | (funcall setfun 'bibtex-entry-head | |
3475 | (concat "^[ \t]*\\(" bibtex-entry-type "\\)[ \t]*[({][ \t\n]*\\(" | |
3476 | bibtex-reference-key "\\)")) | |
3477 | (funcall setfun 'bibtex-entry-maybe-empty-head | |
3478 | (concat bibtex-entry-head "?")) | |
3479 | (funcall setfun 'bibtex-any-valid-entry-type | |
3480 | (concat "^[ \t]*@[ \t]*\\(?:" | |
3481 | (regexp-opt | |
3482 | (append '("String" "Preamble") | |
45f431c6 RW |
3483 | (mapcar 'car bibtex-entry-alist))) "\\)")) |
3484 | (setq imenu-generic-expression | |
3485 | (list (list nil bibtex-entry-head bibtex-key-in-head)) | |
3486 | imenu-case-fold-search t))) | |
ace88aa2 RW |
3487 | |
3488 | ;; Entry commands and menus for BibTeX dialects | |
3489 | ;; We do not use `easy-menu-define' here because this gets confused | |
3490 | ;; if we want to have multiple versions of the "same" menu. | |
3491 | (let ((select-map (make-sparse-keymap))) | |
3492 | ;; Submenu for selecting the dialect | |
3493 | (dolist (dialect (reverse bibtex-dialect-list)) | |
3494 | (define-key select-map (vector dialect) | |
3495 | `(menu-item ,(symbol-name dialect) | |
3496 | (lambda () (interactive) (bibtex-set-dialect ',dialect t)) | |
3497 | :button (:radio . (eq bibtex-dialect ',dialect))))) | |
3498 | ;; We define a menu for each dialect. | |
3499 | ;; Then we select the menu we want via the :visible keyword | |
3500 | (dolist (dialect bibtex-dialect-list) | |
3501 | (let ((entry-alist (bibtex-entry-alist dialect)) | |
3502 | (menu-map (make-sparse-keymap))) | |
3503 | (define-key menu-map [select] | |
3504 | `(menu-item "BibTeX dialect" ,select-map)) | |
3505 | (define-key menu-map [nil-2] '(menu-item "--")) | |
3506 | (define-key menu-map [bibtex-preamble] | |
3507 | '(menu-item "Preamble" bibtex-Preamble)) | |
3508 | (define-key menu-map [bibtex-String] | |
3509 | '(menu-item "String" bibtex-String)) | |
3510 | (define-key menu-map [nil-1] '(menu-item "--")) | |
3511 | (dolist (elt (reverse entry-alist)) | |
3512 | ;; Entry commands | |
3513 | (let* ((entry (car elt)) | |
3514 | (fname (intern (format "bibtex-%s" entry)))) | |
3515 | (unless (fboundp fname) | |
3516 | (eval (list 'defun fname nil | |
3517 | (format "Insert a template for a @%s entry; see also `bibtex-entry'." | |
3518 | entry) | |
3519 | '(interactive "*") | |
3520 | `(bibtex-entry ,entry)))) | |
3521 | ;; Menu entries | |
3522 | (define-key menu-map (vector fname) | |
3523 | `(menu-item ,(or (nth 1 elt) (car elt)) ,fname)))) | |
3524 | (define-key bibtex-mode-map | |
3525 | (vector 'menu-bar dialect) | |
3526 | `(menu-item "Entry-Types" ,menu-map | |
3527 | :visible (eq bibtex-dialect ',dialect)))))) | |
9ae11a89 | 3528 | |
8bf38a9b SM |
3529 | (defun bibtex-field-list (entry-type) |
3530 | "Return list of allowed fields for entry ENTRY-TYPE. | |
3531 | More specifically, the return value is a cons pair (REQUIRED . OPTIONAL), | |
3532 | where REQUIRED and OPTIONAL are lists of the required and optional field | |
2de69e00 | 3533 | names for ENTRY-TYPE according to `bibtex-BibTeX-entry-alist' and friends, |
02c8032e SM |
3534 | `bibtex-include-OPTkey', `bibtex-include-OPTcrossref', |
3535 | and `bibtex-user-optional-fields'." | |
2de69e00 | 3536 | (let ((e-list (assoc-string entry-type bibtex-entry-alist t)) |
8bf38a9b | 3537 | required optional) |
2de69e00 | 3538 | (unless e-list |
ffc1e1db | 3539 | (error "Fields for BibTeX entry type %s not defined" entry-type)) |
2de69e00 RW |
3540 | (if (member-ignore-case entry-type bibtex-include-OPTcrossref) |
3541 | (setq required (nth 2 e-list) | |
3542 | optional (append (nth 3 e-list) (nth 4 e-list))) | |
3543 | (setq required (append (nth 2 e-list) (nth 3 e-list)) | |
3544 | optional (nth 4 e-list))) | |
8bf38a9b SM |
3545 | (if bibtex-include-OPTkey |
3546 | (push (list "key" | |
3547 | "Used for reference key creation if author and editor fields are missing" | |
3548 | (if (or (stringp bibtex-include-OPTkey) | |
cbc0b783 | 3549 | (functionp bibtex-include-OPTkey)) |
8bf38a9b SM |
3550 | bibtex-include-OPTkey)) |
3551 | optional)) | |
3552 | (if (member-ignore-case entry-type bibtex-include-OPTcrossref) | |
3553 | (push '("crossref" "Reference key of the cross-referenced entry") | |
3554 | optional)) | |
3555 | (setq optional (append optional bibtex-user-optional-fields)) | |
3556 | (cons required optional))) | |
3557 | ||
50e4b39e | 3558 | (defun bibtex-entry (entry-type) |
ace88aa2 | 3559 | "Insert a template for a BibTeX entry of type ENTRY-TYPE. |
02c8032e SM |
3560 | After insertion call the value of `bibtex-add-entry-hook' if that value |
3561 | is non-nil." | |
3562 | (interactive | |
3563 | (let ((completion-ignore-case t)) | |
2de69e00 | 3564 | (list (completing-read "Entry Type: " bibtex-entry-alist |
02c8032e | 3565 | nil t nil 'bibtex-entry-type-history)))) |
8bf38a9b SM |
3566 | (let ((key (if bibtex-maintain-sorted-entries |
3567 | (bibtex-read-key (format "%s key: " entry-type)))) | |
3568 | (field-list (bibtex-field-list entry-type))) | |
7fbf4804 SM |
3569 | (unless (bibtex-prepare-new-entry (list key nil entry-type)) |
3570 | (error "Entry with key `%s' already exists" key)) | |
50e4b39e RS |
3571 | (indent-to-column bibtex-entry-offset) |
3572 | (insert "@" entry-type (bibtex-entry-left-delimiter)) | |
8bf38a9b | 3573 | (if key (insert key)) |
9ae11a89 | 3574 | (save-excursion |
a9d77f1f SM |
3575 | (mapc 'bibtex-make-field (car field-list)) |
3576 | (mapc 'bibtex-make-optional-field (cdr field-list)) | |
50e4b39e RS |
3577 | (if bibtex-comma-after-last-field |
3578 | (insert ",")) | |
3579 | (insert "\n") | |
3580 | (indent-to-column bibtex-entry-offset) | |
3581 | (insert (bibtex-entry-right-delimiter) "\n\n")) | |
0640d7bf | 3582 | (bibtex-next-field t) |
d715b065 KG |
3583 | (if (member-ignore-case entry-type bibtex-autofill-types) |
3584 | (bibtex-autofill-entry)) | |
9ae11a89 | 3585 | (run-hooks 'bibtex-add-entry-hook))) |
e5167999 | 3586 | |
5ad23234 | 3587 | (defun bibtex-entry-update (&optional entry-type) |
8bf38a9b SM |
3588 | "Update an existing BibTeX entry. |
3589 | In the BibTeX entry at point, make new fields for those items that may occur | |
5ad23234 RW |
3590 | according to `bibtex-field-list', but are not yet present. |
3591 | Also, add field delimiters to numerical fields if they are not present. | |
3592 | If ENTRY-TYPE is non-nil, change first the entry type to ENTRY-TYPE. | |
3593 | When called interactively with a prefix arg, query for a value of ENTRY-TYPE." | |
3594 | (interactive | |
3595 | (list (if current-prefix-arg | |
3596 | (let ((completion-ignore-case t)) | |
2de69e00 | 3597 | (completing-read "New entry type: " bibtex-entry-alist |
5ad23234 | 3598 | nil t nil 'bibtex-entry-type-history))))) |
8bf38a9b SM |
3599 | (save-excursion |
3600 | (bibtex-beginning-of-entry) | |
5ad23234 RW |
3601 | (when (looking-at bibtex-entry-maybe-empty-head) |
3602 | (goto-char (match-end 0)) | |
3603 | (if entry-type | |
3604 | (save-excursion | |
3605 | (replace-match (concat "@" entry-type) nil nil nil 1)) | |
3606 | (setq entry-type (bibtex-type-in-head))) | |
3607 | (let* ((field-list (bibtex-field-list entry-type)) | |
3608 | (required (copy-tree (car field-list))) | |
3609 | (optional (copy-tree (cdr field-list))) | |
3610 | bounds) | |
3611 | (while (setq bounds (bibtex-parse-field)) | |
3612 | (let ((fname (bibtex-name-in-field bounds t)) | |
3613 | (end (copy-marker (bibtex-end-of-field bounds) t))) | |
3614 | (setq required (delete (assoc-string fname required t) required) | |
3615 | optional (delete (assoc-string fname optional t) optional)) | |
3616 | (when (string-match "\\`[0-9]+\\'" | |
3617 | (bibtex-text-in-field-bounds bounds)) | |
3618 | (goto-char (bibtex-end-of-text-in-field bounds)) | |
3619 | (insert (bibtex-field-right-delimiter)) | |
3620 | (goto-char (bibtex-start-of-text-in-field bounds)) | |
3621 | (insert (bibtex-field-left-delimiter))) | |
3622 | (goto-char end))) | |
3623 | (skip-chars-backward " \t\n") | |
297dde5a RW |
3624 | (mapc 'bibtex-make-field required) |
3625 | (mapc 'bibtex-make-optional-field optional))))) | |
8bf38a9b | 3626 | |
cdc61d35 | 3627 | (defun bibtex-parse-entry (&optional content) |
d715b065 KG |
3628 | "Parse entry at point, return an alist. |
3629 | The alist elements have the form (FIELD . TEXT), where FIELD can also be | |
d528bff7 SM |
3630 | the special strings \"=type=\" and \"=key=\". For the FIELD \"=key=\" |
3631 | TEXT may be nil. Remove \"OPT\" and \"ALT\" from FIELD. | |
cdc61d35 SM |
3632 | Move point to the end of the last field. |
3633 | If optional arg CONTENT is non-nil extract content of text fields." | |
d715b065 | 3634 | (let (alist bounds) |
cb75af76 | 3635 | (when (looking-at bibtex-entry-maybe-empty-head) |
e0dc0c55 SM |
3636 | (push (cons "=type=" (bibtex-type-in-head)) alist) |
3637 | (push (cons "=key=" (bibtex-key-in-head)) alist) | |
cb75af76 | 3638 | (goto-char (match-end 0)) |
cdc61d35 | 3639 | (while (setq bounds (bibtex-parse-field)) |
d528bff7 | 3640 | (push (cons (bibtex-name-in-field bounds t) |
cdc61d35 | 3641 | (bibtex-text-in-field-bounds bounds content)) |
d715b065 KG |
3642 | alist) |
3643 | (goto-char (bibtex-end-of-field bounds)))) | |
b7c3692a | 3644 | (nreverse alist))) |
d715b065 KG |
3645 | |
3646 | (defun bibtex-autofill-entry () | |
02c8032e SM |
3647 | "Try to fill fields of current BibTeX entry based on neighboring entries. |
3648 | The current entry must have a key. Determine the neighboring entry | |
e1dbe924 | 3649 | \(previous or next\) whose key is more similar to the key of the current |
02c8032e SM |
3650 | entry. For all empty fields of the current entry insert the corresponding |
3651 | field contents of the neighboring entry. Finally try to update the text | |
3652 | based on the difference between the keys of the neighboring and the current | |
3653 | entry (for example, the year parts of the keys)." | |
d715b065 | 3654 | (interactive) |
d715b065 KG |
3655 | (bibtex-beginning-of-entry) |
3656 | (when (looking-at bibtex-entry-head) | |
e0dc0c55 SM |
3657 | (let ((type (bibtex-type-in-head)) |
3658 | (key (bibtex-key-in-head)) | |
d715b065 KG |
3659 | (key-end (match-end bibtex-key-in-head)) |
3660 | (case-fold-search t) | |
ffc1e1db | 3661 | (bibtex-sort-ignore-string-entries t) |
d715b065 KG |
3662 | tmp other-key other bounds) |
3663 | ;; The fields we want to change start right after the key. | |
3664 | (goto-char key-end) | |
3665 | ;; First see whether to use the previous or the next entry | |
3666 | ;; for "inspiration". | |
3667 | (save-excursion | |
3668 | (goto-char (1- (match-beginning 0))) | |
3669 | (bibtex-beginning-of-entry) | |
02c8032e SM |
3670 | (if (and (looking-at bibtex-entry-head) |
3671 | (bibtex-string= type (bibtex-type-in-head)) | |
3672 | ;; In case we found ourselves :-( | |
3673 | (not (equal key (setq tmp (bibtex-key-in-head))))) | |
3674 | (setq other-key tmp | |
3675 | other (point)))) | |
d715b065 KG |
3676 | (save-excursion |
3677 | (bibtex-end-of-entry) | |
3678 | (bibtex-skip-to-valid-entry) | |
02c8032e SM |
3679 | (if (and (looking-at bibtex-entry-head) |
3680 | (bibtex-string= type (bibtex-type-in-head)) | |
3681 | ;; In case we found ourselves :-( | |
3682 | (not (equal key (setq tmp (bibtex-key-in-head)))) | |
3683 | (or (not other-key) | |
3684 | ;; Check which is the best match. | |
3685 | (< (length (try-completion "" (list key other-key))) | |
3686 | (length (try-completion "" (list key tmp)))))) | |
3687 | (setq other-key tmp | |
3688 | other (point)))) | |
d715b065 KG |
3689 | ;; Then fill the new entry's fields with the chosen other entry. |
3690 | (when other | |
3691 | (setq other (save-excursion (goto-char other) (bibtex-parse-entry))) | |
3692 | (setq key-end (point)) ;In case parse-entry changed the buffer. | |
cdc61d35 | 3693 | (while (setq bounds (bibtex-parse-field)) |
d528bff7 SM |
3694 | (let ((text (assoc-string (bibtex-name-in-field bounds t) |
3695 | other t))) | |
31df23f5 | 3696 | (if (not (and text |
cdc61d35 | 3697 | (equal "" (bibtex-text-in-field-bounds bounds t)))) |
d715b065 | 3698 | (goto-char (bibtex-end-of-field bounds)) |
31df23f5 | 3699 | (goto-char (bibtex-start-of-text-in-field bounds)) |
d715b065 KG |
3700 | (delete-region (point) (bibtex-end-of-text-in-field bounds)) |
3701 | (insert (cdr text))))) | |
3702 | ;; Finally try to update the text based on the difference between | |
3703 | ;; the two keys. | |
3704 | (let* ((prefix (try-completion "" (list key other-key))) | |
3705 | ;; If the keys are foo91 and foo92, don't replace 1 for 2 | |
3706 | ;; but 91 for 92 instead. | |
3707 | (_ (if (string-match "[0-9]+\\'" prefix) | |
3708 | (setq prefix (substring prefix 0 (match-beginning 0))))) | |
3709 | (suffix (substring key (length prefix))) | |
3710 | (other-suffix (substring other-key (length prefix)))) | |
3711 | (while (re-search-backward (regexp-quote other-suffix) key-end 'move) | |
3712 | (replace-match suffix))))))) | |
3713 | ||
ffc1e1db RW |
3714 | (defun bibtex-print-help-message (&optional field comma) |
3715 | "Print helpful information about current FIELD in current BibTeX entry. | |
3716 | Optional arg COMMA is as in `bibtex-enclosing-field'. It is t for | |
3717 | interactive calls." | |
3718 | (interactive (list nil t)) | |
3719 | (unless field (setq field (car (bibtex-find-text-internal nil nil comma)))) | |
3720 | (if (string-match "@" field) | |
3721 | (cond ((bibtex-string= field "@string") | |
3722 | (message "String definition")) | |
3723 | ((bibtex-string= field "@preamble") | |
3724 | (message "Preamble definition")) | |
3725 | (t (message "Entry key"))) | |
3726 | (let* ((case-fold-search t) | |
3727 | (type (save-excursion | |
3728 | (bibtex-beginning-of-entry) | |
3729 | (looking-at bibtex-entry-maybe-empty-head) | |
3730 | (bibtex-type-in-head))) | |
3731 | (field-list (bibtex-field-list type)) | |
3732 | (comment (assoc-string field (append (car field-list) | |
3733 | (cdr field-list)) t))) | |
2de69e00 RW |
3734 | (message "%s" (cond ((nth 1 comment) (nth 1 comment)) |
3735 | ((setq comment (assoc-string field bibtex-field-alist t)) | |
3736 | (nth 1 comment)) | |
3737 | (t "No comment available")))))) | |
d30bfc76 | 3738 | |
84aa4fc6 | 3739 | (defun bibtex-make-field (field &optional move interactive nodelim) |
d715b065 KG |
3740 | "Make a field named FIELD in current BibTeX entry. |
3741 | FIELD is either a string or a list of the form | |
3742 | \(FIELD-NAME COMMENT-STRING INIT ALTERNATIVE-FLAG) as in | |
2de69e00 | 3743 | `bibtex-BibTeX-entry-alist' and friends. |
02c8032e SM |
3744 | If MOVE is non-nil, move point past the present field before making |
3745 | the new field. If INTERACTIVE is non-nil, move point to the end of | |
3746 | the new field. Otherwise move point past the new field. | |
84aa4fc6 | 3747 | MOVE and INTERACTIVE are t when called interactively. |
cbc0b783 | 3748 | INIT is surrounded by field delimiters, unless NODELIM is non-nil." |
7fbf4804 | 3749 | (interactive |
8bf38a9b SM |
3750 | (list (let ((completion-ignore-case t) |
3751 | (field-list (bibtex-field-list | |
e0dc0c55 | 3752 | (save-excursion |
ffc1e1db RW |
3753 | (bibtex-beginning-of-entry) |
3754 | (looking-at bibtex-any-entry-maybe-empty-head) | |
e0dc0c55 | 3755 | (bibtex-type-in-head))))) |
8bf38a9b SM |
3756 | (completing-read "BibTeX field name: " |
3757 | (append (car field-list) (cdr field-list)) | |
3f3ed959 | 3758 | nil nil nil bibtex-field-history)) |
02c8032e | 3759 | t t)) |
d715b065 KG |
3760 | (unless (consp field) |
3761 | (setq field (list field))) | |
cdc61d35 SM |
3762 | (when move |
3763 | (bibtex-find-text) | |
3764 | (if (looking-at "[}\"]") | |
3765 | (forward-char))) | |
d715b065 KG |
3766 | (insert ",\n") |
3767 | (indent-to-column (+ bibtex-entry-offset bibtex-field-indentation)) | |
2de69e00 RW |
3768 | ;; If there are multiple sets of alternatives, we could use |
3769 | ;; the numeric value of (nth 3 field) to number these sets. Useful?? | |
d715b065 KG |
3770 | (if (nth 3 field) (insert "ALT")) |
3771 | (insert (car field) " ") | |
3772 | (if bibtex-align-at-equal-sign | |
3773 | (indent-to-column (+ bibtex-entry-offset | |
3774 | (- bibtex-text-indentation 2)))) | |
3775 | (insert "= ") | |
d528bff7 SM |
3776 | (unless bibtex-align-at-equal-sign |
3777 | (indent-to-column (+ bibtex-entry-offset | |
3778 | bibtex-text-indentation))) | |
d715b065 | 3779 | (let ((init (nth 2 field))) |
cbc0b783 RW |
3780 | (if (not init) (setq init "") |
3781 | (if (functionp init) (setq init (funcall init))) | |
3782 | (unless (stringp init) (error "`%s' is not a string" init))) | |
3783 | ;; NODELIM is required by `bibtex-insert-kill' | |
3784 | (if nodelim (insert init) | |
3785 | (insert (bibtex-field-left-delimiter) init | |
84aa4fc6 | 3786 | (bibtex-field-right-delimiter)))) |
2c10c0f0 | 3787 | (when interactive |
ffc1e1db RW |
3788 | ;; (bibtex-find-text nil nil bibtex-help-message) |
3789 | (if (memq (preceding-char) '(?} ?\")) (forward-char -1)) | |
3790 | (if bibtex-help-message (bibtex-print-help-message (car field))))) | |
9ae11a89 | 3791 | |
cb4ad359 | 3792 | (defun bibtex-beginning-of-entry () |
7fbf4804 | 3793 | "Move to beginning of BibTeX entry (beginning of line). |
cb4ad359 | 3794 | If inside an entry, move to the beginning of it, otherwise move to the |
a9d77f1f SM |
3795 | beginning of the previous entry. If point is ahead of all BibTeX entries |
3796 | move point to the beginning of buffer. Return the new location of point." | |
745bc783 | 3797 | (interactive) |
50e4b39e RS |
3798 | (skip-chars-forward " \t") |
3799 | (if (looking-at "@") | |
a9cb9b80 | 3800 | (forward-char)) |
d715b065 KG |
3801 | (re-search-backward "^[ \t]*@" nil 'move) |
3802 | (point)) | |
e5167999 | 3803 | |
cb4ad359 | 3804 | (defun bibtex-end-of-entry () |
7fbf4804 | 3805 | "Move to end of BibTeX entry (past the closing brace). |
cb4ad359 | 3806 | If inside an entry, move to the end of it, otherwise move to the end |
a9d77f1f | 3807 | of the previous entry. Do not move if ahead of first entry. |
d715b065 | 3808 | Return the new location of point." |
745bc783 | 3809 | (interactive) |
7fbf4804 | 3810 | (let ((case-fold-search t) |
ffc1e1db RW |
3811 | (pnt (point)) |
3812 | (_ (bibtex-beginning-of-entry)) | |
3813 | (bounds (bibtex-valid-entry t))) | |
3814 | (cond (bounds (goto-char (cdr bounds))) ; regular entry | |
3815 | ;; @String or @Preamble | |
3816 | ((setq bounds (or (bibtex-parse-string t) (bibtex-parse-preamble))) | |
7fbf4804 | 3817 | (goto-char (bibtex-end-of-string bounds))) |
ffc1e1db RW |
3818 | ((looking-at bibtex-any-valid-entry-type) |
3819 | ;; Parsing of entry failed | |
f2dfa899 | 3820 | (error "Syntactically incorrect BibTeX entry starts here")) |
32226619 JB |
3821 | (t (if (called-interactively-p 'interactive) |
3822 | (message "Not on a known BibTeX entry.")) | |
ffc1e1db RW |
3823 | (goto-char pnt))) |
3824 | (point))) | |
f0cb6034 | 3825 | |
d10e87a2 SM |
3826 | (defun bibtex-goto-line (arg) |
3827 | "Goto line ARG, counting from beginning of (narrowed) buffer." | |
3828 | ;; code adapted from `goto-line' | |
3829 | (goto-char (point-min)) | |
3830 | (if (eq selective-display t) | |
3831 | (re-search-forward "[\n\C-m]" nil 'end (1- arg)) | |
3832 | (forward-line (1- arg)))) | |
3833 | ||
3834 | (defun bibtex-reposition-window () | |
7fbf4804 | 3835 | "Make the current BibTeX entry visible. |
d10e87a2 SM |
3836 | If entry is smaller than `window-body-height', entry is centered in window. |
3837 | Otherwise display the beginning of entry." | |
3838 | (interactive) | |
3839 | (let ((pnt (point)) | |
3840 | (beg (line-number-at-pos (bibtex-beginning-of-entry))) | |
3841 | (end (line-number-at-pos (bibtex-end-of-entry)))) | |
3842 | (if (> (window-body-height) (- end beg)) | |
3843 | ;; entry fits in current window | |
3844 | (progn | |
3845 | (bibtex-goto-line (/ (+ 1 beg end) 2)) | |
3846 | (recenter) | |
3847 | (goto-char pnt)) | |
3848 | ;; entry too large for current window | |
3849 | (bibtex-goto-line beg) | |
3850 | (recenter 0) | |
3851 | (if (> (1+ (- (line-number-at-pos pnt) beg)) | |
3852 | (window-body-height)) | |
3853 | (bibtex-goto-line beg) | |
3854 | (goto-char pnt))))) | |
50e4b39e RS |
3855 | |
3856 | (defun bibtex-mark-entry () | |
3857 | "Put mark at beginning, point at end of current BibTeX entry." | |
3858 | (interactive) | |
f2dfa899 | 3859 | (push-mark (bibtex-beginning-of-entry)) |
50e4b39e RS |
3860 | (bibtex-end-of-entry)) |
3861 | ||
3862 | (defun bibtex-count-entries (&optional count-string-entries) | |
3863 | "Count number of entries in current buffer or region. | |
d10e87a2 SM |
3864 | With prefix argument COUNT-STRING-ENTRIES count all entries, |
3865 | otherwise count all entries except @String entries. | |
3866 | If mark is active count entries in region, if not in whole buffer." | |
50e4b39e | 3867 | (interactive "P") |
7fbf4804 | 3868 | (let ((number 0) |
cdc61d35 SM |
3869 | (bibtex-sort-ignore-string-entries (not count-string-entries))) |
3870 | (save-restriction | |
3871 | (if mark-active (narrow-to-region (region-beginning) (region-end))) | |
a2a25d24 | 3872 | (bibtex-map-entries (lambda (_key _beg _end) (setq number (1+ number))))) |
7fbf4804 | 3873 | (message "%s contains %d entries." |
e0dc0c55 | 3874 | (if mark-active "Region" "Buffer") |
d715b065 | 3875 | number))) |
50e4b39e | 3876 | |
cb4ad359 | 3877 | (defun bibtex-ispell-entry () |
d10e87a2 | 3878 | "Check BibTeX entry for spelling errors." |
745bc783 | 3879 | (interactive) |
d715b065 KG |
3880 | (ispell-region (save-excursion (bibtex-beginning-of-entry)) |
3881 | (save-excursion (bibtex-end-of-entry)))) | |
745bc783 | 3882 | |
cb4ad359 | 3883 | (defun bibtex-ispell-abstract () |
d10e87a2 | 3884 | "Check abstract of BibTeX entry for spelling errors." |
745bc783 | 3885 | (interactive) |
d715b065 KG |
3886 | (let ((bounds (save-excursion |
3887 | (bibtex-beginning-of-entry) | |
ffc1e1db | 3888 | (bibtex-search-forward-field "abstract" t)))) |
7fbf4804 SM |
3889 | (if bounds |
3890 | (ispell-region (bibtex-start-of-text-in-field bounds) | |
3891 | (bibtex-end-of-text-in-field bounds)) | |
3892 | (error "No abstract in entry")))) | |
745bc783 | 3893 | |
cb4ad359 RS |
3894 | (defun bibtex-narrow-to-entry () |
3895 | "Narrow buffer to current BibTeX entry." | |
745bc783 | 3896 | (interactive) |
cb4ad359 | 3897 | (save-excursion |
7fbf4804 SM |
3898 | (widen) |
3899 | (narrow-to-region (bibtex-beginning-of-entry) | |
3900 | (bibtex-end-of-entry)))) | |
3901 | ||
3902 | (defun bibtex-entry-index () | |
02c8032e | 3903 | "Return index of BibTeX entry head at or past position of point. |
c48f463b | 3904 | The index is a list (KEY CROSSREF-KEY ENTRY-TYPE) that is used for sorting |
02c8032e SM |
3905 | the entries of the BibTeX buffer. CROSSREF-KEY is nil unless the value |
3906 | of `bibtex-maintain-sorted-entries' is `crossref'. Move point to the end | |
3907 | of the head of the entry found. Return nil if no entry found." | |
7fbf4804 SM |
3908 | (let ((case-fold-search t)) |
3909 | (if (re-search-forward bibtex-entry-maybe-empty-head nil t) | |
3910 | (let ((key (bibtex-key-in-head)) | |
c48f463b RW |
3911 | ;; all entry types should be downcase (for ease of comparison) |
3912 | (entry-type (downcase (bibtex-type-in-head)))) | |
7fbf4804 | 3913 | ;; Don't search CROSSREF-KEY if we don't need it. |
02c8032e SM |
3914 | (if (eq bibtex-maintain-sorted-entries 'crossref) |
3915 | (let ((bounds (bibtex-search-forward-field | |
ffc1e1db | 3916 | "\\(OPT\\)?crossref" t))) |
02c8032e SM |
3917 | (list key |
3918 | (if bounds (bibtex-text-in-field-bounds bounds t)) | |
c48f463b RW |
3919 | entry-type)) |
3920 | (list key nil entry-type)))))) | |
7fbf4804 | 3921 | |
7a0574f3 | 3922 | (defun bibtex-init-sort-entry-class-alist () |
f2dfa899 | 3923 | "Initialize `bibtex-sort-entry-class-alist' (buffer-local)." |
7a0574f3 SM |
3924 | (unless (local-variable-p 'bibtex-sort-entry-class-alist) |
3925 | (set (make-local-variable 'bibtex-sort-entry-class-alist) | |
3926 | (let ((i -1) alist) | |
a2a25d24 | 3927 | (dolist (class bibtex-sort-entry-class) |
7a0574f3 SM |
3928 | (setq i (1+ i)) |
3929 | (dolist (entry class) | |
c48f463b | 3930 | ;; All entry types should be downcase (for ease of comparison). |
7a0574f3 | 3931 | (push (cons (if (stringp entry) (downcase entry) entry) i) |
a2a25d24 SM |
3932 | alist))) |
3933 | alist)))) | |
7a0574f3 | 3934 | |
7fbf4804 SM |
3935 | (defun bibtex-lessp (index1 index2) |
3936 | "Predicate for sorting BibTeX entries with indices INDEX1 and INDEX2. | |
c48f463b | 3937 | Each index is a list (KEY CROSSREF-KEY ENTRY-TYPE). |
8bf38a9b SM |
3938 | The predicate depends on the variable `bibtex-maintain-sorted-entries'. |
3939 | If its value is nil use plain sorting." | |
7fbf4804 SM |
3940 | (cond ((not index1) (not index2)) ; indices can be nil |
3941 | ((not index2) nil) | |
02c8032e | 3942 | ((eq bibtex-maintain-sorted-entries 'crossref) |
65e10478 RW |
3943 | ;; CROSSREF-KEY may be nil or it can point to an entry |
3944 | ;; in another BibTeX file. In both cases we ignore CROSSREF-KEY. | |
3945 | (if (and (nth 1 index1) | |
3946 | (cdr (assoc-string (nth 1 index1) bibtex-reference-keys))) | |
3947 | (if (and (nth 1 index2) | |
3948 | (cdr (assoc-string (nth 1 index2) bibtex-reference-keys))) | |
7fbf4804 SM |
3949 | (or (string-lessp (nth 1 index1) (nth 1 index2)) |
3950 | (and (string-equal (nth 1 index1) (nth 1 index2)) | |
3951 | (string-lessp (nth 0 index1) (nth 0 index2)))) | |
3952 | (not (string-lessp (nth 0 index2) (nth 1 index1)))) | |
65e10478 RW |
3953 | (if (and (nth 1 index2) |
3954 | (cdr (assoc-string (nth 1 index2) bibtex-reference-keys))) | |
7fbf4804 SM |
3955 | (string-lessp (nth 0 index1) (nth 1 index2)) |
3956 | (string-lessp (nth 0 index1) (nth 0 index2))))) | |
02c8032e | 3957 | ((eq bibtex-maintain-sorted-entries 'entry-class) |
d715b065 KG |
3958 | (let ((n1 (cdr (or (assoc (nth 2 index1) bibtex-sort-entry-class-alist) |
3959 | (assoc 'catch-all bibtex-sort-entry-class-alist) | |
3960 | '(nil . 1000)))) ; if there is nothing else | |
3961 | (n2 (cdr (or (assoc (nth 2 index2) bibtex-sort-entry-class-alist) | |
3962 | (assoc 'catch-all bibtex-sort-entry-class-alist) | |
3963 | '(nil . 1000))))) ; if there is nothing else | |
7fbf4804 SM |
3964 | (or (< n1 n2) |
3965 | (and (= n1 n2) | |
3966 | (string-lessp (car index1) (car index2)))))) | |
02c8032e | 3967 | (t ; (eq bibtex-maintain-sorted-entries 'plain) |
7fbf4804 | 3968 | (string-lessp (car index1) (car index2))))) |
745bc783 | 3969 | |
50e4b39e RS |
3970 | (defun bibtex-sort-buffer () |
3971 | "Sort BibTeX buffer alphabetically by key. | |
7fbf4804 | 3972 | The predicate for sorting is defined via `bibtex-maintain-sorted-entries'. |
a9d77f1f SM |
3973 | If its value is nil use plain sorting. Text outside of BibTeX entries is not |
3974 | affected. If `bibtex-sort-ignore-string-entries' is non-nil, @String entries | |
d10e87a2 | 3975 | are ignored." |
745bc783 | 3976 | (interactive) |
7a0574f3 SM |
3977 | (bibtex-beginning-of-first-entry) ; Needed by `sort-subr' |
3978 | (bibtex-init-sort-entry-class-alist) ; Needed by `bibtex-lessp'. | |
65e10478 | 3979 | (if (and (eq bibtex-maintain-sorted-entries 'crossref) |
03db5e5f | 3980 | (functionp bibtex-reference-keys)) |
65e10478 | 3981 | (bibtex-parse-keys)) ; Needed by `bibtex-lessp'. |
7a0574f3 SM |
3982 | (sort-subr nil |
3983 | 'bibtex-skip-to-valid-entry ; NEXTREC function | |
3984 | 'bibtex-end-of-entry ; ENDREC function | |
3985 | 'bibtex-entry-index ; STARTKEY function | |
3986 | nil ; ENDKEY function | |
3987 | 'bibtex-lessp)) ; PREDICATE | |
7fbf4804 | 3988 | |
7af32e66 | 3989 | (defun bibtex-search-crossref (crossref-key &optional pnt split noerror) |
7fbf4804 | 3990 | "Move point to the beginning of BibTeX entry CROSSREF-KEY. |
02c8032e SM |
3991 | If `bibtex-files' is non-nil, search all these files. |
3992 | Otherwise the search is limited to the current buffer. | |
3993 | Return position of entry if CROSSREF-KEY is found or nil otherwise. | |
3994 | If CROSSREF-KEY is in the same buffer like current entry but before it | |
09e80d9f | 3995 | an error is signaled. If NOERROR is non-nil this error is suppressed. |
f2dfa899 RW |
3996 | Optional arg PNT is the position of the referencing entry. It defaults |
3997 | to position of point. If optional arg SPLIT is non-nil, split window | |
3998 | so that both the referencing and the crossrefed entry are displayed. | |
3999 | ||
4000 | If called interactively, CROSSREF-KEY defaults to either the crossref key | |
4001 | of current entry or a key matched by `bibtex-cite-matcher-alist', | |
4002 | whatever is nearer to the position of point. SPLIT is t. NOERROR is nil | |
4003 | for a crossref key, t otherwise." | |
d715b065 | 4004 | (interactive |
f2dfa899 RW |
4005 | (save-excursion |
4006 | (let* ((pnt (point)) | |
4007 | (_ (bibtex-beginning-of-entry)) | |
4008 | (end (cdr (bibtex-valid-entry t))) | |
4009 | (_ (unless end (error "Not inside valid entry"))) | |
4010 | (beg (match-end 0)) ; set by `bibtex-valid-entry' | |
45cb4eb4 | 4011 | (bounds (bibtex-search-forward-field "\\(OPT\\)?crossref" end)) |
f2dfa899 RW |
4012 | case-fold-search best temp crossref-key) |
4013 | (if bounds | |
4014 | (setq crossref-key (bibtex-text-in-field-bounds bounds t) | |
4015 | best (cons (bibtex-dist pnt (bibtex-end-of-field bounds) | |
4016 | (bibtex-start-of-field bounds)) | |
4017 | crossref-key))) | |
4018 | (dolist (matcher bibtex-cite-matcher-alist) | |
4019 | (goto-char beg) | |
4020 | (while (re-search-forward (car matcher) end t) | |
4021 | (setq temp (bibtex-dist pnt (match-end (cdr matcher)) | |
4022 | (match-beginning (cdr matcher)))) | |
4023 | ;; Accept the key closest to the position of point. | |
4024 | (if (or (not best) (< temp (car best))) | |
4025 | (setq best (cons temp (match-string-no-properties | |
4026 | (cdr matcher))))))) | |
4027 | (goto-char pnt) | |
4028 | (setq temp (bibtex-read-key "Find crossref key: " (cdr best) t)) | |
4029 | (list temp (point) t (not (and crossref-key | |
4030 | (string= temp crossref-key))))))) | |
4031 | ||
02c8032e SM |
4032 | (let (buffer pos eqb) |
4033 | (save-excursion | |
7af32e66 | 4034 | (setq pos (bibtex-search-entry crossref-key t) |
02c8032e SM |
4035 | buffer (current-buffer))) |
4036 | (setq eqb (eq buffer (current-buffer))) | |
e0dc0c55 | 4037 | (cond ((not pos) |
02c8032e SM |
4038 | (if split (message "Crossref key `%s' not found" crossref-key))) |
4039 | (split ; called (quasi) interactively | |
4040 | (unless pnt (setq pnt (point))) | |
e0dc0c55 | 4041 | (goto-char pnt) |
f2dfa899 RW |
4042 | (if (and eqb (= pos (save-excursion (bibtex-beginning-of-entry)))) |
4043 | (message "Key `%s' is current entry" crossref-key) | |
4044 | (if eqb (select-window (split-window)) | |
4045 | (pop-to-buffer buffer)) | |
4046 | (goto-char pos) | |
4047 | (bibtex-reposition-window) | |
4048 | (beginning-of-line) | |
4049 | (if (and eqb (> pnt pos) (not noerror)) | |
4050 | (error "The referencing entry must precede the crossrefed entry!")))) | |
7af32e66 | 4051 | ;; `bibtex-search-crossref' is called noninteractively during |
02c8032e SM |
4052 | ;; clean-up of an entry. Then it is not possible to check |
4053 | ;; whether the current entry and the crossrefed entry have | |
4054 | ;; the correct sorting order. | |
4055 | (eqb (goto-char pos)) | |
4056 | (t (set-buffer buffer) (goto-char pos))) | |
e0dc0c55 | 4057 | pos)) |
7af32e66 RW |
4058 | ;; backward compatibility |
4059 | (defalias 'bibtex-find-crossref 'bibtex-search-crossref) | |
7fbf4804 | 4060 | |
f2dfa899 RW |
4061 | (defun bibtex-dist (pos beg end) |
4062 | "Return distance between POS and region delimited by BEG and END." | |
4063 | (cond ((and (<= beg pos) (<= pos end)) 0) | |
4064 | ((< pos beg) (- beg pos)) | |
4065 | (t (- pos end)))) | |
4066 | ||
7af32e66 RW |
4067 | ;;;###autoload |
4068 | (defun bibtex-search-entry (key &optional global start display) | |
7fbf4804 | 4069 | "Move point to the beginning of BibTeX entry named KEY. |
d528bff7 | 4070 | Return position of entry if KEY is found or nil if not found. |
7af32e66 RW |
4071 | With GLOBAL non-nil, search KEY in `bibtex-files'. Otherwise the search |
4072 | is limited to the current buffer. Optional arg START is buffer position | |
4073 | where the search starts. If it is nil, start search at beginning of buffer. | |
02c8032e | 4074 | If DISPLAY is non-nil, display the buffer containing KEY. |
7af32e66 | 4075 | Otherwise, use `set-buffer'. |
022fe7ce RW |
4076 | When called interactively, START is nil, DISPLAY is t. |
4077 | Also, GLOBAL is t if the current mode is not `bibtex-mode' | |
4078 | or `bibtex-search-entry-globally' is non-nil. | |
4079 | A prefix arg negates the value of `bibtex-search-entry-globally'." | |
7af32e66 | 4080 | (interactive |
022fe7ce RW |
4081 | (let ((global (or (not (eq major-mode 'bibtex-mode)) |
4082 | (if bibtex-search-entry-globally | |
4083 | (not current-prefix-arg) | |
4084 | current-prefix-arg)))) | |
7af32e66 | 4085 | (list (bibtex-read-key "Find key: " nil global) global nil t))) |
02c8032e | 4086 | (if (and global bibtex-files) |
65e10478 | 4087 | (let ((buffer-list (bibtex-initialize t)) |
02c8032e SM |
4088 | buffer found) |
4089 | (while (and (not found) | |
4090 | (setq buffer (pop buffer-list))) | |
4091 | (with-current-buffer buffer | |
03db5e5f | 4092 | (if (cdr (assoc-string key bibtex-reference-keys)) |
7af32e66 RW |
4093 | ;; `bibtex-search-entry' moves point if key found |
4094 | (setq found (bibtex-search-entry key))))) | |
02c8032e | 4095 | (cond ((and found display) |
3199b96f CY |
4096 | (switch-to-buffer buffer) |
4097 | (bibtex-reposition-window)) | |
02c8032e | 4098 | (found (set-buffer buffer)) |
d10e87a2 | 4099 | (display (message "Key `%s' not found" key))) |
02c8032e SM |
4100 | found) |
4101 | ||
19f0b8b5 | 4102 | (let* ((case-fold-search t) |
02c8032e SM |
4103 | (pnt (save-excursion |
4104 | (goto-char (or start (point-min))) | |
4105 | (if (re-search-forward (concat "^[ \t]*\\(" | |
4106 | bibtex-entry-type | |
4107 | "\\)[ \t]*[({][ \t\n]*\\(" | |
4108 | (regexp-quote key) | |
4109 | "\\)[ \t\n]*[,=]") | |
4110 | nil t) | |
4111 | (match-beginning 0))))) | |
4112 | (cond (pnt | |
d10e87a2 SM |
4113 | (goto-char pnt) |
4114 | (if display (bibtex-reposition-window))) | |
4115 | (display (message "Key `%s' not found" key))) | |
4116 | pnt))) | |
7af32e66 RW |
4117 | ;; backward compatibility |
4118 | (defalias 'bibtex-find-entry 'bibtex-search-entry) | |
7fbf4804 SM |
4119 | |
4120 | (defun bibtex-prepare-new-entry (index) | |
4121 | "Prepare a new BibTeX entry with index INDEX. | |
c48f463b | 4122 | INDEX is a list (KEY CROSSREF-KEY ENTRY-TYPE). |
7fbf4804 SM |
4123 | Move point where the entry KEY should be placed. |
4124 | If `bibtex-maintain-sorted-entries' is non-nil, perform a binary | |
d10e87a2 | 4125 | search to look for place for KEY. This requires that buffer is sorted, |
921a9483 | 4126 | see `bibtex-validate'. |
7fbf4804 | 4127 | Return t if preparation was successful or nil if entry KEY already exists." |
7a0574f3 | 4128 | (bibtex-init-sort-entry-class-alist) ; Needed by `bibtex-lessp'. |
65e10478 | 4129 | (if (and (eq bibtex-maintain-sorted-entries 'crossref) |
03db5e5f | 4130 | (functionp bibtex-reference-keys)) |
65e10478 | 4131 | (bibtex-parse-keys)) ; Needed by `bibtex-lessp'. |
7fbf4804 SM |
4132 | (let ((key (nth 0 index)) |
4133 | key-exist) | |
4134 | (cond ((or (null key) | |
4135 | (and (stringp key) | |
4136 | (string-equal key "")) | |
7af32e66 | 4137 | (and (not (setq key-exist (bibtex-search-entry key))) |
7fbf4804 SM |
4138 | (not bibtex-maintain-sorted-entries))) |
4139 | (bibtex-move-outside-of-entry)) | |
4140 | ;; if key-exist is non-nil due to the previous cond clause | |
4141 | ;; then point will be at beginning of entry named key. | |
4142 | (key-exist) | |
f2dfa899 | 4143 | (t ; `bibtex-maintain-sorted-entries' is non-nil |
7fbf4804 | 4144 | (let* ((case-fold-search t) |
cdc61d35 SM |
4145 | (left (save-excursion (bibtex-beginning-of-first-entry))) |
4146 | (bounds (save-excursion (goto-char (point-max)) | |
4147 | (bibtex-skip-to-valid-entry t))) | |
4148 | (right (if bounds (cdr bounds) (point-min))) | |
7fbf4804 SM |
4149 | (found (if (>= left right) left)) |
4150 | actual-index new) | |
4151 | (save-excursion | |
4152 | ;; Binary search | |
4153 | (while (not found) | |
4154 | (goto-char (/ (+ left right) 2)) | |
4155 | (bibtex-skip-to-valid-entry t) | |
4156 | (setq actual-index (bibtex-entry-index)) | |
4157 | (cond ((bibtex-lessp index actual-index) | |
4158 | (setq new (bibtex-beginning-of-entry)) | |
4159 | (if (equal right new) | |
4160 | (setq found right) | |
4161 | (setq right new))) | |
4162 | (t | |
4163 | (bibtex-end-of-entry) | |
4164 | (bibtex-skip-to-valid-entry) | |
4165 | (setq new (point)) | |
4166 | (if (equal left new) | |
4167 | (setq found right) | |
4168 | (setq left new)))))) | |
4169 | (goto-char found) | |
4170 | (bibtex-beginning-of-entry) | |
4171 | (setq actual-index (save-excursion (bibtex-entry-index))) | |
4172 | (when (or (not actual-index) | |
4173 | (bibtex-lessp actual-index index)) | |
4174 | ;; buffer contains no valid entries or | |
4175 | ;; greater than last entry --> append | |
4176 | (bibtex-end-of-entry) | |
d528bff7 | 4177 | (unless (bobp) (newline (forward-line 2))) |
7fbf4804 SM |
4178 | (beginning-of-line))))) |
4179 | (unless key-exist t))) | |
cb4ad359 | 4180 | |
50e4b39e RS |
4181 | (defun bibtex-validate (&optional test-thoroughly) |
4182 | "Validate if buffer or region is syntactically correct. | |
e0dc0c55 SM |
4183 | Check also for duplicate keys and correct sort order provided |
4184 | `bibtex-maintain-sorted-entries' is non-nil. | |
4185 | With optional argument TEST-THOROUGHLY non-nil check also for | |
4186 | the absence of required fields and for questionable month fields. | |
7fbf4804 | 4187 | If mark is active, validate current region, if not the whole buffer. |
e0dc0c55 SM |
4188 | Only check known entry types, so you can put comments outside of entries. |
4189 | Return t if test was successful, nil otherwise." | |
31bc4210 | 4190 | (interactive "P") |
7fbf4804 SM |
4191 | (let* ((case-fold-search t) |
4192 | error-list syntax-error) | |
4193 | (save-excursion | |
4194 | (save-restriction | |
ffc1e1db | 4195 | (if mark-active (narrow-to-region (region-beginning) (region-end))) |
7fbf4804 | 4196 | |
ffc1e1db | 4197 | ;; Check syntactical structure of entries |
7fbf4804 SM |
4198 | (goto-char (point-min)) |
4199 | (bibtex-progress-message "Checking syntactical structure") | |
ffc1e1db RW |
4200 | (let (bounds end) |
4201 | (while (setq end (re-search-forward "^[ \t]*@" nil t)) | |
7fbf4804 | 4202 | (bibtex-progress-message) |
ffc1e1db RW |
4203 | (goto-char (match-beginning 0)) |
4204 | (cond ((setq bounds (bibtex-valid-entry)) | |
4205 | (goto-char (cdr bounds))) | |
4206 | ((setq bounds (or (bibtex-parse-string) | |
4207 | (bibtex-parse-preamble))) | |
4208 | (goto-char (bibtex-end-of-string bounds))) | |
4209 | ((looking-at bibtex-any-valid-entry-type) | |
4210 | (push (cons (bibtex-current-line) | |
4211 | "Syntax error (check esp. commas, braces, and quotes)") | |
4212 | error-list) | |
4213 | (goto-char (match-end 0))) | |
4214 | (t (goto-char end))))) | |
7fbf4804 SM |
4215 | (bibtex-progress-message 'done) |
4216 | ||
4217 | (if error-list | |
ffc1e1db | 4218 | ;; Continue only if there were no syntax errors. |
7fbf4804 | 4219 | (setq syntax-error t) |
e0dc0c55 | 4220 | |
ffc1e1db | 4221 | ;; Check for duplicate keys and correct sort order |
65e10478 RW |
4222 | (bibtex-init-sort-entry-class-alist) ; Needed by `bibtex-lessp'. |
4223 | (bibtex-parse-keys) ; Possibly needed by `bibtex-lessp'. | |
4224 | ; Always needed by subsequent global key check. | |
e0dc0c55 SM |
4225 | (let (previous current key-list) |
4226 | (bibtex-progress-message "Checking for duplicate keys") | |
4227 | (bibtex-map-entries | |
a2a25d24 | 4228 | (lambda (key _beg _end) |
e0dc0c55 | 4229 | (bibtex-progress-message) |
e0dc0c55 SM |
4230 | (setq current (bibtex-entry-index)) |
4231 | (cond ((not previous)) | |
4232 | ((member key key-list) | |
4233 | (push (cons (bibtex-current-line) | |
4234 | (format "Duplicate key `%s'" key)) | |
4235 | error-list)) | |
4236 | ((and bibtex-maintain-sorted-entries | |
4237 | (not (bibtex-lessp previous current))) | |
4238 | (push (cons (bibtex-current-line) | |
4239 | "Entries out of order") | |
4240 | error-list))) | |
4241 | (push key key-list) | |
4242 | (setq previous current))) | |
4243 | (bibtex-progress-message 'done)) | |
4244 | ||
4245 | ;; Check for duplicate keys in `bibtex-files'. | |
65e10478 RW |
4246 | ;; `bibtex-validate' only compares keys in current buffer with keys |
4247 | ;; in `bibtex-files'. `bibtex-validate-globally' compares keys for | |
4248 | ;; each file in `bibtex-files' with keys of all other files in | |
4249 | ;; `bibtex-files'. | |
02c8032e | 4250 | ;; We don't want to be fooled by outdated `bibtex-reference-keys'. |
65e10478 | 4251 | (dolist (buffer (bibtex-initialize nil t)) |
02c8032e | 4252 | (dolist (key (with-current-buffer buffer bibtex-reference-keys)) |
e0dc0c55 SM |
4253 | (when (and (cdr key) |
4254 | (cdr (assoc-string (car key) bibtex-reference-keys))) | |
7af32e66 | 4255 | (bibtex-search-entry (car key)) |
e0dc0c55 SM |
4256 | (push (cons (bibtex-current-line) |
4257 | (format "Duplicate key `%s' in %s" (car key) | |
4258 | (abbreviate-file-name (buffer-file-name buffer)))) | |
4259 | error-list)))) | |
7fbf4804 SM |
4260 | |
4261 | (when test-thoroughly | |
7fbf4804 SM |
4262 | (bibtex-progress-message |
4263 | "Checking required fields and month fields") | |
d528bff7 | 4264 | (let ((bibtex-sort-ignore-string-entries t)) |
55fe21fc | 4265 | (bibtex-map-entries |
2de69e00 | 4266 | (lambda (_key beg end) |
50e4b39e | 4267 | (bibtex-progress-message) |
2de69e00 RW |
4268 | (bibtex-beginning-first-field beg) |
4269 | (let* ((beg-line (save-excursion (goto-char beg) | |
4270 | (bibtex-current-line))) | |
4271 | (entry-list (assoc-string (bibtex-type-in-head) | |
4272 | bibtex-entry-alist t)) | |
4273 | (crossref (bibtex-search-forward-field "crossref" end)) | |
4274 | (req (if crossref (copy-sequence (nth 2 entry-list)) | |
4275 | (append (nth 2 entry-list) | |
4276 | (copy-sequence (nth 3 entry-list))))) | |
4277 | (num-alt (length (delq nil (delete-dups | |
4278 | (mapcar (lambda (x) (nth 3 x)) | |
4279 | req))))) | |
4280 | (alt-fields (make-vector num-alt nil)) | |
4281 | bounds field idx) | |
ffc1e1db | 4282 | (while (setq bounds (bibtex-parse-field)) |
d528bff7 SM |
4283 | (let ((field-name (bibtex-name-in-field bounds))) |
4284 | (if (and (bibtex-string= field-name "month") | |
e0dc0c55 SM |
4285 | ;; Check only abbreviated month fields. |
4286 | (let ((month (bibtex-text-in-field-bounds bounds))) | |
4287 | (not (or (string-match "\\`[\"{].+[\"}]\\'" month) | |
4288 | (assoc-string | |
4289 | month | |
4290 | bibtex-predefined-month-strings t))))) | |
4291 | (push (cons (bibtex-current-line) | |
7fbf4804 SM |
4292 | "Questionable month field") |
4293 | error-list)) | |
ffc1e1db | 4294 | (setq field (assoc-string field-name req t) |
2de69e00 RW |
4295 | req (delete field req)) |
4296 | (if (setq idx (nth 3 field)) | |
4297 | (if (aref alt-fields idx) | |
ffc1e1db RW |
4298 | (push (cons (bibtex-current-line) |
4299 | "More than one non-empty alternative") | |
4300 | error-list) | |
2de69e00 | 4301 | (aset alt-fields idx t)))) |
ffc1e1db | 4302 | (goto-char (bibtex-end-of-field bounds))) |
2de69e00 RW |
4303 | (let ((alt-expect (make-vector num-alt nil))) |
4304 | (dolist (field req) ; absent required fields | |
4305 | (if (setq idx (nth 3 field)) | |
4306 | (bibtex-vec-push alt-expect idx (car field)) | |
4307 | (push (cons beg-line | |
e0dc0c55 SM |
4308 | (format "Required field `%s' missing" |
4309 | (car field))) | |
4310 | error-list))) | |
2de69e00 RW |
4311 | (dotimes (idx num-alt) |
4312 | (unless (aref alt-fields idx) | |
4313 | (push (cons beg-line | |
4314 | (format "Alternative fields `%s' missing" | |
4315 | (aref alt-expect idx))) | |
4316 | error-list)))))))) | |
7fbf4804 | 4317 | (bibtex-progress-message 'done))))) |
e0dc0c55 | 4318 | |
50e4b39e | 4319 | (if error-list |
e0dc0c55 SM |
4320 | (let ((file (file-name-nondirectory (buffer-file-name))) |
4321 | (dir default-directory) | |
4322 | (err-buf "*BibTeX validation errors*")) | |
4323 | (setq error-list (sort error-list 'car-less-than-car)) | |
4324 | (with-current-buffer (get-buffer-create err-buf) | |
4325 | (setq default-directory dir) | |
4326 | (unless (eq major-mode 'compilation-mode) (compilation-mode)) | |
d2ce10d2 GM |
4327 | (let ((inhibit-read-only t)) |
4328 | (delete-region (point-min) (point-max)) | |
4329 | (insert "BibTeX mode command `bibtex-validate'\n" | |
4330 | (if syntax-error | |
4331 | "Maybe undetected errors due to syntax errors. \ | |
4332 | Correct and validate again.\n" | |
4333 | "\n")) | |
4334 | (dolist (err error-list) | |
4335 | (insert (format "%s:%d: %s\n" file (car err) (cdr err)))) | |
4336 | (set-buffer-modified-p nil)) | |
5f68c1b7 GM |
4337 | (goto-char (point-min)) |
4338 | (forward-line 2)) ; first error message | |
e0dc0c55 | 4339 | (display-buffer err-buf) |
ffc1e1db | 4340 | nil) ; return `nil' (i.e., buffer is invalid) |
e0dc0c55 SM |
4341 | (message "%s is syntactically correct" |
4342 | (if mark-active "Region" "Buffer")) | |
ffc1e1db | 4343 | t))) ; return `t' (i.e., buffer is valid) |
e0dc0c55 SM |
4344 | |
4345 | (defun bibtex-validate-globally (&optional strings) | |
4346 | "Check for duplicate keys in `bibtex-files'. | |
02c8032e | 4347 | With optional prefix arg STRINGS, check for duplicate strings, too. |
e0dc0c55 SM |
4348 | Return t if test was successful, nil otherwise." |
4349 | (interactive "P") | |
65e10478 | 4350 | (let ((buffer-list (bibtex-initialize t)) |
e0dc0c55 SM |
4351 | buffer-key-list current-buf current-keys error-list) |
4352 | ;; Check for duplicate keys within BibTeX buffer | |
4353 | (dolist (buffer buffer-list) | |
9a529312 | 4354 | (with-current-buffer buffer |
004dedd3 RW |
4355 | (save-excursion |
4356 | (let (entry-type key key-list) | |
4357 | (goto-char (point-min)) | |
4358 | (while (re-search-forward bibtex-entry-head nil t) | |
4359 | (setq entry-type (bibtex-type-in-head) | |
4360 | key (bibtex-key-in-head)) | |
4361 | (if (or (and strings (bibtex-string= entry-type "string")) | |
2de69e00 | 4362 | (assoc-string entry-type bibtex-entry-alist t)) |
004dedd3 RW |
4363 | (if (member key key-list) |
4364 | (push (format "%s:%d: Duplicate key `%s'\n" | |
4365 | (buffer-file-name) | |
4366 | (bibtex-current-line) key) | |
4367 | error-list) | |
4368 | (push key key-list)))) | |
4369 | (push (cons buffer key-list) buffer-key-list))))) | |
e0dc0c55 SM |
4370 | |
4371 | ;; Check for duplicate keys among BibTeX buffers | |
4372 | (while (setq current-buf (pop buffer-list)) | |
4373 | (setq current-keys (cdr (assq current-buf buffer-key-list))) | |
4374 | (with-current-buffer current-buf | |
4375 | (dolist (buffer buffer-list) | |
4376 | (dolist (key (cdr (assq buffer buffer-key-list))) | |
4377 | (when (assoc-string key current-keys) | |
7af32e66 | 4378 | (bibtex-search-entry key) |
24ee740d | 4379 | (push (format "%s:%d: Duplicate key `%s' in %s\n" |
e0dc0c55 SM |
4380 | (buffer-file-name) (bibtex-current-line) key |
4381 | (abbreviate-file-name (buffer-file-name buffer))) | |
4382 | error-list)))))) | |
4383 | ||
4384 | ;; Process error list | |
4385 | (if error-list | |
4386 | (let ((err-buf "*BibTeX validation errors*")) | |
4387 | (with-current-buffer (get-buffer-create err-buf) | |
4388 | (unless (eq major-mode 'compilation-mode) (compilation-mode)) | |
d2ce10d2 GM |
4389 | (let ((inhibit-read-only t)) |
4390 | (delete-region (point-min) (point-max)) | |
4391 | (insert "BibTeX mode command `bibtex-validate-globally'\n\n") | |
4392 | (dolist (err (sort error-list 'string-lessp)) (insert err)) | |
4393 | (set-buffer-modified-p nil)) | |
5f68c1b7 GM |
4394 | (goto-char (point-min)) |
4395 | (forward-line 2)) ; first error message | |
e0dc0c55 | 4396 | (display-buffer err-buf) |
ffc1e1db | 4397 | nil) ; return `nil' (i.e., buffer is invalid) |
e0dc0c55 | 4398 | (message "No duplicate keys.") |
ffc1e1db RW |
4399 | t))) ; return `t' (i.e., buffer is valid) |
4400 | ||
4401 | (defun bibtex-next-field (begin &optional comma) | |
4402 | "Move point to end of text of next BibTeX field or entry head. | |
4403 | With prefix BEGIN non-nil, move point to its beginning. Optional arg COMMA | |
4404 | is as in `bibtex-enclosing-field'. It is t for interactive calls." | |
4405 | (interactive (list current-prefix-arg t)) | |
4406 | (let ((bounds (bibtex-find-text-internal t nil comma)) | |
4407 | end-of-entry) | |
4408 | (if (not bounds) | |
4409 | (setq end-of-entry t) | |
4410 | (goto-char (nth 3 bounds)) | |
4411 | (if (assoc-string (car bounds) '("@String" "@Preamble") t) | |
4412 | (setq end-of-entry t) | |
4413 | ;; BibTeX key or field | |
4414 | (if (looking-at ",[ \t\n]*") (goto-char (match-end 0))) | |
4415 | ;; end of entry | |
4416 | (if (looking-at "[)}][ \t\n]*") (setq end-of-entry t)))) | |
4417 | (if (and end-of-entry | |
4418 | (re-search-forward bibtex-any-entry-maybe-empty-head nil t)) | |
4419 | (goto-char (match-beginning 0))) | |
4420 | (bibtex-find-text begin nil bibtex-help-message))) | |
4421 | ||
4422 | (defun bibtex-find-text (&optional begin noerror help comma) | |
4423 | "Move point to end of text of current BibTeX field or entry head. | |
02c8032e SM |
4424 | With optional prefix BEGIN non-nil, move point to its beginning. |
4425 | Unless NOERROR is non-nil, an error is signaled if point is not | |
cdc61d35 | 4426 | on a BibTeX field. If optional arg HELP is non-nil print help message. |
ffc1e1db RW |
4427 | When called interactively, the value of HELP is `bibtex-help-message'. |
4428 | Optional arg COMMA is as in `bibtex-enclosing-field'. It is t for | |
4429 | interactive calls." | |
4430 | (interactive (list current-prefix-arg nil bibtex-help-message t)) | |
4431 | (let ((bounds (bibtex-find-text-internal t nil comma))) | |
02c8032e SM |
4432 | (cond (bounds |
4433 | (if begin | |
cdc61d35 | 4434 | (progn (goto-char (nth 1 bounds)) |
02c8032e SM |
4435 | (if (looking-at "[{\"]") |
4436 | (forward-char))) | |
cdc61d35 SM |
4437 | (goto-char (nth 2 bounds)) |
4438 | (if (memq (preceding-char) '(?} ?\")) | |
02c8032e | 4439 | (forward-char -1))) |
ffc1e1db RW |
4440 | (if help (bibtex-print-help-message (car bounds)))) |
4441 | ((not noerror) (error "Not on BibTeX field"))))) | |
50e4b39e | 4442 | |
ffc1e1db RW |
4443 | (defun bibtex-find-text-internal (&optional noerror subfield comma) |
4444 | "Find text part of current BibTeX field or entry head. | |
c48f463b RW |
4445 | Return list (NAME START-TEXT END-TEXT END STRING-CONST) with field name |
4446 | or entry type, start and end of text, and end of field or entry head. | |
ba7e3f51 RW |
4447 | STRING-CONST is a flag which is non-nil if current subfield delimited by # |
4448 | is a BibTeX string constant. Return value is nil if field or entry head | |
4449 | are not found. | |
4450 | If optional arg NOERROR is non-nil, an error message is suppressed | |
4451 | if text is not found. If optional arg SUBFIELD is non-nil START-TEXT | |
4452 | and END-TEXT correspond to the current subfield delimited by #. | |
ffc1e1db | 4453 | Optional arg COMMA is as in `bibtex-enclosing-field'." |
cdc61d35 SM |
4454 | (save-excursion |
4455 | (let ((pnt (point)) | |
ffc1e1db | 4456 | (bounds (bibtex-enclosing-field comma t)) |
cdc61d35 | 4457 | (case-fold-search t) |
ba7e3f51 | 4458 | name start-text end-text end failure done no-sub string-const) |
cdc61d35 SM |
4459 | (bibtex-beginning-of-entry) |
4460 | (cond (bounds | |
4461 | (setq name (bibtex-name-in-field bounds t) | |
ffc1e1db RW |
4462 | start-text (bibtex-start-of-text-in-field bounds) |
4463 | end-text (bibtex-end-of-text-in-field bounds) | |
4464 | end (bibtex-end-of-field bounds))) | |
cdc61d35 | 4465 | ;; @String |
ffc1e1db RW |
4466 | ((setq bounds (bibtex-parse-string t)) |
4467 | (if (<= pnt (bibtex-end-of-string bounds)) | |
4468 | (setq name "@String" ;; not a field name! | |
4469 | start-text (bibtex-start-of-text-in-string bounds) | |
4470 | end-text (bibtex-end-of-text-in-string bounds) | |
4471 | end (bibtex-end-of-string bounds)) | |
4472 | (setq failure t))) | |
cdc61d35 | 4473 | ;; @Preamble |
ffc1e1db RW |
4474 | ((setq bounds (bibtex-parse-preamble)) |
4475 | (if (<= pnt (bibtex-end-of-string bounds)) | |
4476 | (setq name "@Preamble" ;; not a field name! | |
4477 | start-text (bibtex-start-of-text-in-string bounds) | |
4478 | end-text (bibtex-end-of-text-in-string bounds) | |
4479 | end (bibtex-end-of-string bounds)) | |
4480 | (setq failure t))) | |
4481 | ;; BibTeX head | |
4482 | ((looking-at bibtex-entry-maybe-empty-head) | |
4483 | (goto-char (match-end 0)) | |
4484 | (if comma (save-match-data | |
4485 | (re-search-forward "\\=[ \t\n]*," nil t))) | |
4486 | (if (<= pnt (point)) | |
4487 | (setq name (match-string-no-properties bibtex-type-in-head) | |
4488 | start-text (or (match-beginning bibtex-key-in-head) | |
4489 | (match-end 0)) | |
4490 | end-text (or (match-end bibtex-key-in-head) | |
4491 | (match-end 0)) | |
4492 | end end-text | |
f2dfa899 | 4493 | no-sub t) ; subfields do not make sense |
ffc1e1db RW |
4494 | (setq failure t))) |
4495 | (t (setq failure t))) | |
4496 | (when (and subfield (not failure)) | |
4497 | (setq failure no-sub) | |
4498 | (unless failure | |
4499 | (goto-char start-text) | |
cdc61d35 SM |
4500 | (while (not done) |
4501 | (if (or (prog1 (looking-at bibtex-field-const) | |
ba7e3f51 RW |
4502 | (setq end-text (match-end 0) |
4503 | string-const t)) | |
cdc61d35 | 4504 | (prog1 (setq bounds (bibtex-parse-field-string)) |
ba7e3f51 RW |
4505 | (setq end-text (cdr bounds) |
4506 | string-const nil))) | |
cdc61d35 | 4507 | (progn |
ffc1e1db | 4508 | (if (and (<= start-text pnt) (<= pnt end-text)) |
cdc61d35 | 4509 | (setq done t) |
ffc1e1db | 4510 | (goto-char end-text)) |
cdc61d35 | 4511 | (if (looking-at "[ \t\n]*#[ \t\n]*") |
ffc1e1db RW |
4512 | (setq start-text (goto-char (match-end 0))))) |
4513 | (setq done t failure t))))) | |
4514 | (cond ((not failure) | |
ba7e3f51 | 4515 | (list name start-text end-text end string-const)) |
ffc1e1db RW |
4516 | ((and no-sub (not noerror)) |
4517 | (error "Not on text part of BibTeX field")) | |
4518 | ((not noerror) (error "Not on BibTeX field")))))) | |
4519 | ||
4520 | (defun bibtex-remove-OPT-or-ALT (&optional comma) | |
7fbf4804 | 4521 | "Remove the string starting optional/alternative fields. |
ffc1e1db RW |
4522 | Align text and go thereafter to end of text. Optional arg COMMA |
4523 | is as in `bibtex-enclosing-field'. It is t for interactive calls." | |
4524 | (interactive (list t)) | |
7fbf4804 | 4525 | (let ((case-fold-search t) |
ffc1e1db | 4526 | (bounds (bibtex-enclosing-field comma))) |
50e4b39e | 4527 | (save-excursion |
f9bd4abe | 4528 | (goto-char (bibtex-start-of-name-in-field bounds)) |
2de69e00 RW |
4529 | (when (and (looking-at "OPT\\|ALT") |
4530 | (not (and bibtex-no-opt-remove-re | |
4531 | (string-match | |
4532 | bibtex-no-opt-remove-re | |
4533 | (buffer-substring-no-properties | |
4534 | (bibtex-start-of-name-in-field bounds) | |
4535 | (bibtex-end-of-name-in-field bounds)))))) | |
d715b065 | 4536 | (delete-region (match-beginning 0) (match-end 0)) |
7fbf4804 SM |
4537 | ;; make field non-OPT |
4538 | (search-forward "=") | |
4539 | (forward-char -1) | |
4540 | (delete-horizontal-space) | |
4541 | (if bibtex-align-at-equal-sign | |
4542 | (indent-to-column (- bibtex-text-indentation 2)) | |
4543 | (insert " ")) | |
4544 | (search-forward "=") | |
4545 | (delete-horizontal-space) | |
4546 | (if bibtex-align-at-equal-sign | |
4547 | (insert " ") | |
ffc1e1db RW |
4548 | (indent-to-column bibtex-text-indentation)))))) |
4549 | ||
4550 | (defun bibtex-remove-delimiters (&optional comma) | |
4551 | "Remove \"\" or {} around current BibTeX field text. | |
4552 | Optional arg COMMA is as in `bibtex-enclosing-field'. It is t for | |
4553 | interactive calls." | |
4554 | (interactive (list t)) | |
ba7e3f51 RW |
4555 | (let ((bounds (bibtex-find-text-internal nil t comma))) |
4556 | (unless (nth 4 bounds) | |
4557 | (delete-region (1- (nth 2 bounds)) (nth 2 bounds)) | |
4558 | (delete-region (nth 1 bounds) (1+ (nth 1 bounds)))))) | |
50e4b39e | 4559 | |
ffc1e1db | 4560 | (defun bibtex-kill-field (&optional copy-only comma) |
7fbf4804 SM |
4561 | "Kill the entire enclosing BibTeX field. |
4562 | With prefix arg COPY-ONLY, copy the current field to `bibtex-field-kill-ring', | |
ffc1e1db RW |
4563 | but do not actually kill it. Optional arg COMMA is as in |
4564 | `bibtex-enclosing-field'. It is t for interactive calls." | |
4565 | (interactive (list current-prefix-arg t)) | |
7fbf4804 | 4566 | (save-excursion |
7fbf4804 | 4567 | (let* ((case-fold-search t) |
ffc1e1db | 4568 | (bounds (bibtex-enclosing-field comma)) |
7fbf4804 SM |
4569 | (end (bibtex-end-of-field bounds)) |
4570 | (beg (bibtex-start-of-field bounds))) | |
4571 | (goto-char end) | |
403111a8 RW |
4572 | ;; Preserve white space at end of BibTeX entry |
4573 | (if (looking-at "[ \t\n]*[)}]") | |
4574 | (progn (skip-chars-backward " \t\n") | |
4575 | (setq end (point))) | |
4576 | (skip-chars-forward ",")) | |
02c8032e | 4577 | (push (list (bibtex-name-in-field bounds) nil |
7fbf4804 SM |
4578 | (bibtex-text-in-field-bounds bounds)) |
4579 | bibtex-field-kill-ring) | |
50e4b39e | 4580 | (if (> (length bibtex-field-kill-ring) bibtex-field-kill-ring-max) |
7fbf4804 SM |
4581 | (setcdr (nthcdr (1- bibtex-field-kill-ring-max) |
4582 | bibtex-field-kill-ring) | |
4583 | nil)) | |
50e4b39e | 4584 | (setq bibtex-field-kill-ring-yank-pointer bibtex-field-kill-ring) |
7fbf4804 SM |
4585 | (unless copy-only |
4586 | (delete-region beg end)))) | |
50e4b39e RS |
4587 | (setq bibtex-last-kill-command 'field)) |
4588 | ||
ffc1e1db | 4589 | (defun bibtex-copy-field-as-kill (&optional comma) |
38934f76 | 4590 | "Copy the BibTeX field at point to `bibtex-field-kill-ring'. |
ffc1e1db RW |
4591 | Optional arg COMMA is as in `bibtex-enclosing-field'. It is t for |
4592 | interactive calls." | |
4593 | (interactive (list t)) | |
4594 | (bibtex-kill-field t comma)) | |
745bc783 | 4595 | |
50e4b39e | 4596 | (defun bibtex-kill-entry (&optional copy-only) |
f9bd4abe | 4597 | "Kill the entire enclosing BibTeX entry. |
02c8032e SM |
4598 | With prefix arg COPY-ONLY, copy the current entry to `bibtex-entry-kill-ring', |
4599 | but do not actually kill it." | |
50e4b39e | 4600 | (interactive "P") |
7fbf4804 SM |
4601 | (save-excursion |
4602 | (let* ((case-fold-search t) | |
4603 | (beg (bibtex-beginning-of-entry)) | |
403111a8 RW |
4604 | (key (progn (looking-at bibtex-any-entry-maybe-empty-head) |
4605 | (bibtex-key-in-head))) | |
7fbf4804 SM |
4606 | (end (progn (bibtex-end-of-entry) |
4607 | (if (re-search-forward | |
ffc1e1db | 4608 | bibtex-any-entry-maybe-empty-head nil 'move) |
7fbf4804 SM |
4609 | (goto-char (match-beginning 0))) |
4610 | (point)))) | |
02c8032e | 4611 | (push (buffer-substring-no-properties beg end) |
7fbf4804 SM |
4612 | bibtex-entry-kill-ring) |
4613 | (if (> (length bibtex-entry-kill-ring) bibtex-entry-kill-ring-max) | |
4614 | (setcdr (nthcdr (1- bibtex-entry-kill-ring-max) | |
4615 | bibtex-entry-kill-ring) | |
4616 | nil)) | |
e0dc0c55 SM |
4617 | (setq bibtex-entry-kill-ring-yank-pointer bibtex-entry-kill-ring) |
4618 | (unless copy-only | |
403111a8 RW |
4619 | (delete-region beg end) |
4620 | ;; remove key from `bibtex-reference-keys'. | |
4621 | (unless (functionp bibtex-reference-keys) | |
4622 | (setq bibtex-reference-keys | |
4623 | (delete (cons key t) bibtex-reference-keys)))))) | |
50e4b39e RS |
4624 | (setq bibtex-last-kill-command 'entry)) |
4625 | ||
4626 | (defun bibtex-copy-entry-as-kill () | |
d528bff7 | 4627 | "Copy the entire enclosing BibTeX entry to `bibtex-entry-kill-ring'." |
745bc783 | 4628 | (interactive) |
50e4b39e RS |
4629 | (bibtex-kill-entry t)) |
4630 | ||
4631 | (defun bibtex-yank (&optional n) | |
4632 | "Reinsert the last BibTeX item. | |
4633 | More precisely, reinsert the field or entry killed or yanked most recently. | |
4634 | With argument N, reinsert the Nth most recently killed BibTeX item. | |
921a9483 | 4635 | See also the command \\[bibtex-yank-pop]." |
50e4b39e | 4636 | (interactive "*p") |
004dedd3 | 4637 | (unless n (setq n 1)) |
ffc1e1db | 4638 | (bibtex-insert-kill (1- n) t) |
f0cb6034 | 4639 | (setq this-command 'bibtex-yank)) |
50e4b39e RS |
4640 | |
4641 | (defun bibtex-yank-pop (n) | |
02c8032e | 4642 | "Replace just-yanked killed BibTeX item with a different item. |
50e4b39e | 4643 | This command is allowed only immediately after a `bibtex-yank' or a |
ffc1e1db | 4644 | `bibtex-yank-pop'. In this case, the region contains a reinserted |
02c8032e SM |
4645 | previously killed BibTeX item. `bibtex-yank-pop' deletes that item |
4646 | and inserts in its place a different killed BibTeX item. | |
50e4b39e RS |
4647 | |
4648 | With no argument, the previous kill is inserted. | |
4649 | With argument N, insert the Nth previous kill. | |
4650 | If N is negative, this is a more recent kill. | |
4651 | ||
4652 | The sequence of kills wraps around, so that after the oldest one | |
4653 | comes the newest one." | |
4654 | (interactive "*p") | |
d528bff7 SM |
4655 | (unless (eq last-command 'bibtex-yank) |
4656 | (error "Previous command was not a BibTeX yank")) | |
50e4b39e | 4657 | (setq this-command 'bibtex-yank) |
403111a8 RW |
4658 | (let ((inhibit-read-only t) key) |
4659 | ;; point is at end of yanked entry | |
4660 | (unless (functionp bibtex-reference-keys) | |
4661 | ;; remove key of yanked entry from `bibtex-reference-keys' | |
4662 | (save-excursion | |
4663 | (goto-char (mark t)) | |
4664 | (if (and (looking-at bibtex-any-entry-maybe-empty-head) | |
4665 | (setq key (bibtex-key-in-head))) | |
4666 | (setq bibtex-reference-keys | |
4667 | (delete (cons key t) bibtex-reference-keys))))) | |
50e4b39e | 4668 | (delete-region (point) (mark t)) |
ffc1e1db RW |
4669 | (bibtex-insert-kill n t))) |
4670 | ||
4671 | (defun bibtex-empty-field (&optional comma) | |
4672 | "Delete the text part of the current field, replace with empty text. | |
4673 | Optional arg COMMA is as in `bibtex-enclosing-field'. It is t for | |
4674 | interactive calls." | |
4675 | (interactive (list t)) | |
4676 | (let ((bounds (bibtex-enclosing-field comma))) | |
f9bd4abe GM |
4677 | (goto-char (bibtex-start-of-text-in-field bounds)) |
4678 | (delete-region (point) (bibtex-end-of-text-in-field bounds)) | |
cdc61d35 SM |
4679 | (insert (bibtex-field-left-delimiter) |
4680 | (bibtex-field-right-delimiter)) | |
4681 | (bibtex-find-text t nil bibtex-help-message))) | |
745bc783 | 4682 | |
31bc4210 | 4683 | (defun bibtex-pop-previous (arg) |
d0388eac | 4684 | "Replace text of current field with the similar field in previous entry. |
f0cb6034 | 4685 | With arg, goes up ARG entries. Repeated, goes up so many times. May be |
31bc4210 RS |
4686 | intermixed with \\[bibtex-pop-next] (bibtex-pop-next)." |
4687 | (interactive "p") | |
4688 | (bibtex-pop arg 'previous)) | |
745bc783 JB |
4689 | |
4690 | (defun bibtex-pop-next (arg) | |
4691 | "Replace text of current field with the text of similar field in next entry. | |
f0cb6034 | 4692 | With arg, goes down ARG entries. Repeated, goes down so many times. May be |
745bc783 JB |
4693 | intermixed with \\[bibtex-pop-previous] (bibtex-pop-previous)." |
4694 | (interactive "p") | |
31bc4210 | 4695 | (bibtex-pop arg 'next)) |
745bc783 | 4696 | |
7fbf4804 | 4697 | (defun bibtex-clean-entry (&optional new-key called-by-reformat) |
cb4ad359 | 4698 | "Finish editing the current BibTeX entry and clean it up. |
e56d3af5 | 4699 | Check that no required fields are empty and format entry dependent |
7fbf4804 | 4700 | on the value of `bibtex-entry-format'. |
f9bd4abe | 4701 | If the reference key of the entry is empty or a prefix argument is given, |
d10e87a2 | 4702 | calculate a new reference key. (Note: this works only if fields in entry |
7fbf4804 SM |
4703 | begin on separate lines prior to calling `bibtex-clean-entry' or if |
4704 | 'realign is contained in `bibtex-entry-format'.) | |
d715b065 | 4705 | Don't call `bibtex-clean-entry' on @Preamble entries. |
50e4b39e | 4706 | At end of the cleaning process, the functions in |
7fbf4804 | 4707 | `bibtex-clean-entry-hook' are called with region narrowed to entry." |
f2dfa899 RW |
4708 | ;; Opt. arg CALLED-BY-REFORMAT is t if `bibtex-clean-entry' |
4709 | ;; is called by `bibtex-reformat' | |
cb4ad359 | 4710 | (interactive "P") |
7fbf4804 | 4711 | (let ((case-fold-search t) |
02c8032e | 4712 | (start (bibtex-beginning-of-entry)) |
8e6ea7a3 SM |
4713 | (_ (or (looking-at bibtex-any-entry-maybe-empty-head) |
4714 | (error "Not inside a BibTeX entry"))) | |
02c8032e SM |
4715 | (entry-type (bibtex-type-in-head)) |
4716 | (key (bibtex-key-in-head))) | |
7af32e66 RW |
4717 | (cond ((bibtex-string= entry-type "preamble") |
4718 | ;; (bibtex-format-preamble) | |
4719 | (error "No clean up of @Preamble entries")) | |
4720 | ((bibtex-string= entry-type "string") | |
4721 | (setq entry-type 'string)) | |
4722 | ;; (bibtex-format-string) | |
4723 | (t (bibtex-format-entry))) | |
d715b065 | 4724 | ;; set key |
297dde5a RW |
4725 | (if (or new-key (not key)) |
4726 | (save-excursion | |
4727 | ;; First delete the old key so that a customized algorithm | |
4728 | ;; for generating the new key does not get confused by the | |
4729 | ;; old key. | |
4730 | (re-search-forward (if (eq entry-type 'string) | |
4731 | bibtex-string-maybe-empty-head | |
4732 | bibtex-entry-maybe-empty-head)) | |
4733 | (if (match-beginning bibtex-key-in-head) | |
4734 | (delete-region (match-beginning bibtex-key-in-head) | |
4735 | (match-end bibtex-key-in-head))) | |
4736 | (setq key (bibtex-generate-autokey)) | |
4737 | ;; Sometimes `bibtex-generate-autokey' returns an empty string | |
4738 | (if (or bibtex-autokey-edit-before-use (string= "" key)) | |
4739 | (setq key (if (eq entry-type 'string) | |
4740 | (bibtex-read-string-key key) | |
4741 | (bibtex-read-key "Key to use: " key)))) | |
4742 | (insert key))) | |
e0dc0c55 | 4743 | |
4f9ae122 | 4744 | (unless called-by-reformat |
02c8032e SM |
4745 | (let* ((end (save-excursion |
4746 | (bibtex-end-of-entry) | |
4747 | (if (re-search-forward | |
4748 | bibtex-entry-maybe-empty-head nil 'move) | |
4749 | (goto-char (match-beginning 0))) | |
4750 | (point))) | |
4f9ae122 | 4751 | (entry (buffer-substring start end)) |
e0dc0c55 SM |
4752 | ;; include the crossref key in index |
4753 | (index (let ((bibtex-maintain-sorted-entries 'crossref)) | |
02c8032e | 4754 | (bibtex-entry-index))) ; moves point to end of head |
d528bff7 | 4755 | error) |
e0dc0c55 | 4756 | ;; sorting |
4f9ae122 SM |
4757 | (if (and bibtex-maintain-sorted-entries |
4758 | (not (and bibtex-sort-ignore-string-entries | |
02c8032e | 4759 | (eq entry-type 'string)))) |
4f9ae122 SM |
4760 | (progn |
4761 | (delete-region start end) | |
02c8032e SM |
4762 | (setq error (not (bibtex-prepare-new-entry index)) |
4763 | start (point)) ; update start | |
4764 | (save-excursion (insert entry))) | |
7af32e66 | 4765 | (bibtex-search-entry key) |
d528bff7 | 4766 | (setq error (or (/= (point) start) |
7af32e66 | 4767 | (bibtex-search-entry key nil end)))) |
d528bff7 | 4768 | (if error |
e0dc0c55 | 4769 | (error "New inserted entry yields duplicate key")) |
65e10478 | 4770 | (dolist (buffer (bibtex-initialize)) |
e0dc0c55 SM |
4771 | (with-current-buffer buffer |
4772 | (if (cdr (assoc-string key bibtex-reference-keys)) | |
4773 | (error "Duplicate key in %s" (buffer-file-name))))) | |
4774 | ||
03db5e5f RW |
4775 | ;; Only update `bibtex-strings' and `bibtex-reference-keys' |
4776 | ;; if they have been built already. | |
02c8032e | 4777 | (cond ((eq entry-type 'string) |
03db5e5f RW |
4778 | ;; We have a @String entry. |
4779 | (unless (or (functionp bibtex-strings) | |
4780 | (assoc key bibtex-strings)) | |
4781 | (push (cons key (bibtex-text-in-string | |
4782 | (bibtex-parse-string) t)) | |
4783 | bibtex-strings))) | |
e0dc0c55 | 4784 | ;; We have a normal entry. |
03db5e5f RW |
4785 | ((not (functionp bibtex-reference-keys)) |
4786 | (let ((found (assoc key bibtex-reference-keys))) | |
4787 | (cond ((not found) | |
4788 | (push (cons key t) bibtex-reference-keys)) | |
4789 | ((not (cdr found)) | |
4790 | ;; Turn a crossref key into a header key | |
4791 | (setq bibtex-reference-keys | |
4792 | (cons (cons key t) | |
4793 | (delete (list key) bibtex-reference-keys)))))) | |
4794 | ;; If entry has a crossref key, it goes into the list | |
4795 | ;; `bibtex-reference-keys', too. | |
e0dc0c55 SM |
4796 | (if (and (nth 1 index) |
4797 | (not (assoc (nth 1 index) bibtex-reference-keys))) | |
4798 | (push (list (nth 1 index)) bibtex-reference-keys))))) | |
4799 | ||
4800 | ;; final clean up | |
4801 | (if bibtex-clean-entry-hook | |
4802 | (save-excursion | |
4803 | (save-restriction | |
4804 | (bibtex-narrow-to-entry) | |
4805 | (run-hooks 'bibtex-clean-entry-hook))))))) | |
50e4b39e | 4806 | |
d715b065 KG |
4807 | (defun bibtex-fill-field-bounds (bounds justify &optional move) |
4808 | "Fill BibTeX field delimited by BOUNDS. | |
4809 | If JUSTIFY is non-nil justify as well. | |
4810 | If optional arg MOVE is non-nil move point to end of field." | |
4811 | (let ((end-field (copy-marker (bibtex-end-of-field bounds)))) | |
ffc1e1db RW |
4812 | (if (not justify) |
4813 | (goto-char (bibtex-start-of-text-in-field bounds)) | |
4814 | (goto-char (bibtex-start-of-field bounds)) | |
f2dfa899 | 4815 | (forward-char) ; leading comma |
ffc1e1db | 4816 | (bibtex-delete-whitespace) |
5767d190 | 4817 | (insert "\n") |
ffc1e1db RW |
4818 | (indent-to-column (+ bibtex-entry-offset |
4819 | bibtex-field-indentation)) | |
4820 | (re-search-forward "[ \t\n]*=" end-field) | |
4821 | (replace-match "=") | |
4822 | (forward-char -1) | |
4823 | (if bibtex-align-at-equal-sign | |
4824 | (indent-to-column | |
4825 | (+ bibtex-entry-offset (- bibtex-text-indentation 2))) | |
4826 | (insert " ")) | |
4827 | (forward-char) | |
4828 | (bibtex-delete-whitespace) | |
4829 | (if bibtex-align-at-equal-sign | |
4830 | (insert " ") | |
4831 | (indent-to-column bibtex-text-indentation))) | |
f2dfa899 | 4832 | ;; Paragraphs within fields are not preserved. Bother? |
1fdecd0c RF |
4833 | (fill-region-as-paragraph (line-beginning-position) end-field |
4834 | default-justification nil (point)) | |
d715b065 KG |
4835 | (if move (goto-char end-field)))) |
4836 | ||
4837 | (defun bibtex-fill-field (&optional justify) | |
4838 | "Like \\[fill-paragraph], but fill current BibTeX field. | |
ffc1e1db | 4839 | If optional prefix JUSTIFY is non-nil justify as well. |
d715b065 KG |
4840 | In BibTeX mode this function is bound to `fill-paragraph-function'." |
4841 | (interactive "*P") | |
4842 | (let ((pnt (copy-marker (point))) | |
ffc1e1db RW |
4843 | (bounds (bibtex-enclosing-field t))) |
4844 | (bibtex-fill-field-bounds bounds justify) | |
4845 | (goto-char pnt))) | |
d715b065 | 4846 | |
50e4b39e | 4847 | (defun bibtex-fill-entry () |
7fbf4804 SM |
4848 | "Fill current BibTeX entry. |
4849 | Realign entry, so that every field starts on a separate line. Field | |
d0388eac | 4850 | names appear in column `bibtex-field-indentation', field text starts in |
f0cb6034 | 4851 | column `bibtex-text-indentation' and continuation lines start here, too. |
d715b065 | 4852 | If `bibtex-align-at-equal-sign' is non-nil, align equal signs, too." |
50e4b39e RS |
4853 | (interactive "*") |
4854 | (let ((pnt (copy-marker (point))) | |
ffc1e1db | 4855 | (beg (bibtex-beginning-of-entry)) ; move point |
7fbf4804 | 4856 | bounds) |
55fe21fc | 4857 | (bibtex-delete-whitespace) |
50e4b39e | 4858 | (indent-to-column bibtex-entry-offset) |
ffc1e1db RW |
4859 | (bibtex-beginning-first-field beg) |
4860 | (while (setq bounds (bibtex-parse-field)) | |
d715b065 | 4861 | (bibtex-fill-field-bounds bounds t t)) |
50e4b39e RS |
4862 | (if (looking-at ",") |
4863 | (forward-char)) | |
ffc1e1db | 4864 | (skip-chars-backward " \t\n") |
55fe21fc | 4865 | (bibtex-delete-whitespace) |
5767d190 | 4866 | (insert "\n") |
50e4b39e RS |
4867 | (indent-to-column bibtex-entry-offset) |
4868 | (goto-char pnt))) | |
4869 | ||
4f9ae122 SM |
4870 | (defun bibtex-realign () |
4871 | "Realign BibTeX entries such that they are separated by one blank line." | |
4872 | (goto-char (point-min)) | |
1fdecd0c | 4873 | (let ((case-fold-search t) |
cdc61d35 SM |
4874 | (entry-type (concat "[ \t\n]*\\(" bibtex-entry-type "\\)"))) |
4875 | ;; No blank lines prior to the first entry if there no | |
e0dc0c55 | 4876 | ;; non-white characters in front of it. |
cdc61d35 | 4877 | (when (looking-at entry-type) |
4f9ae122 | 4878 | (replace-match "\\1")) |
cdc61d35 SM |
4879 | ;; Entries are separated by one blank line. |
4880 | (while (re-search-forward entry-type nil t) | |
e0dc0c55 | 4881 | (replace-match "\n\n\\1")) |
cdc61d35 | 4882 | ;; One blank line past the last entry if it is followed by |
e0dc0c55 SM |
4883 | ;; non-white characters, no blank line otherwise. |
4884 | (beginning-of-line) | |
cdc61d35 | 4885 | (when (re-search-forward bibtex-entry-type nil t) |
e0dc0c55 SM |
4886 | (bibtex-end-of-entry) |
4887 | (bibtex-delete-whitespace) | |
4888 | (open-line (if (eobp) 1 2))))) | |
4f9ae122 SM |
4889 | |
4890 | (defun bibtex-reformat (&optional read-options) | |
d0388eac | 4891 | "Reformat all BibTeX entries in buffer or region. |
e0dc0c55 | 4892 | Without prefix argument, reformatting is based on `bibtex-entry-format'. |
d0388eac | 4893 | With prefix argument, read options for reformatting from minibuffer. |
f0cb6034 | 4894 | With \\[universal-argument] \\[universal-argument] prefix argument, reuse previous answers (if any) again. |
4f9ae122 | 4895 | If mark is active reformat entries in region, if not in whole buffer." |
50e4b39e RS |
4896 | (interactive "*P") |
4897 | (let* ((pnt (point)) | |
4898 | (use-previous-options | |
4f9ae122 | 4899 | (and (equal (prefix-numeric-value read-options) 16) |
50e4b39e | 4900 | (or bibtex-reformat-previous-options |
f9bd4abe | 4901 | bibtex-reformat-previous-reference-keys))) |
50e4b39e | 4902 | (bibtex-entry-format |
e0dc0c55 SM |
4903 | (cond (read-options |
4904 | (if use-previous-options | |
4905 | bibtex-reformat-previous-options | |
4906 | (setq bibtex-reformat-previous-options | |
2f438239 RW |
4907 | (delq nil |
4908 | (mapcar (lambda (option) | |
4909 | (if (y-or-n-p (car option)) (cdr option))) | |
4910 | `(("Realign entries (recommended)? " . realign) | |
4911 | ("Remove empty optional and alternative fields? " . opts-or-alts) | |
4912 | ("Remove delimiters around pure numerical fields? " . numerical-fields) | |
4913 | (,(concat (if bibtex-comma-after-last-field "Insert" "Remove") | |
4914 | " comma at end of entry? ") . last-comma) | |
4915 | ("Replace double page dashes by single ones? " . page-dashes) | |
4916 | ("Delete whitespace at the beginning and end of fields? " . whitespace) | |
4917 | ("Inherit booktitle? " . inherit-booktitle) | |
4918 | ("Force delimiters? " . delimiters) | |
4919 | ("Unify case of entry types and field names? " . unify-case) | |
4920 | ("Enclose parts of field entries by braces? " . braces) | |
4921 | ("Replace parts of field entries by string constants? " . strings) | |
4922 | ("Sort fields? " . sort-fields))))))) | |
e0dc0c55 SM |
4923 | ;; Do not include required-fields because `bibtex-reformat' |
4924 | ;; cannot handle the error messages of `bibtex-format-entry'. | |
4925 | ;; Use `bibtex-validate' to check for required fields. | |
4926 | ((eq t bibtex-entry-format) | |
4927 | '(realign opts-or-alts numerical-fields delimiters | |
f2dfa899 | 4928 | last-comma page-dashes unify-case inherit-booktitle |
b7c3692a | 4929 | whitespace braces strings sort-fields)) |
e0dc0c55 | 4930 | (t |
403111a8 | 4931 | (cons 'realign (remove 'required-fields bibtex-entry-format))))) |
4f9ae122 SM |
4932 | (reformat-reference-keys |
4933 | (if read-options | |
4934 | (if use-previous-options | |
4935 | bibtex-reformat-previous-reference-keys | |
4936 | (setq bibtex-reformat-previous-reference-keys | |
4937 | (y-or-n-p "Generate new reference keys automatically? "))))) | |
4f9ae122 SM |
4938 | (bibtex-sort-ignore-string-entries t) |
4939 | bibtex-autokey-edit-before-use) | |
4940 | ||
50e4b39e | 4941 | (save-restriction |
ffc1e1db | 4942 | (if mark-active (narrow-to-region (region-beginning) (region-end))) |
4f9ae122 | 4943 | (if (memq 'realign bibtex-entry-format) |
e0dc0c55 | 4944 | (bibtex-realign)) |
50e4b39e | 4945 | (bibtex-progress-message "Formatting" 1) |
a2a25d24 | 4946 | (bibtex-map-entries (lambda (_key _beg _end) |
7fbf4804 | 4947 | (bibtex-progress-message) |
4f9ae122 | 4948 | (bibtex-clean-entry reformat-reference-keys t))) |
50e4b39e | 4949 | (bibtex-progress-message 'done)) |
e0dc0c55 | 4950 | (when reformat-reference-keys |
4f9ae122 | 4951 | (kill-local-variable 'bibtex-reference-keys) |
e0dc0c55 SM |
4952 | (when bibtex-maintain-sorted-entries |
4953 | (bibtex-progress-message "Sorting" 1) | |
4954 | (bibtex-sort-buffer) | |
4955 | (bibtex-progress-message 'done))) | |
50e4b39e RS |
4956 | (goto-char pnt))) |
4957 | ||
4f9ae122 | 4958 | (defun bibtex-convert-alien (&optional read-options) |
d10e87a2 | 4959 | "Make an alien BibTeX buffer fully usable by BibTeX mode. |
4f9ae122 | 4960 | If a file does not conform with all standards used by BibTeX mode, |
d10e87a2 | 4961 | some of the high-level features of BibTeX mode are not available. |
7fbf4804 | 4962 | This function tries to convert current buffer to conform with these standards. |
4f9ae122 SM |
4963 | With prefix argument READ-OPTIONS non-nil, read options for reformatting |
4964 | entries from minibuffer." | |
50e4b39e RS |
4965 | (interactive "*P") |
4966 | (message "Starting to validate buffer...") | |
48c4d6a2 | 4967 | (sit-for 1) |
4f9ae122 | 4968 | (bibtex-realign) |
f2dfa899 | 4969 | (deactivate-mark) ; So `bibtex-validate' works on the whole buffer. |
ffc1e1db RW |
4970 | (if (not (let (bibtex-maintain-sorted-entries) |
4971 | (bibtex-validate))) | |
4972 | (message "Correct errors and call `bibtex-convert-alien' again") | |
7fbf4804 | 4973 | (message "Starting to reformat entries...") |
48c4d6a2 | 4974 | (sit-for 2) |
4f9ae122 | 4975 | (bibtex-reformat read-options) |
7fbf4804 | 4976 | (goto-char (point-max)) |
f2dfa899 | 4977 | (message "Buffer is now parsable. Please save it."))) |
7fbf4804 | 4978 | |
a2a25d24 SM |
4979 | (define-obsolete-function-alias 'bibtex-complete 'completion-at-point "24.1") |
4980 | (defun bibtex-completion-at-point-function () | |
d528bff7 SM |
4981 | (let ((pnt (point)) |
4982 | (case-fold-search t) | |
a2a25d24 SM |
4983 | (beg (save-excursion |
4984 | (re-search-backward "[ \t{\"]") | |
4985 | (forward-char) | |
4986 | (point))) | |
4987 | (end (point)) | |
d528bff7 | 4988 | bounds name compl) |
7fbf4804 | 4989 | (save-excursion |
ffc1e1db | 4990 | (if (and (setq bounds (bibtex-enclosing-field nil t)) |
7fbf4804 SM |
4991 | (>= pnt (bibtex-start-of-text-in-field bounds)) |
4992 | (<= pnt (bibtex-end-of-text-in-field bounds))) | |
d528bff7 SM |
4993 | (setq name (bibtex-name-in-field bounds t) |
4994 | compl (cond ((bibtex-string= name "crossref") | |
02c8032e SM |
4995 | ;; point is in crossref field |
4996 | 'crossref-key) | |
d528bff7 | 4997 | ((bibtex-string= name "month") |
02c8032e | 4998 | ;; point is in month field |
d528bff7 | 4999 | bibtex-predefined-month-strings) |
02c8032e | 5000 | ;; point is in other field |
cdc61d35 | 5001 | (t (bibtex-strings)))) |
7fbf4804 | 5002 | (bibtex-beginning-of-entry) |
ffc1e1db | 5003 | (cond ((setq bounds (bibtex-parse-string t)) |
cdc61d35 SM |
5004 | ;; point is inside a @String key |
5005 | (cond ((and (>= pnt (nth 1 (car bounds))) | |
5006 | (<= pnt (nth 2 (car bounds)))) | |
5007 | (setq compl 'string)) | |
5008 | ;; point is inside a @String field | |
5009 | ((and (>= pnt (bibtex-start-of-text-in-string bounds)) | |
5010 | (<= pnt (bibtex-end-of-text-in-string bounds))) | |
5011 | (setq compl (bibtex-strings))))) | |
5012 | ;; point is inside a @Preamble field | |
ffc1e1db RW |
5013 | ((setq bounds (bibtex-parse-preamble)) |
5014 | (if (and (>= pnt (bibtex-start-of-text-in-string bounds)) | |
5015 | (<= pnt (bibtex-end-of-text-in-string bounds))) | |
5016 | (setq compl (bibtex-strings)))) | |
02c8032e SM |
5017 | ((and (looking-at bibtex-entry-maybe-empty-head) |
5018 | ;; point is inside a key | |
5019 | (or (and (match-beginning bibtex-key-in-head) | |
5020 | (>= pnt (match-beginning bibtex-key-in-head)) | |
5021 | (<= pnt (match-end bibtex-key-in-head))) | |
5022 | ;; or point is on empty key | |
5023 | (and (not (match-beginning bibtex-key-in-head)) | |
5024 | (= pnt (match-end 0))))) | |
5025 | (setq compl 'key))))) | |
5026 | ||
5027 | (cond ((eq compl 'key) | |
a2a25d24 SM |
5028 | ;; Key completion: no cleanup needed. |
5029 | (list beg end | |
5030 | (lambda (s p a) | |
5031 | (let (completion-ignore-case) | |
5032 | (complete-with-action a (bibtex-global-key-alist) s p))))) | |
02c8032e SM |
5033 | |
5034 | ((eq compl 'crossref-key) | |
a2a25d24 SM |
5035 | ;; Crossref key completion. |
5036 | (let* ((buf (current-buffer))) | |
5037 | (list beg end | |
5038 | (lambda (s p a) | |
5039 | (cond | |
5040 | ((eq a 'metadata) `(metadata (category . bibtex-key))) | |
5041 | (t (let ((completion-ignore-case nil)) | |
5042 | (complete-with-action | |
5043 | a (bibtex-global-key-alist) s p))))) | |
3fe48822 | 5044 | :exit-function (bibtex-complete-crossref-cleanup buf)))) |
02c8032e SM |
5045 | |
5046 | ((eq compl 'string) | |
a2a25d24 SM |
5047 | ;; String key completion: no cleanup needed. |
5048 | (list beg end | |
5049 | (lambda (s p a) | |
5050 | (let ((completion-ignore-case t)) | |
5051 | (complete-with-action a bibtex-strings s p))))) | |
7fbf4804 | 5052 | |
d528bff7 | 5053 | (compl |
a2a25d24 SM |
5054 | ;; String completion. |
5055 | (list beg end | |
5056 | (lambda (s p a) | |
5057 | (cond | |
5058 | ((eq a 'metadata) `(metadata (category . bibtex-string))) | |
5059 | (t (let ((completion-ignore-case t)) | |
5060 | (complete-with-action a compl s p))))) | |
3fe48822 | 5061 | :exit-function (bibtex-complete-string-cleanup compl)))))) |
745bc783 | 5062 | |
7fbf4804 SM |
5063 | (defun bibtex-String (&optional key) |
5064 | "Insert a new BibTeX @String entry with key KEY." | |
02c8032e | 5065 | (interactive (list (bibtex-read-string-key))) |
7fbf4804 | 5066 | (let ((bibtex-maintain-sorted-entries |
d528bff7 SM |
5067 | (unless bibtex-sort-ignore-string-entries |
5068 | bibtex-maintain-sorted-entries)) | |
7fbf4804 SM |
5069 | endpos) |
5070 | (unless (bibtex-prepare-new-entry (list key nil "String")) | |
5071 | (error "Entry with key `%s' already exists" key)) | |
5072 | (if (zerop (length key)) (setq key nil)) | |
50e4b39e | 5073 | (indent-to-column bibtex-entry-offset) |
7fbf4804 SM |
5074 | (insert "@String" |
5075 | (bibtex-entry-left-delimiter)) | |
5076 | (if key | |
5077 | (insert key) | |
5078 | (setq endpos (point))) | |
5079 | (insert " = " | |
5080 | (bibtex-field-left-delimiter)) | |
5081 | (if key | |
5082 | (setq endpos (point))) | |
5083 | (insert (bibtex-field-right-delimiter) | |
5084 | (bibtex-entry-right-delimiter) | |
5085 | "\n") | |
5086 | (goto-char endpos))) | |
50e4b39e RS |
5087 | |
5088 | (defun bibtex-Preamble () | |
f0cb6034 | 5089 | "Insert a new BibTeX @Preamble entry." |
7fbf4804 | 5090 | (interactive "*") |
cb4ad359 | 5091 | (bibtex-move-outside-of-entry) |
50e4b39e | 5092 | (indent-to-column bibtex-entry-offset) |
7fbf4804 | 5093 | (insert "@Preamble" |
c2fa1079 SM |
5094 | (bibtex-entry-left-delimiter) |
5095 | (bibtex-field-left-delimiter)) | |
d715b065 | 5096 | (let ((endpos (point))) |
cdc61d35 SM |
5097 | (insert (bibtex-field-right-delimiter) |
5098 | (bibtex-entry-right-delimiter) | |
d715b065 KG |
5099 | "\n") |
5100 | (goto-char endpos))) | |
2798dfd6 | 5101 | |
12fab222 | 5102 | (defun bibtex-url (&optional pos no-browse) |
e0dc0c55 SM |
5103 | "Browse a URL for the BibTeX entry at point. |
5104 | Optional POS is the location of the BibTeX entry. | |
d528bff7 | 5105 | The URL is generated using the schemes defined in `bibtex-generate-url-list' |
f2dfa899 RW |
5106 | \(see there\). If multiple schemes match for this entry, or the same scheme |
5107 | matches more than once, use the one for which the first step's match is the | |
5108 | closest to POS. The URL is passed to `browse-url' unless NO-BROWSE is t. | |
12fab222 | 5109 | Return the URL or nil if none can be generated." |
e0dc0c55 | 5110 | (interactive) |
f2dfa899 | 5111 | (unless pos (setq pos (point))) |
d528bff7 | 5112 | (save-excursion |
f2dfa899 | 5113 | (goto-char pos) |
d528bff7 | 5114 | (bibtex-beginning-of-entry) |
f2dfa899 RW |
5115 | (let ((end (save-excursion (bibtex-end-of-entry))) |
5116 | (fields-alist (save-excursion (bibtex-parse-entry t))) | |
e0dc0c55 | 5117 | ;; Always ignore case, |
d528bff7 | 5118 | (case-fold-search t) |
297dde5a | 5119 | text url scheme obj fmt fl-match) |
f2dfa899 RW |
5120 | ;; The return value of `bibtex-parse-entry' (i.e., FIELDS-ALIST) |
5121 | ;; is always used to generate the URL. However, if the BibTeX | |
5122 | ;; entry contains more than one URL, we have multiple matches | |
5123 | ;; for the first step defining the generation of the URL. | |
5124 | ;; Therefore, we try to initiate the generation of the URL | |
5125 | ;; based on the match of `bibtex-font-lock-url' that is the | |
5126 | ;; closest to POS. If that fails (no match found) we try to | |
5127 | ;; initiate the generation of the URL based on the properly | |
5128 | ;; concatenated CONTENT of the field as returned by | |
5129 | ;; `bibtex-text-in-field-bounds'. The latter approach can | |
5130 | ;; differ from the former because `bibtex-font-lock-url' uses | |
5131 | ;; the buffer itself. | |
5132 | (while (bibtex-font-lock-url end t) | |
5133 | (push (list (bibtex-dist pos (match-beginning 0) (match-end 0)) | |
5134 | (match-beginning 0) | |
5135 | (buffer-substring-no-properties | |
5136 | (match-beginning 0) (match-end 0))) | |
5137 | fl-match) | |
5138 | ;; `bibtex-font-lock-url' moves point to end of match. | |
5139 | (forward-char)) | |
5140 | (when fl-match | |
5141 | (setq fl-match (car (sort fl-match (lambda (x y) (< (car x) (car y)))))) | |
5142 | (goto-char (nth 1 fl-match)) | |
5143 | (bibtex-beginning-of-field) (re-search-backward ",") | |
5144 | (let* ((bounds (bibtex-parse-field)) | |
5145 | (name (bibtex-name-in-field bounds)) | |
5146 | (content (bibtex-text-in-field-bounds bounds t)) | |
5147 | (lst bibtex-generate-url-list)) | |
5148 | ;; This match can fail when CONTENT differs from text in buffer. | |
5149 | (when (string-match (regexp-quote (nth 2 fl-match)) content) | |
5150 | ;; TEXT is the part of CONTENT that starts with the match | |
5151 | ;; of `bibtex-font-lock-url' we are looking for. | |
5152 | (setq text (substring content (match-beginning 0))) | |
5153 | (while (and (not url) (setq scheme (pop lst))) | |
5154 | ;; Verify the match of `bibtex-font-lock-url' by | |
5155 | ;; comparing with TEXT. | |
5156 | (when (and (bibtex-string= (caar scheme) name) | |
5157 | (string-match (cdar scheme) text)) | |
5158 | (setq url t scheme (cdr scheme))))))) | |
5159 | ||
5160 | ;; If the match of `bibtex-font-lock-url' was not approved | |
5161 | ;; parse FIELDS-ALIST, i.e., the output of `bibtex-parse-entry'. | |
5162 | (unless url | |
5163 | (let ((lst bibtex-generate-url-list)) | |
5164 | (while (and (not url) (setq scheme (pop lst))) | |
5165 | (when (and (setq text (cdr (assoc-string (caar scheme) | |
5166 | fields-alist t))) | |
5167 | (string-match (cdar scheme) text)) | |
5168 | (setq url t scheme (cdr scheme)))))) | |
5169 | ||
5170 | (when url | |
5171 | (setq url (if (null scheme) (match-string 0 text) | |
5172 | (if (stringp (car scheme)) | |
5173 | (setq fmt (pop scheme))) | |
297dde5a | 5174 | (dolist (step scheme) |
6646e848 RW |
5175 | ;; In the first STEP, if the field contains multiple |
5176 | ;; matches, we want the match the closest to point. | |
5177 | ;; (if (eq step (car scheme)) | |
297dde5a | 5178 | (setq text (cdr (assoc-string (car step) fields-alist t))) |
f2dfa899 RW |
5179 | (if (string-match (nth 1 step) text) |
5180 | (push (cond ((functionp (nth 2 step)) | |
5181 | (funcall (nth 2 step) text)) | |
5182 | ((numberp (nth 2 step)) | |
5183 | (match-string (nth 2 step) text)) | |
5184 | (t | |
5185 | (replace-match (nth 2 step) t nil text))) | |
5186 | obj) | |
5187 | ;; If SCHEME is set up correctly, | |
5188 | ;; we should never reach this point | |
5189 | (error "Match failed: %s" text))) | |
5190 | (if fmt (apply 'format fmt (nreverse obj)) | |
5191 | (apply 'concat (nreverse obj))))) | |
32226619 | 5192 | (if (called-interactively-p 'interactive) (message "%s" url)) |
f2dfa899 | 5193 | (unless no-browse (browse-url url))) |
32226619 JB |
5194 | (if (and (not url) (called-interactively-p 'interactive)) |
5195 | (message "No URL known.")) | |
12fab222 | 5196 | url))) |
d528bff7 | 5197 | |
9858f6c3 | 5198 | ;; We could combine multiple search results with set operations |
34699b85 RW |
5199 | ;; AND, OR, MINUS, and NOT. Would this be useful? |
5200 | ;; How complicated are searches in real life? | |
5201 | ;; We could also have other searches such as "publication year newer than...". | |
5202 | (defun bibtex-search-entries (field regexp &optional global display) | |
5203 | "Search BibTeX entries for FIELD matching REGEXP. | |
5204 | REGEXP may be a regexp to search for. | |
5205 | If REGEXP is a function, it is called for each entry with two args, | |
5206 | the buffer positions of beginning and end of entry. Then an entry | |
5207 | is accepted if this function returns non-nil. | |
5208 | If FIELD is an empty string perform search for REGEXP in whole entry. | |
5209 | With GLOBAL non-nil, search in `bibtex-files'. Otherwise the search | |
5210 | is limited to the current buffer. | |
5211 | If DISPLAY is non-nil, display search results in `bibtex-search-buffer'. | |
5212 | When called interactively, DISPLAY is t. | |
5213 | Also, GLOBAL is t if `bibtex-search-entry-globally' is non-nil. | |
5214 | A prefix arg negates the value of `bibtex-search-entry-globally'. | |
5215 | Return alist with elements (KEY FILE ENTRY), | |
5216 | where FILE is the BibTeX file of ENTRY." | |
5217 | (interactive | |
5218 | (list (completing-read | |
5219 | "Field: " | |
5220 | (delete-dups | |
5221 | (apply 'append | |
5222 | bibtex-user-optional-fields | |
ff8be6ef | 5223 | (mapcar (lambda (x) (mapcar 'car (apply 'append (nthcdr 2 x)))) |
2de69e00 | 5224 | bibtex-entry-alist))) nil t) |
34699b85 RW |
5225 | (read-string "Regexp: ") |
5226 | (if bibtex-search-entry-globally | |
5227 | (not current-prefix-arg) | |
5228 | current-prefix-arg) | |
5229 | t)) | |
5230 | (let ((funp (functionp regexp)) | |
5231 | entries text file) | |
5232 | ;; If REGEXP is a function, the value of FIELD is ignored anyway. | |
5233 | ;; Yet to ensure the code below does not fail, we make FIELD | |
5234 | ;; a non-empty string. | |
5235 | (if (and funp (string= "" field)) (setq field "unrestricted")) | |
5236 | (dolist (buffer (if (and global bibtex-files) | |
5237 | (bibtex-initialize t) | |
5238 | (list (current-buffer)))) | |
5239 | (with-current-buffer buffer | |
5240 | (setq file (if buffer-file-name | |
5241 | (file-name-nondirectory buffer-file-name) | |
5242 | (buffer-name buffer))) | |
5243 | (save-excursion | |
5244 | (goto-char (point-min)) | |
5245 | (if (string= "" field) | |
5246 | ;; Unrestricted search. | |
5247 | (while (re-search-forward regexp nil t) | |
7ae9f0fb RW |
5248 | (save-excursion |
5249 | (let ((mbeg (match-beginning 0)) | |
5250 | (mend (match-end 0)) | |
5251 | (beg (bibtex-beginning-of-entry)) | |
5252 | (end (bibtex-end-of-entry)) | |
5253 | key) | |
5254 | (if (and (<= beg mbeg) | |
5255 | (<= mend end) | |
5256 | (progn | |
5257 | (goto-char beg) | |
5258 | (looking-at bibtex-entry-head)) | |
5259 | (setq key (bibtex-key-in-head)) | |
5260 | (not (assoc key entries))) | |
5261 | (push (list key file | |
5262 | (buffer-substring-no-properties beg end)) | |
5263 | entries))))) | |
34699b85 RW |
5264 | ;; The following is slow. But it works reliably even in more |
5265 | ;; complicated cases with BibTeX string constants and crossrefed | |
5266 | ;; entries. If you prefer speed over reliability, perform an | |
5267 | ;; unrestricted search. | |
5268 | (bibtex-map-entries | |
5269 | (lambda (key beg end) | |
297dde5a RW |
5270 | (if (and (cond (funp (funcall regexp beg end)) |
5271 | ((and (setq text (bibtex-text-in-field field t)) | |
5272 | (string-match regexp text)))) | |
5273 | (not (assoc key entries))) | |
5274 | (push (list key file | |
5275 | (buffer-substring-no-properties beg end)) | |
5276 | entries)))))))) | |
34699b85 RW |
5277 | (if display |
5278 | (if entries | |
5279 | (bibtex-display-entries entries) | |
5280 | (message "No BibTeX entries %smatching `%s'" | |
5281 | (if (string= "" field) "" | |
5282 | (format "with field `%s' " field)) | |
5283 | regexp))) | |
5284 | entries)) | |
5285 | ||
5286 | (defun bibtex-display-entries (entries &optional append) | |
5287 | "Display BibTeX ENTRIES in `bibtex-search-buffer'. | |
5288 | ENTRIES is an alist with elements (KEY FILE ENTRY), | |
5289 | where FILE is the BibTeX file of ENTRY. | |
5290 | If APPEND is non-nil, append ENTRIES to those already displayed." | |
5291 | (pop-to-buffer (get-buffer-create bibtex-search-buffer)) | |
5292 | ;; It would be nice if this buffer was editable, though editing | |
5293 | ;; can be meaningful only for individual existing entries | |
5294 | ;; (unlike reordering or creating new entries). | |
5295 | ;; Fancy workaround: Editing commands in the virtual buffer could | |
5296 | ;; jump to the real entry in the real buffer. | |
5297 | (let (buffer-read-only) | |
5298 | (if append (goto-char (point-max)) (erase-buffer)) | |
5299 | (dolist (entry (sort entries (lambda (x y) (string< (car x) (car y))))) | |
5300 | (insert "% " (nth 1 entry) "\n" (nth 2 entry) "\n\n"))) | |
5301 | ;; `bibtex-sort-buffer' fails with the file names associated with | |
5302 | ;; each entry. Prior to sorting we could make the file name | |
5303 | ;; a BibTeX field of each entry (using `bibtex-make-field'). | |
5304 | ;; Or we could make it a text property that we unfold afterwards. | |
5305 | ;; (bibtex-sort-buffer) | |
5306 | (bibtex-mode) | |
5307 | (set-buffer-modified-p nil) | |
5308 | (setq buffer-read-only t) | |
5309 | (goto-char (point-min))) | |
5310 | ||
745bc783 | 5311 | \f |
5c69dbfc | 5312 | ;; Make BibTeX a Feature |
cb4ad359 RS |
5313 | |
5314 | (provide 'bibtex) | |
9ae11a89 | 5315 | ;;; bibtex.el ends here |