Commit | Line | Data |
---|---|---|
c0274f38 ER |
1 | ;;; bibtex.el --- BibTeX mode for GNU Emacs |
2 | ||
7fbf4804 | 3 | ;; Copyright (C) 1992,94,95,96,97,98,1999,2003 Free Software Foundation, Inc. |
9750e079 | 4 | |
31bc4210 | 5 | ;; Author: Stefan Schoef <schoef@offis.uni-oldenburg.de> |
7fbf4804 SM |
6 | ;; Bengt Martensson <bengt@mathematik.uni-Bremen.de> |
7 | ;; Mark Shapiro <shapiro@corto.inria.fr> | |
8 | ;; Mike Newton <newton@gumby.cs.caltech.edu> | |
9 | ;; Aaron Larson <alarson@src.honeywell.com> | |
10 | ;; Dirk Herrmann <D.Herrmann@tu-bs.de> | |
e04464bb | 11 | ;; Maintainer: Roland Winkler <roland.winkler@physik.uni-erlangen.de> |
cb4ad359 | 12 | ;; Keywords: BibTeX, LaTeX, TeX |
f961a17c | 13 | |
745bc783 JB |
14 | ;; This file is part of GNU Emacs. |
15 | ||
16 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
17 | ;; it under the terms of the GNU General Public License as published by | |
a1ddedc6 | 18 | ;; the Free Software Foundation; either version 2, or (at your option) |
745bc783 JB |
19 | ;; any later version. |
20 | ||
21 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
22 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | ;; GNU General Public License for more details. | |
25 | ||
26 | ;; You should have received a copy of the GNU General Public License | |
b578f267 EN |
27 | ;; along with GNU Emacs; see the file COPYING. If not, write to the |
28 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
29 | ;; Boston, MA 02111-1307, USA. | |
745bc783 | 30 | |
5c69dbfc | 31 | ;;; Commentary: |
b578f267 | 32 | |
cb4ad359 | 33 | ;; Major mode for editing and validating BibTeX files. |
e5167999 | 34 | |
5c69dbfc | 35 | ;; Usage: |
cb4ad359 | 36 | ;; See documentation for function bibtex-mode (or type "\M-x describe-mode" |
d0388eac | 37 | ;; when you are in BibTeX mode). |
e5167999 | 38 | |
5c69dbfc RS |
39 | ;; Todo: |
40 | ;; Distribute texinfo file. | |
9ae11a89 | 41 | |
5c69dbfc | 42 | ;;; Code: |
b578f267 | 43 | |
28f2ee66 | 44 | \f |
5c69dbfc | 45 | ;; User Options: |
e5167999 | 46 | |
f754fb7b | 47 | (defgroup bibtex nil |
7fbf4804 | 48 | "BibTeX mode" |
f754fb7b RS |
49 | :group 'tex |
50 | :prefix "bibtex-") | |
51 | ||
52 | (defgroup bibtex-autokey nil | |
7fbf4804 | 53 | "Generate automatically a key from the author/editor and the title field" |
f754fb7b | 54 | :group 'bibtex |
ab2d0cdb | 55 | :prefix "bibtex-autokey-") |
f754fb7b RS |
56 | |
57 | (defcustom bibtex-mode-hook nil | |
58 | "List of functions to call on entry to BibTeX mode." | |
59 | :group 'bibtex | |
ab2d0cdb | 60 | :type 'hook) |
f754fb7b RS |
61 | |
62 | (defcustom bibtex-field-delimiters 'braces | |
7fbf4804 | 63 | "*Type of field delimiters. Allowed values are `braces' or `double-quotes'." |
f754fb7b RS |
64 | :group 'bibtex |
65 | :type '(choice (const braces) | |
7fbf4804 | 66 | (const double-quotes))) |
50e4b39e | 67 | |
f754fb7b | 68 | (defcustom bibtex-entry-delimiters 'braces |
7fbf4804 | 69 | "*Type of entry delimiters. Allowed values are `braces' or `parentheses'." |
f754fb7b RS |
70 | :group 'bibtex |
71 | :type '(choice (const braces) | |
7fbf4804 | 72 | (const parentheses))) |
cb4ad359 | 73 | |
f754fb7b | 74 | (defcustom bibtex-include-OPTcrossref '("InProceedings" "InCollection") |
7fbf4804 | 75 | "*List of entries that get an OPTcrossref field." |
f754fb7b RS |
76 | :group 'bibtex |
77 | :type '(repeat string)) | |
e5167999 | 78 | |
f754fb7b | 79 | (defcustom bibtex-include-OPTkey t |
50e4b39e RS |
80 | "*If non-nil, all entries will have an OPTkey field. |
81 | If this is a string, it will be used as the initial field text. | |
f754fb7b RS |
82 | If this is a function, it will be called to generate the initial field text." |
83 | :group 'bibtex | |
84 | :type '(choice (const :tag "None" nil) | |
7fbf4804 SM |
85 | (string :tag "Initial text") |
86 | (function :tag "Initialize Function" :value fun) | |
87 | (other :tag "Default" t))) | |
f754fb7b RS |
88 | |
89 | (defcustom bibtex-user-optional-fields | |
50e4b39e | 90 | '(("annote" "Personal annotation (ignored)")) |
cb4ad359 | 91 | "*List of optional fields the user wants to have always present. |
50e4b39e | 92 | Entries should be of the same form as the OPTIONAL and |
d0388eac | 93 | CROSSREF-OPTIONAL lists in `bibtex-entry-field-alist' (see documentation |
f754fb7b RS |
94 | of this variable for details)." |
95 | :group 'bibtex | |
7fbf4804 SM |
96 | :type '(repeat (group (string :tag "Field") |
97 | (string :tag "Comment") | |
98 | (option (group :inline t | |
99 | :extra-offset -4 | |
100 | (choice :tag "Init" :value "" | |
101 | string | |
102 | function)))))) | |
103 | ||
104 | (defcustom bibtex-entry-format | |
105 | '(opts-or-alts required-fields numerical-fields) | |
106 | "*Type of formatting performed by `bibtex-clean-entry'. | |
f0cb6034 | 107 | It may be t, nil, or a list of symbols out of the following: |
d0388eac RS |
108 | opts-or-alts Delete empty optional and alternative fields and |
109 | remove OPT and ALT prefixes from used fields. | |
7fbf4804 | 110 | required-fields Signal an error if a required field is missing. |
d0388eac RS |
111 | numerical-fields Delete delimiters around numeral fields. |
112 | page-dashes Change double dashes in page field to single dash | |
113 | (for scribe compatibility). | |
114 | inherit-booktitle If entry contains a crossref field and booktitle | |
50e4b39e | 115 | field is empty, it is set to the contents of the |
d0388eac RS |
116 | title field of the crossreferenced entry. |
117 | Caution: this will work only if buffer is | |
118 | correctly sorted. | |
119 | realign Realign entries, so that field texts and perhaps equal | |
50e4b39e | 120 | signs (depending on the value of |
f0cb6034 | 121 | `bibtex-align-at-equal-sign') begin in the same column. |
d0388eac RS |
122 | last-comma Add or delete comma on end of last field in entry, |
123 | according to value of `bibtex-comma-after-last-field'. | |
124 | delimiters Change delimiters according to variables | |
125 | `bibtex-field-delimiters' and `bibtex-entry-delimiters'. | |
126 | unify-case Change case of entry and field names. | |
127 | ||
128 | The value t means do all of the above formatting actions. | |
129 | The value nil means do no formatting at all." | |
f754fb7b RS |
130 | :group 'bibtex |
131 | :type '(choice (const :tag "None" nil) | |
7fbf4804 SM |
132 | (const :tag "All" t) |
133 | (set :menu-tag "Some" | |
134 | (const opts-or-alts) | |
135 | (const required-fields) | |
136 | (const numerical-fields) | |
137 | (const page-dashes) | |
138 | (const inherit-booktitle) | |
139 | (const realign) | |
140 | (const last-comma) | |
141 | (const delimiters) | |
142 | (const unify-case)))) | |
50e4b39e | 143 | |
f754fb7b | 144 | (defcustom bibtex-clean-entry-hook nil |
50e4b39e | 145 | "*List of functions to call when entry has been cleaned. |
d0388eac | 146 | Functions are called with point inside the cleaned entry, and the buffer |
f754fb7b RS |
147 | narrowed to just the entry." |
148 | :group 'bibtex | |
ab2d0cdb | 149 | :type 'hook) |
cb4ad359 | 150 | |
f754fb7b | 151 | (defcustom bibtex-maintain-sorted-entries nil |
d0388eac | 152 | "*If non-nil, BibTeX mode maintains all BibTeX entries in sorted order. |
d715b065 | 153 | Allowed non-nil values are: |
7fbf4804 SM |
154 | plain All entries are sorted alphabetically. |
155 | crossref All entries are sorted alphabetically unless an entry has a | |
156 | crossref field. These crossrefed entries are placed in | |
157 | alphabetical order immediately preceding the main entry. | |
158 | entry-class The entries are divided into classes according to their | |
159 | entry name, see `bibtex-sort-entry-class'. Within each class | |
160 | the entries are sorted alphabetically. | |
161 | See also `bibtex-sort-ignore-string-entries'." | |
162 | :group 'bibtex | |
163 | :type '(choice (const nil) | |
164 | (const plain) | |
165 | (const crossref) | |
166 | (const entry-class))) | |
167 | ||
168 | (defvar bibtex-sort-entry-class | |
169 | '(("String") | |
d715b065 KG |
170 | (catch-all) |
171 | ("Book" "Proceedings")) | |
7fbf4804 | 172 | "*List of classes of BibTeX entry names, used for sorting entries. |
d715b065 KG |
173 | If value of `bibtex-maintain-sorted-entries' is `entry-class' |
174 | entries are ordered according to the classes they belong to. Each | |
175 | class contains a list of entry names. An entry `catch-all' applies | |
176 | to all entries not explicitely mentioned.") | |
7fbf4804 | 177 | |
d715b065 | 178 | (defcustom bibtex-sort-ignore-string-entries t |
7fbf4804 SM |
179 | "*If non-nil, BibTeX @String entries are not sort-significant. |
180 | That means they are ignored when determining ordering of the buffer | |
181 | \(e.g., sorting, locating alphabetical position for new entries, etc.)." | |
f754fb7b RS |
182 | :group 'bibtex |
183 | :type 'boolean) | |
9ae11a89 | 184 | |
f754fb7b | 185 | (defcustom bibtex-field-kill-ring-max 20 |
d0388eac | 186 | "*Max length of `bibtex-field-kill-ring' before discarding oldest elements." |
f754fb7b RS |
187 | :group 'bibtex |
188 | :type 'integer) | |
50e4b39e | 189 | |
d715b065 KG |
190 | (defcustom bibtex-entry-kill-ring-max 20 |
191 | "*Max length of `bibtex-entry-kill-ring' before discarding oldest elements." | |
192 | :group 'bibtex | |
193 | :type 'integer) | |
194 | ||
f754fb7b | 195 | (defcustom bibtex-parse-keys-timeout 60 |
7fbf4804 | 196 | "*Specify interval for parsing BibTeX buffers. |
f0cb6034 | 197 | All BibTeX buffers in Emacs are parsed if Emacs has been idle |
d0388eac | 198 | `bibtex-parse-keys-timeout' seconds. Only buffers which were modified |
f754fb7b RS |
199 | after last parsing and which are maintained in sorted order are parsed." |
200 | :group 'bibtex | |
201 | :type 'integer) | |
af6fb89d | 202 | |
d715b065 KG |
203 | (defcustom bibtex-parse-keys-fast t |
204 | "*If non-nil, use fast but simplified algorithm for parsing BibTeX keys. | |
205 | If parsing fails, try to set this variable to nil." | |
206 | :group 'bibtex | |
207 | :type 'boolean) | |
208 | ||
cb4ad359 RS |
209 | (defvar bibtex-entry-field-alist |
210 | '( | |
7fbf4804 SM |
211 | ("Article" |
212 | ((("author" "Author1 [and Author2 ...] [and others]") | |
d715b065 KG |
213 | ("title" "Title of the article (BibTeX converts it to lowercase)") |
214 | ("journal" "Name of the journal (use string, remove braces)") | |
215 | ("year" "Year of publication")) | |
216 | (("volume" "Volume of the journal") | |
217 | ("number" "Number of the journal (only allowed if entry contains volume)") | |
218 | ("pages" "Pages in the journal") | |
219 | ("month" "Month of the publication as a string (remove braces)") | |
220 | ("note" "Remarks to be put at the end of the \\bibitem"))) | |
221 | ((("author" "Author1 [and Author2 ...] [and others]") | |
222 | ("title" "Title of the article (BibTeX converts it to lowercase)")) | |
223 | (("pages" "Pages in the journal") | |
224 | ("journal" "Name of the journal (use string, remove braces)") | |
225 | ("year" "Year of publication") | |
226 | ("volume" "Volume of the journal") | |
227 | ("number" "Number of the journal") | |
228 | ("month" "Month of the publication as a string (remove braces)") | |
229 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
230 | ("Book" |
231 | ((("author" "Author1 [and Author2 ...] [and others]" "" t) | |
d715b065 KG |
232 | ("editor" "Editor1 [and Editor2 ...] [and others]" "" t) |
233 | ("title" "Title of the book") | |
234 | ("publisher" "Publishing company") | |
235 | ("year" "Year of publication")) | |
236 | (("volume" "Volume of the book in the series") | |
237 | ("number" "Number of the book in a small series (overwritten by volume)") | |
238 | ("series" "Series in which the book appeared") | |
239 | ("address" "Address of the publisher") | |
240 | ("edition" "Edition of the book as a capitalized English word") | |
241 | ("month" "Month of the publication as a string (remove braces)") | |
242 | ("note" "Remarks to be put at the end of the \\bibitem"))) | |
243 | ((("author" "Author1 [and Author2 ...] [and others]" "" t) | |
244 | ("editor" "Editor1 [and Editor2 ...] [and others]" "" t) | |
245 | ("title" "Title of the book")) | |
246 | (("publisher" "Publishing company") | |
247 | ("year" "Year of publication") | |
248 | ("volume" "Volume of the book in the series") | |
249 | ("number" "Number of the book in a small series (overwritten by volume)") | |
250 | ("series" "Series in which the book appeared") | |
251 | ("address" "Address of the publisher") | |
252 | ("edition" "Edition of the book as a capitalized English word") | |
253 | ("month" "Month of the publication as a string (remove braces)") | |
254 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
255 | ("Booklet" |
256 | ((("title" "Title of the booklet (BibTeX converts it to lowercase)")) | |
d715b065 KG |
257 | (("author" "Author1 [and Author2 ...] [and others]") |
258 | ("howpublished" "The way in which the booklet was published") | |
259 | ("address" "Address of the publisher") | |
260 | ("month" "Month of the publication as a string (remove braces)") | |
261 | ("year" "Year of publication") | |
262 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
263 | ("InBook" |
264 | ((("author" "Author1 [and Author2 ...] [and others]" "" t) | |
d715b065 KG |
265 | ("editor" "Editor1 [and Editor2 ...] [and others]" "" t) |
266 | ("title" "Title of the book") | |
267 | ("chapter" "Chapter in the book") | |
268 | ("publisher" "Publishing company") | |
269 | ("year" "Year of publication")) | |
270 | (("volume" "Volume of the book in the series") | |
271 | ("number" "Number of the book in a small series (overwritten by volume)") | |
272 | ("series" "Series in which the book appeared") | |
273 | ("type" "Word to use instead of \"chapter\"") | |
274 | ("address" "Address of the publisher") | |
275 | ("edition" "Edition of the book as a capitalized English word") | |
276 | ("month" "Month of the publication as a string (remove braces)") | |
277 | ("pages" "Pages in the book") | |
278 | ("note" "Remarks to be put at the end of the \\bibitem"))) | |
279 | ((("author" "Author1 [and Author2 ...] [and others]" "" t) | |
280 | ("editor" "Editor1 [and Editor2 ...] [and others]" "" t) | |
281 | ("title" "Title of the book") | |
282 | ("chapter" "Chapter in the book")) | |
283 | (("pages" "Pages in the book") | |
284 | ("publisher" "Publishing company") | |
285 | ("year" "Year of publication") | |
286 | ("volume" "Volume of the book in the series") | |
287 | ("number" "Number of the book in a small series (overwritten by volume)") | |
288 | ("series" "Series in which the book appeared") | |
289 | ("type" "Word to use instead of \"chapter\"") | |
290 | ("address" "Address of the publisher") | |
291 | ("edition" "Edition of the book as a capitalized English word") | |
292 | ("month" "Month of the publication as a string (remove braces)") | |
293 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
294 | ("InCollection" |
295 | ((("author" "Author1 [and Author2 ...] [and others]") | |
d715b065 KG |
296 | ("title" "Title of the article in book (BibTeX converts it to lowercase)") |
297 | ("booktitle" "Name of the book") | |
298 | ("publisher" "Publishing company") | |
299 | ("year" "Year of publication")) | |
300 | (("editor" "Editor1 [and Editor2 ...] [and others]") | |
301 | ("volume" "Volume of the book in the series") | |
302 | ("number" "Number of the book in a small series (overwritten by volume)") | |
303 | ("series" "Series in which the book appeared") | |
304 | ("type" "Word to use instead of \"chapter\"") | |
305 | ("chapter" "Chapter in the book") | |
306 | ("pages" "Pages in the book") | |
307 | ("address" "Address of the publisher") | |
308 | ("edition" "Edition of the book as a capitalized English word") | |
309 | ("month" "Month of the publication as a string (remove braces)") | |
310 | ("note" "Remarks to be put at the end of the \\bibitem"))) | |
311 | ((("author" "Author1 [and Author2 ...] [and others]") | |
312 | ("title" "Title of the article in book (BibTeX converts it to lowercase)") | |
313 | ("booktitle" "Name of the book")) | |
314 | (("pages" "Pages in the book") | |
315 | ("publisher" "Publishing company") | |
316 | ("year" "Year of publication") | |
317 | ("editor" "Editor1 [and Editor2 ...] [and others]") | |
318 | ("volume" "Volume of the book in the series") | |
319 | ("number" "Number of the book in a small series (overwritten by volume)") | |
320 | ("series" "Series in which the book appeared") | |
321 | ("type" "Word to use instead of \"chapter\"") | |
322 | ("chapter" "Chapter in the book") | |
323 | ("address" "Address of the publisher") | |
324 | ("edition" "Edition of the book as a capitalized English word") | |
325 | ("month" "Month of the publication as a string (remove braces)") | |
326 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
327 | ("InProceedings" |
328 | ((("author" "Author1 [and Author2 ...] [and others]") | |
d715b065 KG |
329 | ("title" "Title of the article in proceedings (BibTeX converts it to lowercase)") |
330 | ("booktitle" "Name of the conference proceedings") | |
331 | ("year" "Year of publication")) | |
332 | (("editor" "Editor1 [and Editor2 ...] [and others]") | |
333 | ("volume" "Volume of the conference proceedings in the series") | |
334 | ("number" "Number of the conference proceedings in a small series (overwritten by volume)") | |
335 | ("series" "Series in which the conference proceedings appeared") | |
336 | ("pages" "Pages in the conference proceedings") | |
337 | ("address" "Location of the Proceedings") | |
338 | ("month" "Month of the publication as a string (remove braces)") | |
339 | ("organization" "Sponsoring organization of the conference") | |
340 | ("publisher" "Publishing company, its location") | |
341 | ("note" "Remarks to be put at the end of the \\bibitem"))) | |
342 | ((("author" "Author1 [and Author2 ...] [and others]") | |
343 | ("title" "Title of the article in proceedings (BibTeX converts it to lowercase)")) | |
344 | (("booktitle" "Name of the conference proceedings") | |
345 | ("pages" "Pages in the conference proceedings") | |
346 | ("year" "Year of publication") | |
347 | ("editor" "Editor1 [and Editor2 ...] [and others]") | |
348 | ("volume" "Volume of the conference proceedings in the series") | |
349 | ("number" "Number of the conference proceedings in a small series (overwritten by volume)") | |
350 | ("series" "Series in which the conference proceedings appeared") | |
351 | ("address" "Location of the Proceedings") | |
352 | ("month" "Month of the publication as a string (remove braces)") | |
353 | ("organization" "Sponsoring organization of the conference") | |
354 | ("publisher" "Publishing company, its location") | |
355 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
356 | ("Manual" |
357 | ((("title" "Title of the manual")) | |
d715b065 KG |
358 | (("author" "Author1 [and Author2 ...] [and others]") |
359 | ("organization" "Publishing organization of the manual") | |
360 | ("address" "Address of the organization") | |
361 | ("edition" "Edition of the manual as a capitalized English word") | |
362 | ("month" "Month of the publication as a string (remove braces)") | |
363 | ("year" "Year of publication") | |
364 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
365 | ("MastersThesis" |
366 | ((("author" "Author1 [and Author2 ...] [and others]") | |
d715b065 KG |
367 | ("title" "Title of the master\'s thesis (BibTeX converts it to lowercase)") |
368 | ("school" "School where the master\'s thesis was written") | |
369 | ("year" "Year of publication")) | |
370 | (("type" "Type of the master\'s thesis (if other than \"Master\'s thesis\")") | |
371 | ("address" "Address of the school (if not part of field \"school\") or country") | |
372 | ("month" "Month of the publication as a string (remove braces)") | |
373 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
374 | ("Misc" |
375 | (() | |
d715b065 KG |
376 | (("author" "Author1 [and Author2 ...] [and others]") |
377 | ("title" "Title of the work (BibTeX converts it to lowercase)") | |
378 | ("howpublished" "The way in which the work was published") | |
379 | ("month" "Month of the publication as a string (remove braces)") | |
380 | ("year" "Year of publication") | |
381 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
382 | ("PhdThesis" |
383 | ((("author" "Author1 [and Author2 ...] [and others]") | |
d715b065 KG |
384 | ("title" "Title of the PhD. thesis") |
385 | ("school" "School where the PhD. thesis was written") | |
386 | ("year" "Year of publication")) | |
387 | (("type" "Type of the PhD. thesis") | |
388 | ("address" "Address of the school (if not part of field \"school\") or country") | |
389 | ("month" "Month of the publication as a string (remove braces)") | |
390 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
391 | ("Proceedings" |
392 | ((("title" "Title of the conference proceedings") | |
d715b065 KG |
393 | ("year" "Year of publication")) |
394 | (("booktitle" "Title of the proceedings for cross references") | |
395 | ("editor" "Editor1 [and Editor2 ...] [and others]") | |
396 | ("volume" "Volume of the conference proceedings in the series") | |
397 | ("number" "Number of the conference proceedings in a small series (overwritten by volume)") | |
398 | ("series" "Series in which the conference proceedings appeared") | |
399 | ("address" "Location of the Proceedings") | |
400 | ("month" "Month of the publication as a string (remove braces)") | |
401 | ("organization" "Sponsoring organization of the conference") | |
402 | ("publisher" "Publishing company, its location") | |
403 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
404 | ("TechReport" |
405 | ((("author" "Author1 [and Author2 ...] [and others]") | |
d715b065 KG |
406 | ("title" "Title of the technical report (BibTeX converts it to lowercase)") |
407 | ("institution" "Sponsoring institution of the report") | |
408 | ("year" "Year of publication")) | |
409 | (("type" "Type of the report (if other than \"technical report\")") | |
410 | ("number" "Number of the technical report") | |
411 | ("address" "Address of the institution (if not part of field \"institution\") or country") | |
412 | ("month" "Month of the publication as a string (remove braces)") | |
413 | ("note" "Remarks to be put at the end of the \\bibitem")))) | |
7fbf4804 SM |
414 | ("Unpublished" |
415 | ((("author" "Author1 [and Author2 ...] [and others]") | |
d715b065 KG |
416 | ("title" "Title of the unpublished work (BibTeX converts it to lowercase)") |
417 | ("note" "Remarks to be put at the end of the \\bibitem")) | |
418 | (("month" "Month of the publication as a string (remove braces)") | |
419 | ("year" "Year of publication")))) | |
cb4ad359 RS |
420 | ) |
421 | ||
f9bd4abe | 422 | "Defines entry types and their associated fields. |
cb4ad359 | 423 | List of |
73cc75b5 | 424 | \(ENTRY-NAME (REQUIRED OPTIONAL) (CROSSREF-REQUIRED CROSSREF-OPTIONAL)) |
cb4ad359 | 425 | triples. |
50e4b39e RS |
426 | If the third element is nil, the first pair is always used. |
427 | If not, the second pair is used in the case of presence of a crossref | |
428 | field and the third in the case of absence. | |
f0cb6034 | 429 | REQUIRED, OPTIONAL, CROSSREF-REQUIRED and CROSSREF-OPTIONAL are lists. |
50e4b39e | 430 | Each element of these lists is a list of the form |
73cc75b5 | 431 | \(FIELD-NAME COMMENT-STRING INIT ALTERNATIVE-FLAG). |
50e4b39e RS |
432 | COMMENT-STRING, INIT, and ALTERNATIVE-FLAG are optional. |
433 | FIELD-NAME is the name of the field, COMMENT-STRING the comment to | |
434 | appear in the echo area, INIT is either the initial content of the | |
435 | field or a function, which is called to determine the initial content | |
436 | of the field, and ALTERNATIVE-FLAG (either nil or t) marks if the | |
d0388eac | 437 | field is an alternative. ALTERNATIVE-FLAG may be t only in the |
50e4b39e RS |
438 | REQUIRED or CROSSREF-REQUIRED lists.") |
439 | ||
7fbf4804 SM |
440 | (defvar bibtex-comment-start "@Comment" |
441 | "String starting a BibTeX comment.") | |
ab2d0cdb | 442 | |
f754fb7b RS |
443 | (defcustom bibtex-add-entry-hook nil |
444 | "List of functions to call when entry has been inserted." | |
445 | :group 'bibtex | |
ab2d0cdb | 446 | :type 'hook) |
50e4b39e | 447 | |
f754fb7b | 448 | (defcustom bibtex-predefined-month-strings |
7fbf4804 SM |
449 | '(("jan" . "January") |
450 | ("feb" . "February") | |
451 | ("mar" . "March") | |
452 | ("apr" . "April") | |
453 | ("may" . "May") | |
454 | ("jun" . "June") | |
455 | ("jul" . "July") | |
456 | ("aug" . "August") | |
457 | ("sep" . "September") | |
458 | ("oct" . "October") | |
459 | ("nov" . "November") | |
460 | ("dec" . "December")) | |
461 | "Alist of month string definitions used in the BibTeX style files. | |
d715b065 | 462 | Each element is a pair of strings (ABBREVIATION . EXPANSION)." |
f754fb7b | 463 | :group 'bibtex |
7fbf4804 SM |
464 | :type '(repeat (cons (string :tag "Month abbreviation") |
465 | (string :tag "Month expansion")))) | |
50e4b39e | 466 | |
f754fb7b | 467 | (defcustom bibtex-predefined-strings |
50e4b39e RS |
468 | (append |
469 | bibtex-predefined-month-strings | |
7fbf4804 SM |
470 | '(("acmcs" . "ACM Computing Surveys") |
471 | ("acta" . "Acta Informatica") | |
472 | ("cacm" . "Communications of the ACM") | |
473 | ("ibmjrd" . "IBM Journal of Research and Development") | |
474 | ("ibmsj" . "IBM Systems Journal") | |
475 | ("ieeese" . "IEEE Transactions on Software Engineering") | |
476 | ("ieeetc" . "IEEE Transactions on Computers") | |
477 | ("ieeetcad" . "IEEE Transactions on Computer-Aided Design of Integrated Circuits") | |
478 | ("ipl" . "Information Processing Letters") | |
479 | ("jacm" . "Journal of the ACM") | |
480 | ("jcss" . "Journal of Computer and System Sciences") | |
481 | ("scp" . "Science of Computer Programming") | |
482 | ("sicomp" . "SIAM Journal on Computing") | |
483 | ("tcs" . "Theoretical Computer Science") | |
484 | ("tocs" . "ACM Transactions on Computer Systems") | |
485 | ("tods" . "ACM Transactions on Database Systems") | |
486 | ("tog" . "ACM Transactions on Graphics") | |
487 | ("toms" . "ACM Transactions on Mathematical Software") | |
488 | ("toois" . "ACM Transactions on Office Information Systems") | |
489 | ("toplas" . "ACM Transactions on Programming Languages and Systems"))) | |
490 | "Alist of string definitions used in the BibTeX style files. | |
d715b065 | 491 | Each element is a pair of strings (ABBREVIATION . EXPANSION)." |
f754fb7b | 492 | :group 'bibtex |
7fbf4804 SM |
493 | :type '(repeat (cons (string :tag "String") |
494 | (string :tag "String expansion")))) | |
cb4ad359 | 495 | |
f754fb7b | 496 | (defcustom bibtex-string-files nil |
cb4ad359 RS |
497 | "*List of BibTeX files containing string definitions. |
498 | Those files must be specified using pathnames relative to the | |
d715b065 | 499 | directories specified in `bibtex-string-file-path'." |
f754fb7b RS |
500 | :group 'bibtex |
501 | :type '(repeat file)) | |
50e4b39e RS |
502 | |
503 | (defvar bibtex-string-file-path (getenv "BIBINPUTS") | |
28f2ee66 | 504 | "*Colon separated list of paths to search for `bibtex-string-files'.") |
cb4ad359 | 505 | |
f754fb7b | 506 | (defcustom bibtex-help-message t |
d715b065 | 507 | "*If non-nil print help messages in the echo area on entering a new field." |
f754fb7b RS |
508 | :group 'bibtex |
509 | :type 'boolean) | |
cb4ad359 | 510 | |
f754fb7b | 511 | (defcustom bibtex-autokey-prefix-string "" |
50e4b39e | 512 | "*String to use as a prefix for all generated keys. |
d715b065 | 513 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
514 | :group 'bibtex-autokey |
515 | :type 'string) | |
50e4b39e | 516 | |
f754fb7b | 517 | (defcustom bibtex-autokey-names 1 |
cb4ad359 | 518 | "*Number of names to use for the automatically generated reference key. |
d0388eac | 519 | Possibly more names are used according to `bibtex-autokey-names-stretch'. |
d715b065 KG |
520 | If this variable is nil, all names are used. |
521 | See `bibtex-generate-autokey' for details." | |
f754fb7b | 522 | :group 'bibtex-autokey |
ab2d0cdb | 523 | :type '(choice (const :tag "All" infty) |
7fbf4804 | 524 | integer)) |
cb4ad359 | 525 | |
f754fb7b | 526 | (defcustom bibtex-autokey-names-stretch 0 |
50e4b39e RS |
527 | "*Number of names that can additionally be used. |
528 | These names are used only, if all names are used then. | |
d715b065 | 529 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
530 | :group 'bibtex-autokey |
531 | :type 'integer) | |
50e4b39e | 532 | |
f754fb7b | 533 | (defcustom bibtex-autokey-additional-names "" |
50e4b39e | 534 | "*String to prepend to the generated key if not all names could be used. |
d715b065 | 535 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
536 | :group 'bibtex-autokey |
537 | :type 'string) | |
50e4b39e RS |
538 | |
539 | (defvar bibtex-autokey-transcriptions | |
7fbf4804 SM |
540 | '(;; language specific characters |
541 | ("\\\\aa" . "a") ; \aa -> a | |
542 | ("\\\\AA" . "A") ; \AA -> A | |
543 | ("\\\"a\\|\\\\\\\"a\\|\\\\ae" . "ae") ; "a,\"a,\ae -> ae | |
544 | ("\\\"A\\|\\\\\\\"A\\|\\\\AE" . "Ae") ; "A,\"A,\AE -> Ae | |
545 | ("\\\\i" . "i") ; \i -> i | |
546 | ("\\\\j" . "j") ; \j -> j | |
547 | ("\\\\l" . "l") ; \l -> l | |
548 | ("\\\\L" . "L") ; \L -> L | |
549 | ("\\\"o\\|\\\\\\\"o\\|\\\\o\\|\\\\oe" . "oe") ; "o,\"o,\o,\oe -> oe | |
550 | ("\\\"O\\|\\\\\\\"O\\|\\\\O\\|\\\\OE" . "Oe") ; "O,\"O,\O,\OE -> Oe | |
551 | ("\\\"s\\|\\\\\\\"s\\|\\\\3" . "ss") ; "s,\"s,\3 -> ss | |
552 | ("\\\"u\\|\\\\\\\"u" . "ue") ; "u,\"u -> ue | |
553 | ("\\\"U\\|\\\\\\\"U" . "Ue") ; "U,\"U -> Ue | |
50e4b39e | 554 | ;; accents |
7fbf4804 | 555 | ("\\\\`\\|\\\\'\\|\\\\\\^\\|\\\\~\\|\\\\=\\|\\\\\\.\\|\\\\u\\|\\\\v\\|\\\\H\\|\\\\t\\|\\\\c\\|\\\\d\\|\\\\b" . "") |
d715b065 KG |
556 | ;; braces, quotes, concatenation. |
557 | ("[`'\"{}#]" . "") | |
7fbf4804 SM |
558 | ;; spaces |
559 | ("[ \t\n]+" . " ")) | |
d715b065 | 560 | "Alist of (OLD-REGEXP . NEW-STRING) pairs. |
d0388eac RS |
561 | Used by the default values of `bibtex-autokey-name-change-strings' and |
562 | `bibtex-autokey-titleword-change-strings'. Defaults to translating some | |
563 | language specific characters to their ASCII transcriptions, and | |
50e4b39e RS |
564 | removing any character accents.") |
565 | ||
f754fb7b | 566 | (defcustom bibtex-autokey-name-change-strings |
50e4b39e | 567 | bibtex-autokey-transcriptions |
d715b065 | 568 | "Alist of (OLD-REGEXP . NEW-STRING) pairs. |
d0388eac RS |
569 | Any part of name matching a OLD-REGEXP is replaced by NEW-STRING. |
570 | Case is significant in OLD-REGEXP. All regexps are tried in the | |
7fbf4804 | 571 | order in which they appear in the list. |
d715b065 | 572 | See `bibtex-generate-autokey' for details." |
f754fb7b | 573 | :group 'bibtex-autokey |
7fbf4804 SM |
574 | :type '(repeat (cons (regexp :tag "Old") |
575 | (string :tag "New")))) | |
cb4ad359 | 576 | |
ab2d0cdb RS |
577 | (defcustom bibtex-autokey-name-case-convert 'downcase |
578 | "*Function called for each name to perform case conversion. | |
d715b065 | 579 | See `bibtex-generate-autokey' for details." |
ab2d0cdb RS |
580 | :group 'bibtex-autokey |
581 | :type '(choice (const :tag "Preserve case" identity) | |
7fbf4804 SM |
582 | (const :tag "Downcase" downcase) |
583 | (const :tag "Capitalize" capitalize) | |
584 | (const :tag "Upcase" upcase) | |
585 | (function :tag "Conversion function"))) | |
ab2d0cdb | 586 | |
f754fb7b | 587 | (defcustom bibtex-autokey-name-length 'infty |
cb4ad359 RS |
588 | "*Number of characters from name to incorporate into key. |
589 | If this is set to anything but a number, all characters are used. | |
d715b065 | 590 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
591 | :group 'bibtex-autokey |
592 | :type '(choice (const :tag "All" infty) | |
7fbf4804 | 593 | integer)) |
cb4ad359 | 594 | |
f754fb7b | 595 | (defcustom bibtex-autokey-name-separator "" |
cb4ad359 | 596 | "*String that comes between any two names in the key. |
d715b065 | 597 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
598 | :group 'bibtex-autokey |
599 | :type 'string) | |
cb4ad359 | 600 | |
f754fb7b | 601 | (defcustom bibtex-autokey-year-length 2 |
24c5a085 | 602 | "*Number of rightmost digits from the year field to incorporate into key. |
d715b065 | 603 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
604 | :group 'bibtex-autokey |
605 | :type 'integer) | |
50e4b39e | 606 | |
7fbf4804 SM |
607 | (defcustom bibtex-autokey-use-crossref t |
608 | "*If non-nil use fields from crossreferenced entry if necessary. | |
609 | If this variable is non-nil and some field has no entry, but a | |
610 | valid crossref entry, the field from the crossreferenced entry is used. | |
d715b065 | 611 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
612 | :group 'bibtex-autokey |
613 | :type 'boolean) | |
cb4ad359 | 614 | |
f754fb7b | 615 | (defcustom bibtex-autokey-titlewords 5 |
cb4ad359 RS |
616 | "*Number of title words to use for the automatically generated reference key. |
617 | If this is set to anything but a number, all title words are used. | |
50e4b39e | 618 | Possibly more words from the title are used according to |
d0388eac | 619 | `bibtex-autokey-titlewords-stretch'. |
d715b065 | 620 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
621 | :group 'bibtex-autokey |
622 | :type '(choice (const :tag "All" infty) | |
7fbf4804 | 623 | integer)) |
cb4ad359 | 624 | |
f754fb7b | 625 | (defcustom bibtex-autokey-title-terminators |
50e4b39e | 626 | '("\\." "!" "\\?" ":" ";" "--") |
cb4ad359 RS |
627 | "*Regexp list defining the termination of the main part of the title. |
628 | Case of the regexps is ignored. | |
d715b065 | 629 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
630 | :group 'bibtex-autokey |
631 | :type '(repeat regexp)) | |
cb4ad359 | 632 | |
f754fb7b | 633 | (defcustom bibtex-autokey-titlewords-stretch 2 |
cb4ad359 RS |
634 | "*Number of words that can additionally be used from the title. |
635 | These words are used only, if a sentence from the title can be ended then. | |
d715b065 | 636 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
637 | :group 'bibtex-autokey |
638 | :type 'integer) | |
cb4ad359 | 639 | |
ab2d0cdb RS |
640 | (defcustom bibtex-autokey-titleword-ignore |
641 | '("A" "An" "On" "The" "Eine?" "Der" "Die" "Das" | |
642 | "[^A-Z].*" ".*[^a-zA-Z0-9].*") | |
643 | "*Determines words from the title that are not to be used in the key. | |
644 | Each item of the list is a regexp. If a word of the title matchs a | |
645 | regexp from that list, it is not included in the title part of the key. | |
d715b065 | 646 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
647 | :group 'bibtex-autokey |
648 | :type '(repeat regexp)) | |
cb4ad359 | 649 | |
ab2d0cdb RS |
650 | (defcustom bibtex-autokey-titleword-case-convert 'downcase |
651 | "*Function called for each titleword to perform case conversion. | |
d715b065 | 652 | See `bibtex-generate-autokey' for details." |
ab2d0cdb RS |
653 | :group 'bibtex-autokey |
654 | :type '(choice (const :tag "Preserve case" identity) | |
7fbf4804 SM |
655 | (const :tag "Downcase" downcase) |
656 | (const :tag "Capitalize" capitalize) | |
657 | (const :tag "Upcase" upcase) | |
658 | (function :tag "Conversion function"))) | |
ab2d0cdb | 659 | |
f754fb7b | 660 | (defcustom bibtex-autokey-titleword-abbrevs nil |
cb4ad359 | 661 | "*Determines exceptions to the usual abbreviation mechanism. |
d715b065 | 662 | An alist of (OLD-REGEXP . NEW-STRING) pairs. Case is ignored |
d0388eac | 663 | in matching against OLD-REGEXP, and the first matching pair is used. |
d715b065 | 664 | See `bibtex-generate-autokey' for details." |
7fbf4804 SM |
665 | :group 'bibtex-autokey |
666 | :type '(repeat (cons (regexp :tag "Old") | |
667 | (string :tag "New")))) | |
cb4ad359 | 668 | |
f754fb7b | 669 | (defcustom bibtex-autokey-titleword-change-strings |
50e4b39e | 670 | bibtex-autokey-transcriptions |
d715b065 | 671 | "Alist of (OLD-REGEXP . NEW-STRING) pairs. |
d0388eac RS |
672 | Any part of title word matching a OLD-REGEXP is replaced by NEW-STRING. |
673 | Case is significant in OLD-REGEXP. All regexps are tried in the | |
7fbf4804 | 674 | order in which they appear in the list. |
d715b065 | 675 | See `bibtex-generate-autokey' for details." |
f754fb7b | 676 | :group 'bibtex-autokey |
7fbf4804 SM |
677 | :type '(repeat (cons (regexp :tag "Old") |
678 | (string :tag "New")))) | |
cb4ad359 | 679 | |
f754fb7b | 680 | (defcustom bibtex-autokey-titleword-length 5 |
cb4ad359 RS |
681 | "*Number of characters from title words to incorporate into key. |
682 | If this is set to anything but a number, all characters are used. | |
d715b065 | 683 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
684 | :group 'bibtex-autokey |
685 | :type '(choice (const :tag "All" infty) | |
7fbf4804 | 686 | integer)) |
cb4ad359 | 687 | |
f754fb7b | 688 | (defcustom bibtex-autokey-titleword-separator "_" |
cb4ad359 | 689 | "*String to be put between the title words. |
d715b065 | 690 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
691 | :group 'bibtex-autokey |
692 | :type 'string) | |
cb4ad359 | 693 | |
f754fb7b | 694 | (defcustom bibtex-autokey-name-year-separator "" |
cb4ad359 | 695 | "*String to be put between name part and year part of key. |
d715b065 | 696 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
697 | :group 'bibtex-autokey |
698 | :type 'string) | |
cb4ad359 | 699 | |
f754fb7b | 700 | (defcustom bibtex-autokey-year-title-separator ":_" |
cb4ad359 | 701 | "*String to be put between name part and year part of key. |
d715b065 | 702 | See `bibtex-generate-autokey' for details." |
f754fb7b RS |
703 | :group 'bibtex-autokey |
704 | :type 'string) | |
50e4b39e | 705 | |
f754fb7b RS |
706 | (defcustom bibtex-autokey-edit-before-use t |
707 | "*If non-nil, user is allowed to edit the generated key before it is used." | |
708 | :group 'bibtex-autokey | |
709 | :type 'boolean) | |
cb4ad359 | 710 | |
ab2d0cdb | 711 | (defcustom bibtex-autokey-before-presentation-function nil |
7fbf4804 | 712 | "*Function to call before the generated key is presented. |
d715b065 KG |
713 | If non-nil this should be a function which is called before the generated key |
714 | is presented. The function must take one argument (the automatically | |
715 | generated key), and must return a string (the key to use)." | |
f754fb7b | 716 | :group 'bibtex-autokey |
b4a64de4 | 717 | :type '(choice (const nil) function)) |
50e4b39e | 718 | |
f754fb7b | 719 | (defcustom bibtex-entry-offset 0 |
50e4b39e | 720 | "*Offset for BibTeX entries. |
f754fb7b RS |
721 | Added to the value of all other variables which determine colums." |
722 | :group 'bibtex | |
723 | :type 'integer) | |
50e4b39e | 724 | |
f754fb7b RS |
725 | (defcustom bibtex-field-indentation 2 |
726 | "*Starting column for the name part in BibTeX fields." | |
727 | :group 'bibtex | |
728 | :type 'integer) | |
50e4b39e | 729 | |
f754fb7b | 730 | (defcustom bibtex-text-indentation |
7fbf4804 SM |
731 | (+ bibtex-field-indentation |
732 | (length "organization = ")) | |
50e4b39e | 733 | "*Starting column for the text part in BibTeX fields. |
f754fb7b RS |
734 | Should be equal to the space needed for the longest name part." |
735 | :group 'bibtex | |
736 | :type 'integer) | |
50e4b39e | 737 | |
f754fb7b | 738 | (defcustom bibtex-contline-indentation |
50e4b39e | 739 | (+ bibtex-text-indentation 1) |
f754fb7b RS |
740 | "*Starting column for continuation lines of BibTeX fields." |
741 | :group 'bibtex | |
742 | :type 'integer) | |
50e4b39e | 743 | |
f754fb7b | 744 | (defcustom bibtex-align-at-equal-sign nil |
50e4b39e | 745 | "*If non-nil, align fields at equal sign instead of field text. |
7fbf4804 SM |
746 | If non-nil, the column for the equal sign is the value of |
747 | `bibtex-text-indentation', minus 2." | |
f754fb7b RS |
748 | :group 'bibtex |
749 | :type 'boolean) | |
750 | ||
751 | (defcustom bibtex-comma-after-last-field nil | |
752 | "*If non-nil, a comma is put at end of last field in the entry template." | |
753 | :group 'bibtex | |
754 | :type 'boolean) | |
50e4b39e | 755 | |
d715b065 KG |
756 | (defcustom bibtex-autoadd-commas t |
757 | "If non-nil automatically add missing commas at end of BibTeX fields." | |
758 | :type 'boolean) | |
759 | ||
760 | (defcustom bibtex-autofill-types '("Proceedings") | |
761 | "Automatically fill fields if possible for those BibTeX entry types." | |
762 | :type '(repeat string)) | |
763 | ||
7fbf4804 SM |
764 | (defcustom bibtex-complete-key-cleanup nil |
765 | "*Function called by `bibtex-complete' after insertion of a key fragment." | |
766 | :group 'bibtex-autokey | |
767 | :type '(choice (const :tag "None" nil) | |
768 | (function :tag "Cleanup function"))) | |
769 | ||
31bc4210 RS |
770 | ;; bibtex-font-lock-keywords is a user option as well, but since the |
771 | ;; patterns used to define this variable are defined in a later | |
50e4b39e | 772 | ;; section of this file, it is defined later. |
28f2ee66 GM |
773 | |
774 | \f | |
5c69dbfc | 775 | ;; Syntax Table, Keybindings and BibTeX Entry List |
9ae11a89 ER |
776 | (defvar bibtex-mode-syntax-table |
777 | (let ((st (make-syntax-table))) | |
50e4b39e | 778 | (modify-syntax-entry ?\" "\"" st) |
9ae11a89 ER |
779 | (modify-syntax-entry ?$ "$$ " st) |
780 | (modify-syntax-entry ?% "< " st) | |
50e4b39e RS |
781 | (modify-syntax-entry ?' "w " st) |
782 | (modify-syntax-entry ?@ "w " st) | |
9ae11a89 ER |
783 | (modify-syntax-entry ?\\ "\\" st) |
784 | (modify-syntax-entry ?\f "> " st) | |
785 | (modify-syntax-entry ?\n "> " st) | |
7fbf4804 SM |
786 | ;; Keys cannot have = in them (wrong font-lock of @string{foo=bar}). |
787 | (modify-syntax-entry ?= "." st) | |
9ae11a89 | 788 | (modify-syntax-entry ?~ " " st) |
7fbf4804 SM |
789 | st) |
790 | "Syntax table used in BibTeX mode buffers.") | |
9ae11a89 | 791 | |
9ae11a89 ER |
792 | (defvar bibtex-mode-map |
793 | (let ((km (make-sparse-keymap))) | |
28f2ee66 | 794 | ;; The Key `C-c&' is reserved for reftex.el |
9ae11a89 ER |
795 | (define-key km "\t" 'bibtex-find-text) |
796 | (define-key km "\n" 'bibtex-next-field) | |
7fbf4804 | 797 | (define-key km "\M-\t" 'bibtex-complete) |
50e4b39e RS |
798 | (define-key km "\C-c\"" 'bibtex-remove-delimiters) |
799 | (define-key km "\C-c{" 'bibtex-remove-delimiters) | |
800 | (define-key km "\C-c}" 'bibtex-remove-delimiters) | |
9ae11a89 | 801 | (define-key km "\C-c\C-c" 'bibtex-clean-entry) |
50e4b39e | 802 | (define-key km "\C-c\C-q" 'bibtex-fill-entry) |
cb4ad359 | 803 | (define-key km "\C-c?" 'bibtex-print-help-message) |
9ae11a89 ER |
804 | (define-key km "\C-c\C-p" 'bibtex-pop-previous) |
805 | (define-key km "\C-c\C-n" 'bibtex-pop-next) | |
50e4b39e RS |
806 | (define-key km "\C-c\C-k" 'bibtex-kill-field) |
807 | (define-key km "\C-c\M-k" 'bibtex-copy-field-as-kill) | |
808 | (define-key km "\C-c\C-w" 'bibtex-kill-entry) | |
809 | (define-key km "\C-c\M-w" 'bibtex-copy-entry-as-kill) | |
810 | (define-key km "\C-c\C-y" 'bibtex-yank) | |
811 | (define-key km "\C-c\M-y" 'bibtex-yank-pop) | |
9ae11a89 | 812 | (define-key km "\C-c\C-d" 'bibtex-empty-field) |
50e4b39e RS |
813 | (define-key km "\C-c\C-f" 'bibtex-make-field) |
814 | (define-key km "\C-c$" 'bibtex-ispell-abstract) | |
815 | (define-key km "\M-\C-a" 'bibtex-beginning-of-entry) | |
816 | (define-key km "\M-\C-e" 'bibtex-end-of-entry) | |
817 | (define-key km "\C-\M-l" 'bibtex-reposition-window) | |
818 | (define-key km "\C-\M-h" 'bibtex-mark-entry) | |
819 | (define-key km "\C-c\C-b" 'bibtex-entry) | |
cb4ad359 RS |
820 | (define-key km "\C-c\C-rn" 'bibtex-narrow-to-entry) |
821 | (define-key km "\C-c\C-rw" 'widen) | |
50e4b39e | 822 | (define-key km "\C-c\C-o" 'bibtex-remove-OPT-or-ALT) |
cb4ad359 | 823 | (define-key km "\C-c\C-e\C-i" 'bibtex-InProceedings) |
9ae11a89 | 824 | (define-key km "\C-c\C-ei" 'bibtex-InCollection) |
cb4ad359 RS |
825 | (define-key km "\C-c\C-eI" 'bibtex-InBook) |
826 | (define-key km "\C-c\C-e\C-a" 'bibtex-Article) | |
827 | (define-key km "\C-c\C-e\C-b" 'bibtex-InBook) | |
828 | (define-key km "\C-c\C-eb" 'bibtex-Book) | |
829 | (define-key km "\C-c\C-eB" 'bibtex-Booklet) | |
830 | (define-key km "\C-c\C-e\C-c" 'bibtex-InCollection) | |
9ae11a89 ER |
831 | (define-key km "\C-c\C-e\C-m" 'bibtex-Manual) |
832 | (define-key km "\C-c\C-em" 'bibtex-MastersThesis) | |
833 | (define-key km "\C-c\C-eM" 'bibtex-Misc) | |
cb4ad359 | 834 | (define-key km "\C-c\C-e\C-p" 'bibtex-InProceedings) |
9ae11a89 | 835 | (define-key km "\C-c\C-ep" 'bibtex-Proceedings) |
cb4ad359 | 836 | (define-key km "\C-c\C-eP" 'bibtex-PhdThesis) |
50e4b39e RS |
837 | (define-key km "\C-c\C-e\M-p" 'bibtex-Preamble) |
838 | (define-key km "\C-c\C-e\C-s" 'bibtex-String) | |
cb4ad359 | 839 | (define-key km "\C-c\C-e\C-t" 'bibtex-TechReport) |
9ae11a89 | 840 | (define-key km "\C-c\C-e\C-u" 'bibtex-Unpublished) |
7fbf4804 SM |
841 | km) |
842 | "Keymap used in BibTeX mode.") | |
9ae11a89 | 843 | |
50e4b39e | 844 | (easy-menu-define |
7fbf4804 SM |
845 | bibtex-edit-menu bibtex-mode-map "BibTeX-Edit Menu in BibTeX mode" |
846 | '("BibTeX-Edit" | |
847 | ("Moving inside an Entry" | |
848 | ["End of Field" bibtex-find-text t] | |
849 | ["Next Field" bibtex-next-field t] | |
850 | ["Beginning of Entry" bibtex-beginning-of-entry t] | |
851 | ["End of Entry" bibtex-end-of-entry t]) | |
d715b065 KG |
852 | ("Moving in BibTeX Buffer" |
853 | ["Find Entry" bibtex-find-entry t] | |
854 | ["Find Crossref Entry" bibtex-find-crossref t]) | |
7fbf4804 SM |
855 | ("Operating on Current Entry" |
856 | ["Fill Entry" bibtex-fill-entry t] | |
857 | ["Clean Entry" bibtex-clean-entry t] | |
858 | "--" | |
859 | ["Kill Entry" bibtex-kill-entry t] | |
860 | ["Copy Entry to Kill Ring" bibtex-copy-entry-as-kill t] | |
861 | ["Paste Most Recently Killed Entry" bibtex-yank t] | |
862 | ["Paste Previously Killed Entry" bibtex-yank-pop t] | |
863 | "--" | |
864 | ["Ispell Entry" bibtex-ispell-entry t] | |
865 | ["Ispell Entry Abstract" bibtex-ispell-abstract t] | |
866 | ["Narrow to Entry" bibtex-narrow-to-entry t] | |
867 | "--" | |
868 | ["View Cite Locations (RefTeX)" reftex-view-crossref-from-bibtex | |
869 | (fboundp 'reftex-view-crossref-from-bibtex)]) | |
870 | ("Operating on Current Field" | |
d715b065 | 871 | ["Fill Field" fill-paragraph t] |
7fbf4804 SM |
872 | ["Remove Delimiters" bibtex-remove-delimiters t] |
873 | ["Remove OPT or ALT Prefix" bibtex-remove-OPT-or-ALT t] | |
874 | ["Clear Field" bibtex-empty-field t] | |
875 | "--" | |
876 | ["Kill Field" bibtex-kill-field t] | |
877 | ["Copy Field to Kill Ring" bibtex-copy-field-as-kill t] | |
878 | ["Paste Most Recently Killed Field" bibtex-yank t] | |
879 | ["Paste Previously Killed Field" bibtex-yank-pop t] | |
880 | "--" | |
881 | ["Make New Field" bibtex-make-field t] | |
882 | "--" | |
883 | ["Snatch from Similar Following Field" bibtex-pop-next t] | |
884 | ["Snatch from Similar Preceding Field" bibtex-pop-previous t] | |
885 | "--" | |
886 | ["String or Key Complete" bibtex-complete t] | |
887 | "--" | |
888 | ["Help about Current Field" bibtex-print-help-message t]) | |
889 | ("Operating on Buffer or Region" | |
890 | ["Validate Entries" bibtex-validate t] | |
891 | ["Sort Entries" bibtex-sort-buffer t] | |
892 | ["Reformat Entries" bibtex-reformat t] | |
893 | ["Count Entries" bibtex-count-entries t]) | |
894 | ("Miscellaneous" | |
895 | ["Convert Alien Buffer" bibtex-convert-alien t]))) | |
50e4b39e RS |
896 | |
897 | (easy-menu-define | |
7fbf4804 SM |
898 | bibtex-entry-menu bibtex-mode-map "Entry-Types Menu in BibTeX mode" |
899 | (list "Entry-Types" | |
900 | ["Article in Journal" bibtex-Article t] | |
901 | ["Article in Conference Proceedings" bibtex-InProceedings t] | |
902 | ["Article in a Collection" bibtex-InCollection t] | |
903 | ["Chapter or Pages in a Book" bibtex-InBook t] | |
904 | ["Conference Proceedings" bibtex-Proceedings t] | |
905 | ["Book" bibtex-Book t] | |
906 | ["Booklet (Bound, but no Publisher/Institution)" bibtex-Booklet t] | |
907 | ["PhD. Thesis" bibtex-PhdThesis t] | |
908 | ["Master's Thesis" bibtex-MastersThesis t] | |
909 | ["Technical Report" bibtex-TechReport t] | |
910 | ["Technical Manual" bibtex-Manual t] | |
911 | ["Unpublished" bibtex-Unpublished t] | |
912 | ["Miscellaneous" bibtex-Misc t] | |
913 | ["String" bibtex-String t] | |
914 | ["Preamble" bibtex-Preamble t])) | |
9ae11a89 | 915 | |
31bc4210 | 916 | \f |
5c69dbfc | 917 | ;; Internal Variables |
9ae11a89 | 918 | |
7fbf4804 SM |
919 | (defvar bibtex-pop-previous-search-point nil |
920 | "Next point where `bibtex-pop-previous' starts looking for a similar entry.") | |
921 | ||
922 | (defvar bibtex-pop-next-search-point nil | |
923 | "Next point where `bibtex-pop-next' starts looking for a similar entry.") | |
924 | ||
925 | (defvar bibtex-field-kill-ring nil | |
926 | "Ring of least recently killed fields. | |
927 | At most `bibtex-field-kill-ring-max' items are kept here.") | |
9ae11a89 | 928 | |
7fbf4804 SM |
929 | (defvar bibtex-field-kill-ring-yank-pointer nil |
930 | "The tail of `bibtex-field-kill-ring' whose car is the last item yanked.") | |
745bc783 | 931 | |
7fbf4804 SM |
932 | (defvar bibtex-entry-kill-ring nil |
933 | "Ring of least recently killed entries. | |
934 | At most `bibtex-entry-kill-ring-max' items are kept here.") | |
50e4b39e | 935 | |
7fbf4804 SM |
936 | (defvar bibtex-entry-kill-ring-yank-pointer nil |
937 | "The tail of `bibtex-entry-kill-ring' whose car is the last item yanked.") | |
50e4b39e | 938 | |
7fbf4804 SM |
939 | (defvar bibtex-last-kill-command nil |
940 | "Type of the last kill command (either 'field or 'entry).") | |
50e4b39e | 941 | |
d715b065 KG |
942 | (defvar bibtex-strings |
943 | (lazy-completion-table bibtex-strings | |
944 | bibtex-parse-strings (bibtex-string-files-init)) | |
945 | "Completion table for BibTeX string keys. | |
7fbf4804 | 946 | Initialized from `bibtex-predefined-strings' and `bibtex-string-files'.") |
d715b065 | 947 | (make-variable-buffer-local 'bibtex-strings) |
50e4b39e | 948 | |
d715b065 KG |
949 | (defvar bibtex-reference-keys |
950 | (lazy-completion-table bibtex-reference-keys bibtex-parse-keys nil nil t) | |
951 | "Completion table for BibTeX reference keys.") | |
952 | (make-variable-buffer-local 'bibtex-reference-keys) | |
50e4b39e | 953 | |
7fbf4804 SM |
954 | (defvar bibtex-buffer-last-parsed-tick nil |
955 | "Last value returned by `buffer-modified-tick' when buffer | |
956 | was parsed for keys the last time.") | |
745bc783 | 957 | |
7fbf4804 SM |
958 | (defvar bibtex-parse-idle-timer nil |
959 | "Stores if timer is already installed.") | |
0640d7bf | 960 | |
7fbf4804 SM |
961 | (defvar bibtex-progress-lastperc nil |
962 | "Last reported percentage for the progress message.") | |
50e4b39e | 963 | |
7fbf4804 SM |
964 | (defvar bibtex-progress-lastmes nil |
965 | "Last reported progress message.") | |
50e4b39e | 966 | |
7fbf4804 SM |
967 | (defvar bibtex-progress-interval nil |
968 | "Interval for progress messages.") | |
50e4b39e | 969 | |
7fbf4804 SM |
970 | (defvar bibtex-key-history nil |
971 | "History list for reading keys.") | |
50e4b39e | 972 | |
7fbf4804 | 973 | (defvar bibtex-entry-type-history nil |
d715b065 | 974 | "History list for reading entry types.") |
50e4b39e | 975 | |
7fbf4804 SM |
976 | (defvar bibtex-field-history nil |
977 | "History list for reading field names.") | |
50e4b39e | 978 | |
7fbf4804 SM |
979 | (defvar bibtex-reformat-previous-options nil |
980 | "Last reformat options given.") | |
50e4b39e | 981 | |
7fbf4804 SM |
982 | (defvar bibtex-reformat-previous-reference-keys nil |
983 | "Last reformat reference keys option given.") | |
50e4b39e | 984 | |
7fbf4804 SM |
985 | (defconst bibtex-field-name "[^\"#%'(),={} \t\n0-9][^\"#%'(),={} \t\n]*" |
986 | "Regexp matching the name part of a BibTeX field.") | |
50e4b39e | 987 | |
7fbf4804 SM |
988 | (defconst bibtex-entry-type (concat "@" bibtex-field-name) |
989 | "Regexp matching the type part of a BibTeX entry.") | |
990 | ||
991 | (defconst bibtex-reference-key "[][a-zA-Z0-9.:;?!`'/*@+|()<>&_^$-]+" | |
992 | "Regexp matching the reference key part of a BibTeX entry.") | |
993 | ||
994 | (defconst bibtex-field-const "[][a-zA-Z0-9.:;?!`'/*@+=|<>&_^$-]+" | |
995 | "Regexp matching a BibTeX field constant.") | |
996 | ||
997 | (defconst bibtex-entry-head | |
998 | (concat "^[ \t]*\\(" | |
999 | bibtex-entry-type | |
1000 | "\\)[ \t]*[({][ \t\n]*\\(" | |
1001 | bibtex-reference-key | |
1002 | "\\)") | |
1003 | "Regexp matching the header line of a BibTeX entry.") | |
1004 | ||
1005 | (defconst bibtex-entry-maybe-empty-head | |
1006 | (concat bibtex-entry-head "?") | |
d715b065 | 1007 | "Regexp matching the header line of a BibTeX entry (possibly without key).") |
7fbf4804 SM |
1008 | |
1009 | (defconst bibtex-type-in-head 1 | |
1010 | "Regexp subexpression number of the type part in `bibtex-entry-head'.") | |
1011 | ||
1012 | (defconst bibtex-key-in-head 2 | |
1013 | "Regexp subexpression number of the key part in `bibtex-entry-head'.") | |
1014 | ||
1015 | (defconst bibtex-entry-postfix "[ \t\n]*,?[ \t\n]*[})]" | |
1016 | "Regexp matching the postfix of a BibTeX entry.") | |
1017 | ||
1018 | (defvar bibtex-known-entry-type-re | |
1019 | (regexp-opt (mapcar 'car bibtex-entry-field-alist)) | |
1020 | "Regexp matching the name of a BibTeX entry type.") | |
1021 | ||
1022 | (defvar bibtex-valid-entry-re | |
1023 | (concat "@[ \t]*\\(" bibtex-known-entry-type-re "\\)") | |
1024 | "Regexp matching the name of a valid BibTeX entry.") | |
1025 | ||
1026 | (defvar bibtex-valid-entry-whitespace-re | |
1027 | (concat "[ \t\n]*\\(" bibtex-valid-entry-re "\\)") | |
1028 | "Regexp matching the name of a valid BibTeX entry preceded by whitespace.") | |
1029 | ||
1030 | (defvar bibtex-any-valid-entry-re | |
1031 | (concat "@[ \t]*" | |
1032 | (regexp-opt (append '("String") | |
1033 | (mapcar 'car bibtex-entry-field-alist)) | |
1034 | t)) | |
1035 | "Regexp matching the name of any valid BibTeX entry (including string).") | |
1036 | ||
1037 | ||
1038 | (defconst bibtex-empty-field-re "\"\"\\|{}" | |
1039 | "Regexp matching an empty field.") | |
1040 | ||
1041 | (defconst bibtex-quoted-string-re | |
1042 | (concat "\"" | |
1043 | "\\(" | |
1044 | "[^\"\\]" ; anything but quote or backslash | |
1045 | "\\|" | |
1046 | "\\(" | |
1047 | "\\\\\\(.\\|\n\\)" ; any backslash quoted character | |
1048 | "\\)" | |
1049 | "\\)*" | |
1050 | "\"") | |
1051 | "Regexp matching a field string enclosed by quotes.") | |
1052 | ||
1053 | (defconst bibtex-font-lock-syntactic-keywords | |
1054 | `((,(concat "^[ \t]*\\(" (substring bibtex-comment-start 0 1) "\\)" | |
1055 | (substring bibtex-comment-start 1) "\\>") | |
1056 | 1 '(11)))) | |
1057 | ||
1058 | (defvar bibtex-font-lock-keywords | |
1059 | (list | |
1060 | ;; entry type and reference key | |
1061 | (list bibtex-entry-maybe-empty-head | |
1062 | (list bibtex-type-in-head 'font-lock-function-name-face) | |
1063 | (list bibtex-key-in-head 'font-lock-constant-face nil t)) | |
1064 | ;; optional field names (treated as comments) | |
1065 | (list | |
1066 | (concat "^[ \t]*\\(OPT" bibtex-field-name "\\)[ \t]*=") | |
1067 | 1 'font-lock-comment-face) | |
1068 | ;; field names | |
1069 | (list (concat "^[ \t]*\\(" bibtex-field-name "\\)[ \t]*=") | |
1070 | 1 'font-lock-variable-name-face)) | |
1071 | "*Default expressions to highlight in BibTeX mode.") | |
1072 | ||
1073 | (defvar bibtex-field-name-for-parsing nil | |
1074 | "Temporary variable storing the name string to be parsed by the callback | |
1075 | function `bibtex-parse-field-name'.") | |
1076 | ||
1077 | (defvar bibtex-sort-entry-class-alist | |
1078 | (let ((i -1) alist) | |
1079 | (dolist (class bibtex-sort-entry-class alist) | |
1080 | (setq i (1+ i)) | |
1081 | (dolist (entry class) | |
d715b065 KG |
1082 | ;; all entry names should be downcase (for ease of comparison) |
1083 | (push (cons (if (stringp entry) (downcase entry) entry) i) alist)))) | |
7fbf4804 SM |
1084 | "Alist for the classes of the entry types if the value of |
1085 | `bibtex-maintain-sorted-entries' is `entry-class'.") | |
0640d7bf | 1086 | |
cb4ad359 | 1087 | \f |
7fbf4804 SM |
1088 | ;; Special support taking care of variants |
1089 | (defvar zmacs-regions) | |
1090 | (if (boundp 'mark-active) | |
1091 | (defun bibtex-mark-active () | |
1092 | ;; In Emacs mark-active indicates if mark is active. | |
1093 | mark-active) | |
1094 | (defun bibtex-mark-active () | |
1095 | ;; In XEmacs (mark) returns nil when not active. | |
1096 | (if zmacs-regions (mark) (mark t)))) | |
745bc783 | 1097 | |
7fbf4804 SM |
1098 | (if (fboundp 'run-with-idle-timer) |
1099 | ;; timer.el is distributed with Emacs | |
1100 | (fset 'bibtex-run-with-idle-timer 'run-with-idle-timer) | |
1101 | ;; timer.el is not distributed with XEmacs | |
1102 | ;; Notice that this does not (yet) pass the arguments, but they | |
1103 | ;; are not used (yet) in bibtex.el. Fix if needed. | |
1104 | (defun bibtex-run-with-idle-timer (secs repeat function &rest args) | |
1105 | (start-itimer "bibtex" function secs (if repeat secs nil) t))) | |
cb4ad359 | 1106 | |
7fbf4804 SM |
1107 | \f |
1108 | ;; Support for hideshow minor mode | |
1109 | (defun bibtex-hs-forward-sexp (arg) | |
1110 | "Replacement for `forward-sexp' to be used by `hs-minor-mode'." | |
1111 | (if (< arg 0) | |
1112 | (backward-sexp 1) | |
1113 | (if (looking-at "@\\S(*\\s(") | |
1114 | (progn | |
1115 | (goto-char (match-end 0)) | |
1116 | (forward-char -1) | |
1117 | (forward-sexp 1)) | |
1118 | (forward-sexp 1)))) | |
50e4b39e | 1119 | |
7fbf4804 SM |
1120 | (add-to-list |
1121 | 'hs-special-modes-alist | |
1122 | '(bibtex-mode "@\\S(*\\s(" "\\s)" nil bibtex-hs-forward-sexp nil)) | |
1123 | ||
1124 | \f | |
d715b065 KG |
1125 | (defconst bibtex-braced-string-syntax-table |
1126 | (let ((st (make-syntax-table))) | |
1127 | (modify-syntax-entry ?\{ "(}" st) | |
1128 | (modify-syntax-entry ?\} "){" st) | |
1129 | (modify-syntax-entry ?\[ "." st) | |
1130 | (modify-syntax-entry ?\] "." st) | |
1131 | (modify-syntax-entry ?\( "." st) | |
1132 | (modify-syntax-entry ?\) "." st) | |
1133 | (modify-syntax-entry ?\\ "." st) | |
1134 | (modify-syntax-entry ?\" "." st) | |
1135 | st) | |
1136 | "Syntax-table to parse matched braces.") | |
1137 | ||
1138 | (defconst bibtex-quoted-string-syntax-table | |
1139 | (let ((st (make-syntax-table))) | |
1140 | (modify-syntax-entry ?\\ "\\" st) | |
1141 | (modify-syntax-entry ?\" "\"" st) | |
1142 | st) | |
1143 | "Syntax-table to parse matched quotes.") | |
f9bd4abe GM |
1144 | |
1145 | (defun bibtex-parse-field-string () | |
7fbf4804 | 1146 | "Parse a field string enclosed by braces or quotes. |
f9bd4abe GM |
1147 | If a syntactically correct string is found, a pair containing the start and |
1148 | end position of the field string is returned, nil otherwise." | |
d715b065 KG |
1149 | (let ((end-point |
1150 | (or (and (eq (following-char) ?\") | |
1151 | (save-excursion | |
1152 | (with-syntax-table bibtex-quoted-string-syntax-table | |
1153 | (forward-sexp 1)) | |
1154 | (point))) | |
1155 | (and (eq (following-char) ?\{) | |
1156 | (save-excursion | |
1157 | (with-syntax-table bibtex-braced-string-syntax-table | |
1158 | (forward-sexp 1)) | |
1159 | (point)))))) | |
1160 | (if end-point | |
1161 | (cons (point) end-point)))) | |
f9bd4abe GM |
1162 | |
1163 | (defun bibtex-parse-association (parse-lhs parse-rhs) | |
7fbf4804 | 1164 | "Parse a string of the format <left-hand-side = right-hand-side>. |
f9bd4abe GM |
1165 | The functions PARSE-LHS and PARSE-RHS are used to parse the corresponding |
1166 | substrings. These functions are expected to return nil if parsing is not | |
1167 | successfull. If both functions return non-nil, a pair containing the returned | |
7fbf4804 | 1168 | values of the functions PARSE-LHS and PARSE-RHS is returned." |
f9bd4abe | 1169 | (save-match-data |
7fbf4804 | 1170 | (save-excursion |
d715b065 KG |
1171 | (let ((left (funcall parse-lhs)) |
1172 | right) | |
1173 | (if (and left | |
7fbf4804 SM |
1174 | (looking-at "[ \t\n]*=[ \t\n]*") |
1175 | (goto-char (match-end 0)) | |
1176 | (setq right (funcall parse-rhs))) | |
1177 | (cons left right)))))) | |
f9bd4abe GM |
1178 | |
1179 | (defun bibtex-parse-field-name () | |
7fbf4804 | 1180 | "Parse the field name stored in `bibtex-field-name-for-parsing'. |
f9bd4abe GM |
1181 | If the field name is found, return a triple consisting of the position of the |
1182 | very first character of the match, the actual starting position of the name | |
d715b065 KG |
1183 | part and end position of the match. Move point to end of field name. |
1184 | If `bibtex-autoadd-commas' is non-nil add missing comma at end of preceeding | |
1185 | BibTeX field as necessary." | |
1186 | (cond ((looking-at ",[ \t\n]*") | |
1187 | (let ((start (point))) | |
1188 | (goto-char (match-end 0)) | |
1189 | (when (looking-at bibtex-field-name-for-parsing) | |
1190 | (goto-char (match-end 0)) | |
1191 | (list start (match-beginning 0) (match-end 0))))) | |
1192 | ;; Maybe add a missing comma. | |
1193 | ((and bibtex-autoadd-commas | |
1194 | (looking-at (concat "[ \t\n]*\\(?:" bibtex-field-name-for-parsing | |
1195 | "\\)[ \t\n]*="))) | |
1196 | (skip-chars-backward " \t\n") | |
1197 | (insert ",") | |
1198 | (forward-char -1) | |
1199 | ;; Now try again. | |
1200 | (bibtex-parse-field-name)))) | |
d30bfc76 | 1201 | |
f9bd4abe | 1202 | (defun bibtex-parse-field-text () |
7fbf4804 | 1203 | "Parse the text part of a BibTeX field. |
f9bd4abe GM |
1204 | The text part is either a string, or an empty string, or a constant followed |
1205 | by one or more <# (string|constant)> pairs. If a syntactically correct text | |
1206 | is found, a pair containing the start and end position of the text is | |
7fbf4804 | 1207 | returned, nil otherwise. Move point to end of field text." |
f9bd4abe | 1208 | (let ((starting-point (point)) |
7fbf4804 | 1209 | end-point failure boundaries) |
d715b065 | 1210 | (while (not (or end-point failure)) |
7fbf4804 SM |
1211 | (cond ((looking-at bibtex-field-const) |
1212 | (goto-char (match-end 0))) | |
1213 | ((setq boundaries (bibtex-parse-field-string)) | |
1214 | (goto-char (cdr boundaries))) | |
1215 | ((setq failure t))) | |
f9bd4abe | 1216 | (if (not (looking-at "[ \t\n]*#[ \t\n]*")) |
7fbf4804 SM |
1217 | (setq end-point (point)) |
1218 | (goto-char (match-end 0)))) | |
1219 | (if (and (not failure) | |
1220 | end-point) | |
1221 | (cons starting-point end-point)))) | |
f9bd4abe GM |
1222 | |
1223 | (defun bibtex-parse-field (name) | |
7fbf4804 | 1224 | "Parse a BibTeX field of regexp NAME. |
f9bd4abe GM |
1225 | If a syntactically correct field is found, a pair containing the boundaries of |
1226 | the name and text parts of the field is returned." | |
7fbf4804 SM |
1227 | (let ((bibtex-field-name-for-parsing name)) |
1228 | (bibtex-parse-association 'bibtex-parse-field-name | |
1229 | 'bibtex-parse-field-text))) | |
f9bd4abe | 1230 | |
7fbf4804 SM |
1231 | (defun bibtex-search-forward-field (name &optional bound) |
1232 | "Search forward to find a field of name NAME. | |
f9bd4abe GM |
1233 | If a syntactically correct field is found, a pair containing the boundaries of |
1234 | the name and text parts of the field is returned. The search is limited by | |
d715b065 KG |
1235 | optional arg BOUND. If BOUND is t the search is limited by the end of the current |
1236 | entry. Do not move point." | |
f9bd4abe | 1237 | (save-match-data |
7fbf4804 | 1238 | (save-excursion |
d715b065 KG |
1239 | (unless (integer-or-marker-p bound) |
1240 | (setq bound (if bound | |
1241 | (save-excursion (bibtex-end-of-entry)) | |
1242 | (point-max)))) | |
7fbf4804 SM |
1243 | (let ((case-fold-search t) |
1244 | (bibtex-field-name-for-parsing name) | |
1245 | boundaries temp-boundaries) | |
1246 | (while (and (not boundaries) | |
1247 | (< (point) bound) | |
1248 | (search-forward "," bound t)) | |
1249 | (goto-char (match-beginning 0)) | |
1250 | (if (and (setq temp-boundaries | |
1251 | (bibtex-parse-association 'bibtex-parse-field-name | |
1252 | 'bibtex-parse-field-text)) | |
1253 | (<= (cddr temp-boundaries) bound)) | |
1254 | (setq boundaries temp-boundaries) | |
1255 | (forward-char 1))) | |
1256 | boundaries)))) | |
1257 | ||
1258 | (defun bibtex-search-backward-field (name &optional bound) | |
1259 | "Search backward to find a field of name NAME. | |
f9bd4abe GM |
1260 | If a syntactically correct field is found, a pair containing the boundaries of |
1261 | the name and text parts of the field is returned. The search is limited by | |
d715b065 KG |
1262 | optional arg BOUND. If BOUND is t the search is limited by the beginning of the |
1263 | current entry. Do not move point." | |
f9bd4abe | 1264 | (save-match-data |
7fbf4804 | 1265 | (save-excursion |
d715b065 KG |
1266 | (unless (integer-or-marker-p bound) |
1267 | (setq bound (if bound | |
1268 | (save-excursion (bibtex-beginning-of-entry)) | |
1269 | (point-min)))) | |
7fbf4804 SM |
1270 | (let ((case-fold-search t) |
1271 | (bibtex-field-name-for-parsing name) | |
1272 | boundaries temp-boundaries) | |
1273 | (while (and (not boundaries) | |
1274 | (>= (point) bound) | |
1275 | (search-backward "," bound t)) | |
1276 | (if (setq temp-boundaries | |
1277 | (bibtex-parse-association 'bibtex-parse-field-name | |
1278 | 'bibtex-parse-field-text)) | |
1279 | (setq boundaries temp-boundaries))) | |
1280 | boundaries)))) | |
f9bd4abe | 1281 | |
d715b065 | 1282 | (defsubst bibtex-start-of-field (bounds) |
7fbf4804 | 1283 | (nth 0 (car bounds))) |
d715b065 | 1284 | (defsubst bibtex-start-of-name-in-field (bounds) |
7fbf4804 | 1285 | (nth 1 (car bounds))) |
d715b065 | 1286 | (defsubst bibtex-end-of-name-in-field (bounds) |
7fbf4804 | 1287 | (nth 2 (car bounds))) |
d715b065 | 1288 | (defsubst bibtex-end-of-field (bounds) |
7fbf4804 | 1289 | (cddr bounds)) |
d715b065 | 1290 | (defsubst bibtex-start-of-text-in-field (bounds) |
7fbf4804 | 1291 | (cadr bounds)) |
d715b065 | 1292 | (defsubst bibtex-end-of-text-in-field (bounds) |
7fbf4804 SM |
1293 | (cddr bounds)) |
1294 | ||
1295 | (defun bibtex-name-in-field (bounds) | |
1296 | "Get content of name in BibTeX field defined via BOUNDS." | |
1297 | (buffer-substring-no-properties (nth 1 (car bounds)) | |
1298 | (nth 2 (car bounds)))) | |
1299 | ||
1300 | (defun bibtex-text-in-field-bounds (bounds &optional remove-delim) | |
1301 | "Get content of text in BibTeX field defined via BOUNDS. | |
1302 | If optional arg REMOVE-DELIM is non-nil remove enclosing field delimiters | |
1303 | if present." | |
1304 | (let ((content (buffer-substring-no-properties (cadr bounds) | |
1305 | (cddr bounds)))) | |
1306 | (if (and remove-delim | |
1307 | (string-match "\\`[{\"]\\(.*\\)[}\"]\\'" content)) | |
1308 | (substring content (match-beginning 1) (match-end 1)) | |
1309 | content))) | |
1310 | ||
1311 | (defun bibtex-text-in-field (field &optional follow-crossref) | |
1312 | "Get content of field FIELD of current BibTeX entry. Return nil if not found. | |
1313 | If optional arg FOLLOW-CROSSREF is non-nil, follow crossref." | |
1314 | (save-excursion | |
1315 | (save-restriction | |
d715b065 | 1316 | ;; We want to jump back and forth while searching FIELD |
7fbf4804 SM |
1317 | (bibtex-narrow-to-entry) |
1318 | (goto-char (point-min)) | |
1319 | (let ((bounds (bibtex-search-forward-field field)) | |
1320 | crossref-field) | |
1321 | (cond (bounds (bibtex-text-in-field-bounds bounds t)) | |
1322 | ((and follow-crossref | |
1323 | (progn (goto-char (point-min)) | |
1324 | (setq bounds (bibtex-search-forward-field | |
1325 | "\\(OPT\\)?crossref")))) | |
1326 | (setq crossref-field (bibtex-text-in-field-bounds bounds t)) | |
1327 | (widen) | |
1328 | (if (bibtex-find-crossref crossref-field) | |
1329 | ;; Do not pass FOLLOW-CROSSREF because we want | |
1330 | ;; to follow crossrefs only one level of recursion. | |
1331 | (bibtex-text-in-field field)))))))) | |
f9bd4abe GM |
1332 | |
1333 | (defun bibtex-parse-string-prefix () | |
7fbf4804 | 1334 | "Parse the prefix part of a BibTeX string entry, including reference key. |
f9bd4abe GM |
1335 | If the string prefix is found, return a triple consisting of the position of |
1336 | the very first character of the match, the actual starting position of the | |
1337 | reference key and the end position of the match." | |
7fbf4804 | 1338 | (let ((case-fold-search t)) |
f9bd4abe | 1339 | (if (looking-at "^[ \t]*@string[ \t\n]*[({][ \t\n]*") |
7fbf4804 SM |
1340 | (let ((start (point))) |
1341 | (goto-char (match-end 0)) | |
1342 | (when (looking-at bibtex-reference-key) | |
1343 | (goto-char (match-end 0)) | |
1344 | (list start | |
1345 | (match-beginning 0) | |
1346 | (match-end 0))))))) | |
f9bd4abe GM |
1347 | |
1348 | (defun bibtex-parse-string-postfix () | |
7fbf4804 | 1349 | "Parse the postfix part of a BibTeX string entry, including the text. |
f9bd4abe GM |
1350 | If the string postfix is found, return a triple consisting of the position of |
1351 | the actual starting and ending position of the text and the very last | |
7fbf4804 | 1352 | character of the string entry. Move point past BibTeX string entry." |
f9bd4abe | 1353 | (let* ((case-fold-search t) |
d715b065 KG |
1354 | (bounds (bibtex-parse-field-text))) |
1355 | (when bounds | |
1356 | (goto-char (cdr bounds)) | |
7fbf4804 SM |
1357 | (when (looking-at "[ \t\n]*[})]") |
1358 | (goto-char (match-end 0)) | |
d715b065 KG |
1359 | (list (car bounds) |
1360 | (cdr bounds) | |
7fbf4804 | 1361 | (match-end 0)))))) |
f9bd4abe GM |
1362 | |
1363 | (defun bibtex-parse-string () | |
7fbf4804 | 1364 | "Parse a BibTeX string entry. |
f9bd4abe | 1365 | If a syntactically correct entry is found, a pair containing the boundaries of |
7fbf4804 SM |
1366 | the reference key and text parts of the entry is returned. |
1367 | Move point past BibTeX string entry." | |
f9bd4abe | 1368 | (bibtex-parse-association 'bibtex-parse-string-prefix |
7fbf4804 | 1369 | 'bibtex-parse-string-postfix)) |
f9bd4abe GM |
1370 | |
1371 | (defun bibtex-search-forward-string () | |
7fbf4804 | 1372 | "Search forward to find a BibTeX string entry. |
f9bd4abe | 1373 | If a syntactically correct entry is found, a pair containing the boundaries of |
7fbf4804 SM |
1374 | the reference key and text parts of the string is returned. Do not move point." |
1375 | (save-excursion | |
1376 | (save-match-data | |
1377 | (let ((case-fold-search t) | |
1378 | boundaries) | |
1379 | (while (and (not boundaries) | |
1380 | (search-forward-regexp | |
1381 | "^[ \t]*@string[ \t\n]*[({][ \t\n]*" nil t)) | |
1382 | (goto-char (match-beginning 0)) | |
1383 | (unless (setq boundaries (bibtex-parse-string)) | |
1384 | (forward-char 1))) | |
1385 | boundaries)))) | |
f9bd4abe GM |
1386 | |
1387 | (defun bibtex-search-backward-string () | |
7fbf4804 | 1388 | "Search backward to find a BibTeX string entry. |
f9bd4abe | 1389 | If a syntactically correct entry is found, a pair containing the boundaries of |
7fbf4804 SM |
1390 | the reference key and text parts of the field is returned. Do not move point." |
1391 | (save-excursion | |
1392 | (save-match-data | |
1393 | (let ((case-fold-search t) | |
1394 | boundaries) | |
1395 | (while (and (not boundaries) | |
1396 | (search-backward-regexp | |
1397 | "^[ \t]*@string[ \t\n]*[({][ \t\n]*" nil t)) | |
1398 | (goto-char (match-beginning 0)) | |
1399 | (setq boundaries (bibtex-parse-string))) | |
1400 | boundaries)))) | |
1401 | ||
1402 | (defun bibtex-reference-key-in-string (bounds) | |
1403 | (buffer-substring-no-properties (nth 1 (car bounds)) | |
1404 | (nth 2 (car bounds)))) | |
1405 | ||
1406 | (defun bibtex-text-in-string (bounds &optional remove-delim) | |
1407 | "Get content of text in BibTeX string field defined via BOUNDS. | |
1408 | If optional arg REMOVE-DELIM is non-nil remove enclosing field | |
1409 | delimiters if present." | |
1410 | (let ((content (buffer-substring-no-properties (nth 0 (cdr bounds)) | |
1411 | (nth 1 (cdr bounds))))) | |
1412 | (if (and remove-delim | |
1413 | (string-match "\\`{\\(.*\\)}\\'" content)) | |
1414 | (substring content (match-beginning 1) (match-end 1)) | |
1415 | content))) | |
f9bd4abe | 1416 | |
d715b065 | 1417 | (defsubst bibtex-start-of-text-in-string (bounds) |
7fbf4804 | 1418 | (nth 0 (cdr bounds))) |
d715b065 | 1419 | (defsubst bibtex-end-of-text-in-string (bounds) |
7fbf4804 | 1420 | (nth 1 (cdr bounds))) |
d715b065 | 1421 | (defsubst bibtex-end-of-string (bounds) |
7fbf4804 | 1422 | (nth 2 (cdr bounds))) |
745bc783 | 1423 | |
d715b065 | 1424 | (defsubst bibtex-type-in-head () |
7fbf4804 SM |
1425 | "Extract BibTeX type in head." |
1426 | ;; ignore @ | |
1427 | (buffer-substring-no-properties (1+ (match-beginning bibtex-type-in-head)) | |
1428 | (match-end bibtex-type-in-head))) | |
31bc4210 | 1429 | |
7fbf4804 SM |
1430 | (defun bibtex-key-in-head (&optional empty) |
1431 | "Extract BibTeX key in head. Return optional arg EMPTY if key is empty." | |
1432 | (if (match-beginning bibtex-key-in-head) | |
1433 | (buffer-substring-no-properties (match-beginning bibtex-key-in-head) | |
1434 | (match-end bibtex-key-in-head)) | |
1435 | empty)) | |
f9bd4abe | 1436 | |
5c69dbfc | 1437 | ;; Helper Functions |
e5167999 | 1438 | |
55fe21fc | 1439 | (defun bibtex-delete-whitespace () |
7fbf4804 | 1440 | "Delete all whitespace starting at point." |
50e4b39e RS |
1441 | (if (looking-at "[ \t\n]+") |
1442 | (delete-region (point) (match-end 0)))) | |
1443 | ||
55fe21fc | 1444 | (defun bibtex-current-line () |
7fbf4804 | 1445 | "Compute line number of point regardless whether the buffer is narrowed." |
50e4b39e RS |
1446 | (+ (count-lines 1 (point)) |
1447 | (if (equal (current-column) 0) 1 0))) | |
1448 | ||
43a8874d | 1449 | (defun bibtex-member-of-regexp (string list) |
7fbf4804 SM |
1450 | "Return non-nil if STRING is exactly matched by an element of LIST. |
1451 | The value is actually the tail of LIST whose car matches STRING." | |
1452 | (let (case-fold-search) | |
1453 | (while (and list | |
dd310c45 | 1454 | (not (string-match (concat "\\`\\(?:" (car list) "\\)\\'") string))) |
50e4b39e RS |
1455 | (setq list (cdr list))) |
1456 | list)) | |
cb4ad359 | 1457 | |
55fe21fc | 1458 | (defun bibtex-assoc-of-regexp (string alist) |
7fbf4804 SM |
1459 | "Return non-nil if STRING is exactly matched by the car of an |
1460 | element of ALIST (case ignored). The value is actually the element | |
1461 | of LIST whose car matches STRING." | |
1462 | (let ((case-fold-search t)) | |
1463 | (while (and alist | |
dd310c45 | 1464 | (not (string-match (concat "\\`\\(?:" (caar alist) "\\)\\'") string))) |
50e4b39e RS |
1465 | (setq alist (cdr alist))) |
1466 | (car alist))) | |
1467 | ||
55fe21fc | 1468 | (defun bibtex-skip-to-valid-entry (&optional backward) |
7fbf4804 SM |
1469 | "Unless at beginning of a valid BibTeX entry, move point to beginning of the |
1470 | next valid one. With optional argument BACKWARD non-nil, move backward to | |
1471 | beginning of previous valid one. A valid entry is a syntactical correct one | |
1472 | with type contained in `bibtex-entry-field-alist' or, if | |
1473 | `bibtex-sort-ignore-string-entries' is nil, a syntactical correct string | |
d715b065 KG |
1474 | entry. Return buffer position of beginning and ending of entry if a valid |
1475 | entry is found, nil otherwise." | |
1476 | (interactive "P") | |
7fbf4804 SM |
1477 | (let ((case-fold-search t) |
1478 | found) | |
d715b065 KG |
1479 | (while (not (or found (if backward (bobp) (eobp)))) |
1480 | (let ((pnt (point)) | |
1481 | bounds) | |
7fbf4804 | 1482 | (cond ((or (and (looking-at bibtex-valid-entry-re) |
d715b065 | 1483 | (setq found (bibtex-search-entry nil nil t)) |
7fbf4804 SM |
1484 | (equal (match-beginning 0) pnt)) |
1485 | (and (not bibtex-sort-ignore-string-entries) | |
d715b065 KG |
1486 | (setq bounds (bibtex-parse-string)) |
1487 | (setq found (cons (bibtex-start-of-field bounds) | |
1488 | (bibtex-end-of-string bounds))))) | |
7fbf4804 SM |
1489 | (goto-char pnt)) |
1490 | (backward | |
7fbf4804 SM |
1491 | (if (re-search-backward "^[ \t]*\\(@\\)" nil 'move) |
1492 | (goto-char (match-beginning 1)))) | |
d715b065 | 1493 | (t (if (re-search-forward "\n[ \t]*@" nil 'move) |
7fbf4804 SM |
1494 | (forward-char -1)))))) |
1495 | found)) | |
9ae11a89 | 1496 | |
55fe21fc | 1497 | (defun bibtex-map-entries (fun) |
7fbf4804 | 1498 | "Call FUN for each BibTeX entry starting with the current. |
d715b065 KG |
1499 | Do this to the end of the file. FUN is called with three arguments, the key of |
1500 | the entry and the buffer positions (marker) of beginning and end of entry. | |
1501 | Point is inside the entry. If `bibtex-sort-ignore-string-entries' is non-nil, | |
1502 | FUN will not be called for @String entries." | |
7fbf4804 | 1503 | (let ((case-fold-search t)) |
50e4b39e | 1504 | (bibtex-beginning-of-entry) |
d715b065 KG |
1505 | (while (re-search-forward bibtex-entry-head nil t) |
1506 | (let ((entry-type (bibtex-type-in-head)) | |
1507 | (key (bibtex-key-in-head "")) | |
1508 | (beg (copy-marker (match-beginning 0))) | |
1509 | (end (copy-marker (save-excursion (bibtex-end-of-entry))))) | |
1510 | (save-excursion | |
7fbf4804 | 1511 | (if (or (and (not bibtex-sort-ignore-string-entries) |
d715b065 | 1512 | (string-equal "string" (downcase entry-type))) |
7fbf4804 | 1513 | (assoc-ignore-case entry-type bibtex-entry-field-alist)) |
d715b065 KG |
1514 | (funcall fun key beg end))) |
1515 | (goto-char end))))) | |
50e4b39e RS |
1516 | |
1517 | (defun bibtex-progress-message (&optional flag interval) | |
7fbf4804 SM |
1518 | "Echo a message about progress of current buffer. |
1519 | If FLAG is a string, the message is initialized (in this case a | |
1520 | value for INTERVAL may be given as well (if not this is set to 5)). | |
1521 | If FLAG is done, the message is deinitialized. | |
1522 | If FLAG is absent, a message is echoed if point was incremented | |
1523 | at least INTERVAL percent since last message was echoed." | |
1524 | (cond ((stringp flag) | |
1525 | (setq bibtex-progress-lastmes flag) | |
1526 | (setq bibtex-progress-interval (or interval 5) | |
1527 | bibtex-progress-lastperc 0)) | |
1528 | ((equal flag 'done) | |
1529 | (message "%s (done)" bibtex-progress-lastmes) | |
1530 | (setq bibtex-progress-lastmes nil)) | |
1531 | (t | |
1532 | (let* ((size (- (point-max) (point-min))) | |
1533 | (perc (if (= size 0) | |
1534 | 100 | |
1535 | (/ (* 100 (- (point) (point-min))) size)))) | |
1536 | (when (>= perc (+ bibtex-progress-lastperc | |
1537 | bibtex-progress-interval)) | |
1538 | (setq bibtex-progress-lastperc perc) | |
1539 | (message "%s (%d%%)" bibtex-progress-lastmes perc)))))) | |
50e4b39e RS |
1540 | |
1541 | (defun bibtex-field-left-delimiter () | |
7fbf4804 | 1542 | "Return a string dependent on `bibtex-field-delimiters'." |
50e4b39e RS |
1543 | (if (equal bibtex-field-delimiters 'braces) |
1544 | "{" | |
1545 | "\"")) | |
1546 | ||
1547 | (defun bibtex-field-right-delimiter () | |
7fbf4804 | 1548 | "Return a string dependent on `bibtex-field-delimiters'." |
50e4b39e RS |
1549 | (if (equal bibtex-field-delimiters 'braces) |
1550 | "}" | |
1551 | "\"")) | |
1552 | ||
1553 | (defun bibtex-entry-left-delimiter () | |
7fbf4804 | 1554 | "Return a string dependent on `bibtex-field-delimiters'." |
50e4b39e RS |
1555 | (if (equal bibtex-entry-delimiters 'braces) |
1556 | "{" | |
1557 | "(")) | |
1558 | ||
1559 | (defun bibtex-entry-right-delimiter () | |
7fbf4804 | 1560 | "Return a string dependent on `bibtex-field-delimiters'." |
50e4b39e RS |
1561 | (if (equal bibtex-entry-delimiters 'braces) |
1562 | "}" | |
1563 | ")")) | |
1564 | ||
7fbf4804 | 1565 | (defun bibtex-search-entry (empty-head &optional bound noerror backward) |
d715b065 KG |
1566 | "Search for a BibTeX entry (maybe without reference key if EMPTY-HEAD is t). |
1567 | BOUND and NOERROR are exactly as in `re-search-forward'. If BACKWARD | |
1568 | is non-nil, search is done in reverse direction. Point is moved past the | |
1569 | closing delimiter (at the beginning of entry if BACKWARD is non-nil). | |
1570 | Return a cons pair with buffer positions of beginning and end of entry. | |
1571 | After call to this function MATCH-BEGINNING and MATCH-END functions | |
1572 | are defined, but only for the head part of the entry | |
1573 | \(especially (match-end 0) just gives the end of the head part)." | |
50e4b39e | 1574 | (let ((pnt (point)) |
d715b065 KG |
1575 | (entry-head-re (if empty-head |
1576 | bibtex-entry-maybe-empty-head | |
1577 | bibtex-entry-head))) | |
50e4b39e RS |
1578 | (if backward |
1579 | (let (found) | |
1580 | (while (and (not found) | |
d715b065 | 1581 | (re-search-backward entry-head-re bound noerror)) |
f9bd4abe | 1582 | (setq found (bibtex-search-entry empty-head pnt t))) |
50e4b39e | 1583 | (if found |
d715b065 KG |
1584 | (progn (goto-char (match-beginning 0)) |
1585 | found) | |
7fbf4804 SM |
1586 | (cond ((equal noerror nil) |
1587 | ;; yell | |
d715b065 | 1588 | (error "Backward search of BibTeX entry failed")) |
7fbf4804 SM |
1589 | ((equal noerror t) |
1590 | ;; don't move | |
1591 | (goto-char pnt))) | |
50e4b39e | 1592 | nil)) |
7fbf4804 | 1593 | (let ((limit (or bound (point-max))) |
50e4b39e RS |
1594 | found) |
1595 | (while (and (not found) | |
d715b065 | 1596 | (re-search-forward entry-head-re bound noerror)) |
7fbf4804 SM |
1597 | (save-match-data |
1598 | (let ((entry-closer | |
1599 | (if (save-excursion | |
1600 | (goto-char (match-end bibtex-type-in-head)) | |
1601 | (looking-at "[ \t]*(")) | |
1602 | ;; entry opened with parenthesis | |
1603 | ?\) | |
1604 | ?\})) | |
1605 | (infix-start (point)) | |
1606 | finished bounds) | |
1607 | (while (not finished) | |
1608 | (skip-chars-forward " \t\n" limit) | |
1609 | (if (and (setq bounds (bibtex-parse-field bibtex-field-name)) | |
1610 | (<= (bibtex-end-of-field bounds) limit)) | |
1611 | (setq infix-start (bibtex-end-of-field bounds)) | |
1612 | (setq finished t)) | |
1613 | (goto-char infix-start)) | |
1614 | ;; This matches the infix* part. The AND construction assures | |
1615 | ;; that BOUND is respected. | |
1616 | (when (and (looking-at bibtex-entry-postfix) | |
1617 | (eq (char-before (match-end 0)) entry-closer) | |
1618 | (<= (match-end 0) limit)) | |
1619 | (goto-char (match-end 0)) | |
1620 | (setq found t))))) | |
50e4b39e | 1621 | (if found |
d715b065 | 1622 | (cons (match-beginning 0) (point)) |
7fbf4804 SM |
1623 | (cond ((not noerror) |
1624 | ;; yell | |
1625 | (error "Search of BibTeX entry failed")) | |
1626 | ((equal noerror t) | |
1627 | ;; don't move | |
1628 | (goto-char pnt))) | |
50e4b39e | 1629 | nil))))) |
e5167999 | 1630 | |
cb4ad359 | 1631 | (defun bibtex-flash-head () |
7fbf4804 SM |
1632 | "Flash at BibTeX entry head before point, if exists." |
1633 | (let ((case-fold-search t) | |
1634 | flash) | |
f9bd4abe | 1635 | (cond ((re-search-backward bibtex-entry-head nil t) |
7fbf4804 SM |
1636 | (goto-char (match-beginning bibtex-type-in-head)) |
1637 | (setq flash (match-end bibtex-key-in-head))) | |
1638 | (t | |
1639 | (end-of-line) | |
1640 | (skip-chars-backward " \t") | |
1641 | (setq flash (point)) | |
1642 | (beginning-of-line) | |
1643 | (skip-chars-forward " \t"))) | |
cb4ad359 | 1644 | (if (pos-visible-in-window-p (point)) |
7fbf4804 | 1645 | (sit-for 1) |
cb4ad359 | 1646 | (message "From: %s" |
7fbf4804 | 1647 | (buffer-substring (point) flash))))) |
e5167999 | 1648 | |
d715b065 KG |
1649 | (defun bibtex-make-optional-field (field) |
1650 | "Make an optional field named FIELD in current BibTeX entry." | |
1651 | (if (consp field) | |
1652 | (bibtex-make-field (cons (concat "OPT" (car field)) (cdr field))) | |
1653 | (bibtex-make-field (concat "OPT" field)))) | |
50e4b39e | 1654 | |
cb4ad359 | 1655 | (defun bibtex-move-outside-of-entry () |
7fbf4804 | 1656 | "Make sure point is outside of a BibTeX entry." |
f0cb6034 | 1657 | (let ((orig-point (point))) |
28f2ee66 | 1658 | (bibtex-end-of-entry) |
7fbf4804 SM |
1659 | (when (<= (point) orig-point) |
1660 | ;; We moved backward, so we weren't inside an entry to begin with. | |
1661 | ;; Leave point at the beginning of a line, and preferably | |
1662 | ;; at the beginning of a paragraph. | |
1663 | (goto-char orig-point) | |
1664 | (beginning-of-line 1) | |
1665 | (let ((cb (char-before (1- (point))))) | |
1666 | (unless (and cb (= ?\n cb)) | |
1667 | (re-search-forward "^[ \t]*[@\n]" nil 'move) | |
1668 | (backward-char 1)))) | |
f0cb6034 | 1669 | (skip-chars-forward " \t\n"))) |
50e4b39e RS |
1670 | |
1671 | (defun bibtex-beginning-of-first-entry () | |
7fbf4804 | 1672 | "Go to the beginning of the first BibTeX entry in buffer. Return point." |
e5167999 | 1673 | (goto-char (point-min)) |
50e4b39e RS |
1674 | (if (re-search-forward "^[ \t]*@" nil 'move) |
1675 | (beginning-of-line)) | |
1676 | (point)) | |
1677 | ||
1678 | (defun bibtex-beginning-of-last-entry () | |
7fbf4804 | 1679 | "Go to the beginning of the last BibTeX entry in buffer." |
50e4b39e RS |
1680 | (goto-char (point-max)) |
1681 | (if (re-search-backward "^[ \t]*@" nil 'move) | |
1682 | (beginning-of-line)) | |
1683 | (point)) | |
e5167999 | 1684 | |
cb4ad359 | 1685 | (defun bibtex-inside-field () |
7fbf4804 | 1686 | "Try to avoid point being at end of a BibTeX field." |
cb4ad359 | 1687 | (end-of-line) |
0640d7bf | 1688 | (skip-chars-backward " \t") |
cb4ad359 | 1689 | (cond ((= (preceding-char) ?,) |
7fbf4804 SM |
1690 | (forward-char -2))) |
1691 | (cond ((or (= (preceding-char) ?}) | |
1692 | (= (preceding-char) ?\")) | |
0640d7bf | 1693 | (forward-char -1)))) |
9ae11a89 | 1694 | |
50e4b39e | 1695 | (defun bibtex-enclosing-field (&optional noerr) |
7fbf4804 SM |
1696 | "Search for BibTeX field enclosing point. Point moves to end of field. |
1697 | Use `match-beginning' and `match-end' to parse the field. If NOERR is non-nil, | |
1698 | no error is signalled. In this case, bounds are returned on success, | |
1699 | nil otherwise." | |
d715b065 | 1700 | (let ((bounds (bibtex-search-backward-field bibtex-field-name t))) |
7fbf4804 | 1701 | (if (and bounds |
d715b065 KG |
1702 | (<= (bibtex-start-of-field bounds) (point)) |
1703 | (>= (bibtex-end-of-field bounds) (point))) | |
7fbf4804 SM |
1704 | bounds |
1705 | (unless noerr | |
1706 | (error "Can't find enclosing BibTeX field"))))) | |
f9bd4abe GM |
1707 | |
1708 | (defun bibtex-enclosing-entry-maybe-empty-head () | |
d715b065 | 1709 | "Search for BibTeX entry enclosing point. Move point to end of entry. |
7fbf4804 SM |
1710 | Beginning (but not end) of entry is given by (`match-beginning' 0)." |
1711 | (let ((case-fold-search t) | |
1712 | (old-point (point))) | |
1713 | (unless (re-search-backward bibtex-entry-maybe-empty-head nil t) | |
d715b065 KG |
1714 | (goto-char old-point) |
1715 | (error "Can't find beginning of enclosing BibTeX entry")) | |
0640d7bf | 1716 | (goto-char (match-beginning bibtex-type-in-head)) |
7fbf4804 | 1717 | (unless (bibtex-search-entry t nil t) |
d715b065 KG |
1718 | (goto-char old-point) |
1719 | (error "Can't find end of enclosing BibTeX entry")))) | |
50e4b39e RS |
1720 | |
1721 | (defun bibtex-insert-current-kill (n) | |
1722 | (if (not bibtex-last-kill-command) | |
f0cb6034 | 1723 | (error "BibTeX kill ring is empty") |
50e4b39e RS |
1724 | (let* ((kr (if (equal bibtex-last-kill-command 'field) |
1725 | 'bibtex-field-kill-ring | |
1726 | 'bibtex-entry-kill-ring)) | |
1727 | (kryp (if (equal bibtex-last-kill-command 'field) | |
1728 | 'bibtex-field-kill-ring-yank-pointer | |
1729 | 'bibtex-entry-kill-ring-yank-pointer)) | |
7fbf4804 SM |
1730 | (ARGth-kill-element (nthcdr (mod (- n (length (eval kryp))) |
1731 | (length (eval kr))) | |
1732 | (eval kr))) | |
50e4b39e RS |
1733 | (current (car (set kryp ARGth-kill-element)))) |
1734 | (cond | |
1735 | ((equal bibtex-last-kill-command 'field) | |
1736 | (let (bibtex-help-message) | |
1737 | (bibtex-find-text nil t) | |
1738 | (if (looking-at "[}\"]") | |
1739 | (forward-char))) | |
1740 | (set-mark (point)) | |
1741 | (message "Mark set") | |
1742 | (bibtex-make-field (list (elt current 1) nil (elt current 2)) t)) | |
1743 | ((equal bibtex-last-kill-command 'entry) | |
1744 | (if (not (eobp)) | |
1745 | (bibtex-beginning-of-entry)) | |
1746 | (set-mark (point)) | |
1747 | (message "Mark set") | |
1748 | (insert (elt current 1))) | |
1749 | (t | |
7fbf4804 SM |
1750 | (error "Unknown tag field: %s. Please submit a bug report" |
1751 | bibtex-last-kill-command)))))) | |
f9bd4abe | 1752 | |
50e4b39e | 1753 | (defun bibtex-format-entry () |
7fbf4804 SM |
1754 | "Helper function for `bibtex-clean-entry'. |
1755 | Formats current entry according to variable `bibtex-entry-format'." | |
1756 | (save-excursion | |
1757 | (save-restriction | |
1758 | (bibtex-narrow-to-entry) | |
1759 | (let ((case-fold-search t) | |
1760 | (format (if (equal bibtex-entry-format t) | |
1761 | '(realign opts-or-alts required-fields | |
1762 | numerical-fields | |
1763 | last-comma page-dashes delimiters | |
1764 | unify-case inherit-booktitle) | |
1765 | bibtex-entry-format)) | |
1766 | crossref-key bounds alternatives-there non-empty-alternative | |
1767 | entry-list req creq field-done field-list) | |
1768 | ||
1769 | ;; identify entry type | |
1770 | (goto-char (point-min)) | |
1771 | (re-search-forward bibtex-entry-type) | |
1772 | (let ((beg-type (1+ (match-beginning 0))) | |
1773 | (end-type (match-end 0))) | |
1774 | (setq entry-list (assoc-ignore-case (buffer-substring-no-properties | |
1775 | beg-type end-type) | |
1776 | bibtex-entry-field-alist) | |
1777 | req (nth 0 (nth 1 entry-list)) ; required part | |
1778 | creq (nth 0 (nth 2 entry-list))) ; crossref part | |
1779 | ||
1780 | ;; unify case of entry name | |
1781 | (when (memq 'unify-case format) | |
1782 | (delete-region beg-type end-type) | |
1783 | (insert (car entry-list))) | |
1784 | ||
1785 | ;; update left entry delimiter | |
1786 | (when (memq 'delimiters format) | |
1787 | (goto-char end-type) | |
1788 | (skip-chars-forward " \t\n") | |
1789 | (delete-char 1) | |
1790 | (insert (bibtex-entry-left-delimiter)))) | |
1791 | ||
1792 | ;; determine if entry has crossref field and if at least | |
1793 | ;; one alternative is non-empty | |
1794 | (goto-char (point-min)) | |
1795 | (while (setq bounds (bibtex-search-forward-field | |
1796 | bibtex-field-name)) | |
1797 | (goto-char (bibtex-start-of-name-in-field bounds)) | |
1798 | (cond ((looking-at "ALT") | |
1799 | (setq alternatives-there t) | |
1800 | (goto-char (bibtex-start-of-text-in-field bounds)) | |
1801 | (if (not (looking-at bibtex-empty-field-re)) | |
1802 | (setq non-empty-alternative t))) | |
1803 | ((and (looking-at "\\(OPT\\)?crossref\\>") | |
1804 | (progn (goto-char (bibtex-start-of-text-in-field bounds)) | |
1805 | (not (looking-at bibtex-empty-field-re)))) | |
1806 | (setq crossref-key | |
1807 | (bibtex-text-in-field-bounds bounds t)))) | |
1808 | (goto-char (bibtex-end-of-field bounds))) | |
50e4b39e | 1809 | (if (and alternatives-there |
7fbf4804 SM |
1810 | (not non-empty-alternative) |
1811 | (memq 'required-fields format)) | |
1812 | (error "All alternatives are empty")) | |
1813 | ||
1814 | ;; process all fields | |
1815 | (goto-char (point-min)) | |
1816 | (while (setq bounds (bibtex-search-forward-field bibtex-field-name)) | |
1817 | (let* ((beg-field (copy-marker (bibtex-start-of-field bounds))) | |
1818 | (end-field (copy-marker (bibtex-end-of-field bounds))) | |
1819 | (beg-name (copy-marker (bibtex-start-of-name-in-field bounds))) | |
1820 | (end-name (copy-marker (bibtex-end-of-name-in-field bounds))) | |
1821 | (beg-text (copy-marker (bibtex-start-of-text-in-field bounds))) | |
1822 | (end-text (copy-marker (bibtex-end-of-text-in-field bounds))) | |
1823 | (opt-alt (string-match "OPT\\|ALT" | |
1824 | (buffer-substring-no-properties beg-name (+ beg-name 3)))) | |
1825 | (field-name (buffer-substring-no-properties | |
1826 | (if opt-alt (+ beg-name 3) beg-name) end-name)) | |
1827 | (empty-field (string-match bibtex-empty-field-re | |
1828 | (buffer-substring-no-properties beg-field end-field))) | |
1829 | deleted) | |
1830 | ||
1831 | ;; We have more elegant high-level functions for several | |
1832 | ;; tasks done by bibtex-format-entry. However, they contain | |
1833 | ;; quite some redundancy compared with what we need to do | |
1834 | ;; anyway. So for speed-up we avoid using them. | |
1835 | ||
1836 | (when (and opt-alt | |
1837 | (memq 'opts-or-alts format)) | |
1838 | (if empty-field | |
1839 | ;; Either it is an empty ALT field. Then we have checked | |
1840 | ;; already that we have one non-empty alternative. | |
1841 | ;; Or it is an empty OPT field that we do not miss anyway. | |
1842 | ;; So we can safely delete this field. | |
1843 | (progn (delete-region beg-field end-field) | |
1844 | (setq deleted t)) | |
1845 | ;; otherwise: not empty, delete "OPT" or "ALT" | |
1846 | (goto-char beg-name) | |
1847 | (delete-char 3))) | |
1848 | ||
1849 | (unless deleted | |
1850 | (push field-name field-list) | |
1851 | ||
1852 | ;; remove delimiters from purely numerical fields | |
1853 | (when (and (memq 'numerical-fields format) | |
1854 | (progn (goto-char beg-text) | |
1855 | (looking-at "\\(\"[0-9]+\"\\)\\|\\({[0-9]+}\\)"))) | |
1856 | (goto-char end-text) | |
1857 | (delete-char -1) | |
1858 | (goto-char beg-text) | |
1859 | (delete-char 1)) | |
1860 | ||
1861 | ;; update delimiters | |
1862 | (when (memq 'delimiters format) | |
1863 | (goto-char beg-text) | |
1864 | (when (looking-at "[{\"]") | |
1865 | (delete-char 1) | |
1866 | (insert (bibtex-field-left-delimiter))) | |
1867 | (goto-char (1- (marker-position end-text))) | |
1868 | (when (looking-at "[}\"]") | |
1869 | (delete-char 1) | |
1870 | (insert (bibtex-field-right-delimiter)))) | |
1871 | ||
1872 | ;; update page dashes | |
1873 | (if (and (memq 'page-dashes format) | |
dd310c45 | 1874 | (string-match "\\`\\(OPT\\)?pages\\'" field-name) |
7fbf4804 SM |
1875 | (progn (goto-char beg-text) |
1876 | (looking-at | |
1877 | "\\([\"{][0-9]+\\)[ \t\n]*--?[ \t\n]*\\([0-9]+[\"}]\\)"))) | |
1878 | (replace-match "\\1-\\2")) | |
1879 | ||
d715b065 | 1880 | ;; use book title of crossref'd entry |
7fbf4804 | 1881 | (if (and (memq 'inherit-booktitle format) |
7fbf4804 | 1882 | empty-field |
d715b065 | 1883 | (equal (downcase field-name) "booktitle") |
7fbf4804 SM |
1884 | crossref-key) |
1885 | (let ((title (save-restriction | |
1886 | (widen) | |
1887 | (if (bibtex-find-entry crossref-key) | |
1888 | (bibtex-text-in-field "title"))))) | |
1889 | (when title | |
1890 | (setq empty-field nil) | |
1891 | (goto-char (1+ beg-text)) | |
1892 | (insert title)))) | |
1893 | ||
d715b065 KG |
1894 | ;; Use booktitle to set a missing title. |
1895 | (if (and empty-field | |
1896 | (equal (downcase field-name) "title")) | |
1897 | (let ((booktitle (bibtex-text-in-field "booktitle"))) | |
1898 | (when booktitle | |
1899 | (setq empty-field nil) | |
1900 | (goto-char (1+ beg-text)) | |
1901 | (insert booktitle)))) | |
7fbf4804 SM |
1902 | |
1903 | ;; if empty field, complain | |
1904 | (if (and empty-field | |
1905 | (memq 'required-fields format) | |
1906 | (assoc-ignore-case field-name | |
1907 | (if crossref-key creq req))) | |
1908 | (error "Mandatory field `%s' is empty" field-name)) | |
1909 | ||
1910 | ;; unify case of field name | |
1911 | (if (memq 'unify-case format) | |
1912 | (let ((fname (car (assoc-ignore-case | |
1913 | field-name (append (nth 0 (nth 1 entry-list)) | |
1914 | (nth 1 (nth 1 entry-list)) | |
1915 | bibtex-user-optional-fields))))) | |
1916 | (if fname | |
1917 | (progn | |
1918 | (delete-region beg-name end-name) | |
1919 | (goto-char beg-name) | |
1920 | (insert fname)) | |
1921 | ;; there are no rules we could follow | |
1922 | (downcase-region beg-name end-name)))) | |
1923 | ||
1924 | ;; update point | |
1925 | (goto-char end-field)))) | |
1926 | ||
1927 | ;; check whether all required fields are present | |
1928 | (if (memq 'required-fields format) | |
1929 | (let (altlist (found 0)) | |
1930 | (dolist (fname (if crossref-key creq req)) | |
1931 | (if (nth 3 fname) | |
1932 | (push (car fname) altlist)) | |
1933 | (unless (or (member (car fname) field-list) | |
1934 | (nth 3 fname)) | |
1935 | (error "Mandatory field `%s' is missing" (car fname)))) | |
1936 | (when altlist | |
1937 | (dolist (fname altlist) | |
1938 | (if (member fname field-list) | |
1939 | (setq found (1+ found)))) | |
1940 | (cond ((= found 0) | |
1941 | (error "Alternative mandatory field `%s' is missing" | |
1942 | altlist)) | |
1943 | ((> found 1) | |
1944 | (error "Alternative fields `%s' is defined %s times" | |
1945 | altlist found)))))) | |
1946 | ||
1947 | ;; update point | |
1948 | (if (looking-at (bibtex-field-right-delimiter)) | |
1949 | (forward-char)) | |
1950 | ||
1951 | ;; update comma after last field | |
1952 | (if (memq 'last-comma format) | |
1953 | (cond ((and bibtex-comma-after-last-field | |
1954 | (not (looking-at ","))) | |
1955 | (insert ",")) | |
1956 | ((and (not bibtex-comma-after-last-field) | |
1957 | (looking-at ",")) | |
1958 | (delete-char 1)))) | |
1959 | ||
1960 | ;; update right entry delimiter | |
1961 | (if (looking-at ",") | |
1962 | (forward-char)) | |
1963 | (when (memq 'delimiters format) | |
1964 | (skip-chars-forward " \t\n") | |
1965 | (delete-char 1) | |
1966 | (insert (bibtex-entry-right-delimiter))) | |
1967 | ||
1968 | ;; fill entry | |
1969 | (if (memq 'realign format) | |
1970 | (bibtex-fill-entry)))))) | |
cb4ad359 | 1971 | |
7fbf4804 | 1972 | \f |
cb4ad359 | 1973 | (defun bibtex-autokey-abbrev (string len) |
7fbf4804 SM |
1974 | "Return an abbreviation of STRING with at least LEN characters. |
1975 | If LEN is positive the abbreviation is terminated only after a consonant | |
1976 | or at the word end. If LEN is negative the abbreviation is strictly | |
1977 | enforced using abs (LEN) characters. If LEN is not a number, STRING | |
1978 | is returned unchanged." | |
1979 | (cond ((or (not (numberp len)) | |
1980 | (<= (length string) (abs len))) | |
50e4b39e RS |
1981 | string) |
1982 | ((equal len 0) | |
1983 | "") | |
7fbf4804 SM |
1984 | ((< len 0) |
1985 | (substring string 0 (abs len))) | |
1986 | (t (let* ((case-fold-search t) | |
1987 | (abort-char (string-match "[^aeiou]" string (1- len)))) | |
1988 | (if abort-char | |
1989 | (substring string 0 (1+ abort-char)) | |
1990 | string))))) | |
1991 | ||
1992 | (defun bibtex-autokey-get-field (field &optional change-list) | |
1993 | "Get content of BibTeX field FIELD. Return empty string if not found. | |
1994 | Optional arg CHANGE-LIST is a list of substitution patterns that is | |
1995 | applied to the content of FIELD. It is an alist with pairs | |
1996 | \(OLD-REGEXP . NEW-STRING\)." | |
1997 | (let ((content (bibtex-text-in-field field bibtex-autokey-use-crossref)) | |
1998 | case-fold-search) | |
1999 | (unless content (setq content "")) | |
2000 | (dolist (pattern change-list content) | |
2001 | (setq content (replace-regexp-in-string (car pattern) | |
2002 | (cdr pattern) | |
2003 | content))))) | |
2004 | ||
2005 | (defun bibtex-autokey-get-names () | |
2006 | "Get contents of the name field of the current entry. | |
2007 | Do some modifications based on `bibtex-autokey-name-change-strings' | |
2008 | and return results as a list." | |
2009 | (let ((case-fold-search t)) | |
2010 | (mapcar 'bibtex-autokey-demangle-name | |
2011 | (split-string (bibtex-autokey-get-field | |
d715b065 | 2012 | "author\\|editor" |
7fbf4804 | 2013 | bibtex-autokey-name-change-strings) |
d715b065 | 2014 | "[ \t\n]+and[ \t\n]+")))) |
50e4b39e RS |
2015 | |
2016 | (defun bibtex-autokey-demangle-name (fullname) | |
7fbf4804 | 2017 | "Get the last part from a well-formed name and perform abbreviations." |
f9bd4abe | 2018 | (let* (case-fold-search |
7fbf4804 SM |
2019 | (name (cond ((string-match "\\([A-Z][^, ]*\\)[^,]*," fullname) |
2020 | ;; Name is of the form "von Last, First" or | |
2021 | ;; "von Last, Jr, First" | |
2022 | ;; --> Take the first capital part before the comma | |
dd310c45 | 2023 | (match-string 1 fullname)) |
7fbf4804 SM |
2024 | ((string-match "\\([^, ]*\\)," fullname) |
2025 | ;; Strange name: we have a comma, but nothing capital | |
2026 | ;; So we accept even lowercase names | |
dd310c45 SM |
2027 | (match-string 1 fullname)) |
2028 | ((string-match "\\(\\<[a-z][^ ]* +\\)+\\([A-Z][^ ]*\\)" | |
7fbf4804 SM |
2029 | fullname) |
2030 | ;; name is of the form "First von Last", "von Last", | |
2031 | ;; "First von von Last", or "d'Last" | |
2032 | ;; --> take the first capital part after the "von" parts | |
dd310c45 SM |
2033 | (match-string 2 fullname)) |
2034 | ((string-match "\\([^ ]+\\) *\\'" fullname) | |
7fbf4804 SM |
2035 | ;; name is of the form "First Middle Last" or "Last" |
2036 | ;; --> take the last token | |
dd310c45 | 2037 | (match-string 1 fullname)) |
7fbf4804 SM |
2038 | (t (error "Name `%s' is incorrectly formed" fullname))))) |
2039 | (bibtex-autokey-abbrev | |
2040 | (funcall bibtex-autokey-name-case-convert name) | |
2041 | bibtex-autokey-name-length))) | |
2042 | ||
2043 | (defun bibtex-autokey-get-title () | |
2044 | "Get title field contents up to a terminator." | |
2045 | (let ((titlestring | |
2046 | (bibtex-autokey-get-field "title" | |
2047 | bibtex-autokey-titleword-change-strings))) | |
2048 | ;; ignore everything past a terminator | |
2049 | (let ((case-fold-search t)) | |
2050 | (dolist (terminator bibtex-autokey-title-terminators) | |
2051 | (if (string-match terminator titlestring) | |
2052 | (setq titlestring (substring titlestring 0 (match-beginning 0)))))) | |
2053 | ;; gather words from titlestring into a list. Ignore | |
2054 | ;; specific words and use only a specific amount of words. | |
2055 | (let (case-fold-search titlewords titlewords-extra titleword end-match | |
2056 | (counter 0)) | |
2057 | (while (and (or (not (numberp bibtex-autokey-titlewords)) | |
2058 | (< counter (+ bibtex-autokey-titlewords | |
2059 | bibtex-autokey-titlewords-stretch))) | |
2060 | (string-match "\\b\\w+" titlestring)) | |
2061 | (setq end-match (match-end 0) | |
2062 | titleword (substring titlestring | |
2063 | (match-beginning 0) end-match)) | |
2064 | (unless (bibtex-member-of-regexp titleword | |
2065 | bibtex-autokey-titleword-ignore) | |
2066 | (setq titleword | |
2067 | (funcall bibtex-autokey-titleword-case-convert titleword)) | |
2068 | (if (or (not (numberp bibtex-autokey-titlewords)) | |
2069 | (< counter bibtex-autokey-titlewords)) | |
2070 | (setq titlewords (append titlewords (list titleword))) | |
2071 | (setq titlewords-extra | |
2072 | (append titlewords-extra (list titleword)))) | |
2073 | (setq counter (1+ counter))) | |
2074 | (setq titlestring (substring titlestring end-match))) | |
2075 | (unless (string-match "\\b\\w+" titlestring) | |
2076 | (setq titlewords (append titlewords titlewords-extra))) | |
2077 | (mapcar 'bibtex-autokey-demangle-title titlewords)))) | |
2078 | ||
2079 | (defun bibtex-autokey-demangle-title (titleword) | |
2080 | "Do some abbreviations on TITLEWORD. | |
2081 | The rules are defined in `bibtex-autokey-titleword-abbrevs' | |
2082 | and `bibtex-autokey-titleword-length'." | |
2083 | (let ((abbrev (bibtex-assoc-of-regexp | |
2084 | titleword bibtex-autokey-titleword-abbrevs))) | |
2085 | (if abbrev | |
2086 | (cdr abbrev) | |
2087 | (bibtex-autokey-abbrev titleword | |
2088 | bibtex-autokey-titleword-length)))) | |
cb4ad359 RS |
2089 | |
2090 | (defun bibtex-generate-autokey () | |
7fbf4804 | 2091 | "Generate automatically a key from the author/editor and the title field. |
03dbb1e7 KH |
2092 | This will only work for entries where each field begins on a separate line. |
2093 | The generation algorithm works as follows: | |
2094 | 1. Use the value of `bibtex-autokey-prefix-string' as a prefix. | |
2095 | 2. If there is a non-empty author (preferred) or editor field, | |
2096 | use it as the name part of the key. | |
ab2d0cdb RS |
2097 | 3. Change any substring found in |
2098 | `bibtex-autokey-name-change-strings' to the corresponding new | |
2099 | one (see documentation of this variable for further detail). | |
2100 | 4. For every of at least first `bibtex-autokey-names' names in | |
2101 | the name field, determine the last name. If there are maximal | |
03dbb1e7 KH |
2102 | `bibtex-autokey-names' + `bibtex-autokey-names-stretch' |
2103 | names, all names are used. | |
7fbf4804 SM |
2104 | 5. From every last name, take at least `bibtex-autokey-name-length' |
2105 | characters (abort only after a consonant or at a word end). | |
ab2d0cdb RS |
2106 | 6. Convert all last names according to the conversion function |
2107 | `bibtex-autokey-name-case-convert'. | |
2108 | 7. Build the name part of the key by concatenating all | |
2109 | abbreviated last names with the string | |
2110 | `bibtex-autokey-name-separator' between any two. If there are | |
2111 | more names than are used in the name part, prepend the string | |
2112 | contained in `bibtex-autokey-additional-names'. | |
03dbb1e7 KH |
2113 | 8. Build the year part of the key by truncating the contents of |
2114 | the year field to the rightmost `bibtex-autokey-year-length' | |
7fbf4804 SM |
2115 | digits (useful values are 2 and 4). If the year field (or any |
2116 | other field required to generate the key) is absent, but the entry | |
2117 | has a valid crossref field and the variable | |
2118 | `bibtex-autokey-use-crossref' is non-nil, use the field of the | |
2119 | crossreferenced entry instead. | |
ab2d0cdb | 2120 | 9. For the title part of the key change the contents of the |
f9bd4abe | 2121 | title field of the entry according to |
ab2d0cdb RS |
2122 | `bibtex-autokey-titleword-change-strings' to the |
2123 | corresponding new one (see documentation of this variable for | |
03dbb1e7 KH |
2124 | further detail). |
2125 | 10. Abbreviate the result to the string up to (but not including) | |
2126 | the first occurrence of a regexp matched by the items of | |
ab2d0cdb RS |
2127 | `bibtex-autokey-title-terminators' and delete those words which |
2128 | appear in `bibtex-autokey-titleword-ignore'. | |
2129 | Build the title part of the key by using at least the first | |
2130 | `bibtex-autokey-titlewords' words from this | |
2131 | abbreviated title. If the abbreviated title ends after | |
2132 | maximal `bibtex-autokey-titlewords' + | |
2133 | `bibtex-autokey-titlewords-stretch' words, all | |
2134 | words from the abbreviated title are used. | |
2135 | 11. Convert all used titlewords according to the conversion function | |
2136 | `bibtex-autokey-titleword-case-convert'. | |
2137 | 12. For every used title word that appears in | |
2138 | `bibtex-autokey-titleword-abbrevs' use the corresponding | |
2139 | abbreviation (see documentation of this variable for further | |
2140 | detail). | |
2141 | 13. From every title word not generated by an abbreviation, take | |
2142 | at least `bibtex-autokey-titleword-length' characters (abort | |
2143 | only after a consonant or at a word end). | |
2144 | 14. Build the title part of the key by concatenating all | |
2145 | abbreviated title words with the string | |
2146 | `bibtex-autokey-titleword-separator' between any two. | |
2147 | 15. At least, to get the key, concatenate | |
2148 | `bibtex-autokey-prefix-string', the name part, the year part | |
2149 | and the title part with `bibtex-autokey-name-year-separator' | |
2150 | between the name part and the year part if both are non-empty | |
2151 | and `bibtex-autokey-year-title-separator' between the year | |
2152 | part and the title part if both are non-empty. If the year | |
2153 | part is empty, but not the other two parts, | |
2154 | `bibtex-autokey-year-title-separator' is used as well. | |
2155 | 16. If the value of `bibtex-autokey-before-presentation-function' | |
2156 | is non-nil, it must be a function taking one argument. This | |
2157 | function is then called with the generated key as the | |
2158 | argument. The return value of this function (a string) is | |
2159 | used as the key. | |
03dbb1e7 | 2160 | 17. If the value of `bibtex-autokey-edit-before-use' is non-nil, |
ab2d0cdb | 2161 | the key is then presented in the minibuffer to the user, |
f0cb6034 | 2162 | where it can be edited. The key given by the user is then |
ab2d0cdb | 2163 | used." |
7fbf4804 | 2164 | (let* ((name-etal "") |
cb4ad359 | 2165 | (namelist |
7fbf4804 SM |
2166 | (let ((nl (bibtex-autokey-get-names)) |
2167 | nnl) | |
50e4b39e RS |
2168 | (if (or (not (numberp bibtex-autokey-names)) |
2169 | (<= (length nl) | |
2170 | (+ bibtex-autokey-names | |
2171 | bibtex-autokey-names-stretch))) | |
2172 | nl | |
2173 | (setq name-etal bibtex-autokey-additional-names) | |
7fbf4804 SM |
2174 | (while (< (length nnl) bibtex-autokey-names) |
2175 | (setq nnl (append nnl (list (car nl))) | |
2176 | nl (cdr nl))) | |
2177 | nnl))) | |
d715b065 | 2178 | (namepart (concat (mapconcat 'identity |
7fbf4804 SM |
2179 | namelist |
2180 | bibtex-autokey-name-separator) | |
2181 | name-etal)) | |
2182 | (yearfield (bibtex-autokey-get-field "year")) | |
2183 | (yearpart (if (equal yearfield "") | |
2184 | "" | |
2185 | (substring yearfield | |
2186 | (- (length yearfield) | |
2187 | bibtex-autokey-year-length)))) | |
d715b065 | 2188 | (titlepart (mapconcat 'identity |
7fbf4804 SM |
2189 | (bibtex-autokey-get-title) |
2190 | bibtex-autokey-titleword-separator)) | |
2191 | (autokey (concat bibtex-autokey-prefix-string | |
2192 | namepart | |
2193 | (unless (or (equal namepart "") | |
2194 | (equal yearpart "")) | |
2195 | bibtex-autokey-name-year-separator) | |
2196 | yearpart | |
2197 | (unless (or (and (equal namepart "") | |
2198 | (equal yearpart "")) | |
2199 | (equal titlepart "")) | |
2200 | bibtex-autokey-year-title-separator) | |
2201 | titlepart))) | |
ab2d0cdb | 2202 | (if bibtex-autokey-before-presentation-function |
7fbf4804 SM |
2203 | (funcall bibtex-autokey-before-presentation-function autokey) |
2204 | autokey))) | |
e5167999 | 2205 | |
7fbf4804 | 2206 | \f |
d715b065 | 2207 | (defun bibtex-parse-keys (&optional add abortable verbose) |
7fbf4804 SM |
2208 | "Set `bibtex-reference-keys' to the keys used in the whole buffer. |
2209 | The buffer might possibly be restricted. | |
2210 | Find both entry keys and crossref entries. | |
d715b065 KG |
2211 | If ADD is non-nil add the new keys to `bibtex-reference-keys' instead of |
2212 | simply resetting it. If ADD is an alist of keys, also add ADD to | |
2213 | `bibtex-reference-keys'. If ABORTABLE is non-nil abort on user | |
2214 | input. If VERBOSE is non-nil gives messages about progress. | |
2215 | Return alist of keys if parsing was completed, `aborted' otherwise." | |
2216 | (let ((reference-keys (if (and add | |
2217 | (listp bibtex-reference-keys)) | |
2218 | bibtex-reference-keys))) | |
2219 | (if (listp add) | |
2220 | (dolist (key add) | |
2221 | (unless (assoc (car key) reference-keys) | |
2222 | (push key reference-keys)))) | |
7fbf4804 SM |
2223 | (save-excursion |
2224 | (save-match-data | |
7fbf4804 SM |
2225 | (if verbose |
2226 | (bibtex-progress-message | |
2227 | (concat (buffer-name) ": parsing reference keys"))) | |
d715b065 KG |
2228 | (catch 'userkey |
2229 | (goto-char (point-min)) | |
2230 | (if bibtex-parse-keys-fast | |
2231 | (let ((case-fold-search t) | |
2232 | (re (concat bibtex-entry-head "\\|" | |
2233 | ",[ \t\n]*crossref[ \t\n]*=[ \t\n]*" | |
2234 | "\\(\"[^\"]*\"\\|{[^}]*}\\)[ \t\n]*[,})]"))) | |
2235 | (while (re-search-forward re nil t) | |
2236 | (if (and abortable (input-pending-p)) | |
2237 | ;; user has aborted by typing a key --> return `aborted' | |
2238 | (throw 'userkey 'aborted)) | |
2239 | (let ((key (cond ((match-end 3) | |
2240 | ;; This is a crossref. | |
2241 | (buffer-substring-no-properties | |
2242 | (1+ (match-beginning 3)) (1- (match-end 3)))) | |
2243 | ((assoc-ignore-case (bibtex-type-in-head) | |
2244 | bibtex-entry-field-alist) | |
2245 | ;; This is an entry. | |
2246 | (match-string-no-properties bibtex-key-in-head))))) | |
2247 | (if (and (stringp key) | |
2248 | (not (assoc key reference-keys))) | |
2249 | (push (list key) reference-keys))))) | |
2250 | ||
2251 | (let (;; ignore @String entries because they are handled | |
2252 | ;; separately by bibtex-parse-strings | |
2253 | (bibtex-sort-ignore-string-entries t) | |
2254 | crossref-key bounds) | |
2255 | (bibtex-map-entries | |
2256 | (lambda (key beg end) | |
2257 | (if (and abortable | |
2258 | (input-pending-p)) | |
2259 | ;; user has aborted by typing a key --> return `aborted' | |
2260 | (throw 'userkey 'aborted)) | |
2261 | (if verbose (bibtex-progress-message)) | |
2262 | (unless (assoc key reference-keys) | |
2263 | (push (list key) reference-keys)) | |
2264 | (if (and (setq bounds (bibtex-search-forward-field "crossref" end)) | |
2265 | (setq crossref-key (bibtex-text-in-field-bounds bounds t)) | |
2266 | (not (assoc crossref-key reference-keys))) | |
2267 | (push (list crossref-key) reference-keys)))))) | |
2268 | ||
7fbf4804 SM |
2269 | (if verbose |
2270 | (bibtex-progress-message 'done)) | |
d715b065 KG |
2271 | ;; successful operation --> return `bibtex-reference-keys' |
2272 | (setq bibtex-reference-keys reference-keys)))))) | |
7fbf4804 | 2273 | |
d715b065 | 2274 | (defun bibtex-parse-strings (&optional add abortable) |
7fbf4804 SM |
2275 | "Set `bibtex-strings' to the string definitions in the whole buffer. |
2276 | The buffer might possibly be restricted. | |
d715b065 KG |
2277 | If ADD is non-nil add the new strings to `bibtex-strings' instead of |
2278 | simply resetting it. If ADD is an alist of strings, also add ADD to | |
2279 | `bibtex-strings'. If ABORTABLE is non-nil abort on user input. | |
2280 | Return alist of strings if parsing was completed, `aborted' otherwise." | |
7fbf4804 SM |
2281 | (save-excursion |
2282 | (save-match-data | |
2283 | (goto-char (point-min)) | |
d715b065 KG |
2284 | (let ((strings (if (and add |
2285 | (listp bibtex-strings)) | |
2286 | bibtex-strings)) | |
7fbf4804 | 2287 | bounds key) |
d715b065 KG |
2288 | (if (listp add) |
2289 | (dolist (string add) | |
2290 | (unless (assoc (car string) strings) | |
2291 | (push string strings)))) | |
2292 | (catch 'userkey | |
2293 | (while (setq bounds (bibtex-search-forward-string)) | |
2294 | (if (and abortable | |
2295 | (input-pending-p)) | |
2296 | ;; user has aborted by typing a key --> return `aborted' | |
2297 | (throw 'userkey 'aborted)) | |
2298 | (setq key (bibtex-reference-key-in-string bounds)) | |
2299 | (if (not (assoc-ignore-case key strings)) | |
2300 | (push (cons key (bibtex-text-in-string bounds t)) | |
2301 | strings)) | |
2302 | (goto-char (bibtex-end-of-text-in-string bounds))) | |
2303 | ;; successful operation --> return `bibtex-strings' | |
2304 | (setq bibtex-strings strings)))))) | |
7fbf4804 SM |
2305 | |
2306 | (defun bibtex-string-files-init () | |
2307 | "Return initialization for `bibtex-strings'. | |
2308 | Use `bibtex-predefined-strings' and bib files `bibtex-string-files'." | |
2309 | (save-match-data | |
2310 | ;; collect pathnames | |
2311 | (let ((dirlist (split-string (or bibtex-string-file-path ".") | |
2312 | ":+")) | |
2313 | (case-fold-search) | |
2314 | compl) | |
2315 | (dolist (filename bibtex-string-files) | |
dd310c45 | 2316 | (unless (string-match "\\.bib\\'" filename) |
7fbf4804 SM |
2317 | (setq filename (concat filename ".bib"))) |
2318 | ;; test filenames | |
2319 | (let (fullfilename bounds found) | |
2320 | (dolist (dir dirlist) | |
2321 | (when (file-readable-p | |
2322 | (setq fullfilename (expand-file-name filename dir))) | |
2323 | ;; file was found | |
2324 | (with-temp-buffer | |
2325 | (insert-file-contents fullfilename) | |
2326 | (goto-char (point-min)) | |
2327 | (while (setq bounds (bibtex-search-forward-string)) | |
2328 | (push (cons (bibtex-reference-key-in-string bounds) | |
2329 | (bibtex-text-in-string bounds t)) | |
2330 | compl) | |
2331 | (goto-char (bibtex-end-of-string bounds)))) | |
2332 | (setq found t))) | |
2333 | (unless found | |
d715b065 | 2334 | (error "File %s not in paths defined via bibtex-string-file-path" |
7fbf4804 SM |
2335 | filename)))) |
2336 | (append bibtex-predefined-strings (nreverse compl))))) | |
50e4b39e RS |
2337 | |
2338 | (defun bibtex-parse-buffers-stealthily () | |
7fbf4804 SM |
2339 | "Called by `bibtex-run-with-idle-timer'. Whenever emacs has been idle |
2340 | for `bibtex-parse-keys-timeout' seconds, all BibTeX buffers (starting | |
2341 | with the current) are parsed." | |
2342 | (save-excursion | |
2343 | (let ((buffers (buffer-list)) | |
2344 | (strings-init (bibtex-string-files-init))) | |
50e4b39e RS |
2345 | (while (and buffers (not (input-pending-p))) |
2346 | (set-buffer (car buffers)) | |
7fbf4804 SM |
2347 | (if (and (eq major-mode 'bibtex-mode) |
2348 | (not (eq (buffer-modified-tick) | |
2349 | bibtex-buffer-last-parsed-tick))) | |
2350 | (save-restriction | |
2351 | (widen) | |
2352 | ;; Output no progress messages in bibtex-parse-keys | |
2353 | ;; because when in y-or-n-p that can hide the question. | |
d715b065 | 2354 | (if (and (listp (bibtex-parse-keys nil t)) |
7fbf4804 | 2355 | ;; update bibtex-strings |
d715b065 | 2356 | (listp (bibtex-parse-strings strings-init t))) |
7fbf4804 SM |
2357 | |
2358 | ;; remember that parsing was successful | |
2359 | (setq bibtex-buffer-last-parsed-tick (buffer-modified-tick))))) | |
2360 | (setq buffers (cdr buffers)))))) | |
2361 | ||
2362 | (defun bibtex-complete-internal (completions) | |
2363 | "Complete word fragment before point to longest prefix of one | |
2364 | string defined in list COMPLETIONS. If point is not after the part | |
2365 | of a word, all strings are listed. Return completion." | |
50e4b39e | 2366 | (let* ((case-fold-search t) |
50e4b39e RS |
2367 | (beg (save-excursion |
2368 | (re-search-backward "[ \t{\"]") | |
2369 | (forward-char) | |
2370 | (point))) | |
7fbf4804 | 2371 | (end (point)) |
50e4b39e | 2372 | (part-of-word (buffer-substring-no-properties beg end)) |
7fbf4804 SM |
2373 | (completion (try-completion part-of-word completions))) |
2374 | (cond ((not completion) | |
2375 | (error "Can't find completion for `%s'" part-of-word)) | |
2376 | ((eq completion t) | |
2377 | part-of-word) | |
50e4b39e RS |
2378 | ((not (string= part-of-word completion)) |
2379 | (delete-region beg end) | |
2380 | (insert completion) | |
7fbf4804 | 2381 | completion) |
50e4b39e RS |
2382 | (t |
2383 | (message "Making completion list...") | |
7fbf4804 SM |
2384 | (with-output-to-temp-buffer "*Completions*" |
2385 | (display-completion-list (all-completions part-of-word | |
2386 | completions))) | |
2387 | (message "Making completion list...done") | |
2388 | nil)))) | |
2389 | ||
2390 | (defun bibtex-complete-string-cleanup (str) | |
d715b065 KG |
2391 | "Cleanup after inserting string STR. |
2392 | Remove enclosing field delimiters for string STR. Display message with | |
2393 | expansion of STR." | |
7fbf4804 SM |
2394 | (let ((pair (assoc str bibtex-strings))) |
2395 | (when pair | |
2396 | (if (cdr pair) | |
2397 | (message "Abbreviation for `%s'" (cdr pair))) | |
2398 | (save-excursion | |
2399 | (bibtex-inside-field) | |
2400 | (let ((bounds (bibtex-enclosing-field))) | |
2401 | (goto-char (bibtex-start-of-text-in-field bounds)) | |
2402 | (let ((boundaries (bibtex-parse-field-string))) | |
2403 | (if (and boundaries | |
2404 | (equal (cdr boundaries) | |
2405 | (bibtex-end-of-text-in-field bounds))) | |
2406 | (bibtex-remove-delimiters)))))))) | |
2407 | ||
2408 | (defun bibtex-choose-completion-string (choice buffer mini-p base-size) | |
2409 | ;; Code borrowed from choose-completion-string: | |
2410 | ;; We must duplicate the code from choose-completion-string | |
2411 | ;; because it runs the hook choose-completion-string-functions | |
2412 | ;; before it inserts the completion. But we want to do something | |
2413 | ;; after the completion has been inserted. | |
2414 | ;; | |
2415 | ;; Insert the completion into the buffer where it was requested. | |
2416 | (set-buffer buffer) | |
2417 | (if base-size | |
2418 | (delete-region (+ base-size (point-min)) | |
2419 | (point)) | |
2420 | ;; Delete the longest partial match for CHOICE | |
2421 | ;; that can be found before point. | |
2422 | (choose-completion-delete-max-match choice)) | |
2423 | (insert choice) | |
2424 | (remove-text-properties (- (point) (length choice)) (point) | |
2425 | '(mouse-face nil)) | |
2426 | ;; Update point in the window that BUFFER is showing in. | |
2427 | (let ((window (get-buffer-window buffer t))) | |
2428 | (set-window-point window (point)))) | |
cb4ad359 | 2429 | |
50e4b39e | 2430 | (defun bibtex-pop (arg direction) |
d715b065 | 2431 | "Generic function used by `bibtex-pop-previous' and `bibtex-pop-next'." |
50e4b39e RS |
2432 | (let (bibtex-help-message) |
2433 | (bibtex-find-text nil)) | |
2434 | (save-excursion | |
2435 | ;; parse current field | |
2436 | (bibtex-inside-field) | |
f9bd4abe | 2437 | (let* ((case-fold-search t) |
7fbf4804 SM |
2438 | (bounds (bibtex-enclosing-field)) |
2439 | (start-old-text (bibtex-start-of-text-in-field bounds)) | |
2440 | (stop-old-text (bibtex-end-of-text-in-field bounds)) | |
2441 | (start-name (bibtex-start-of-name-in-field bounds)) | |
2442 | (stop-name (bibtex-end-of-name-in-field bounds)) | |
2443 | ;; construct regexp for field with same name as this one, | |
2444 | ;; ignoring possible OPT's or ALT's | |
2445 | (field-name (progn | |
2446 | (goto-char start-name) | |
2447 | (buffer-substring-no-properties | |
2448 | (if (looking-at "\\(OPT\\)\\|\\(ALT\\)") | |
2449 | (match-end 0) | |
2450 | (point)) | |
2451 | stop-name)))) | |
2452 | ;; if executed several times in a row, start each search where | |
2453 | ;; the last one was finished | |
2454 | (unless (eq last-command 'bibtex-pop) | |
2455 | (bibtex-enclosing-entry-maybe-empty-head) | |
2456 | (setq bibtex-pop-previous-search-point (match-beginning 0) | |
2457 | bibtex-pop-next-search-point (point))) | |
2458 | (if (eq direction 'previous) | |
2459 | (goto-char bibtex-pop-previous-search-point) | |
2460 | (goto-char bibtex-pop-next-search-point)) | |
2461 | ;; Now search for arg'th previous/next similar field | |
2462 | (let (bounds failure new-text) | |
2463 | (while (and (not failure) | |
2464 | (> arg 0)) | |
2465 | (cond ((eq direction 'previous) | |
2466 | (if (setq bounds (bibtex-search-backward-field field-name)) | |
2467 | (goto-char (bibtex-start-of-field bounds)) | |
2468 | (setq failure t))) | |
2469 | ((eq direction 'next) | |
2470 | (if (setq bounds (bibtex-search-forward-field field-name)) | |
2471 | (goto-char (bibtex-end-of-field bounds)) | |
2472 | (setq failure t)))) | |
2473 | (setq arg (- arg 1))) | |
2474 | (if failure | |
2475 | (error "No %s matching BibTeX field" | |
2476 | (if (eq direction 'previous) "previous" "next")) | |
2477 | ;; Found a matching field. Remember boundaries. | |
2478 | (setq bibtex-pop-previous-search-point (bibtex-start-of-field bounds) | |
2479 | bibtex-pop-next-search-point (bibtex-end-of-field bounds) | |
2480 | new-text (bibtex-text-in-field-bounds bounds)) | |
2481 | (bibtex-flash-head) | |
2482 | ;; Go back to where we started, delete old text, and pop new. | |
2483 | (goto-char stop-old-text) | |
2484 | (delete-region start-old-text stop-old-text) | |
2485 | (insert new-text))))) | |
50e4b39e RS |
2486 | (let (bibtex-help-message) |
2487 | (bibtex-find-text nil)) | |
2488 | (setq this-command 'bibtex-pop)) | |
2489 | ||
d715b065 KG |
2490 | (defsubst bibtex-read-key (prompt &optional key) |
2491 | "Read BibTeX key from minibuffer using PROMPT and default KEY." | |
2492 | (completing-read prompt bibtex-reference-keys | |
2493 | nil nil key 'bibtex-key-history)) | |
50e4b39e RS |
2494 | \f |
2495 | ;; Interactive Functions: | |
2496 | ||
2497 | ;;;###autoload | |
2498 | (defun bibtex-mode () | |
2499 | "Major mode for editing BibTeX files. | |
2500 | ||
50e4b39e RS |
2501 | General information on working with BibTeX mode: |
2502 | ||
d715b065 | 2503 | You should use commands such as \\[bibtex-Book] to get a template for a |
50e4b39e RS |
2504 | specific entry. You should then fill in all desired fields using |
2505 | \\[bibtex-next-field] to jump from field to field. After having filled | |
2506 | in all desired fields in the entry, you should clean the new entry | |
d715b065 | 2507 | with the command \\[bibtex-clean-entry]. |
cb4ad359 | 2508 | |
d715b065 KG |
2509 | Some features of BibTeX mode are available only by setting the variable |
2510 | `bibtex-maintain-sorted-entries' to non-nil. However, then BibTeX mode will | |
2511 | work only with buffers containing valid (syntactical correct) entries | |
50e4b39e RS |
2512 | and with entries being sorted. This is usually the case, if you have |
2513 | created a buffer completely with BibTeX mode and finished every new | |
2514 | entry with \\[bibtex-clean-entry]. | |
2515 | ||
d715b065 KG |
2516 | For third party BibTeX files, call the function `bibtex-convert-alien' |
2517 | to fully take advantage of all features of BibTeX mode. | |
50e4b39e RS |
2518 | |
2519 | ||
2520 | Special information: | |
2521 | ||
2522 | A command such as \\[bibtex-Book] will outline the fields for a BibTeX book entry. | |
cb4ad359 | 2523 | |
50e4b39e RS |
2524 | The optional fields start with the string OPT, and are thus ignored by BibTeX. |
2525 | Alternatives from which only one is required start with the string ALT. | |
2526 | The OPT or ALT string may be removed from a field with \\[bibtex-remove-OPT-or-ALT]. | |
2527 | \\[bibtex-make-field] inserts a new field after the current one. | |
2528 | \\[bibtex-kill-field] kills the current field entirely. | |
d715b065 | 2529 | \\[bibtex-yank] yanks the last recently killed field after the current field. |
50e4b39e RS |
2530 | \\[bibtex-remove-delimiters] removes the double-quotes or braces around the text of the current field. |
2531 | \\[bibtex-empty-field] replaces the text of the current field with the default \"\" or {}. | |
2532 | ||
2533 | The command \\[bibtex-clean-entry] cleans the current entry, i.e. it removes OPT/ALT | |
2534 | from all non-empty optional or alternative fields, checks that no required | |
2535 | fields are empty, and does some formatting dependent on the value of | |
7fbf4804 | 2536 | `bibtex-entry-format'. |
f0cb6034 RS |
2537 | Note: some functions in BibTeX mode depend on entries being in a special |
2538 | format (all fields beginning on separate lines), so it is usually a bad | |
7fbf4804 | 2539 | idea to remove `realign' from `bibtex-entry-format'. |
cb4ad359 RS |
2540 | |
2541 | Use \\[bibtex-find-text] to position the cursor at the end of the current field. | |
2542 | Use \\[bibtex-next-field] to move to end of the next field. | |
2543 | ||
2544 | The following may be of interest as well: | |
9ae11a89 | 2545 | |
cb4ad359 | 2546 | Functions: |
7fbf4804 SM |
2547 | `bibtex-entry' |
2548 | `bibtex-kill-entry' | |
2549 | `bibtex-yank-pop' | |
2550 | `bibtex-pop-previous' | |
2551 | `bibtex-pop-next' | |
2552 | `bibtex-complete' | |
2553 | `bibtex-print-help-message' | |
2554 | `bibtex-generate-autokey' | |
2555 | `bibtex-beginning-of-entry' | |
2556 | `bibtex-end-of-entry' | |
2557 | `bibtex-reposition-window' | |
2558 | `bibtex-mark-entry' | |
2559 | `bibtex-ispell-abstract' | |
2560 | `bibtex-ispell-entry' | |
2561 | `bibtex-narrow-to-entry' | |
2562 | `bibtex-sort-buffer' | |
2563 | `bibtex-validate' | |
2564 | `bibtex-count' | |
2565 | `bibtex-fill-entry' | |
2566 | `bibtex-reformat' | |
2567 | `bibtex-convert-alien' | |
cb4ad359 RS |
2568 | |
2569 | Variables: | |
7fbf4804 SM |
2570 | `bibtex-field-delimiters' |
2571 | `bibtex-include-OPTcrossref' | |
2572 | `bibtex-include-OPTkey' | |
2573 | `bibtex-user-optional-fields' | |
2574 | `bibtex-entry-format' | |
2575 | `bibtex-sort-ignore-string-entries' | |
2576 | `bibtex-maintain-sorted-entries' | |
2577 | `bibtex-entry-field-alist' | |
2578 | `bibtex-predefined-strings' | |
2579 | `bibtex-string-files' | |
cb4ad359 RS |
2580 | |
2581 | --------------------------------------------------------- | |
d0388eac | 2582 | Entry to BibTeX mode calls the value of `bibtex-mode-hook' if that value is |
50e4b39e RS |
2583 | non-nil. |
2584 | ||
f0cb6034 | 2585 | \\{bibtex-mode-map}" |
cb4ad359 RS |
2586 | (interactive) |
2587 | (kill-all-local-variables) | |
2588 | (use-local-map bibtex-mode-map) | |
2589 | (setq major-mode 'bibtex-mode) | |
2590 | (setq mode-name "BibTeX") | |
2591 | (set-syntax-table bibtex-mode-syntax-table) | |
7fbf4804 | 2592 | (make-local-variable 'bibtex-buffer-last-parsed-tick) |
50e4b39e | 2593 | ;; Install stealthy parse function if not already installed |
7fbf4804 SM |
2594 | (unless bibtex-parse-idle-timer |
2595 | (setq bibtex-parse-idle-timer (bibtex-run-with-idle-timer | |
2596 | bibtex-parse-keys-timeout t | |
2597 | 'bibtex-parse-buffers-stealthily))) | |
2598 | (set (make-local-variable 'paragraph-start) "[ \f\n\t]*$") | |
2599 | (set (make-local-variable 'comment-start) bibtex-comment-start) | |
2600 | (set (make-local-variable 'comment-start-skip) | |
2601 | (concat (regexp-quote bibtex-comment-start) "\\>[ \t]*")) | |
2602 | (set (make-local-variable 'comment-column) 0) | |
dd310c45 | 2603 | (set (make-local-variable 'defun-prompt-regexp) "^[ \t]*@[a-zA-Z0-9]+[ \t]*") |
7fbf4804 | 2604 | (set (make-local-variable 'outline-regexp) "[ \t]*@") |
d715b065 | 2605 | (set (make-local-variable 'fill-paragraph-function) 'bibtex-fill-field) |
7fbf4804 SM |
2606 | (set (make-local-variable 'fill-prefix) (make-string (+ bibtex-entry-offset |
2607 | bibtex-contline-indentation) | |
2608 | ? )) | |
2609 | (set (make-local-variable 'font-lock-defaults) | |
2610 | '(bibtex-font-lock-keywords | |
2611 | nil t ((?$ . "\"") | |
2612 | ;; Mathematical expressions should be fontified as strings | |
2613 | (?\" . ".") | |
2614 | ;; Quotes are field delimiters and quote-delimited | |
2615 | ;; entries should be fontified in the same way as | |
2616 | ;; brace-delimited ones | |
2617 | ) | |
2618 | nil | |
d715b065 KG |
2619 | (font-lock-syntactic-keywords . bibtex-font-lock-syntactic-keywords) |
2620 | (font-lock-mark-block-function | |
2621 | . (lambda () | |
7fbf4804 | 2622 | (set-mark (bibtex-end-of-entry)) |
d715b065 | 2623 | (bibtex-beginning-of-entry))))) |
50e4b39e | 2624 | (setq imenu-generic-expression |
7fbf4804 SM |
2625 | (list (list nil bibtex-entry-head bibtex-key-in-head))) |
2626 | (make-local-variable 'choose-completion-string-functions) | |
c0b08eb0 | 2627 | (setq imenu-case-fold-search t) |
ab2d0cdb RS |
2628 | ;; XEmacs needs easy-menu-add, Emacs does not care |
2629 | (easy-menu-add bibtex-edit-menu) | |
2630 | (easy-menu-add bibtex-entry-menu) | |
cb4ad359 | 2631 | (run-hooks 'bibtex-mode-hook)) |
9ae11a89 | 2632 | |
50e4b39e | 2633 | (defun bibtex-entry (entry-type) |
f0cb6034 | 2634 | "Insert a new BibTeX entry. |
d0388eac | 2635 | After insertion it calls the functions in `bibtex-add-entry-hook'." |
9ae11a89 | 2636 | (interactive (let* ((completion-ignore-case t) |
7fbf4804 | 2637 | (e-t (completing-read |
cb4ad359 RS |
2638 | "Entry Type: " |
2639 | bibtex-entry-field-alist | |
50e4b39e | 2640 | nil t nil 'bibtex-entry-type-history))) |
7fbf4804 | 2641 | (list e-t))) |
d715b065 | 2642 | (let* (required optional |
7fbf4804 | 2643 | (key (if bibtex-maintain-sorted-entries |
d715b065 | 2644 | (bibtex-read-key (format "%s key: " entry-type)))) |
50e4b39e RS |
2645 | (e (assoc-ignore-case entry-type bibtex-entry-field-alist)) |
2646 | (r-n-o (elt e 1)) | |
2647 | (c-ref (elt e 2))) | |
2648 | (if (not e) | |
f0cb6034 | 2649 | (error "Bibtex entry type %s not defined" entry-type)) |
7fbf4804 SM |
2650 | (if (and (member entry-type bibtex-include-OPTcrossref) |
2651 | c-ref) | |
50e4b39e RS |
2652 | (setq required (elt c-ref 0) |
2653 | optional (elt c-ref 1)) | |
2654 | (setq required (elt r-n-o 0) | |
2655 | optional (elt r-n-o 1))) | |
7fbf4804 SM |
2656 | (unless (bibtex-prepare-new-entry (list key nil entry-type)) |
2657 | (error "Entry with key `%s' already exists" key)) | |
50e4b39e RS |
2658 | (indent-to-column bibtex-entry-offset) |
2659 | (insert "@" entry-type (bibtex-entry-left-delimiter)) | |
e5167999 | 2660 | (if key |
7fbf4804 | 2661 | (insert key)) |
9ae11a89 ER |
2662 | (save-excursion |
2663 | (mapcar 'bibtex-make-field required) | |
cb4ad359 | 2664 | (if (member entry-type bibtex-include-OPTcrossref) |
7fbf4804 | 2665 | (bibtex-make-optional-field '("crossref"))) |
9ae11a89 | 2666 | (if bibtex-include-OPTkey |
7fbf4804 SM |
2667 | (if (or (stringp bibtex-include-OPTkey) |
2668 | (fboundp bibtex-include-OPTkey)) | |
50e4b39e RS |
2669 | (bibtex-make-optional-field |
2670 | (list "key" nil bibtex-include-OPTkey)) | |
f0cb6034 | 2671 | (bibtex-make-optional-field '("key")))) |
9ae11a89 | 2672 | (mapcar 'bibtex-make-optional-field optional) |
50e4b39e RS |
2673 | (mapcar 'bibtex-make-optional-field bibtex-user-optional-fields) |
2674 | (if bibtex-comma-after-last-field | |
2675 | (insert ",")) | |
2676 | (insert "\n") | |
2677 | (indent-to-column bibtex-entry-offset) | |
2678 | (insert (bibtex-entry-right-delimiter) "\n\n")) | |
0640d7bf | 2679 | (bibtex-next-field t) |
d715b065 KG |
2680 | (if (member-ignore-case entry-type bibtex-autofill-types) |
2681 | (bibtex-autofill-entry)) | |
9ae11a89 | 2682 | (run-hooks 'bibtex-add-entry-hook))) |
e5167999 | 2683 | |
d715b065 KG |
2684 | (defun bibtex-parse-entry () |
2685 | "Parse entry at point, return an alist. | |
2686 | The alist elements have the form (FIELD . TEXT), where FIELD can also be | |
2687 | the special strings \"=type=\" and \"=key=\"." | |
2688 | (let (alist bounds) | |
2689 | (when (looking-at bibtex-entry-head) | |
2690 | (push (cons "=type=" (match-string bibtex-type-in-head)) alist) | |
2691 | (push (cons "=key=" (match-string bibtex-key-in-head)) alist) | |
2692 | (goto-char (match-end bibtex-key-in-head)) | |
2693 | (while (setq bounds (bibtex-parse-field bibtex-field-name)) | |
2694 | (push (cons (bibtex-name-in-field bounds) | |
2695 | (bibtex-text-in-field-bounds bounds)) | |
2696 | alist) | |
2697 | (goto-char (bibtex-end-of-field bounds)))) | |
2698 | alist)) | |
2699 | ||
2700 | (defun bibtex-autofill-entry () | |
2701 | "Try to fill fields based on surrounding entries." | |
2702 | (interactive) | |
2703 | (undo-boundary) ;So you can easily undo it, if it didn't work right. | |
2704 | (bibtex-beginning-of-entry) | |
2705 | (when (looking-at bibtex-entry-head) | |
2706 | (let ((type (match-string bibtex-type-in-head)) | |
2707 | (key (match-string bibtex-key-in-head)) | |
2708 | (key-end (match-end bibtex-key-in-head)) | |
2709 | (case-fold-search t) | |
2710 | tmp other-key other bounds) | |
2711 | ;; The fields we want to change start right after the key. | |
2712 | (goto-char key-end) | |
2713 | ;; First see whether to use the previous or the next entry | |
2714 | ;; for "inspiration". | |
2715 | (save-excursion | |
2716 | (goto-char (1- (match-beginning 0))) | |
2717 | (bibtex-beginning-of-entry) | |
2718 | (when (and | |
2719 | (looking-at bibtex-entry-head) | |
2720 | (equal type (match-string bibtex-type-in-head)) | |
2721 | ;; In case we found ourselves :-( | |
2722 | (not (equal key (setq tmp (match-string bibtex-key-in-head))))) | |
2723 | (setq other-key tmp) | |
2724 | (setq other (point)))) | |
2725 | (save-excursion | |
2726 | (bibtex-end-of-entry) | |
2727 | (bibtex-skip-to-valid-entry) | |
2728 | (when (and | |
2729 | (looking-at bibtex-entry-head) | |
2730 | (equal type (match-string bibtex-type-in-head)) | |
2731 | ;; In case we found ourselves :-( | |
2732 | (not (equal key (setq tmp (match-string bibtex-key-in-head)))) | |
2733 | (or (not other-key) | |
2734 | ;; Check which is the best match. | |
2735 | (< (length (try-completion "" (list key other-key))) | |
2736 | (length (try-completion "" (list key tmp)))))) | |
2737 | (setq other-key tmp) | |
2738 | (setq other (point)))) | |
2739 | ;; Then fill the new entry's fields with the chosen other entry. | |
2740 | (when other | |
2741 | (setq other (save-excursion (goto-char other) (bibtex-parse-entry))) | |
2742 | (setq key-end (point)) ;In case parse-entry changed the buffer. | |
2743 | (while (setq bounds (bibtex-parse-field bibtex-field-name)) | |
2744 | (goto-char (bibtex-start-of-name-in-field bounds)) | |
2745 | (let* ((name (buffer-substring | |
2746 | (if (looking-at "ALT\\|OPT") (match-end 0) (point)) | |
2747 | (bibtex-end-of-name-in-field bounds))) | |
2748 | (text (assoc-ignore-case name other))) | |
2749 | (goto-char (bibtex-start-of-text-in-field bounds)) | |
2750 | (if (not (and (looking-at bibtex-empty-field-re) text)) | |
2751 | (goto-char (bibtex-end-of-field bounds)) | |
2752 | (delete-region (point) (bibtex-end-of-text-in-field bounds)) | |
2753 | (insert (cdr text))))) | |
2754 | ;; Finally try to update the text based on the difference between | |
2755 | ;; the two keys. | |
2756 | (let* ((prefix (try-completion "" (list key other-key))) | |
2757 | ;; If the keys are foo91 and foo92, don't replace 1 for 2 | |
2758 | ;; but 91 for 92 instead. | |
2759 | (_ (if (string-match "[0-9]+\\'" prefix) | |
2760 | (setq prefix (substring prefix 0 (match-beginning 0))))) | |
2761 | (suffix (substring key (length prefix))) | |
2762 | (other-suffix (substring other-key (length prefix)))) | |
2763 | (while (re-search-backward (regexp-quote other-suffix) key-end 'move) | |
2764 | (replace-match suffix))))))) | |
2765 | ||
cb4ad359 | 2766 | (defun bibtex-print-help-message () |
7fbf4804 | 2767 | "Print helpful information about current field in current BibTeX entry." |
cb4ad359 | 2768 | (interactive) |
7fbf4804 SM |
2769 | (save-excursion |
2770 | (let* ((case-fold-search t) | |
2771 | (bounds (bibtex-enclosing-field)) | |
2772 | (mb (bibtex-start-of-name-in-field bounds)) | |
2773 | (field-name (buffer-substring-no-properties | |
2774 | (if (progn (goto-char mb) | |
2775 | (looking-at "OPT\\|ALT")) | |
d715b065 | 2776 | (match-end 0) mb) |
7fbf4804 SM |
2777 | (bibtex-end-of-name-in-field bounds))) |
2778 | (entry-type (progn (re-search-backward | |
2779 | bibtex-entry-maybe-empty-head nil t) | |
2780 | (bibtex-type-in-head))) | |
2781 | (entry-list (assoc-ignore-case entry-type | |
2782 | bibtex-entry-field-alist)) | |
2783 | (c-r-list (elt entry-list 2)) | |
2784 | (req-opt-list (if (and (member entry-type | |
2785 | bibtex-include-OPTcrossref) | |
2786 | c-r-list) | |
2787 | c-r-list | |
2788 | (elt entry-list 1))) | |
2789 | (list-of-entries (append (elt req-opt-list 0) | |
2790 | (elt req-opt-list 1) | |
2791 | bibtex-user-optional-fields | |
2792 | (if (member entry-type | |
2793 | bibtex-include-OPTcrossref) | |
2794 | '(("crossref" "Reference key of the cross-referenced entry"))) | |
2795 | (if bibtex-include-OPTkey | |
2796 | '(("key" "Used for reference key creation if author and editor fields are missing"))))) | |
2797 | (comment (assoc-ignore-case field-name list-of-entries))) | |
31bc4210 RS |
2798 | (if comment |
2799 | (message (elt comment 1)) | |
7fbf4804 | 2800 | (message "No comment available"))))) |
d30bfc76 | 2801 | |
d715b065 KG |
2802 | (defun bibtex-make-field (field &optional called-by-yank) |
2803 | "Make a field named FIELD in current BibTeX entry. | |
2804 | FIELD is either a string or a list of the form | |
2805 | \(FIELD-NAME COMMENT-STRING INIT ALTERNATIVE-FLAG) as in | |
2806 | `bibtex-entry-field-alist'." | |
7fbf4804 SM |
2807 | (interactive |
2808 | (list (let* ((entry-type | |
2809 | (save-excursion | |
2810 | (bibtex-enclosing-entry-maybe-empty-head) | |
2811 | (bibtex-type-in-head))) | |
d715b065 KG |
2812 | ;; "preliminary" completion list |
2813 | (fl (nth 1 (assoc-ignore-case | |
2814 | entry-type bibtex-entry-field-alist))) | |
2815 | ;; "full" completion list | |
2816 | (field-list (append (nth 0 fl) | |
2817 | (nth 1 fl) | |
7fbf4804 | 2818 | bibtex-user-optional-fields |
d715b065 KG |
2819 | (if (member entry-type |
2820 | bibtex-include-OPTcrossref) | |
2821 | '(("crossref"))) | |
7fbf4804 | 2822 | (if bibtex-include-OPTkey |
d715b065 | 2823 | '(("key"))))) |
7fbf4804 SM |
2824 | (completion-ignore-case t)) |
2825 | (completing-read "BibTeX field name: " field-list | |
2826 | nil nil nil bibtex-field-history)))) | |
d715b065 KG |
2827 | (unless (consp field) |
2828 | (setq field (list field))) | |
2829 | (if (or (interactive-p) called-by-yank) | |
2830 | (let (bibtex-help-message) | |
2831 | (bibtex-find-text nil t t) | |
2832 | (if (looking-at "[}\"]") | |
2833 | (forward-char)))) | |
2834 | (insert ",\n") | |
2835 | (indent-to-column (+ bibtex-entry-offset bibtex-field-indentation)) | |
2836 | (if (nth 3 field) (insert "ALT")) | |
2837 | (insert (car field) " ") | |
2838 | (if bibtex-align-at-equal-sign | |
2839 | (indent-to-column (+ bibtex-entry-offset | |
2840 | (- bibtex-text-indentation 2)))) | |
2841 | (insert "= ") | |
2842 | (if (not bibtex-align-at-equal-sign) | |
2843 | (indent-to-column (+ bibtex-entry-offset | |
2844 | bibtex-text-indentation))) | |
2845 | (if (not called-by-yank) (insert (bibtex-field-left-delimiter))) | |
2846 | (let ((init (nth 2 field))) | |
2847 | (cond ((stringp init) | |
2848 | (insert init)) | |
2849 | ((fboundp init) | |
2850 | (insert (funcall init))))) | |
2851 | (if (not called-by-yank) (insert (bibtex-field-right-delimiter))) | |
2852 | (if (interactive-p) | |
2853 | (forward-char -1))) | |
9ae11a89 | 2854 | |
cb4ad359 | 2855 | (defun bibtex-beginning-of-entry () |
7fbf4804 | 2856 | "Move to beginning of BibTeX entry (beginning of line). |
cb4ad359 | 2857 | If inside an entry, move to the beginning of it, otherwise move to the |
d715b065 KG |
2858 | beginning of the previous entry. If point is ahead of all BibTeX entries |
2859 | move point to the beginning of buffer. Return the new location of point." | |
745bc783 | 2860 | (interactive) |
50e4b39e RS |
2861 | (skip-chars-forward " \t") |
2862 | (if (looking-at "@") | |
a9cb9b80 | 2863 | (forward-char)) |
d715b065 KG |
2864 | (re-search-backward "^[ \t]*@" nil 'move) |
2865 | (point)) | |
e5167999 | 2866 | |
cb4ad359 | 2867 | (defun bibtex-end-of-entry () |
7fbf4804 | 2868 | "Move to end of BibTeX entry (past the closing brace). |
cb4ad359 | 2869 | If inside an entry, move to the end of it, otherwise move to the end |
7fbf4804 | 2870 | of the previous entry. Do not move if ahead of first entry. |
d715b065 | 2871 | Return the new location of point." |
745bc783 | 2872 | (interactive) |
7fbf4804 SM |
2873 | (let ((case-fold-search t) |
2874 | (org (point)) | |
2875 | (pnt (bibtex-beginning-of-entry)) | |
2876 | err bounds) | |
d715b065 KG |
2877 | (cond ((looking-at bibtex-valid-entry-whitespace-re) |
2878 | (bibtex-search-entry t nil t) | |
2879 | (unless (equal (match-beginning 0) pnt) | |
2880 | (setq err t))) | |
2881 | ((setq bounds (bibtex-parse-string)) | |
7fbf4804 SM |
2882 | (goto-char (bibtex-end-of-string bounds))) |
2883 | ((looking-at "[ \t]*@[ \t]*preamble[ \t\n]*") | |
2884 | (goto-char (match-end 0)) | |
2885 | (cond ((looking-at "(") | |
2886 | (unless (re-search-forward ")[ \t]*\n\n" nil 'move) | |
2887 | (setq err t))) | |
2888 | ((looking-at "{") | |
2889 | (unless (re-search-forward "}[ \t]*\n\n" nil 'move) | |
2890 | (setq err t))) | |
2891 | (t | |
2892 | (setq err t))) | |
2893 | (unless err | |
2894 | (goto-char (match-beginning 0)) | |
2895 | (forward-char))) | |
7fbf4804 SM |
2896 | (t |
2897 | (if (interactive-p) | |
2898 | (message "Not on a known BibTeX entry.")) | |
2899 | (goto-char org))) | |
2900 | (when err | |
2901 | (goto-char pnt) | |
2902 | (error "Syntactically incorrect BibTeX entry starts here"))) | |
50e4b39e | 2903 | (point)) |
f0cb6034 | 2904 | |
7fbf4804 SM |
2905 | (defun bibtex-reposition-window (&optional arg) |
2906 | "Make the current BibTeX entry visible. | |
2907 | Optional argument ARG is exactly as in `recenter'." | |
50e4b39e RS |
2908 | (interactive "P") |
2909 | (save-excursion | |
2910 | (goto-char | |
2911 | (/ (+ (bibtex-beginning-of-entry) (bibtex-end-of-entry)) 2)) | |
2912 | (recenter arg))) | |
2913 | ||
2914 | (defun bibtex-mark-entry () | |
2915 | "Put mark at beginning, point at end of current BibTeX entry." | |
2916 | (interactive) | |
2917 | (set-mark (bibtex-beginning-of-entry)) | |
2918 | (bibtex-end-of-entry)) | |
2919 | ||
2920 | (defun bibtex-count-entries (&optional count-string-entries) | |
2921 | "Count number of entries in current buffer or region. | |
f0cb6034 RS |
2922 | With prefix argument COUNT-STRING-ENTRIES it counts all entries, |
2923 | otherwise it counts all except Strings. | |
50e4b39e RS |
2924 | If mark is active it counts entries in region, if not in whole buffer." |
2925 | (interactive "P") | |
7fbf4804 | 2926 | (let ((number 0) |
50e4b39e RS |
2927 | (bibtex-sort-ignore-string-entries |
2928 | (not count-string-entries))) | |
7fbf4804 SM |
2929 | (save-excursion |
2930 | (save-restriction | |
2931 | (narrow-to-region (if (bibtex-mark-active) | |
2932 | (region-beginning) | |
2933 | (bibtex-beginning-of-first-entry)) | |
2934 | (if (bibtex-mark-active) | |
2935 | (region-end) | |
2936 | (point-max))) | |
2937 | (goto-char (point-min)) | |
d715b065 | 2938 | (bibtex-map-entries (lambda (key beg end) |
7fbf4804 SM |
2939 | (setq number (1+ number)))))) |
2940 | (message "%s contains %d entries." | |
2941 | (if (bibtex-mark-active) "Region" "Buffer") | |
d715b065 | 2942 | number))) |
50e4b39e | 2943 | |
cb4ad359 RS |
2944 | (defun bibtex-ispell-entry () |
2945 | "Spell whole BibTeX entry." | |
745bc783 | 2946 | (interactive) |
d715b065 KG |
2947 | (ispell-region (save-excursion (bibtex-beginning-of-entry)) |
2948 | (save-excursion (bibtex-end-of-entry)))) | |
745bc783 | 2949 | |
cb4ad359 RS |
2950 | (defun bibtex-ispell-abstract () |
2951 | "Spell abstract of BibTeX entry." | |
745bc783 | 2952 | (interactive) |
d715b065 KG |
2953 | (let ((bounds (save-excursion |
2954 | (bibtex-beginning-of-entry) | |
2955 | (bibtex-search-forward-field "abstract" t)))) | |
7fbf4804 SM |
2956 | (if bounds |
2957 | (ispell-region (bibtex-start-of-text-in-field bounds) | |
2958 | (bibtex-end-of-text-in-field bounds)) | |
2959 | (error "No abstract in entry")))) | |
745bc783 | 2960 | |
cb4ad359 RS |
2961 | (defun bibtex-narrow-to-entry () |
2962 | "Narrow buffer to current BibTeX entry." | |
745bc783 | 2963 | (interactive) |
cb4ad359 | 2964 | (save-excursion |
7fbf4804 SM |
2965 | (widen) |
2966 | (narrow-to-region (bibtex-beginning-of-entry) | |
2967 | (bibtex-end-of-entry)))) | |
2968 | ||
2969 | (defun bibtex-entry-index () | |
2970 | "Return the index of the BibTeX entry at point. Move point. | |
2971 | The index is a list (KEY CROSSREF-KEY ENTRY-NAME) that is used for sorting | |
2972 | the entries of the BibTeX buffer. Return nil if no entry found." | |
2973 | (let ((case-fold-search t)) | |
2974 | (if (re-search-forward bibtex-entry-maybe-empty-head nil t) | |
2975 | (let ((key (bibtex-key-in-head)) | |
d715b065 KG |
2976 | ;; all entry names should be downcase (for ease of comparison) |
2977 | (entry-name (downcase (bibtex-type-in-head)))) | |
7fbf4804 SM |
2978 | ;; Don't search CROSSREF-KEY if we don't need it. |
2979 | (if (equal bibtex-maintain-sorted-entries 'crossref) | |
2980 | (save-excursion | |
d715b065 KG |
2981 | (bibtex-beginning-of-entry) |
2982 | (let ((bounds (bibtex-search-forward-field | |
2983 | "\\(OPT\\)?crossref" t))) | |
2984 | (list key | |
2985 | (if bounds (bibtex-text-in-field-bounds bounds t)) | |
2986 | entry-name)))) | |
2987 | (list key nil entry-name))))) | |
7fbf4804 SM |
2988 | |
2989 | (defun bibtex-lessp (index1 index2) | |
2990 | "Predicate for sorting BibTeX entries with indices INDEX1 and INDEX2. | |
2991 | Each index is a list (KEY CROSSREF-KEY ENTRY-NAME). | |
2992 | The predicate depends on the variable `bibtex-maintain-sorted-entries'." | |
2993 | (cond ((not index1) (not index2)) ; indices can be nil | |
2994 | ((not index2) nil) | |
2995 | ((equal bibtex-maintain-sorted-entries 'crossref) | |
2996 | (if (nth 1 index1) | |
2997 | (if (nth 1 index2) | |
2998 | (or (string-lessp (nth 1 index1) (nth 1 index2)) | |
2999 | (and (string-equal (nth 1 index1) (nth 1 index2)) | |
3000 | (string-lessp (nth 0 index1) (nth 0 index2)))) | |
3001 | (not (string-lessp (nth 0 index2) (nth 1 index1)))) | |
3002 | (if (nth 1 index2) | |
3003 | (string-lessp (nth 0 index1) (nth 1 index2)) | |
3004 | (string-lessp (nth 0 index1) (nth 0 index2))))) | |
3005 | ((equal bibtex-maintain-sorted-entries 'entry-class) | |
d715b065 KG |
3006 | (let ((n1 (cdr (or (assoc (nth 2 index1) bibtex-sort-entry-class-alist) |
3007 | (assoc 'catch-all bibtex-sort-entry-class-alist) | |
3008 | '(nil . 1000)))) ; if there is nothing else | |
3009 | (n2 (cdr (or (assoc (nth 2 index2) bibtex-sort-entry-class-alist) | |
3010 | (assoc 'catch-all bibtex-sort-entry-class-alist) | |
3011 | '(nil . 1000))))) ; if there is nothing else | |
7fbf4804 SM |
3012 | (or (< n1 n2) |
3013 | (and (= n1 n2) | |
3014 | (string-lessp (car index1) (car index2)))))) | |
3015 | (t ; (equal bibtex-maintain-sorted-entries 'plain) | |
3016 | (string-lessp (car index1) (car index2))))) | |
745bc783 | 3017 | |
50e4b39e RS |
3018 | (defun bibtex-sort-buffer () |
3019 | "Sort BibTeX buffer alphabetically by key. | |
7fbf4804 | 3020 | The predicate for sorting is defined via `bibtex-maintain-sorted-entries'. |
d0388eac RS |
3021 | Text outside of BibTeX entries is not affected. If |
3022 | `bibtex-sort-ignore-string-entries' is non-nil, @String entries will be | |
0640d7bf | 3023 | ignored." |
745bc783 | 3024 | (interactive) |
7fbf4804 SM |
3025 | (unless bibtex-maintain-sorted-entries |
3026 | (error "You must choose a sorting scheme")) | |
cb4ad359 | 3027 | (save-restriction |
7fbf4804 SM |
3028 | (narrow-to-region (bibtex-beginning-of-first-entry) |
3029 | (save-excursion (goto-char (point-max)) | |
3030 | (bibtex-end-of-entry))) | |
55fe21fc | 3031 | (bibtex-skip-to-valid-entry) |
7fbf4804 SM |
3032 | (sort-subr nil |
3033 | 'bibtex-skip-to-valid-entry ; NEXTREC function | |
3034 | 'bibtex-end-of-entry ; ENDREC function | |
3035 | 'bibtex-entry-index ; STARTKEY function | |
3036 | nil ; ENDKEY function | |
3037 | 'bibtex-lessp))) ; PREDICATE | |
3038 | ||
3039 | (defun bibtex-find-crossref (crossref-key) | |
3040 | "Move point to the beginning of BibTeX entry CROSSREF-KEY. | |
3041 | Return position of entry if CROSSREF-KEY is found and nil otherwise. | |
d715b065 KG |
3042 | If position of current entry is after CROSSREF-KEY an error is signaled. |
3043 | If called interactively, CROSSREF-KEY defaults to crossref key of current | |
3044 | entry." | |
3045 | (interactive | |
3046 | (let ((crossref-key | |
3047 | (save-excursion | |
3048 | (bibtex-beginning-of-entry) | |
3049 | (let ((bounds (bibtex-search-forward-field "crossref" t))) | |
3050 | (if bounds | |
3051 | (bibtex-text-in-field-bounds bounds t)))))) | |
3052 | (list (bibtex-read-key "Find crossref key: " crossref-key)))) | |
7fbf4804 SM |
3053 | (let ((pos (save-excursion (bibtex-find-entry crossref-key)))) |
3054 | (if (and pos (> (point) pos)) | |
3055 | (error "This entry must not follow the crossrefed entry!")) | |
3056 | (goto-char pos))) | |
3057 | ||
3058 | (defun bibtex-find-entry (key) | |
3059 | "Move point to the beginning of BibTeX entry named KEY. | |
3060 | Return position of entry if KEY is found or nil if not found." | |
d715b065 | 3061 | (interactive (list (bibtex-read-key "Find key: "))) |
7fbf4804 SM |
3062 | (let* (case-fold-search |
3063 | (pnt (save-excursion | |
3064 | (goto-char (point-min)) | |
d715b065 KG |
3065 | (if (re-search-forward (concat "^[ \t]*\\(" |
3066 | bibtex-entry-type | |
3067 | "\\)[ \t]*[({][ \t\n]*\\(" | |
3068 | (regexp-quote key) | |
3069 | "\\)[ \t\n]*[,=]") | |
3070 | nil t) | |
3071 | (match-beginning 0))))) | |
7fbf4804 | 3072 | (cond (pnt |
d715b065 | 3073 | (goto-char pnt)) |
7fbf4804 SM |
3074 | ((interactive-p) |
3075 | (message "Key `%s' not found" key))))) | |
3076 | ||
3077 | (defun bibtex-prepare-new-entry (index) | |
3078 | "Prepare a new BibTeX entry with index INDEX. | |
3079 | INDEX is a list (KEY CROSSREF-KEY ENTRY-NAME). | |
3080 | Move point where the entry KEY should be placed. | |
3081 | If `bibtex-maintain-sorted-entries' is non-nil, perform a binary | |
3082 | search to look for place for KEY. This will fail if buffer is not in | |
3083 | sorted order, see \\[bibtex-validate].) | |
3084 | Return t if preparation was successful or nil if entry KEY already exists." | |
3085 | (let ((key (nth 0 index)) | |
3086 | key-exist) | |
3087 | (cond ((or (null key) | |
3088 | (and (stringp key) | |
3089 | (string-equal key "")) | |
3090 | (and (not (setq key-exist (bibtex-find-entry key))) | |
3091 | (not bibtex-maintain-sorted-entries))) | |
3092 | (bibtex-move-outside-of-entry)) | |
3093 | ;; if key-exist is non-nil due to the previous cond clause | |
3094 | ;; then point will be at beginning of entry named key. | |
3095 | (key-exist) | |
3096 | (t ; bibtex-maintain-sorted-entries is non-nil | |
3097 | (let* ((case-fold-search t) | |
3098 | (left (save-excursion (bibtex-beginning-of-first-entry) | |
3099 | (bibtex-skip-to-valid-entry) | |
3100 | (point))) | |
3101 | (right (save-excursion (bibtex-beginning-of-last-entry) | |
3102 | (bibtex-end-of-entry))) | |
3103 | (found (if (>= left right) left)) | |
3104 | actual-index new) | |
3105 | (save-excursion | |
3106 | ;; Binary search | |
3107 | (while (not found) | |
3108 | (goto-char (/ (+ left right) 2)) | |
3109 | (bibtex-skip-to-valid-entry t) | |
3110 | (setq actual-index (bibtex-entry-index)) | |
3111 | (cond ((bibtex-lessp index actual-index) | |
3112 | (setq new (bibtex-beginning-of-entry)) | |
3113 | (if (equal right new) | |
3114 | (setq found right) | |
3115 | (setq right new))) | |
3116 | (t | |
3117 | (bibtex-end-of-entry) | |
3118 | (bibtex-skip-to-valid-entry) | |
3119 | (setq new (point)) | |
3120 | (if (equal left new) | |
3121 | (setq found right) | |
3122 | (setq left new)))))) | |
3123 | (goto-char found) | |
3124 | (bibtex-beginning-of-entry) | |
3125 | (setq actual-index (save-excursion (bibtex-entry-index))) | |
3126 | (when (or (not actual-index) | |
3127 | (bibtex-lessp actual-index index)) | |
3128 | ;; buffer contains no valid entries or | |
3129 | ;; greater than last entry --> append | |
3130 | (bibtex-end-of-entry) | |
3131 | (if (not (bobp)) | |
3132 | (newline (forward-line 2))) | |
3133 | (beginning-of-line))))) | |
3134 | (unless key-exist t))) | |
cb4ad359 | 3135 | |
50e4b39e RS |
3136 | (defun bibtex-validate (&optional test-thoroughly) |
3137 | "Validate if buffer or region is syntactically correct. | |
f9bd4abe | 3138 | Only known entry types are checked, so you can put comments |
50e4b39e RS |
3139 | outside of entries. |
3140 | With optional argument TEST-THOROUGHLY non-nil it checks for absence of | |
3141 | required fields and questionable month fields as well. | |
7fbf4804 | 3142 | If mark is active, validate current region, if not the whole buffer. |
50e4b39e | 3143 | Returns t if test was successful, nil otherwise." |
31bc4210 | 3144 | (interactive "P") |
7fbf4804 SM |
3145 | (let* ((case-fold-search t) |
3146 | error-list syntax-error) | |
3147 | (save-excursion | |
3148 | (save-restriction | |
3149 | (narrow-to-region (if (bibtex-mark-active) | |
3150 | (region-beginning) | |
3151 | (bibtex-beginning-of-first-entry)) | |
3152 | (if (bibtex-mark-active) | |
3153 | (region-end) | |
3154 | (point-max))) | |
3155 | ||
3156 | ;; looking if entries fit syntactical structure | |
3157 | (goto-char (point-min)) | |
3158 | (bibtex-progress-message "Checking syntactical structure") | |
3159 | (let (bibtex-sort-ignore-string-entries) | |
3160 | (while (re-search-forward "^[ \t]*@" nil t) | |
3161 | (bibtex-progress-message) | |
3162 | (forward-char -1) | |
3163 | (let ((pnt (point))) | |
3164 | (if (not (looking-at bibtex-any-valid-entry-re)) | |
3165 | (forward-char) | |
3166 | (bibtex-skip-to-valid-entry) | |
3167 | (if (equal (point) pnt) | |
3168 | (forward-char) | |
3169 | (goto-char pnt) | |
3170 | (push (list (bibtex-current-line) | |
3171 | "Syntax error (check esp. commas, braces, and quotes)") | |
3172 | error-list) | |
3173 | (forward-char)))))) | |
3174 | (bibtex-progress-message 'done) | |
3175 | ||
3176 | (if error-list | |
3177 | (setq syntax-error t) | |
3178 | ;; looking for correct sort order and duplicates (only if | |
3179 | ;; there were no syntax errors) | |
3180 | (if bibtex-maintain-sorted-entries | |
3181 | (let (previous current) | |
3182 | (goto-char (point-min)) | |
3183 | (bibtex-progress-message "Checking correct sort order") | |
3184 | (bibtex-map-entries | |
d715b065 | 3185 | (lambda (key beg end) |
7fbf4804 | 3186 | (bibtex-progress-message) |
d715b065 | 3187 | (goto-char beg) |
7fbf4804 SM |
3188 | (setq current (bibtex-entry-index)) |
3189 | (cond ((or (not previous) | |
3190 | (bibtex-lessp previous current)) | |
3191 | (setq previous current)) | |
3192 | ((string-equal (car previous) (car current)) | |
3193 | (push (list (bibtex-current-line) | |
3194 | "Duplicate key with previous") | |
3195 | error-list)) | |
3196 | (t | |
3197 | (setq previous current) | |
3198 | (push (list (bibtex-current-line) | |
3199 | "Entries out of order") | |
3200 | error-list))))) | |
3201 | (bibtex-progress-message 'done))) | |
3202 | ||
3203 | (when test-thoroughly | |
3204 | (goto-char (point-min)) | |
3205 | (bibtex-progress-message | |
3206 | "Checking required fields and month fields") | |
3207 | (let ((bibtex-sort-ignore-string-entries t) | |
3208 | (questionable-month | |
3209 | (regexp-opt (mapcar 'car bibtex-predefined-month-strings)))) | |
55fe21fc | 3210 | (bibtex-map-entries |
d715b065 | 3211 | (lambda (key beg end) |
50e4b39e | 3212 | (bibtex-progress-message) |
d715b065 | 3213 | (let* ((entry-list (progn |
7fbf4804 SM |
3214 | (goto-char beg) |
3215 | (bibtex-search-entry nil end) | |
3216 | (assoc-ignore-case (bibtex-type-in-head) | |
3217 | bibtex-entry-field-alist))) | |
3218 | (req (copy-sequence (elt (elt entry-list 1) 0))) | |
3219 | (creq (copy-sequence (elt (elt entry-list 2) 0))) | |
3220 | crossref-there bounds) | |
3221 | (goto-char beg) | |
3222 | (while (setq bounds (bibtex-search-forward-field | |
3223 | bibtex-field-name end)) | |
3224 | (goto-char (bibtex-start-of-text-in-field bounds)) | |
3225 | (let ((field-name (downcase (bibtex-name-in-field bounds))) | |
3226 | case-fold-search) | |
3227 | (if (and (equal field-name "month") | |
3228 | (not (string-match questionable-month | |
3229 | (bibtex-text-in-field-bounds bounds)))) | |
3230 | (push (list (bibtex-current-line) | |
3231 | "Questionable month field") | |
3232 | error-list)) | |
3233 | (setq req (delete (assoc-ignore-case field-name req) req) | |
3234 | creq (delete (assoc-ignore-case field-name creq) creq)) | |
3235 | (if (equal field-name "crossref") | |
3236 | (setq crossref-there t)))) | |
3237 | (if crossref-there | |
3238 | (setq req creq)) | |
3239 | (if (or (> (length req) 1) | |
3240 | (and (= (length req) 1) | |
3241 | (not (elt (car req) 3)))) | |
3242 | ;; two (or more) fields missed or one field | |
3243 | ;; missed and this isn't flagged alternative | |
3244 | ;; (notice that this fails if there are more | |
3245 | ;; than two alternatives in a BibTeX entry, | |
3246 | ;; which isn't the case momentarily) | |
3247 | (push (list (save-excursion | |
3248 | (bibtex-beginning-of-entry) | |
3249 | (bibtex-current-line)) | |
3250 | (concat "Required field `" (caar req) "' missing")) | |
3251 | error-list)))))) | |
3252 | (bibtex-progress-message 'done))))) | |
50e4b39e RS |
3253 | (if error-list |
3254 | (let ((bufnam (buffer-name)) | |
3255 | (dir default-directory)) | |
3256 | (setq error-list | |
3257 | (sort error-list | |
3258 | (lambda (a b) | |
3259 | (< (car a) (car b))))) | |
3260 | (let ((pop-up-windows t)) | |
3261 | (pop-to-buffer nil t)) | |
3262 | (switch-to-buffer | |
3263 | (get-buffer-create "*BibTeX validation errors*") t) | |
3264 | ;; don't use switch-to-buffer-other-window, since this | |
3265 | ;; doesn't allow the second parameter NORECORD | |
3266 | (setq default-directory dir) | |
3267 | (toggle-read-only -1) | |
3268 | (compilation-mode) | |
3269 | (delete-region (point-min) (point-max)) | |
3270 | (goto-char (point-min)) | |
7fbf4804 SM |
3271 | (insert "BibTeX mode command `bibtex-validate'\n" |
3272 | (if syntax-error | |
3273 | "Maybe undetected errors due to syntax errors. Correct and validate again." | |
3274 | "") | |
3275 | "\n") | |
3276 | (dolist (err error-list) | |
3277 | (insert bufnam ":" (number-to-string (elt err 0)) | |
3278 | ": " (elt err 1) "\n")) | |
50e4b39e RS |
3279 | (compilation-parse-errors nil nil) |
3280 | (setq compilation-old-error-list compilation-error-list) | |
3281 | ;; this is necessary to avoid reparsing of buffer if you | |
7fbf4804 | 3282 | ;; switch to compilation buffer and enter `compile-goto-error' |
50e4b39e RS |
3283 | (set-buffer-modified-p nil) |
3284 | (toggle-read-only 1) | |
3285 | (goto-char (point-min)) | |
3286 | (other-window -1) | |
3287 | ;; return nil | |
3288 | nil) | |
ab2d0cdb | 3289 | (if (bibtex-mark-active) |
50e4b39e RS |
3290 | (message "Region is syntactically correct") |
3291 | (message "Buffer is syntactically correct")) | |
3292 | t))) | |
745bc783 | 3293 | |
745bc783 | 3294 | (defun bibtex-next-field (arg) |
7fbf4804 | 3295 | "Find end of text of next BibTeX field; with ARG, to its beginning." |
745bc783 JB |
3296 | (interactive "P") |
3297 | (bibtex-inside-field) | |
3298 | (let ((start (point))) | |
3299 | (condition-case () | |
7fbf4804 SM |
3300 | (let ((bounds (bibtex-enclosing-field))) |
3301 | (goto-char (bibtex-end-of-field bounds)) | |
3302 | (forward-char 2)) | |
745bc783 JB |
3303 | (error |
3304 | (goto-char start) | |
3305 | (end-of-line) | |
50e4b39e RS |
3306 | (forward-char)))) |
3307 | (bibtex-find-text arg t)) | |
745bc783 | 3308 | |
7fbf4804 | 3309 | (defun bibtex-find-text (arg &optional as-if-interactive no-error) |
50e4b39e | 3310 | "Go to end of text of current field; with ARG, go to beginning." |
745bc783 JB |
3311 | (interactive "P") |
3312 | (bibtex-inside-field) | |
7fbf4804 SM |
3313 | (let ((bounds (bibtex-enclosing-field (or (interactive-p) |
3314 | as-if-interactive)))) | |
f9bd4abe | 3315 | (if bounds |
7fbf4804 SM |
3316 | (progn (if arg |
3317 | (progn (goto-char (bibtex-start-of-text-in-field bounds)) | |
3318 | (if (looking-at "[{\"]") | |
3319 | (forward-char))) | |
3320 | (goto-char (bibtex-end-of-text-in-field bounds)) | |
3321 | (if (or (= (preceding-char) ?}) | |
3322 | (= (preceding-char) ?\")) | |
3323 | (forward-char -1))) | |
3324 | (if bibtex-help-message | |
3325 | (bibtex-print-help-message))) | |
f9bd4abe | 3326 | (beginning-of-line) |
7fbf4804 SM |
3327 | (cond ((setq bounds (bibtex-parse-string)) |
3328 | (goto-char (if arg | |
3329 | (bibtex-start-of-text-in-string bounds) | |
3330 | (bibtex-end-of-text-in-string bounds)))) | |
3331 | ((looking-at bibtex-entry-maybe-empty-head) | |
3332 | (goto-char (if arg | |
3333 | (match-beginning bibtex-key-in-head) | |
3334 | (match-end 0)))) | |
3335 | (t | |
3336 | (unless no-error | |
3337 | (error "Not on BibTeX field"))))))) | |
50e4b39e RS |
3338 | |
3339 | (defun bibtex-remove-OPT-or-ALT () | |
7fbf4804 SM |
3340 | "Remove the string starting optional/alternative fields. |
3341 | Align text and go thereafter to end of text." | |
745bc783 | 3342 | (interactive) |
f9bd4abe | 3343 | (bibtex-inside-field) |
7fbf4804 SM |
3344 | (let ((case-fold-search t) |
3345 | (bounds (bibtex-enclosing-field))) | |
50e4b39e | 3346 | (save-excursion |
f9bd4abe | 3347 | (goto-char (bibtex-start-of-name-in-field bounds)) |
7fbf4804 | 3348 | (when (looking-at "OPT\\|ALT") |
d715b065 | 3349 | (delete-region (match-beginning 0) (match-end 0)) |
7fbf4804 SM |
3350 | ;; make field non-OPT |
3351 | (search-forward "=") | |
3352 | (forward-char -1) | |
3353 | (delete-horizontal-space) | |
3354 | (if bibtex-align-at-equal-sign | |
3355 | (indent-to-column (- bibtex-text-indentation 2)) | |
3356 | (insert " ")) | |
3357 | (search-forward "=") | |
3358 | (delete-horizontal-space) | |
3359 | (if bibtex-align-at-equal-sign | |
3360 | (insert " ") | |
3361 | (indent-to-column bibtex-text-indentation)))) | |
50e4b39e RS |
3362 | (bibtex-inside-field))) |
3363 | ||
3364 | (defun bibtex-remove-delimiters () | |
7fbf4804 | 3365 | "Remove \"\" or {} around string." |
745bc783 | 3366 | (interactive) |
f9bd4abe GM |
3367 | (save-excursion |
3368 | (bibtex-inside-field) | |
7fbf4804 | 3369 | (let ((bounds (bibtex-enclosing-field))) |
f9bd4abe | 3370 | (goto-char (bibtex-start-of-text-in-field bounds)) |
7fbf4804 SM |
3371 | (delete-char 1) |
3372 | (goto-char (1- (bibtex-end-of-text-in-field bounds))) | |
3373 | (delete-backward-char 1)))) | |
50e4b39e RS |
3374 | |
3375 | (defun bibtex-kill-field (&optional copy-only) | |
7fbf4804 SM |
3376 | "Kill the entire enclosing BibTeX field. |
3377 | With prefix arg COPY-ONLY, copy the current field to `bibtex-field-kill-ring', | |
d0388eac | 3378 | but do not actually kill it." |
50e4b39e | 3379 | (interactive "P") |
7fbf4804 | 3380 | (save-excursion |
745bc783 | 3381 | (bibtex-inside-field) |
7fbf4804 SM |
3382 | (let* ((case-fold-search t) |
3383 | (bounds (bibtex-enclosing-field)) | |
3384 | (end (bibtex-end-of-field bounds)) | |
3385 | (beg (bibtex-start-of-field bounds))) | |
3386 | (goto-char end) | |
50e4b39e | 3387 | (skip-chars-forward " \t\n,") |
7fbf4804 SM |
3388 | (push (list 'field (bibtex-name-in-field bounds) |
3389 | (bibtex-text-in-field-bounds bounds)) | |
3390 | bibtex-field-kill-ring) | |
50e4b39e | 3391 | (if (> (length bibtex-field-kill-ring) bibtex-field-kill-ring-max) |
7fbf4804 SM |
3392 | (setcdr (nthcdr (1- bibtex-field-kill-ring-max) |
3393 | bibtex-field-kill-ring) | |
3394 | nil)) | |
50e4b39e | 3395 | (setq bibtex-field-kill-ring-yank-pointer bibtex-field-kill-ring) |
7fbf4804 SM |
3396 | (unless copy-only |
3397 | (delete-region beg end)))) | |
50e4b39e RS |
3398 | (setq bibtex-last-kill-command 'field)) |
3399 | ||
3400 | (defun bibtex-copy-field-as-kill () | |
3401 | (interactive) | |
3402 | (bibtex-kill-field t)) | |
745bc783 | 3403 | |
50e4b39e | 3404 | (defun bibtex-kill-entry (&optional copy-only) |
f9bd4abe GM |
3405 | "Kill the entire enclosing BibTeX entry. |
3406 | With prefix arg COPY-ONLY the current entry to | |
d0388eac | 3407 | `bibtex-entry-kill-ring', but do not actually kill it." |
50e4b39e | 3408 | (interactive "P") |
7fbf4804 SM |
3409 | (save-excursion |
3410 | (let* ((case-fold-search t) | |
3411 | (beg (bibtex-beginning-of-entry)) | |
3412 | (end (progn (bibtex-end-of-entry) | |
3413 | (if (re-search-forward | |
3414 | bibtex-entry-maybe-empty-head nil 'move) | |
3415 | (goto-char (match-beginning 0))) | |
3416 | (point)))) | |
3417 | (push (list 'entry (buffer-substring-no-properties beg end)) | |
3418 | bibtex-entry-kill-ring) | |
3419 | (if (> (length bibtex-entry-kill-ring) bibtex-entry-kill-ring-max) | |
3420 | (setcdr (nthcdr (1- bibtex-entry-kill-ring-max) | |
3421 | bibtex-entry-kill-ring) | |
3422 | nil)) | |
50e4b39e | 3423 | (setq bibtex-entry-kill-ring-yank-pointer bibtex-entry-kill-ring) |
7fbf4804 SM |
3424 | (unless copy-only |
3425 | (delete-region beg end)))) | |
50e4b39e RS |
3426 | (setq bibtex-last-kill-command 'entry)) |
3427 | ||
3428 | (defun bibtex-copy-entry-as-kill () | |
745bc783 | 3429 | (interactive) |
50e4b39e RS |
3430 | (bibtex-kill-entry t)) |
3431 | ||
3432 | (defun bibtex-yank (&optional n) | |
3433 | "Reinsert the last BibTeX item. | |
3434 | More precisely, reinsert the field or entry killed or yanked most recently. | |
3435 | With argument N, reinsert the Nth most recently killed BibTeX item. | |
3436 | See also the command \\[bibtex-yank-pop]]." | |
3437 | (interactive "*p") | |
3438 | (bibtex-insert-current-kill (1- n)) | |
f0cb6034 | 3439 | (setq this-command 'bibtex-yank)) |
50e4b39e RS |
3440 | |
3441 | (defun bibtex-yank-pop (n) | |
3442 | "Replace just-yanked killed BibTeX item with a different. | |
3443 | This command is allowed only immediately after a `bibtex-yank' or a | |
3444 | `bibtex-yank-pop'. | |
3445 | At such a time, the region contains a reinserted previously killed | |
f0cb6034 | 3446 | BibTeX item. `bibtex-yank-pop' deletes that item and inserts in its |
50e4b39e RS |
3447 | place a different killed BibTeX item. |
3448 | ||
3449 | With no argument, the previous kill is inserted. | |
3450 | With argument N, insert the Nth previous kill. | |
3451 | If N is negative, this is a more recent kill. | |
3452 | ||
3453 | The sequence of kills wraps around, so that after the oldest one | |
3454 | comes the newest one." | |
3455 | (interactive "*p") | |
3456 | (if (not (eq last-command 'bibtex-yank)) | |
3457 | (error "Previous command was not a BibTeX yank")) | |
3458 | (setq this-command 'bibtex-yank) | |
3459 | (let ((inhibit-read-only t)) | |
3460 | (delete-region (point) (mark t)) | |
3461 | (bibtex-insert-current-kill n))) | |
745bc783 JB |
3462 | |
3463 | (defun bibtex-empty-field () | |
cb4ad359 | 3464 | "Delete the text part of the current field, replace with empty text." |
745bc783 JB |
3465 | (interactive) |
3466 | (bibtex-inside-field) | |
f9bd4abe GM |
3467 | (let ((bounds (bibtex-enclosing-field))) |
3468 | (goto-char (bibtex-start-of-text-in-field bounds)) | |
3469 | (delete-region (point) (bibtex-end-of-text-in-field bounds)) | |
3470 | (insert (concat (bibtex-field-left-delimiter) | |
7fbf4804 | 3471 | (bibtex-field-right-delimiter)) ) |
f9bd4abe | 3472 | (bibtex-find-text t))) |
745bc783 | 3473 | |
31bc4210 | 3474 | (defun bibtex-pop-previous (arg) |
d0388eac | 3475 | "Replace text of current field with the similar field in previous entry. |
f0cb6034 | 3476 | With arg, goes up ARG entries. Repeated, goes up so many times. May be |
31bc4210 RS |
3477 | intermixed with \\[bibtex-pop-next] (bibtex-pop-next)." |
3478 | (interactive "p") | |
3479 | (bibtex-pop arg 'previous)) | |
745bc783 JB |
3480 | |
3481 | (defun bibtex-pop-next (arg) | |
3482 | "Replace text of current field with the text of similar field in next entry. | |
f0cb6034 | 3483 | With arg, goes down ARG entries. Repeated, goes down so many times. May be |
745bc783 JB |
3484 | intermixed with \\[bibtex-pop-previous] (bibtex-pop-previous)." |
3485 | (interactive "p") | |
31bc4210 | 3486 | (bibtex-pop arg 'next)) |
745bc783 | 3487 | |
7fbf4804 | 3488 | (defun bibtex-clean-entry (&optional new-key called-by-reformat) |
cb4ad359 | 3489 | "Finish editing the current BibTeX entry and clean it up. |
d715b065 | 3490 | Check that no required fields are empty and formats entry dependent |
7fbf4804 | 3491 | on the value of `bibtex-entry-format'. |
f9bd4abe | 3492 | If the reference key of the entry is empty or a prefix argument is given, |
d715b065 | 3493 | calculate a new reference key. (Note: this will only work if fields in entry |
7fbf4804 SM |
3494 | begin on separate lines prior to calling `bibtex-clean-entry' or if |
3495 | 'realign is contained in `bibtex-entry-format'.) | |
d715b065 | 3496 | Don't call `bibtex-clean-entry' on @Preamble entries. |
50e4b39e | 3497 | At end of the cleaning process, the functions in |
7fbf4804 SM |
3498 | `bibtex-clean-entry-hook' are called with region narrowed to entry." |
3499 | ;; Opt. arg called-by-reformat is t if bibtex-clean-entry | |
3500 | ;; is called by bibtex-reformat | |
cb4ad359 | 3501 | (interactive "P") |
7fbf4804 | 3502 | (let ((case-fold-search t) |
d715b065 | 3503 | entry-type key) |
7fbf4804 | 3504 | (bibtex-beginning-of-entry) |
d715b065 KG |
3505 | (save-excursion |
3506 | (when (re-search-forward bibtex-entry-maybe-empty-head nil t) | |
3507 | (setq entry-type (downcase (bibtex-type-in-head))) | |
3508 | (setq key (bibtex-key-in-head)))) | |
3509 | ;; formatting | |
3510 | (cond ((equal entry-type "preamble") | |
3511 | ;; (bibtex-format-preamble) | |
3512 | (error "No clean up of @Preamble entries")) | |
3513 | ((equal entry-type "string")) | |
3514 | ;; (bibtex-format-string) | |
3515 | (t (bibtex-format-entry))) | |
3516 | ;; set key | |
7fbf4804 | 3517 | (when (or new-key (not key)) |
d715b065 KG |
3518 | (setq key (bibtex-generate-autokey)) |
3519 | (if bibtex-autokey-edit-before-use | |
3520 | (setq key (bibtex-read-key "Key to use: " key))) | |
7fbf4804 SM |
3521 | (re-search-forward bibtex-entry-maybe-empty-head) |
3522 | (if (match-beginning bibtex-key-in-head) | |
3523 | (delete-region (match-beginning bibtex-key-in-head) | |
3524 | (match-end bibtex-key-in-head))) | |
3525 | (insert key)) | |
d715b065 | 3526 | ;; sorting |
7fbf4804 SM |
3527 | (let* ((start (bibtex-beginning-of-entry)) |
3528 | (end (progn (bibtex-end-of-entry) | |
3529 | (if (re-search-forward | |
3530 | bibtex-entry-maybe-empty-head nil 'move) | |
3531 | (goto-char (match-beginning 0))) | |
3532 | (point))) | |
3533 | (entry (buffer-substring start end)) | |
3534 | (index (progn (goto-char start) | |
3535 | (bibtex-entry-index)))) | |
3536 | (delete-region start end) | |
3537 | (unless (prog1 (or called-by-reformat | |
d715b065 KG |
3538 | (if (and bibtex-maintain-sorted-entries |
3539 | (not (and bibtex-sort-ignore-string-entries | |
3540 | (equal entry-type "string")))) | |
7fbf4804 SM |
3541 | (bibtex-prepare-new-entry index) |
3542 | (not (bibtex-find-entry (car index))))) | |
50e4b39e | 3543 | (insert entry) |
0640d7bf | 3544 | (forward-char -1) |
7fbf4804 SM |
3545 | (bibtex-beginning-of-entry) ; moves backward |
3546 | (re-search-forward bibtex-entry-head)) | |
3547 | (error "New inserted entry yields duplicate key"))) | |
d715b065 | 3548 | ;; final clean up |
7fbf4804 | 3549 | (unless called-by-reformat |
50e4b39e RS |
3550 | (save-excursion |
3551 | (save-restriction | |
7fbf4804 | 3552 | (bibtex-narrow-to-entry) |
d715b065 KG |
3553 | ;; Only update the list of keys if it has been built already. |
3554 | (cond ((equal entry-type "string") | |
3555 | (if (listp bibtex-strings) (bibtex-parse-strings t))) | |
3556 | ((listp bibtex-reference-keys) (bibtex-parse-keys t))) | |
7fbf4804 | 3557 | (run-hooks 'bibtex-clean-entry-hook)))))) |
50e4b39e | 3558 | |
d715b065 KG |
3559 | (defun bibtex-fill-field-bounds (bounds justify &optional move) |
3560 | "Fill BibTeX field delimited by BOUNDS. | |
3561 | If JUSTIFY is non-nil justify as well. | |
3562 | If optional arg MOVE is non-nil move point to end of field." | |
3563 | (let ((end-field (copy-marker (bibtex-end-of-field bounds)))) | |
3564 | (goto-char (bibtex-start-of-field bounds)) | |
3565 | (if justify | |
3566 | (progn | |
3567 | (forward-char) | |
3568 | (bibtex-delete-whitespace) | |
3569 | (open-line 1) | |
3570 | (forward-char) | |
3571 | (indent-to-column (+ bibtex-entry-offset | |
3572 | bibtex-field-indentation)) | |
3573 | (re-search-forward "[ \t\n]*=" end-field) | |
3574 | (replace-match "=") | |
3575 | (forward-char -1) | |
3576 | (if bibtex-align-at-equal-sign | |
3577 | (indent-to-column | |
3578 | (+ bibtex-entry-offset (- bibtex-text-indentation 2))) | |
3579 | (insert " ")) | |
3580 | (forward-char) | |
3581 | (bibtex-delete-whitespace) | |
3582 | (if bibtex-align-at-equal-sign | |
3583 | (insert " ") | |
3584 | (indent-to-column bibtex-text-indentation))) | |
3585 | (re-search-forward "[ \t\n]*=[ \t\n]*" end-field)) | |
3586 | (while (re-search-forward "[ \t\n]+" end-field 'move) | |
3587 | (replace-match " ")) | |
3588 | (do-auto-fill) | |
3589 | (if move (goto-char end-field)))) | |
3590 | ||
3591 | (defun bibtex-fill-field (&optional justify) | |
3592 | "Like \\[fill-paragraph], but fill current BibTeX field. | |
3593 | Optional prefix arg JUSTIFY non-nil means justify as well. | |
3594 | In BibTeX mode this function is bound to `fill-paragraph-function'." | |
3595 | (interactive "*P") | |
3596 | (let ((pnt (copy-marker (point))) | |
3597 | (bounds (bibtex-enclosing-field))) | |
3598 | (when bounds | |
3599 | (bibtex-fill-field-bounds bounds justify) | |
3600 | (goto-char pnt)))) | |
3601 | ||
50e4b39e | 3602 | (defun bibtex-fill-entry () |
7fbf4804 SM |
3603 | "Fill current BibTeX entry. |
3604 | Realign entry, so that every field starts on a separate line. Field | |
d0388eac | 3605 | names appear in column `bibtex-field-indentation', field text starts in |
f0cb6034 | 3606 | column `bibtex-text-indentation' and continuation lines start here, too. |
d715b065 | 3607 | If `bibtex-align-at-equal-sign' is non-nil, align equal signs, too." |
50e4b39e RS |
3608 | (interactive "*") |
3609 | (let ((pnt (copy-marker (point))) | |
7fbf4804 SM |
3610 | (end (copy-marker (bibtex-end-of-entry))) |
3611 | bounds) | |
50e4b39e | 3612 | (bibtex-beginning-of-entry) |
55fe21fc | 3613 | (bibtex-delete-whitespace) |
50e4b39e | 3614 | (indent-to-column bibtex-entry-offset) |
7fbf4804 | 3615 | (while (setq bounds (bibtex-search-forward-field bibtex-field-name end)) |
d715b065 | 3616 | (bibtex-fill-field-bounds bounds t t)) |
50e4b39e RS |
3617 | (if (looking-at ",") |
3618 | (forward-char)) | |
55fe21fc | 3619 | (bibtex-delete-whitespace) |
50e4b39e RS |
3620 | (open-line 1) |
3621 | (forward-char) | |
3622 | (indent-to-column bibtex-entry-offset) | |
3623 | (goto-char pnt))) | |
3624 | ||
3625 | (defun bibtex-reformat (&optional additional-options called-by-convert-alien) | |
d0388eac RS |
3626 | "Reformat all BibTeX entries in buffer or region. |
3627 | With prefix argument, read options for reformatting from minibuffer. | |
f0cb6034 | 3628 | With \\[universal-argument] \\[universal-argument] prefix argument, reuse previous answers (if any) again. |
50e4b39e RS |
3629 | If mark is active it reformats entries in region, if not in whole buffer." |
3630 | (interactive "*P") | |
3631 | (let* ((pnt (point)) | |
3632 | (use-previous-options | |
3633 | (and (equal (prefix-numeric-value additional-options) 16) | |
3634 | (or bibtex-reformat-previous-options | |
f9bd4abe | 3635 | bibtex-reformat-previous-reference-keys))) |
50e4b39e RS |
3636 | (bibtex-entry-format |
3637 | (if additional-options | |
3638 | (if use-previous-options | |
3639 | bibtex-reformat-previous-options | |
7fbf4804 SM |
3640 | (setq bibtex-reformat-previous-options |
3641 | (delq nil (list | |
3642 | (if (or called-by-convert-alien | |
3643 | (y-or-n-p "Realign entries (recommended)? ")) | |
3644 | 'realign) | |
3645 | (if (y-or-n-p "Remove empty optional and alternative fields? ") | |
3646 | 'opts-or-alts) | |
3647 | (if (y-or-n-p "Remove delimiters around pure numerical fields? ") | |
3648 | 'numerical-fields) | |
3649 | (if (y-or-n-p (concat (if bibtex-comma-after-last-field "Insert" "Remove") | |
3650 | " comma at end of entry? ")) | |
3651 | 'last-comma) | |
3652 | (if (y-or-n-p "Replace double page dashes by single ones? ") | |
3653 | 'page-dashes) | |
3654 | (if (y-or-n-p "Force delimiters? ") | |
3655 | 'delimiters) | |
3656 | (if (y-or-n-p "Unify case of entry types and field names? ") | |
3657 | 'unify-case))))) | |
50e4b39e | 3658 | '(realign))) |
7fbf4804 SM |
3659 | (reformat-reference-keys (if additional-options |
3660 | (if use-previous-options | |
3661 | bibtex-reformat-previous-reference-keys | |
3662 | (setq bibtex-reformat-previous-reference-keys | |
3663 | (y-or-n-p "Generate new reference keys automatically? "))))) | |
50e4b39e RS |
3664 | bibtex-autokey-edit-before-use |
3665 | (bibtex-sort-ignore-string-entries t) | |
7fbf4804 SM |
3666 | (start-point (if (bibtex-mark-active) |
3667 | (region-beginning) | |
3668 | (bibtex-beginning-of-first-entry) | |
3669 | (bibtex-skip-to-valid-entry) | |
3670 | (point))) | |
3671 | (end-point (if (bibtex-mark-active) | |
3672 | (region-end) | |
3673 | (point-max)))) | |
50e4b39e RS |
3674 | (save-restriction |
3675 | (narrow-to-region start-point end-point) | |
7fbf4804 SM |
3676 | (when (memq 'realign bibtex-entry-format) |
3677 | (goto-char (point-min)) | |
3678 | (while (re-search-forward bibtex-valid-entry-whitespace-re nil t) | |
3679 | (replace-match "\n\\1"))) | |
50e4b39e RS |
3680 | (goto-char start-point) |
3681 | (bibtex-progress-message "Formatting" 1) | |
d715b065 | 3682 | (bibtex-map-entries (lambda (key beg end) |
7fbf4804 SM |
3683 | (bibtex-progress-message) |
3684 | (bibtex-clean-entry reformat-reference-keys t) | |
3685 | (when (memq 'realign bibtex-entry-format) | |
d715b065 | 3686 | (goto-char end) |
7fbf4804 SM |
3687 | (bibtex-delete-whitespace) |
3688 | (open-line 2)))) | |
50e4b39e | 3689 | (bibtex-progress-message 'done)) |
7fbf4804 SM |
3690 | (when (and reformat-reference-keys |
3691 | bibtex-maintain-sorted-entries | |
3692 | (not called-by-convert-alien)) | |
3693 | (bibtex-sort-buffer) | |
d715b065 | 3694 | (kill-local-variable 'bibtex-reference-keys)) |
50e4b39e RS |
3695 | (goto-char pnt))) |
3696 | ||
3697 | (defun bibtex-convert-alien (&optional do-additional-reformatting) | |
7fbf4804 SM |
3698 | "Convert an alien BibTeX buffer to be fully usable by BibTeX mode. |
3699 | If a file does not conform with some standards used by BibTeX mode, | |
3700 | some of the high-level features of BibTeX mode will not be available. | |
3701 | This function tries to convert current buffer to conform with these standards. | |
50e4b39e RS |
3702 | With prefix argument DO-ADDITIONAL-REFORMATTING |
3703 | non-nil, read options for reformatting entries from minibuffer." | |
3704 | (interactive "*P") | |
3705 | (message "Starting to validate buffer...") | |
3706 | (sit-for 1 nil t) | |
3707 | (goto-char (point-min)) | |
3708 | (while (re-search-forward "[ \t\n]+@" nil t) | |
3709 | (replace-match "\n@")) | |
3710 | (message | |
3711 | "If errors occur, correct them and call `bibtex-convert-alien' again") | |
3712 | (sit-for 5 nil t) | |
7fbf4804 SM |
3713 | (deactivate-mark) ; So bibtex-validate works on the whole buffer. |
3714 | (when (let (bibtex-maintain-sorted-entries) | |
3715 | (bibtex-validate)) | |
3716 | (message "Starting to reformat entries...") | |
3717 | (sit-for 2 nil t) | |
3718 | (bibtex-reformat do-additional-reformatting t) | |
3719 | (when bibtex-maintain-sorted-entries | |
3720 | (message "Starting to sort buffer...") | |
3721 | (bibtex-sort-buffer)) | |
3722 | (goto-char (point-max)) | |
3723 | (message "Buffer is now parsable. Please save it."))) | |
3724 | ||
3725 | (defun bibtex-complete () | |
3726 | "Complete word fragment before point according to context. | |
d715b065 | 3727 | If point is inside key or crossref field perform key completion based on |
7fbf4804 SM |
3728 | `bibtex-reference-keys'. Inside any other field perform string |
3729 | completion based on `bibtex-strings'. An error is signaled if point | |
3730 | is outside key or BibTeX field." | |
3731 | (interactive) | |
3732 | (let* ((pnt (point)) | |
3733 | (case-fold-search t) | |
3734 | bounds compl) | |
3735 | (save-excursion | |
3736 | (if (and (setq bounds (bibtex-enclosing-field t)) | |
3737 | (>= pnt (bibtex-start-of-text-in-field bounds)) | |
3738 | (<= pnt (bibtex-end-of-text-in-field bounds))) | |
3739 | (progn | |
3740 | (goto-char (bibtex-start-of-name-in-field bounds)) | |
3741 | (setq compl (if (string= "crossref" | |
3742 | (downcase | |
3743 | (buffer-substring-no-properties | |
3744 | (if (looking-at "\\(OPT\\)\\|\\(ALT\\)") | |
3745 | (match-end 0) | |
3746 | (point)) | |
3747 | (bibtex-end-of-name-in-field bounds)))) | |
3748 | 'key | |
3749 | 'str))) | |
3750 | (bibtex-beginning-of-entry) | |
3751 | (if (and (re-search-forward bibtex-entry-maybe-empty-head nil t) | |
3752 | ;; point is inside a key | |
3753 | (or (and (match-beginning bibtex-key-in-head) | |
3754 | (>= pnt (match-beginning bibtex-key-in-head)) | |
3755 | (<= pnt (match-end bibtex-key-in-head))) | |
3756 | ;; or point is on empty key | |
3757 | (and (not (match-beginning bibtex-key-in-head)) | |
3758 | (= pnt (match-end 0))))) | |
3759 | (setq compl 'key)))) | |
3760 | ||
3761 | (cond ((equal compl 'key) | |
3762 | ;; key completion | |
7fbf4804 SM |
3763 | (setq choose-completion-string-functions |
3764 | (lambda (choice buffer mini-p base-size) | |
3765 | (bibtex-choose-completion-string choice buffer mini-p base-size) | |
3766 | (if bibtex-complete-key-cleanup | |
3767 | (funcall bibtex-complete-key-cleanup choice)) | |
3768 | ;; return t (required by choose-completion-string-functions) | |
3769 | t)) | |
3770 | (let ((choice (bibtex-complete-internal bibtex-reference-keys))) | |
3771 | (if bibtex-complete-key-cleanup | |
3772 | (funcall bibtex-complete-key-cleanup choice)))) | |
3773 | ||
3774 | ((equal compl 'str) | |
3775 | ;; string completion | |
3776 | (setq choose-completion-string-functions | |
3777 | (lambda (choice buffer mini-p base-size) | |
3778 | (bibtex-choose-completion-string choice buffer mini-p base-size) | |
3779 | (bibtex-complete-string-cleanup choice) | |
3780 | ;; return t (required by choose-completion-string-functions) | |
3781 | t)) | |
3782 | (bibtex-complete-string-cleanup (bibtex-complete-internal bibtex-strings))) | |
3783 | ||
3784 | (t (error "Point outside key or BibTeX field"))))) | |
745bc783 | 3785 | |
cb4ad359 | 3786 | (defun bibtex-Article () |
f0cb6034 | 3787 | "Insert a new BibTeX @Article entry; see also `bibtex-entry'." |
7fbf4804 | 3788 | (interactive "*") |
cb4ad359 | 3789 | (bibtex-entry "Article")) |
2798dfd6 | 3790 | |
cb4ad359 | 3791 | (defun bibtex-Book () |
f0cb6034 | 3792 | "Insert a new BibTeX @Book entry; see also `bibtex-entry'." |
7fbf4804 | 3793 | (interactive "*") |
cb4ad359 | 3794 | (bibtex-entry "Book")) |
2798dfd6 | 3795 | |
cb4ad359 | 3796 | (defun bibtex-Booklet () |
f0cb6034 | 3797 | "Insert a new BibTeX @Booklet entry; see also `bibtex-entry'." |
7fbf4804 | 3798 | (interactive "*") |
cb4ad359 RS |
3799 | (bibtex-entry "Booklet")) |
3800 | ||
3801 | (defun bibtex-InBook () | |
f0cb6034 | 3802 | "Insert a new BibTeX @InBook entry; see also `bibtex-entry'." |
7fbf4804 | 3803 | (interactive "*") |
cb4ad359 RS |
3804 | (bibtex-entry "InBook")) |
3805 | ||
3806 | (defun bibtex-InCollection () | |
f0cb6034 | 3807 | "Insert a new BibTeX @InCollection entry; see also `bibtex-entry'." |
7fbf4804 | 3808 | (interactive "*") |
cb4ad359 RS |
3809 | (bibtex-entry "InCollection")) |
3810 | ||
3811 | (defun bibtex-InProceedings () | |
f0cb6034 | 3812 | "Insert a new BibTeX @InProceedings entry; see also `bibtex-entry'." |
7fbf4804 | 3813 | (interactive "*") |
cb4ad359 RS |
3814 | (bibtex-entry "InProceedings")) |
3815 | ||
3816 | (defun bibtex-Manual () | |
f0cb6034 | 3817 | "Insert a new BibTeX @Manual entry; see also `bibtex-entry'." |
7fbf4804 | 3818 | (interactive "*") |
cb4ad359 RS |
3819 | (bibtex-entry "Manual")) |
3820 | ||
3821 | (defun bibtex-MastersThesis () | |
f0cb6034 | 3822 | "Insert a new BibTeX @MastersThesis entry; see also `bibtex-entry'." |
7fbf4804 | 3823 | (interactive "*") |
cb4ad359 RS |
3824 | (bibtex-entry "MastersThesis")) |
3825 | ||
3826 | (defun bibtex-Misc () | |
f0cb6034 | 3827 | "Insert a new BibTeX @Misc entry; see also `bibtex-entry'." |
7fbf4804 | 3828 | (interactive "*") |
cb4ad359 RS |
3829 | (bibtex-entry "Misc")) |
3830 | ||
3831 | (defun bibtex-PhdThesis () | |
f0cb6034 | 3832 | "Insert a new BibTeX @PhdThesis entry; see also `bibtex-entry'." |
7fbf4804 | 3833 | (interactive "*") |
cb4ad359 RS |
3834 | (bibtex-entry "PhdThesis")) |
3835 | ||
3836 | (defun bibtex-Proceedings () | |
f0cb6034 | 3837 | "Insert a new BibTeX @Proceedings entry; see also `bibtex-entry'." |
7fbf4804 | 3838 | (interactive "*") |
cb4ad359 RS |
3839 | (bibtex-entry "Proceedings")) |
3840 | ||
3841 | (defun bibtex-TechReport () | |
f0cb6034 | 3842 | "Insert a new BibTeX @TechReport entry; see also `bibtex-entry'." |
7fbf4804 | 3843 | (interactive "*") |
cb4ad359 RS |
3844 | (bibtex-entry "TechReport")) |
3845 | ||
3846 | (defun bibtex-Unpublished () | |
f0cb6034 | 3847 | "Insert a new BibTeX @Unpublished entry; see also `bibtex-entry'." |
7fbf4804 | 3848 | (interactive "*") |
cb4ad359 RS |
3849 | (bibtex-entry "Unpublished")) |
3850 | ||
7fbf4804 SM |
3851 | (defun bibtex-String (&optional key) |
3852 | "Insert a new BibTeX @String entry with key KEY." | |
d715b065 KG |
3853 | (interactive (list (completing-read "String key: " bibtex-strings |
3854 | nil nil nil 'bibtex-key-history))) | |
7fbf4804 | 3855 | (let ((bibtex-maintain-sorted-entries |
d715b065 KG |
3856 | (if (not bibtex-sort-ignore-string-entries) |
3857 | bibtex-maintain-sorted-entries)) | |
7fbf4804 SM |
3858 | endpos) |
3859 | (unless (bibtex-prepare-new-entry (list key nil "String")) | |
3860 | (error "Entry with key `%s' already exists" key)) | |
3861 | (if (zerop (length key)) (setq key nil)) | |
50e4b39e | 3862 | (indent-to-column bibtex-entry-offset) |
7fbf4804 SM |
3863 | (insert "@String" |
3864 | (bibtex-entry-left-delimiter)) | |
3865 | (if key | |
3866 | (insert key) | |
3867 | (setq endpos (point))) | |
3868 | (insert " = " | |
3869 | (bibtex-field-left-delimiter)) | |
3870 | (if key | |
3871 | (setq endpos (point))) | |
3872 | (insert (bibtex-field-right-delimiter) | |
3873 | (bibtex-entry-right-delimiter) | |
3874 | "\n") | |
3875 | (goto-char endpos))) | |
50e4b39e RS |
3876 | |
3877 | (defun bibtex-Preamble () | |
f0cb6034 | 3878 | "Insert a new BibTeX @Preamble entry." |
7fbf4804 | 3879 | (interactive "*") |
cb4ad359 | 3880 | (bibtex-move-outside-of-entry) |
50e4b39e | 3881 | (indent-to-column bibtex-entry-offset) |
7fbf4804 | 3882 | (insert "@Preamble" |
d715b065 KG |
3883 | (bibtex-entry-left-delimiter)) |
3884 | (let ((endpos (point))) | |
3885 | (insert (bibtex-entry-right-delimiter) | |
3886 | "\n") | |
3887 | (goto-char endpos))) | |
2798dfd6 | 3888 | |
745bc783 | 3889 | \f |
5c69dbfc | 3890 | ;; Make BibTeX a Feature |
cb4ad359 RS |
3891 | |
3892 | (provide 'bibtex) | |
745bc783 | 3893 | |
ab5796a9 | 3894 | ;;; arch-tag: ee2be3af-caad-427f-b42a-d20fad630d04 |
9ae11a89 | 3895 | ;;; bibtex.el ends here |