Commit | Line | Data |
---|---|---|
c0274f38 ER |
1 | ;;; bibtex.el --- BibTeX mode for GNU Emacs |
2 | ||
9750e079 ER |
3 | ;; Copyright (C) 1992 Free Software Foundation, Inc. |
4 | ||
f961a17c ER |
5 | ;; Author: Bengt Martensson <ubrinf!mond!bengt> |
6 | ;; Mark Shapiro <shapiro@corto.inria.fr> | |
7 | ;; Mike Newton <newton@gumby.cs.caltech.edu> | |
8 | ;; Aaron Larson <alarson@src.honeywell.com> | |
9ae11a89 ER |
9 | ;; Version: 1.3.1 |
10 | ;; Maintainer:Aaron Larson <alarson@src.honeywell.com> | |
11 | ;; Adapted-By: ESR | |
f961a17c ER |
12 | ;; Keywords: tex, bib |
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 | |
27 | ;; along with GNU Emacs; see the file COPYING. If not, write to | |
28 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
29 | ||
9ae11a89 ER |
30 | ;;; TODO distribute texinfo file. |
31 | ||
32 | ;;; LCD Archive Entry: | |
33 | ;;; bibtex-mode|Bengt Martensson, Marc Shapiro, Aaron Larson| | |
34 | ;;; alarson@src.honeywell.com| | |
35 | ;;; Support for maintaining BibTeX format bibliography databases| | |
36 | ;;; 93-03-29|version 1.3|~/modes/bibtex-mode.el.Z| | |
37 | ||
e41b2db1 ER |
38 | ;;; Commentary: |
39 | ||
9ae11a89 ER |
40 | ;;; BUGS: |
41 | ;;; 1. using regular expressions to match the entire bibtex entry dies | |
42 | ;;; on long bibtex entires (e.g. those containing abstracts) since | |
43 | ;;; the length of regular expression matches is fairly limited. | |
44 | ;;; 2. When inserting a string (with \C-C\C-E\s) hitting a TAB results | |
45 | ;;; in the error message "Can't find enclosing Bibtex field" instead | |
46 | ;;; of moving to the empty string. [reported by gernot@cs.unsw.oz.au] | |
47 | ;;; 3. Function string-equalp should be in a library file, not in this | |
48 | ;;; file. | |
49 | ||
50 | ;;; (current keeper: alarson@src.honeywell.com | |
51 | ;;; previous: shapiro@corto.inria.fr) | |
e41b2db1 | 52 | |
f961a17c | 53 | ;;; Change Log: |
e5167999 | 54 | |
9ae11a89 ER |
55 | ;; Mon Mar 29 14:06:06 1993 Aaron Larson (alarson at gendibal) |
56 | ;; | |
57 | ;; * bibtex.el: V1.3 released Mar 30, 1993 | |
58 | ;; (bibtex-field-name): Fix to match definition if latex manual, | |
59 | ;; specifically letters, digits, and punctuation other than comma. | |
60 | ;; Underscore is retained for historical reasons. | |
61 | ;; (bibtex-make-field): Fix to work around bug in Lucid prin1-to-string | |
62 | ;; function as reported by Martin Sjolin <marsj@ida.liu.se>. | |
63 | ;; (bibtex-entry): minor code cleanup. | |
64 | ;; (bibtex-mode-map): Remove key binding (C-c n) for | |
65 | ;; narrow-to-bibtex-entry, previous binding violated emacs policy of | |
66 | ;; reserving C-c followed by a letter for user customization. | |
67 | ;; revise modification history to better conform to FSF changelog | |
68 | ;; standards. | |
69 | ;; (bibtex-refile-entry): Removed. Would need disclaimer papers to | |
70 | ;; incorporate it into official sources, and unable to contact author. | |
71 | ;; Fix minor "syntax" errors in documentation strings and such found | |
72 | ;; by new byte compiler. Funs bibtex-mode, bibtex-remove-double-quotes | |
73 | ;; | |
74 | ;; | |
75 | ;; Fri Jan 15 14:06:06 1993 Aaron Larson (alarson at gendibal) | |
76 | ;; | |
77 | ;; * bibtex.el: V1.2 released Feb 15 1993 | |
78 | ;; (find-bibtex-entry-location bibtex-make-field): Fixed placement of | |
79 | ;; "interactive specification". [Bug report from | |
80 | ;; mernst@theory.lcs.mit.edu] | |
81 | ;; Fixed problem where bibtex-entry would fail if user typed entry | |
82 | ;; name in wrong case. | |
83 | ;; (bibtex-inside-field) Position the cursor _before_ the last comma | |
84 | ;; on a line (the comma is not necessarily "inside" the field); this | |
85 | ;; does not seem to break any existing code. ref sct@dcs.edinburgh.ac.uk | |
86 | ;; (bibtex-enclosing-field, bibtex-enclosing-reference): leave | |
87 | ;; point unmoved if no enclosing field/reference is found. As a | |
88 | ;; result of changes (3) and (4) bibtex-next-field works properly, | |
89 | ;; even when called from the entry key position. | |
90 | ;; (bibtex-remove-OPT): realign the '=' after removing the 'opt'. | |
91 | ;; (bibtex-clean-entry): always remove any trailing comma from the | |
92 | ;; end of a bibtex entry (these commas get stripped automatically when | |
93 | ;; optional fields are killed by bibtex-kill-optional-field, but can be | |
94 | ;; left if optional fields are removed by other means). | |
95 | ;; (bibtex-x-help) Replace tab with spaces in X menu as noted by | |
96 | ;; khera@cs.duke.edu | |
97 | ;; (bibtex-refile-entry): Added (from brannon@jove.cs.caltech.edu) | |
98 | ;; (bibtex-sort-ignore-string-entries sort-bibtex-entries, | |
99 | ;; map-bibtex-entries): Added variable as requested by | |
100 | ;; gernot@cs.unsw.oz.au, required changes to funs. | |
101 | ;; (bibtex-current-entry-label): Added at request of | |
102 | ;; yasuro@maekawa.is.uec.ac.jp | |
103 | ;; (bibtex-DEAthesis:) Deleted along with corresponding entry from | |
104 | ;; bibtex-x-help per shapiro@corto.inria.fr | |
105 | ;; Moved narrow-to-bibtex-entry from C-c C-n to C-c n (the previous | |
106 | ;; binding was in conflict with the binding for bibtex-pop-next. | |
107 | ;; bug report from [shapiro@corto.inria.fr] | |
108 | ;; | |
109 | ||
110 | ;;; | |
111 | ;;; alarson@src.honeywell.com 92-Feb-13 | |
112 | ;;; 1. Made bibtex-entry user callable, now prompts for entry type (e.g. | |
113 | ;;; Article), with completion, and bound it to a key. This is now my | |
114 | ;;; preferred way to add most entries. | |
115 | ;;; 2. Made fields of a bibtex entry derived from the alist bibtex-entry- | |
116 | ;;; field-alist. | |
117 | ;;; 3. Fixed handling of escaped double quotes, e.g. "Schr{\"o}dinger". | |
118 | ;;; 4. Fixed bug where unhiding bibtex entries moved point. | |
119 | ;;; 5. Made "field name" specs permit (name . value) for defaulting. E.g. | |
120 | ;;; (setq bibtex-mode-user-optional-fields '(("library" . "alarson"))) | |
121 | ;;; will generate the field: | |
122 | ;;; library = "alarson", | |
123 | ;;; 6. Added binding for narrow-to-bibtex-entry | |
124 | ;;; 7. Adding a bibtex entry now runs hook: bibtex-add-entry-hook | |
125 | ;;; 8. Made bibtex-clean-entry fixup text alignment, and eliminated the | |
126 | ;;; dependency on bibtex-enclosing-reference which has a problem with | |
127 | ;;; long entries (e.g. those containing abstracts). | |
128 | ;;; | |
e5167999 ER |
129 | ;;; alarson@src.honeywell.com 92-Jan-31 |
130 | ;;; Added support for: ispell, beginning/end of entry movement, a simple | |
131 | ;;; outline like mode (hide the bodies of bibtex entries), support for | |
132 | ;;; sorting bibtex entries, and maintaining them in sorted order, and | |
133 | ;;; simple buffer validation. | |
134 | ;;; User visible functions added: | |
135 | ;;; ispell-{abstract,bibtex-entry}, {beginning,end}-of-bibtex-entry | |
136 | ;;; hide-bibtex-entry-bodies, sort-bibtex-entries, validate-bibtex- | |
137 | ;;; buffer, find-bibtex-duplicates | |
138 | ;;; user visible variables added: | |
139 | ;;; bibtex-maintain-sorted-entries | |
140 | ;;; new local keybindings: | |
a857ed13 | 141 | ;;; " tex-insert-quote |
e5167999 ER |
142 | ;;; C-c$ ispell-bibtex-entry |
143 | ;;; M-C-a beginning-of-bibtex-entry | |
144 | ;;; M-C-e end-of-bibtex-entry | |
745bc783 JB |
145 | ;;; Mike Newton (newton@gumby.cs.caltech.edu) 90.11.17 |
146 | ;;; * Handle items like | |
eb8c3be9 | 147 | ;;; title = poft # "Fifth Tri-quarterly" # random-conf, |
745bc783 JB |
148 | ;;; and title = {This title is inside curlies} |
149 | ;;; * added user settable, always present, optional fields | |
150 | ;;; * fixed 'bibtex-find-it's doc string's location | |
eb8c3be9 | 151 | ;;; * bibtex-field-text made more general (it wouldn't handle the # construct) |
745bc783 | 152 | ;;; and it now handles a small subset of the {} cases |
745bc783 JB |
153 | |
154 | ;;; Bengt Martensson, March 6 | |
155 | ;;; Adapted to Bibtex 0.99 by updating the optional fields according | |
156 | ;;; to the document BibTeXing, Oren Patashnik, dated January 31, 1988. | |
e5167999 | 157 | ;;; Updated documentation strings accordingly. Added (provide 'bibtex). |
745bc783 JB |
158 | ;;; If bibtex-include-OPT-crossref is non-nil, every entry will have |
159 | ;;; an OPTcrossref field, analogously for bibtex-include-OPTkey and | |
160 | ;;; bibtex-include-OPTannote. Added bibtex-preamble, bound to ^C^EP, | |
161 | ;;; and also found in X- and sun-menus. Cleaned up the sun-menu | |
162 | ;;; stuff, and made it more uniform with the X-menu stuff. Marc: I | |
163 | ;;; strongly suspect that I broke your parsing... (Or, more | |
164 | ;;; correctly, BibTeX 0.99 broke it.) | |
165 | ;;; Added bibtex-clean-entry-zap-empty-opts, defvar'd to t. If it | |
166 | ;;; is nil, bibtex-clean-entry will leave empty optional fields alone. | |
e5167999 | 167 | |
745bc783 JB |
168 | ;;; Marc Shapiro 1-feb-89: integrated changes by Bengt Martensson 88-05-06: |
169 | ;;; Added Sun menu support. Locally bound to right mouse button in | |
170 | ;;; bibtex-mode. Emacs 18.49 allows local mouse bindings!! | |
171 | ;;; Commented out DEAthesis. | |
172 | ||
173 | ;;; Marc Shapiro 6-oct-88 | |
e5167999 | 174 | ;;; * skip-whitespace replaced by skip-chars-forward |
745bc783 JB |
175 | ;;; * use indent-to-column instead of inserting tabs (changes to |
176 | ;;; bibtex-entry, bibtex-make-entry, bibtex-make-OPT-entry, renamed to | |
177 | ;;; bibtex-make-optional-entry) | |
178 | ;;; * C-c C-k deletes the current OPT entry entirely | |
179 | ;;; * C-c C-d replaces text of field with "" | |
180 | ;;; * renamed bibtex-find-it to bibtex-find-text. With arg, now goes to | |
181 | ;;; start of text. Fixed bugs in it. | |
182 | ||
183 | ;;; Marc Shapiro 23-sep-88 | |
184 | ;;; * bibtex-clean-entry moves past end of entry. | |
185 | ;;; * bibtex-clean-entry signals mandatory fields left empty. | |
186 | ||
187 | ;;; Marc Shapiro 18-jul-88 | |
e5167999 | 188 | ;;; * Fixed bug in bibtex-flash-entry |
745bc783 JB |
189 | ;;; * Moved all the entry type keystrokes to "C-c C-e something" (instead of |
190 | ;;; "C-c something" previously) to make room for more. C-c C-e is | |
191 | ;;; supposed to stand for "entry" [idea taken from mail-mode]. Moved | |
192 | ;;; bibtex-pop-previous to C-c C-p and bibtex-pop-next to C-c C-n. | |
193 | ;;; * removed binding for "\e[25~" | |
194 | ;;; * replaced bibtex-clean-optionals by bibtex-clean-entry, bound to | |
195 | ;;; C-c C-c | |
196 | ||
197 | ;;; Marc Shapiro 13-jul-88 [based on ideas by Sacha Krakowiak of IMAG] | |
198 | ;;; * bibtex-pop-previous replaces current field with value of | |
199 | ;;; similar field in previous entry. May be called n times in a row | |
200 | ;;; (or with arg n) to pop similar field of n'th previous entry. | |
201 | ;;; There is also a bibtex-pop-next to get similar field of next | |
202 | ;;; entry. | |
203 | ;;; * C-c C-k now kills all empty optional fields of current entry, and | |
204 | ;;; removes "OPT" for those optional fields which have text. | |
205 | ||
206 | ;;; Marc Shapiro 14-dec-87 | |
207 | ;;; Cosmetic fixes. Fixed small bug in bibtex-move-outside-of-entry. | |
208 | ;;; Skip Montanaro <steinmetz!sprite!montanaro> 7-dec-87, Shapiro 10-dec-87 | |
209 | ;;; before inserting an entry, make sure we are outside of a bib entry | |
210 | ;;; Marc Shapiro 3-nov-87 | |
211 | ;;; addition for France: DEAthesis | |
212 | ;;; Marc Shapiro 19-oct-1987 | |
213 | ;;; add X window menu option; bug fixes. TAB, LFD, C-c " and C-c C-o now | |
214 | ;;; behave consistently; deletion never occurs blindly. | |
215 | ;;; Marc Shapiro <shapiro@inria.inria.fr> 15-oct-1986 | |
216 | ;;; align long lines nicely; C-c C-o checks for the "OPT" string; | |
217 | ;;; TAB goes to the end of the string; use lower case; use | |
218 | ;;; run-hooks | |
219 | ||
220 | ;;; Bengt Martensson <ubrinf!mond!bengt> 87-06-28 | |
e5167999 | 221 | ;;; Bengt Martensson <bengt@mathematik.uni-Bremen.de> 87-06-28 |
745bc783 JB |
222 | ;;; Original version |
223 | ||
9ae11a89 ER |
224 | ;;; Code: |
225 | ||
745bc783 JB |
226 | ;;; NOTE by Marc Shapiro, 14-dec-87: |
227 | ;;; (bibtex-x-environment) binds an X menu for bibtex mode to x-button-c-right. | |
228 | ;;; Trouble is, in Emacs 18.44 you can't have a mode-specific mouse binding, | |
229 | ;;; so it will remain active in all windows. Yuck! | |
230 | ||
e5167999 ER |
231 | (provide 'bibtex) |
232 | ||
233 | ;;; these guys typically don't have autoloads...[alarson:19920131.1548CST] | |
9ae11a89 ER |
234 | ;;; Check for fboundp first so that if user autoloads them from non standard |
235 | ;;; places, the users bindings will take precedence. | |
a857ed13 RS |
236 | (if (not (fboundp 'tex-insert-quote)) |
237 | (autoload 'tex-insert-quote "tex-mode")) | |
e5167999 ER |
238 | (if (not (fboundp 'sort-subr)) |
239 | (autoload 'sort-subr "sort")) | |
240 | ||
9ae11a89 | 241 | ;;; These should be in a more generally accessible location. |
e5167999 | 242 | |
9ae11a89 ER |
243 | (defun string-equalp (s1 s2) |
244 | "Like string= except differences in case are ignored." | |
245 | (let ((ss1 (if (symbolp s1) (symbol-name s1) s1)) | |
246 | (ss2 (if (symbolp s2) (symbol-name s2) s2))) | |
247 | (and (= (length ss1) (length ss2)) | |
248 | (string-equal (upcase ss1) (upcase ss2))))) | |
249 | ||
250 | ;;; This should be moved into simple.el, and the functions there modified | |
251 | ;;; to call it rather than doing it themselves. | |
252 | (defun put-string-on-kill-ring (string) | |
253 | "Make STRING be the first element of the kill ring." | |
254 | (setq kill-ring (cons string kill-ring)) | |
255 | (if (> (length kill-ring) kill-ring-max) | |
256 | (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)) | |
257 | (setq kill-ring-yank-pointer kill-ring)) | |
e5167999 | 258 | |
e5167999 | 259 | |
e5167999 | 260 | |
745bc783 JB |
261 | |
262 | (defvar bibtex-clean-entry-zap-empty-opts t | |
d30bfc76 | 263 | "*If non-nil, bibtex-clean-entry will delete all empty optional fields.") |
e5167999 | 264 | |
745bc783 | 265 | (defvar bibtex-include-OPTcrossref t |
d30bfc76 | 266 | "*If non-nil, all entries will have an OPTcrossref field.") |
745bc783 | 267 | (defvar bibtex-include-OPTkey t |
d30bfc76 | 268 | "*If non-nil, all entries will have an OPTkey field.") |
745bc783 | 269 | (defvar bibtex-include-OPTannote t |
d30bfc76 | 270 | "*If non-nil, all entries will have an OPTannote field.") |
745bc783 JB |
271 | |
272 | ;; note: the user should be allowed to have their own list of always | |
273 | ;; available optional fields. exs: "keywords" "categories" | |
e5167999 | 274 | |
745bc783 | 275 | (defvar bibtex-mode-user-optional-fields nil ;no default value |
d30bfc76 | 276 | "*List of optional fields that user want to have as always present |
9ae11a89 ER |
277 | when making a bibtex entry. One possibility is for ``keywords''. |
278 | Entries can be either strings or conses, in which case the car should be | |
279 | string and the cdr the value to be inserted.") | |
280 | ||
281 | (defvar bibtex-mode-syntax-table | |
282 | (let ((st (make-syntax-table))) | |
283 | ;; [alarson:19920214.1004CST] make double quote a string quote | |
284 | (modify-syntax-entry ?\" "\"" st) | |
285 | (modify-syntax-entry ?$ "$$ " st) | |
286 | (modify-syntax-entry ?% "< " st) | |
287 | (modify-syntax-entry ?' "w " st) | |
288 | (modify-syntax-entry ?@ "w " st) | |
289 | (modify-syntax-entry ?\\ "\\" st) | |
290 | (modify-syntax-entry ?\f "> " st) | |
291 | (modify-syntax-entry ?\n "> " st) | |
292 | (modify-syntax-entry ?~ " " st) | |
293 | st)) | |
294 | ||
295 | (defvar bibtex-mode-abbrev-table nil "") | |
296 | (define-abbrev-table 'bibtex-mode-abbrev-table ()) | |
297 | (defvar bibtex-mode-map | |
298 | (let ((km (make-sparse-keymap))) | |
299 | ||
300 | (define-key km "\t" 'bibtex-find-text) | |
301 | (define-key km "\n" 'bibtex-next-field) | |
302 | (define-key km "\C-c\"" 'bibtex-remove-double-quotes) | |
303 | (define-key km "\C-c\C-c" 'bibtex-clean-entry) | |
304 | (define-key km "\C-c?" 'describe-mode) | |
305 | (define-key km "\C-c\C-p" 'bibtex-pop-previous) | |
306 | (define-key km "\C-c\C-n" 'bibtex-pop-next) | |
307 | (define-key km "\C-c\C-k" 'bibtex-kill-optional-field) | |
308 | (define-key km "\C-c\C-d" 'bibtex-empty-field) | |
309 | ||
310 | ;; [alarson:19920131.1543CST] | |
a857ed13 | 311 | (define-key km "\"" 'tex-insert-quote) |
9ae11a89 ER |
312 | (define-key km "\C-c$" 'ispell-bibtex-entry) |
313 | (define-key km "\M-\C-a" 'beginning-of-bibtex-entry) | |
314 | (define-key km "\M-\C-e" 'end-of-bibtex-entry) | |
315 | (define-key km "\C-ce" 'bibtex-entry) | |
316 | ; (define-key km "\C-cn" 'narrow-to-bibtex-entry) | |
317 | ||
318 | (define-key km "\C-c\C-e\C-a" 'bibtex-Article) | |
319 | (define-key km "\C-c\C-e\C-b" 'bibtex-Book) | |
320 | ; (define-key km "\C-c\C-e\C-d" 'bibtex-DEAthesis) | |
321 | (define-key km "\C-c\C-e\C-c" 'bibtex-InProceedings) | |
322 | (define-key km "\C-c\C-e\C-i" 'bibtex-InBook) | |
323 | (define-key km "\C-c\C-ei" 'bibtex-InCollection) | |
324 | (define-key km "\C-c\C-eI" 'bibtex-InProceedings) | |
325 | (define-key km "\C-c\C-e\C-m" 'bibtex-Manual) | |
326 | (define-key km "\C-c\C-em" 'bibtex-MastersThesis) | |
327 | (define-key km "\C-c\C-eM" 'bibtex-Misc) | |
328 | (define-key km "\C-c\C-o" 'bibtex-remove-OPT) | |
329 | (define-key km "\C-c\C-e\C-p" 'bibtex-PhdThesis) | |
330 | (define-key km "\C-c\C-ep" 'bibtex-Proceedings) | |
331 | (define-key km "\C-c\C-eP" 'bibtex-preamble) | |
332 | (define-key km "\C-c\C-e\C-t" 'bibtex-TechReport) | |
333 | (define-key km "\C-c\C-e\C-s" 'bibtex-string) | |
334 | (define-key km "\C-c\C-e\C-u" 'bibtex-Unpublished) | |
335 | km)) | |
336 | ||
337 | (defvar bibtex-pop-previous-search-point nil | |
338 | "Next point where bibtex-pop-previous should start looking for a similar | |
339 | entry.") | |
340 | ||
341 | (defvar bibtex-pop-next-search-point nil | |
342 | "Next point where bibtex-pop-next should start looking for a similar | |
343 | entry.") | |
344 | ||
345 | (defvar bibtex-entry-field-alist | |
346 | '( | |
347 | ("Article" . ((("author" "title" "journal" "year") | |
348 | ("volume" "number" "pages" "month" "note")) | |
349 | (("author" "title") | |
350 | ("journal" "year" "volume" "number" "pages" | |
351 | "month" "note")))) | |
352 | ("Book" . ((("author" "title" "publisher" "year") | |
353 | ("editor" "volume" "number" "series" "address" | |
354 | "edition" "month" "note")))) | |
355 | ("Booklet" . ((("title") | |
356 | ("author" "howpublished" "address" "month" "year" "note")))) | |
357 | ||
358 | ;; France: Dipl\^{o}me d'Etudes Approfondies (similar to Master's) | |
359 | ; ("DEAthesis" . ((("author" "title" "school" "year") | |
360 | ; ("address" "month" "note")))) | |
361 | ||
362 | ("InBook" . ((("author" "title" "chapter" "publisher" "year") | |
363 | ("editor" "pages" "volume" "number" "series" "address" | |
364 | "edition" "month" "type" "note")) | |
365 | (("author" "title" "chapter") | |
366 | ("publisher" "year" "editor" "pages" "volume" "number" | |
367 | "series" "address" "edition" "month" "type" "note")))) | |
368 | ||
369 | ||
370 | ("InCollection" . ((("author" "title" | |
371 | "booktitle" "publisher" "year") | |
372 | ("editor" "volume" "number" "series" "type" "chapter" | |
373 | "pages" "address" "edition" "month" "note")) | |
374 | (("author" "title") | |
375 | ("booktitle" "publisher" "year" | |
376 | "editor" "volume" "number" "series" "type" "chapter" | |
377 | "pages" "address" "edition" "month" "note")))) | |
378 | ||
379 | ||
380 | ("InProceedings" . ((("author" "title" "booktitle" "year") | |
381 | ("editor" "volume" "number" "series" "pages" | |
382 | "organization" "publisher" "address" "month" "note")) | |
383 | (("author" "title") | |
384 | ("editor" "volume" "number" "series" "pages" | |
385 | "booktitle" "year" | |
386 | "organization" "publisher" "address" "month" "note")))) | |
387 | ||
388 | ||
389 | ("Manual" . ((("title") | |
390 | ("author" "organization" "address" "edition" "year" | |
391 | "month" "note")))) | |
392 | ||
393 | ("MastersThesis" . ((("author" "title" "school" "year") | |
394 | ("address" "month" "note" "type")))) | |
395 | ||
396 | ("Misc" . ((() | |
397 | ("author" "title" "howpublished" "year" "month" "note")))) | |
398 | ||
399 | ("PhdThesis" . ((("author" "title" "school" "year") | |
400 | ("address" "month" "type" "note")))) | |
401 | ||
402 | ("Proceedings" . ((("title" "year") | |
403 | ("editor" "volume" "number" "series" "publisher" | |
404 | "organization" "address" "month" "note")))) | |
405 | ||
406 | ("TechReport" . ((("author" "title" "institution" "year") | |
407 | ("type" "number" "address" "month" "note")))) | |
408 | ||
409 | ("Unpublished" . ((("author" "title" "note") | |
410 | ("year" "month")))) | |
411 | ) | |
412 | ||
413 | "List of (entry-name (required optional) (crossref-required crossref-optional)) | |
414 | tripples. If the third element is nil, then the first pair can be used. Required | |
415 | and optional are lists of strings. All entry creation functions use this variable | |
416 | to generate entries, and bibtex-entry ensures the entry type is valid. This | |
417 | variable can be used for example to make bibtex manipulate a different set of entry | |
418 | types, e.g. a crossreference document of organization types.") | |
745bc783 JB |
419 | |
420 | ||
421 | ;;; A bibtex file is a sequence of entries, either string definitions | |
422 | ;;; or reference entries. A reference entry has a type part, a | |
423 | ;;; key part, and a comma-separated sequence of fields. A string | |
424 | ;;; entry has a single field. A field has a left and right part, | |
425 | ;;; separated by a '='. The left part is the name, the right part is | |
426 | ;;; the text. Here come the definitions allowing to create and/or parse | |
427 | ;;; entries and fields: | |
428 | ||
429 | ;;; fields | |
430 | (defun bibtex-cfield (name text) | |
d30bfc76 | 431 | "Create a regexp for a bibtex field of name NAME and text TEXT" |
745bc783 JB |
432 | (concat ",[ \t\n]*\\(" |
433 | name | |
434 | "\\)[ \t\n]*=[ \t\n]*\\(" | |
435 | text | |
436 | "\\)")) | |
437 | (defconst bibtex-name-in-cfield 1 | |
d30bfc76 | 438 | "The regexp subexpression number of the name part in bibtex-cfield.") |
745bc783 | 439 | (defconst bibtex-text-in-cfield 2 |
d30bfc76 | 440 | "The regexp subexpression number of the text part in bibtex-cfield.") |
745bc783 | 441 | |
9ae11a89 ER |
442 | ;;; KAWATA Yasuro <yasuro@qqqq.maekawa.is.uec.ac.jp> reported bug that "/" |
443 | ;;; was not premitted in field names. The old value of this var was: | |
444 | ;;; "[A-Za-z][---A-Za-z0-9:_+]*" | |
445 | ;;; According to the LaTeX manual, page 71, the legal values are letters, | |
446 | ;;; digits, and punctuation other than comma. Section 2.1 defines | |
447 | ;;; punctuation as: | |
448 | ;;; .:;,?!`'()[]-/*@ | |
449 | ;;; and says that += can be used in normal text. Specifically #$%&~_^\{} | |
450 | ;;; are called out as special chars. Some experimentation with LaTeX | |
451 | ;;; indicates that # and ~ definitely don't work, but that the following | |
452 | ;;; citation does! \cite{a0.:;?!`'()[]-/*@_&$^+=|<>}. I chose here to | |
453 | ;;; permit _ since it was previously allowed, but otherwise to only handle | |
454 | ;;; punc and += | |
455 | ;;; Amendment: I couldn't get a regexp with both "[]"'s and hyphen to | |
456 | ;;; work. It looks like you need them both to be the first entries in a | |
457 | ;;; regexp pattern. [alarson:19930315.0900CST] | |
458 | ||
459 | (defconst bibtex-field-name "[A-Za-z][---A-Za-z0-9.:;?!`'()/*@_+=]*" | |
745bc783 JB |
460 | "Regexp defining the name part of a bibtex field.") |
461 | ||
462 | ;; bibtex-field-text must be able to handle | |
463 | ;; title = "Proc. Fifteenth Annual" # STOC, | |
464 | ;; month = "10~" # jan, | |
465 | ;; year = "{\noopsort{1973c}}1981", | |
466 | ;; month = apr # "-" # may, | |
467 | ;; key = {Volume-2}, | |
468 | ;; note = "Volume~2 is listed under Knuth \cite{book-full}" | |
469 | ;; i have added a few of these, but not all! -- MON | |
470 | ||
471 | (defconst bibtex-field-const | |
472 | "[0-9A-Za-z][---A-Za-z0-9:_+]*" | |
473 | "Format of a bibtex field constant.") | |
d30bfc76 | 474 | |
e5167999 | 475 | (defconst bibtex-field-string |
745bc783 | 476 | (concat |
e5167999 ER |
477 | "\"[^\"]*[^\\\\]\"\\|\"\"") |
478 | "Match either a string or an empty string.") | |
479 | ||
745bc783 JB |
480 | (defconst bibtex-field-string-or-const |
481 | (concat bibtex-field-const "\\|" bibtex-field-string) | |
d30bfc76 | 482 | "Match either bibtex-field-string or bibtex-field-const.") |
745bc783 | 483 | |
745bc783 JB |
484 | (defconst bibtex-field-text |
485 | (concat | |
486 | "\\(" bibtex-field-string-or-const "\\)" | |
487 | "\\([ \t\n]+#[ \t\n]+\\(" bibtex-field-string-or-const "\\)\\)*\\|" | |
e5167999 | 488 | "{[^{}]*[^\\\\]}") |
745bc783 JB |
489 | "Regexp defining the text part of a bibtex field: either a string, or |
490 | an empty string, or a constant followed by one or more # / constant pairs. | |
e5167999 ER |
491 | Also matches simple {...} patterns.") |
492 | ||
493 | ;(defconst bibtex-field-text | |
494 | ; "\"[^\"]*[^\\\\]\"\\|\"\"\\|[0-9A-Za-z][---A-Za-z0-9:_+]*" | |
495 | ; "Regexp defining the text part of a bibtex field: either a string, or an empty string, or a constant.") | |
745bc783 JB |
496 | |
497 | (defconst bibtex-field | |
498 | (bibtex-cfield bibtex-field-name bibtex-field-text) | |
499 | "Regexp defining the format of a bibtex field") | |
500 | ||
501 | (defconst bibtex-name-in-field bibtex-name-in-cfield | |
d30bfc76 | 502 | "The regexp subexpression number of the name part in bibtex-field") |
745bc783 | 503 | (defconst bibtex-text-in-field bibtex-text-in-cfield |
d30bfc76 | 504 | "The regexp subexpression number of the text part in bibtex-field") |
745bc783 JB |
505 | |
506 | ;;; references | |
507 | (defconst bibtex-reference-type | |
508 | "@[A-Za-z]+" | |
d30bfc76 | 509 | "Regexp defining the type part of a bibtex reference entry") |
745bc783 JB |
510 | (defconst bibtex-reference-head |
511 | (concat "^[ \t]*\\(" | |
512 | bibtex-reference-type | |
513 | "\\)[ \t]*[({]\\(" | |
514 | bibtex-field-name | |
515 | "\\)") | |
d30bfc76 | 516 | "Regexp defining format of the header line of a bibtex reference entry") |
745bc783 | 517 | (defconst bibtex-type-in-head 1 |
d30bfc76 | 518 | "The regexp subexpression number of the type part in bibtex-reference-head") |
745bc783 | 519 | (defconst bibtex-key-in-head 2 |
d30bfc76 JB |
520 | "The regexp subexpression number of the key part in |
521 | bibtex-reference-head") | |
745bc783 JB |
522 | |
523 | (defconst bibtex-reference | |
524 | (concat bibtex-reference-head | |
525 | "\\([ \t\n]*" bibtex-field "\\)*" | |
526 | "[ \t\n]*[})]") | |
d30bfc76 | 527 | "Regexp defining the format of a bibtex reference entry") |
745bc783 | 528 | (defconst bibtex-type-in-reference bibtex-type-in-head |
d30bfc76 | 529 | "The regexp subexpression number of the type part in bibtex-reference") |
745bc783 | 530 | (defconst bibtex-key-in-reference bibtex-key-in-head |
d30bfc76 JB |
531 | "The regexp subexpression number of the key part in |
532 | bibtex-reference") | |
745bc783 | 533 | |
e5167999 | 534 | ;;; strings |
745bc783 JB |
535 | (defconst bibtex-string |
536 | (concat "^[ \t]*@[sS][tT][rR][iI][nN][gG][ \t\n]*[({][ \t\n]*\\(" | |
537 | bibtex-field-name | |
538 | "\\)[ \t\n]*=[ \t\n]*\\(" | |
539 | bibtex-field-text | |
540 | "\\)[ \t\n]*[})]") | |
d30bfc76 | 541 | "Regexp defining the format of a bibtex string entry") |
745bc783 | 542 | (defconst bibtex-name-in-string 1 |
d30bfc76 | 543 | "The regexp subexpression of the name part in bibtex-string") |
745bc783 | 544 | (defconst bibtex-text-in-string 2 |
d30bfc76 | 545 | "The regexp subexpression of the text part in bibtex-string") |
745bc783 | 546 | |
93d35499 | 547 | (defconst bibtex-name-alignment 2 |
745bc783 JB |
548 | "Alignment for the name part in BibTeX fields. |
549 | Chosen on aesthetic grounds only.") | |
550 | ||
551 | (defconst bibtex-text-alignment (length " organization = ") | |
552 | "Alignment for the text part in BibTeX fields. | |
553 | Equal to the space needed for the longest name part.") | |
554 | ||
9ae11a89 | 555 | (defun bibtex-current-entry-label (&optional include-cite kill) |
eb8c3be9 | 556 | "Return the label of the bibtex entry containing, or preceding point. |
9ae11a89 ER |
557 | Optional argument INCLUDE-CITE, if true means put a '\\cite{}' around the |
558 | returned value. Second optional argument KILL, if true, means place the | |
559 | returned value in the kill buffer. Interactively; providing prefix | |
560 | argument makes INCLUDE-CITE true, and kill is true by default. | |
561 | ||
562 | Rationale: | |
563 | The intention is that someone will write a function that can be bound to | |
564 | a mouse key so that people entering TeX can just mouse on the bibtex entry | |
565 | and have the citation key inserted at the current point (which will almost | |
eb8c3be9 | 566 | certainly be in some other buffer). In the interim this function is |
9ae11a89 ER |
567 | marginally useful for keyboard binding and is not bound by default. |
568 | Suggested binding is ^C-k." | |
569 | (interactive (list current-prefix-arg t)) | |
570 | (save-excursion | |
571 | (beginning-of-bibtex-entry) | |
572 | (re-search-forward bibtex-reference-head (save-excursion (end-of-bibtex-entry) (point))) | |
573 | (let* ((key (buffer-substring (match-beginning bibtex-key-in-head) | |
574 | (match-end bibtex-key-in-head))) | |
575 | (val (if include-cite | |
576 | (format "\\cite{%s}" key) | |
577 | key))) | |
578 | (if kill | |
579 | (put-string-on-kill-ring val)) | |
580 | val))) | |
581 | ||
745bc783 JB |
582 | ;;; bibtex mode: |
583 | ||
81354e19 | 584 | ;;;###autoload |
745bc783 JB |
585 | (defun bibtex-mode () |
586 | "Major mode for editing bibtex files. | |
587 | ||
588 | \\{bibtex-mode-map} | |
589 | ||
590 | A command such as \\[bibtex-Book] will outline the fields for a BibTeX book entry. | |
591 | ||
592 | The optional fields start with the string OPT, and thus ignored by BibTeX. | |
593 | The OPT string may be removed from a field with \\[bibtex-remove-OPT]. | |
594 | \\[bibtex-kill-optional-field] kills the current optional field entirely. | |
595 | \\[bibtex-remove-double-quotes] removes the double-quotes around the text of | |
596 | the current field. \\[bibtex-empty-field] replaces the text of the current | |
597 | field with the default \"\". | |
598 | ||
599 | The command \\[bibtex-clean-entry] cleans the current entry, i.e. (i) removes | |
600 | double-quotes from entirely numerical fields, (ii) removes OPT from all | |
601 | non-empty optional fields, (iii) removes all empty optional fields, and (iv) | |
602 | checks that no non-optional fields are empty. | |
603 | ||
604 | Use \\[bibtex-find-text] to position the dot at the end of the current field. | |
605 | Use \\[bibtex-next-field] to move to end of the next field. | |
606 | ||
9ae11a89 ER |
607 | The following may be of interest as well: |
608 | ||
609 | Functions: | |
610 | find-bibtex-duplicates | |
611 | find-bibtex-entry-location | |
612 | hide-bibtex-entry-bodies | |
613 | sort-bibtex-entries | |
614 | validate-bibtex-buffer | |
615 | ||
616 | Variables: | |
617 | bibtex-clean-entry-zap-empty-opts | |
618 | bibtex-entry-field-alist | |
619 | bibtex-include-OPTannote | |
620 | bibtex-include-OPTcrossref | |
621 | bibtex-include-OPTkey | |
622 | bibtex-maintain-sorted-entries | |
623 | bibtex-mode-user-optional-fields | |
624 | ||
745bc783 JB |
625 | Fields: |
626 | address | |
e5167999 | 627 | Publisher's address |
745bc783 JB |
628 | annote |
629 | Long annotation used for annotated bibliographies (begins sentence) | |
630 | author | |
631 | Name(s) of author(s), in BibTeX name format | |
632 | booktitle | |
633 | Book title when the thing being referenced isn't the whole book. | |
634 | For book entries, the title field should be used instead. | |
635 | chapter | |
e5167999 | 636 | Chapter number |
745bc783 JB |
637 | crossref |
638 | The database key of the entry being cross referenced. | |
639 | edition | |
9ae11a89 | 640 | Edition of a book (e.g., \"second\") |
745bc783 JB |
641 | editor |
642 | Name(s) of editor(s), in BibTeX name format. | |
643 | If there is also an author field, then the editor field should be | |
644 | for the book or collection that the work appears in | |
645 | howpublished | |
646 | How something strange has been published (begins sentence) | |
647 | institution | |
648 | Sponsoring institution | |
649 | journal | |
650 | Journal name (macros are provided for many) | |
651 | key | |
e5167999 | 652 | Alphabetizing and labeling key (needed when no author or editor) |
745bc783 JB |
653 | month |
654 | Month (macros are provided) | |
655 | note | |
656 | To help the reader find a reference (begins sentence) | |
657 | number | |
658 | Number of a journal or technical report | |
659 | organization | |
660 | Organization (sponsoring a conference) | |
661 | pages | |
662 | Page number or numbers (use `--' to separate a range) | |
663 | publisher | |
664 | Publisher name | |
665 | school | |
666 | School name (for theses) | |
667 | series | |
668 | The name of a series or set of books. | |
669 | An individual book will will also have it's own title | |
670 | title | |
671 | The title of the thing being referenced | |
672 | type | |
9ae11a89 ER |
673 | Type of a technical report (e.g., \"Research Note\") to be used |
674 | instead of the default \"Technical Report\" | |
745bc783 JB |
675 | volume |
676 | Volume of a journal or multivolume work | |
677 | year | |
678 | Year---should contain only numerals | |
679 | --------------------------------------------------------- | |
680 | Entry to this mode calls the value of bibtex-mode-hook if that value is | |
681 | non-nil." | |
682 | (interactive) | |
683 | (kill-all-local-variables) | |
9ae11a89 | 684 | (set-syntax-table bibtex-mode-syntax-table) |
745bc783 JB |
685 | (use-local-map bibtex-mode-map) |
686 | (setq major-mode 'bibtex-mode) | |
745bc783 JB |
687 | (setq mode-name "BibTeX") |
688 | (set-syntax-table bibtex-mode-syntax-table) | |
689 | (setq local-abbrev-table bibtex-mode-abbrev-table) | |
690 | (make-local-variable 'paragraph-start) | |
691 | (setq paragraph-start "^[ \f\n\t]*$") | |
eb8c3be9 | 692 | (auto-fill-mode 1) ; nice alignments |
745bc783 JB |
693 | (setq left-margin (+ bibtex-text-alignment 1)) |
694 | ||
695 | (run-hooks 'bibtex-mode-hook)) | |
696 | ||
697 | (defun bibtex-move-outside-of-entry () | |
698 | "Make sure we are outside of a bib entry" | |
699 | (cond ((or | |
700 | (= (point) (point-max)) | |
701 | (= (point) (point-min)) | |
702 | (looking-at "[ \n]*@") | |
703 | ) | |
704 | t) | |
705 | (t | |
706 | (backward-paragraph) | |
707 | (forward-paragraph))) | |
e5167999 ER |
708 | (re-search-forward "[ \t\n]*" (point-max) t)) |
709 | ||
710 | (defun ispell-abstract () | |
711 | (interactive) | |
712 | (beginning-of-bibtex-entry) | |
713 | (re-search-forward "^[ \t]*[OPT]*abstract[ \t]*=") | |
714 | (ispell-region (point) | |
715 | (save-excursion (forward-sexp) (point)))) | |
716 | ||
717 | (defun beginning-of-bibtex-entry () | |
718 | (interactive) | |
719 | (re-search-backward "^@" nil 'move)) | |
720 | ||
9ae11a89 ER |
721 | (defun skip-whitespace-and-comments () |
722 | ;; It might be a good idea to have forward-sexp with argument 0 do what | |
723 | ;; this function tries to do, namely skip whitespace and comments. | |
724 | ;; Maybe a better name for this would be skip-to-next-sexp. | |
725 | ;; alternative implementation: | |
726 | ;; (let ((parse-sexp-ignore-comments t)) | |
727 | ;; (forward-sexp 1) | |
728 | ;; (forward-sexp -1)) | |
729 | ;; but I've had problems with this not getting the parse of comments | |
730 | ;; right going backward if they contain unbalanced expressions or string | |
731 | ;; quotes. [alarson:19920217.1021CST] | |
732 | (let ((md (match-data))) | |
733 | (unwind-protect | |
734 | (while (cond ((looking-at "\\s>+\\|\\s +") | |
735 | ;; was whitespace | |
736 | ;; NOTE: also checked end-comment. In latex and | |
737 | ;; lisp modes, newline is an end comment, but it | |
738 | ;; should also be a whitespace char. | |
739 | (goto-char (match-end 0))) | |
740 | ;; If looking at beginning of comment, skip to end. | |
741 | ((looking-at "\\s<") | |
742 | (re-search-forward "\\s>")))) | |
743 | (store-match-data md)))) | |
744 | ||
745 | ;;; [alarson:19920214.1007CST] | |
e5167999 | 746 | (defun end-of-bibtex-entry () |
9ae11a89 ER |
747 | "If inside an entry, move to the end of it, otherwise move to the end |
748 | of the next entry." | |
e5167999 | 749 | (interactive) |
9ae11a89 ER |
750 | ;; if point was previously at the end of an entry, this puts us |
751 | ;; inside the next entry, otherwise we remain in the current one. | |
752 | (progn | |
753 | (skip-whitespace-and-comments) | |
754 | ;;; (skip-chars-forward " \t\n") | |
755 | (end-of-line)) | |
756 | (beginning-of-bibtex-entry) | |
757 | (let ((parse-sexp-ignore-comments t)) | |
758 | (forward-sexp) ; skip entry type | |
759 | (forward-sexp) ; skip entry body | |
760 | )) | |
761 | ;(defun end-of-bibtex-entry () | |
762 | ; (interactive) | |
763 | ; (re-search-forward "}$" nil 'move)) | |
e5167999 ER |
764 | |
765 | (defun ispell-bibtex-entry () | |
766 | (interactive) | |
767 | (ispell-region (progn (beginning-of-bibtex-entry) (point)) | |
768 | (progn (end-of-bibtex-entry) (point)))) | |
769 | ||
770 | (defun narrow-to-bibtex-entry () | |
771 | (interactive) | |
772 | (save-excursion | |
773 | (narrow-to-region (progn (beginning-of-bibtex-entry) (point)) | |
774 | (progn (end-of-bibtex-entry) (point))))) | |
775 | ||
776 | ||
777 | (defun beginning-of-first-bibtex-entry () | |
778 | (goto-char (point-min)) | |
779 | (cond | |
780 | ((re-search-forward "^@" nil 'move) | |
781 | (beginning-of-line)) | |
782 | ((and (bobp) (eobp)) | |
783 | nil) | |
784 | (t | |
785 | (message "Warning: No bibtex entries found!")))) | |
786 | ||
787 | (defun hide-bibtex-entry-bodies (&optional arg) | |
788 | "Hide all lines between first and last bibtex entries not beginning with @. | |
789 | With argument, show all text." | |
790 | (interactive "P") | |
9ae11a89 ER |
791 | (save-excursion |
792 | (beginning-of-first-bibtex-entry) | |
793 | ;; subst-char-in-region modifies the buffer, despite what the | |
794 | ;; documentation says... | |
795 | (let ((modifiedp (buffer-modified-p)) | |
796 | (buffer-read-only nil)) | |
797 | (if arg | |
798 | (subst-char-in-region (point) (point-max) ?\r ?\n t) | |
e5167999 ER |
799 | (while (save-excursion (re-search-forward "\n[^@]" (point-max) t)) |
800 | (save-excursion (replace-regexp "\n\\([^@]\\)" "\r\\1")))) | |
9ae11a89 ER |
801 | (setq selective-display (not arg)) |
802 | (set-buffer-modified-p modifiedp)))) | |
803 | ||
804 | (defvar bibtex-sort-ignore-string-entries nil | |
805 | "*If true, bibtex @STRING entries are ignored when determining ordering | |
806 | of the buffer (e.g. sorting, locating alphabetical position for new entries, | |
807 | etc.)") | |
e5167999 ER |
808 | |
809 | (defun sort-bibtex-entries () | |
810 | "Sort bibtex entries alphabetically by key. | |
9ae11a89 ER |
811 | Text before the first bibtex entry, and following the last is not affected. |
812 | If bibtex-sort-ignore-string-entries is true, @string entries will be ignored. | |
813 | ||
e5167999 ER |
814 | Bugs: |
815 | 1. Text between the closing brace ending one bibtex entry, and the @ starting | |
eb8c3be9 | 816 | the next, is considered part of the PRECEDING entry. Perhaps it should be |
e5167999 ER |
817 | part of the following entry." |
818 | (interactive) | |
819 | (save-restriction | |
820 | (beginning-of-first-bibtex-entry) | |
821 | (narrow-to-region (point) | |
822 | (save-excursion | |
823 | (goto-char (point-max)) | |
824 | (beginning-of-bibtex-entry) | |
825 | (end-of-bibtex-entry) | |
826 | (point))) | |
827 | (sort-subr nil ; reversep | |
eb8c3be9 | 828 | ;; beginning of record function |
e5167999 ER |
829 | 'forward-line |
830 | ;; end of record function | |
9ae11a89 | 831 | (function (lambda () (and (re-search-forward "}\\s-*\n[\n \t]*@" nil 'move) |
e5167999 ER |
832 | (forward-char -2)))) |
833 | ;; start of key function | |
9ae11a89 ER |
834 | (if bibtex-sort-ignore-string-entries |
835 | (function (lambda () | |
836 | (while (and (re-search-forward "^\\s-*\\([@a-zA-Z]*\\)\\s-*{\\s-*") | |
837 | (string-equalp "@string" | |
838 | (buffer-substring (match-beginning 1) | |
839 | (match-end 1))))) | |
840 | nil)) | |
841 | (function (lambda () (re-search-forward "{\\s-*") nil))) | |
e5167999 ER |
842 | ;; end of key function |
843 | (function (lambda () (search-forward ","))) | |
844 | ))) | |
845 | ||
846 | (defun map-bibtex-entries (fun) | |
847 | "Call FUN for each bibtex entry starting with the current, to the end of the file. | |
9ae11a89 ER |
848 | FUN is called with one argument, the key of the entry, and with point inside the entry. |
849 | If bibtex-sort-ignore-string-entries is true, FUN will not be called for @string entries." | |
e5167999 | 850 | (beginning-of-bibtex-entry) |
9ae11a89 ER |
851 | (while (re-search-forward "^@[^{]*{[ \t]*\\([^, ]*\\)" nil t) |
852 | (if (and bibtex-sort-ignore-string-entries | |
853 | (string-equalp "@string{" | |
854 | (buffer-substring (match-beginning 0) | |
855 | (match-beginning 1)))) | |
856 | nil ; ignore the @string entry. | |
857 | (funcall fun (buffer-substring (match-beginning 1) (match-end 1)))))) | |
e5167999 ER |
858 | |
859 | (defun find-bibtex-entry-location (entry-name) | |
e5167999 ER |
860 | "Searches from beginning of current buffer looking for place to put the |
861 | bibtex entry named ENTRY-NAME. Buffer is assumed to be in sorted order, | |
862 | without duplicates (see \\[sort-bibtex-entries]), if it is not, an error will | |
863 | be signalled." | |
9ae11a89 | 864 | (interactive "sBibtex entry key: ") |
e5167999 ER |
865 | (let ((previous nil) |
866 | point) | |
867 | (beginning-of-first-bibtex-entry) | |
868 | (or (catch 'done | |
869 | (map-bibtex-entries (function (lambda (current) | |
870 | (cond | |
871 | ((string-equal entry-name current) | |
872 | (error "Entry duplicates existing!")) | |
873 | ((or (null previous) | |
874 | (string< previous current)) | |
875 | (setq previous current | |
876 | point (point)) | |
877 | (if (string< entry-name current) | |
878 | (progn | |
879 | (beginning-of-bibtex-entry) | |
880 | ;; Many schemes append strings to | |
881 | ;; existing entries to resolve them, | |
882 | ;; so initial substring matches may | |
883 | ;; indicate a duplicate entry. | |
884 | (let ((idx (string-match (regexp-quote entry-name) current))) | |
885 | (if (and (integerp idx) | |
886 | (zerop idx)) | |
887 | (progn | |
888 | (message "Warning: Entry %s may be a duplicate of %s!" | |
889 | entry-name current) | |
890 | (ding t)))) | |
891 | (throw 'done t)))) | |
892 | ((string-equal previous current) | |
893 | (error "Duplicate here with previous!")) | |
894 | (t (error "Entries out of order here!"))))))) | |
895 | (end-of-bibtex-entry)))) | |
896 | ||
897 | (defun validate-bibtex-buffer () | |
898 | "Find some typical errors in bibtex files. | |
899 | 1. At signs (@) not as first char of a line. | |
900 | 2. Double quotes (\") inside strings. | |
901 | 3. Closing braces (}) not the last character of a line." | |
902 | (interactive) | |
903 | (let ((point (point))) | |
904 | (while (re-search-forward ".@" nil t) | |
905 | (let* ((foo (parse-partial-sexp (save-excursion (beginning-of-bibtex-entry) | |
906 | (point)) | |
907 | (point))) | |
908 | (in-a-string (nth 3 foo))) | |
909 | (if (not in-a-string) | |
910 | (error "At sign (@) out of place!")))) | |
911 | (goto-char point) | |
912 | (while (search-forward "\"" nil t) | |
913 | (or (looking-at "[,}][ \t]*$") | |
9ae11a89 | 914 | (char-equal (preceding-char) ?\") |
e5167999 ER |
915 | ;; some versions put closing brace on separate line. |
916 | (looking-at "[ \t]*\n}") | |
917 | (save-excursion | |
918 | (save-restriction | |
919 | (narrow-to-region (point) | |
920 | (progn (beginning-of-line) (point))) | |
921 | (looking-at "^[ \t]*[a-zA-Z]+[ \t]*=[ \t]*\"$"))) | |
922 | (error "Quote out of place, or missing \",\" or \"}\"!"))) | |
923 | (goto-char point) | |
924 | ;; This is only approximate, should actually search for close braces, | |
925 | ;; then see if they are inside a string, or at the end of a line. | |
926 | ;; This just gets the typical case of whitespace after a closing brace. | |
927 | (while (search-forward "}[ \t]+$" nil t) | |
928 | (error "Brace not last char of line!")) | |
929 | (goto-char point) | |
930 | (message "Bibtex buffer appears o.k."))) | |
931 | ||
932 | (defun find-bibtex-duplicates () | |
933 | "Searches forward in current buffer looking for duplicate bibtex entries. | |
934 | Buffer is assumed to be sorted, see \\[sort-bibtex-entries]" | |
935 | (interactive) | |
936 | (let ((point (point))) | |
937 | ;; errors if things are not right... | |
938 | (find-bibtex-entry-location (make-string 10 255)) | |
939 | (goto-char point) | |
940 | (message "No duplicates found!"))) | |
941 | ||
942 | ||
9ae11a89 ER |
943 | ;;; assoc doesn't ignore case, so we need an assoc that does... |
944 | (defun assoc-string-equalp (thing alist) | |
945 | (or (assoc thing alist) | |
946 | (while (and alist | |
947 | (not (string-equalp thing (car (car alist))))) | |
948 | (setq alist (cdr alist))) | |
949 | (car alist))) | |
950 | ||
e5167999 ER |
951 | (defvar bibtex-maintain-sorted-entries nil |
952 | "*If true, bibtex-mode will attempt to maintain all bibtex entries in | |
9ae11a89 ER |
953 | sorted order. |
954 | ||
955 | Note that this is more a property of a file than a personal preference and | |
956 | as such should normally be set via a file local variable entry.") | |
957 | ||
958 | (defun bibtex-entry (entry-type &optional required optional) | |
959 | (interactive (let* ((completion-ignore-case t) | |
960 | (e-t (completing-read "Entry Type: " bibtex-entry-field-alist | |
961 | nil t))) | |
962 | (list e-t))) | |
963 | (if (and (null required) (null optional)) | |
964 | (let* ((e (assoc-string-equalp entry-type bibtex-entry-field-alist)) | |
965 | (r-n-o (elt e 1)) | |
966 | (c-ref (elt e 2))) | |
967 | (if (null e) | |
968 | (error "Bibtex entry type %s not defined!")) | |
969 | (if (and bibtex-include-OPTcrossref c-ref) | |
970 | (setq required (elt c-ref 0) | |
971 | optional (elt c-ref 1)) | |
972 | (setq required (elt r-n-o 0) | |
973 | optional (elt r-n-o 1))))) | |
974 | (let ((key (if bibtex-maintain-sorted-entries | |
975 | (read-string (format "%s key: " entry-type))))) | |
976 | (if key | |
977 | (find-bibtex-entry-location key)) | |
e5167999 ER |
978 | (bibtex-move-outside-of-entry) |
979 | (insert "@" entry-type "{") | |
e5167999 | 980 | (if key |
9ae11a89 ER |
981 | (insert key)) |
982 | (save-excursion | |
983 | (mapcar 'bibtex-make-field required) | |
984 | (if bibtex-include-OPTcrossref | |
985 | (bibtex-make-optional-field "crossref")) | |
986 | (if bibtex-include-OPTkey | |
987 | (bibtex-make-optional-field "key")) | |
988 | (mapcar 'bibtex-make-optional-field optional) | |
989 | (mapcar 'bibtex-make-optional-field | |
990 | bibtex-mode-user-optional-fields) | |
991 | (if bibtex-include-OPTannote | |
992 | (bibtex-make-optional-field "annote")) | |
993 | (insert "\n}\n\n")) | |
994 | (if key | |
995 | (bibtex-next-field t)) | |
996 | (run-hooks 'bibtex-add-entry-hook))) | |
e5167999 ER |
997 | |
998 | ;; (defun bibtex-entry (entry-type required optional) | |
999 | ;; (bibtex-move-outside-of-entry) | |
1000 | ;; (insert (concat "@" entry-type "{,\n\n}\n\n")) | |
1001 | ;; (previous-line 3) | |
1002 | ;; (insert (mapconcat 'bibtex-make-entry required ",\n")) | |
1003 | ;; (if required | |
1004 | ;; (if optional | |
1005 | ;; (insert ",\n"))) | |
1006 | ;; (insert (mapconcat 'bibtex-make-OPT-entry optional ",\n")) | |
1007 | ;; (if bibtex-mode-user-optional-fields ;MON... | |
1008 | ;; (progn | |
1009 | ;; (if optional | |
1010 | ;; (insert ",\n")) | |
1011 | ;; (insert (mapconcat 'bibtex-make-OPT-entry | |
1012 | ;; bibtex-mode-user-optional-fields | |
1013 | ;; ",\n")))) ;MON | |
1014 | ;; (up-list -1) | |
1015 | ;; (forward-char 1)) | |
1016 | ||
d30bfc76 | 1017 | |
9ae11a89 | 1018 | (defun bibtex-make-field (e-t) |
745bc783 | 1019 | (interactive "sBibTeX entry type: ") |
9ae11a89 ER |
1020 | (let ((name (if (consp e-t) (car e-t) e-t)) |
1021 | (value (if (consp e-t) (cdr e-t) ""))) | |
1022 | (insert ",\n") | |
93d35499 | 1023 | (indent-to-column bibtex-name-alignment) |
9ae11a89 ER |
1024 | (insert name " = ") |
1025 | (indent-to-column bibtex-text-alignment) | |
1026 | ;; lucid emacs prin1-to-string breaks the undo chain. When they fix | |
1027 | ;; that, the hack can be removed. [alarson:19930316.0805CST] | |
1028 | ; (insert (prin1-to-string value)) | |
1029 | ;; begin hack | |
1030 | (insert (format (if (stringp value) "\"%s\"" "%s") | |
1031 | value)) | |
1032 | ;; end hack | |
1033 | nil)) | |
1034 | ||
1035 | (defun bibtex-make-optional-field (e-t) | |
745bc783 | 1036 | (interactive "sOptional BibTeX entry type: ") |
9ae11a89 ER |
1037 | (if (consp e-t) |
1038 | (setq e-t (cons (concat "OPT" (car e-t)) (cdr e-t))) | |
1039 | (setq e-t (concat "OPT" e-t))) | |
1040 | (bibtex-make-field e-t)) | |
745bc783 JB |
1041 | |
1042 | ;; What to do about crossref? if present, journal and year are | |
1043 | ;; both optional. Due to this, i move all of them into optional. -- MON | |
1044 | ||
1045 | (defun bibtex-Article () | |
1046 | (interactive) | |
9ae11a89 | 1047 | (bibtex-entry "Article")) |
e5167999 | 1048 | |
745bc783 JB |
1049 | (defun bibtex-Book () |
1050 | (interactive) | |
9ae11a89 | 1051 | (bibtex-entry "Book")) |
745bc783 JB |
1052 | |
1053 | (defun bibtex-Booklet () | |
1054 | (interactive) | |
9ae11a89 | 1055 | (bibtex-entry "Booklet")) |
745bc783 | 1056 | |
9ae11a89 ER |
1057 | ;(defun bibtex-DEAthesis () |
1058 | ; (interactive) | |
1059 | ; (bibtex-entry "DEAthesis")) | |
745bc783 JB |
1060 | |
1061 | (defun bibtex-InBook () | |
1062 | (interactive) | |
9ae11a89 | 1063 | (bibtex-entry "InBook")) |
745bc783 | 1064 | |
745bc783 JB |
1065 | (defun bibtex-InCollection () |
1066 | (interactive) | |
9ae11a89 | 1067 | (bibtex-entry "InCollection")) |
e5167999 | 1068 | |
745bc783 JB |
1069 | (defun bibtex-InProceedings () |
1070 | (interactive) | |
9ae11a89 | 1071 | (bibtex-entry "InProceedings")) |
e5167999 | 1072 | |
745bc783 JB |
1073 | (defun bibtex-Manual () |
1074 | (interactive) | |
9ae11a89 | 1075 | (bibtex-entry "Manual")) |
745bc783 JB |
1076 | |
1077 | (defun bibtex-MastersThesis () | |
1078 | (interactive) | |
9ae11a89 | 1079 | (bibtex-entry "MastersThesis")) |
745bc783 JB |
1080 | |
1081 | (defun bibtex-Misc () | |
1082 | (interactive) | |
9ae11a89 | 1083 | (bibtex-entry "Misc")) |
745bc783 JB |
1084 | |
1085 | (defun bibtex-PhdThesis () | |
1086 | (interactive) | |
9ae11a89 | 1087 | (bibtex-entry "PhdThesis")) |
745bc783 JB |
1088 | |
1089 | (defun bibtex-Proceedings () | |
1090 | (interactive) | |
9ae11a89 | 1091 | (bibtex-entry "Proceedings")) |
745bc783 JB |
1092 | |
1093 | (defun bibtex-TechReport () | |
1094 | (interactive) | |
9ae11a89 | 1095 | (bibtex-entry "TechReport")) |
745bc783 | 1096 | |
745bc783 JB |
1097 | (defun bibtex-Unpublished () |
1098 | (interactive) | |
9ae11a89 | 1099 | (bibtex-entry "Unpublished")) |
745bc783 JB |
1100 | |
1101 | (defun bibtex-string () | |
1102 | (interactive) | |
1103 | (bibtex-move-outside-of-entry) | |
6f680efb | 1104 | (insert "@string{ = \"\"}\n") |
745bc783 JB |
1105 | (previous-line 1) |
1106 | (forward-char 8)) | |
1107 | ||
1108 | (defun bibtex-preamble () | |
1109 | (interactive) | |
1110 | (bibtex-move-outside-of-entry) | |
1111 | (insert "@Preamble{}\n") | |
1112 | (previous-line 1) | |
1113 | (forward-char 10)) | |
1114 | \f | |
1115 | (defun bibtex-next-field (arg) | |
1116 | "Finds end of text of next BibTeX field; with arg, to its beginning" | |
1117 | (interactive "P") | |
1118 | (bibtex-inside-field) | |
1119 | (let ((start (point))) | |
1120 | (condition-case () | |
1121 | (progn | |
1122 | (bibtex-enclosing-field) | |
1123 | (goto-char (match-end 0)) | |
1124 | (forward-char 2)) | |
1125 | (error | |
1126 | (goto-char start) | |
1127 | (end-of-line) | |
1128 | (forward-char 1)))) | |
1129 | (bibtex-find-text arg)) | |
1130 | ||
e5167999 ER |
1131 | ;; (defun bibtex-next-field () |
1132 | ;; "Finds end of text of next field." | |
1133 | ;; (interactive) | |
1134 | ;; (condition-case () | |
1135 | ;; (progn | |
1136 | ;; (bibtex-inside-field) | |
1137 | ;; (re-search-forward ",[ \t\n]*" (point-max) 1) | |
1138 | ;; (bibtex-enclosing-field) | |
1139 | ;; (bibtex-inside-field)) | |
1140 | ;; (error nil))) | |
1141 | ||
745bc783 JB |
1142 | (defun bibtex-find-text (arg) |
1143 | "Go to end of text of current field; with arg, go to beginning." | |
1144 | (interactive "P") | |
1145 | (bibtex-inside-field) | |
1146 | (bibtex-enclosing-field) | |
1147 | (if arg | |
1148 | (progn | |
1149 | (goto-char (match-beginning bibtex-text-in-field)) | |
e5167999 | 1150 | (if (looking-at "\"") |
745bc783 JB |
1151 | (forward-char 1))) |
1152 | (goto-char (match-end bibtex-text-in-field)) | |
e5167999 | 1153 | (if (= (preceding-char) ?\") |
745bc783 JB |
1154 | (forward-char -1)))) |
1155 | ||
e5167999 ER |
1156 | ;; (defun bibtex-find-text () |
1157 | ;; "Go to end of text of current field." | |
1158 | ;; (interactive) | |
1159 | ;; (condition-case () | |
1160 | ;; (progn | |
1161 | ;; (bibtex-inside-field) | |
1162 | ;; (bibtex-enclosing-field) | |
1163 | ;; (goto-char (match-end bibtex-text-in-field)) | |
1164 | ;; (bibtex-inside-field)) | |
1165 | ;; (error nil))) | |
1166 | ||
745bc783 JB |
1167 | (defun bibtex-remove-OPT () |
1168 | "Removes the 'OPT' starting optional arguments and goes to end of text" | |
1169 | (interactive) | |
1170 | (bibtex-inside-field) | |
1171 | (bibtex-enclosing-field) | |
1172 | (save-excursion | |
1173 | (goto-char (match-beginning bibtex-name-in-field)) | |
1174 | (if (looking-at "OPT") | |
9ae11a89 ER |
1175 | ;; sct@dcs.edinburgh.ac.uk |
1176 | (progn | |
1177 | (delete-char (length "OPT")) | |
1178 | (search-forward "=") | |
1179 | (delete-horizontal-space) | |
1180 | (indent-to-column bibtex-text-alignment)))) | |
745bc783 JB |
1181 | (bibtex-inside-field)) |
1182 | ||
1183 | (defun bibtex-inside-field () | |
1184 | "Try to avoid point being at end of a bibtex field." | |
1185 | (interactive) | |
1186 | (end-of-line) | |
e5167999 | 1187 | (skip-chars-backward " \t") ;MON - maybe delete these chars? |
745bc783 | 1188 | (cond ((= (preceding-char) ?,) |
9ae11a89 | 1189 | (forward-char -2))) ; -1 --> -2 sct@dcs.edinburgh.ac.uk |
e5167999 ER |
1190 | (cond ((= (preceding-char) ?\") |
1191 | (forward-char -1)))) ;MON - only go back if quote | |
745bc783 JB |
1192 | |
1193 | (defun bibtex-remove-double-quotes () | |
9ae11a89 | 1194 | "Removes \"\" around string." |
745bc783 JB |
1195 | (interactive) |
1196 | (save-excursion | |
1197 | (bibtex-inside-field) | |
1198 | (bibtex-enclosing-field) | |
1199 | (let ((start (match-beginning bibtex-text-in-field)) | |
1200 | (stop (match-end bibtex-text-in-field))) | |
1201 | (goto-char stop) | |
1202 | (forward-char -1) | |
1203 | (if (looking-at "\"") | |
1204 | (delete-char 1)) | |
1205 | (goto-char start) | |
1206 | (if (looking-at "\"") | |
1207 | (delete-char 1))))) | |
1208 | ||
1209 | (defun bibtex-kill-optional-field () | |
1210 | "Kill the entire enclosing optional BibTeX field" | |
1211 | (interactive) | |
1212 | (bibtex-inside-field) | |
1213 | (bibtex-enclosing-field) | |
1214 | (goto-char (match-beginning bibtex-name-in-field)) | |
1215 | (let ((the-end (match-end 0)) | |
1216 | (the-beginning (match-beginning 0))) | |
1217 | (if (looking-at "OPT") | |
1218 | (progn | |
1219 | (goto-char the-end) | |
1220 | (skip-chars-forward " \t\n,") | |
1221 | (kill-region the-beginning the-end)) | |
1222 | (error "Mandatory fields can't be killed")))) | |
1223 | ||
1224 | (defun bibtex-empty-field () | |
1225 | "Delete the text part of the current field, replace with empty text" | |
1226 | (interactive) | |
1227 | (bibtex-inside-field) | |
1228 | (bibtex-enclosing-field) | |
1229 | (goto-char (match-beginning bibtex-text-in-field)) | |
1230 | (kill-region (point) (match-end bibtex-text-in-field)) | |
1231 | (insert "\"\"") | |
1232 | (bibtex-find-text t)) | |
1233 | ||
1234 | \f | |
1235 | (defun bibtex-pop-previous (arg) | |
1236 | "Replace text of current field with the text of similar field in previous entry. | |
1237 | With arg, go up ARG entries. Repeated, goes up so many times. May be | |
1238 | intermixed with \\[bibtex-pop-next] (bibtex-pop-next)." | |
1239 | (interactive "p") | |
1240 | (bibtex-inside-field) | |
1241 | (save-excursion | |
1242 | ; parse current field | |
1243 | (bibtex-enclosing-field) | |
1244 | (let ((start-old-text (match-beginning bibtex-text-in-field)) | |
1245 | (stop-old-text (match-end bibtex-text-in-field)) | |
1246 | (start-name (match-beginning bibtex-name-in-field)) | |
1247 | (stop-name (match-end bibtex-name-in-field)) | |
1248 | (new-text)) | |
1249 | (goto-char start-name) | |
1250 | ; construct regexp for previous field with same name as this one | |
1251 | (let ((matching-entry | |
1252 | (bibtex-cfield | |
1253 | (buffer-substring (if (looking-at "OPT") | |
1254 | (+ (point) (length "OPT")) | |
1255 | (point)) | |
1256 | stop-name) | |
1257 | bibtex-field-text))) | |
1258 | ||
1259 | ; if executed several times in a row, start each search where the | |
1260 | ; last one finished | |
1261 | (cond ((or (eq last-command 'bibtex-pop-previous) | |
1262 | (eq last-command 'bibtex-pop-next)) | |
1263 | t | |
1264 | ) | |
1265 | (t | |
1266 | (bibtex-enclosing-reference) | |
1267 | (setq bibtex-pop-previous-search-point (match-beginning 0)) | |
1268 | (setq bibtex-pop-next-search-point (match-end 0)))) | |
1269 | (goto-char bibtex-pop-previous-search-point) | |
1270 | ||
1271 | ; Now search for arg'th previous similar field | |
1272 | (cond | |
1273 | ((re-search-backward matching-entry (point-min) t arg) | |
1274 | (setq new-text | |
1275 | (buffer-substring (match-beginning bibtex-text-in-cfield) | |
1276 | (match-end bibtex-text-in-cfield))) | |
1277 | ; Found a matching field. Remember boundaries. | |
1278 | (setq bibtex-pop-next-search-point (match-end 0)) | |
1279 | (setq bibtex-pop-previous-search-point (match-beginning 0)) | |
1280 | (bibtex-flash-head) | |
1281 | ; Go back to where we started, delete old text, and pop new. | |
1282 | (goto-char stop-old-text) | |
1283 | (delete-region start-old-text stop-old-text) | |
1284 | (insert new-text)) | |
1285 | (t ; search failed | |
1286 | (error "No previous matching BibTeX field.")))))) | |
1287 | (setq this-command 'bibtex-pop-previous)) | |
1288 | ||
1289 | (defun bibtex-pop-next (arg) | |
1290 | "Replace text of current field with the text of similar field in next entry. | |
1291 | With arg, go up ARG entries. Repeated, goes up so many times. May be | |
1292 | intermixed with \\[bibtex-pop-previous] (bibtex-pop-previous)." | |
1293 | (interactive "p") | |
1294 | (bibtex-inside-field) | |
1295 | (save-excursion | |
1296 | ; parse current field | |
1297 | (bibtex-enclosing-field) | |
1298 | (let ((start-old-text (match-beginning bibtex-text-in-field)) | |
1299 | (stop-old-text (match-end bibtex-text-in-field)) | |
1300 | (start-name (match-beginning bibtex-name-in-field)) | |
1301 | (stop-name (match-end bibtex-name-in-field)) | |
1302 | (new-text)) | |
1303 | (goto-char start-name) | |
1304 | ; construct regexp for next field with same name as this one, | |
1305 | ; ignoring possible OPT's | |
1306 | (let ((matching-entry | |
1307 | (bibtex-cfield | |
1308 | (buffer-substring (if (looking-at "OPT") | |
1309 | (+ (point) (length "OPT")) | |
1310 | (point)) | |
1311 | stop-name) | |
1312 | bibtex-field-text))) | |
1313 | ||
1314 | ; if executed several times in a row, start each search where the | |
1315 | ; last one finished | |
1316 | (cond ((or (eq last-command 'bibtex-pop-next) | |
1317 | (eq last-command 'bibtex-pop-previous)) | |
1318 | t | |
1319 | ) | |
1320 | (t | |
1321 | (bibtex-enclosing-reference) | |
1322 | (setq bibtex-pop-previous-search-point (match-beginning 0)) | |
1323 | (setq bibtex-pop-next-search-point (match-end 0)))) | |
1324 | (goto-char bibtex-pop-next-search-point) | |
1325 | ||
1326 | ; Now search for arg'th next similar field | |
1327 | (cond | |
1328 | ((re-search-forward matching-entry (point-max) t arg) | |
1329 | (setq new-text | |
1330 | (buffer-substring (match-beginning bibtex-text-in-cfield) | |
1331 | (match-end bibtex-text-in-cfield))) | |
1332 | ; Found a matching field. Remember boundaries. | |
1333 | (setq bibtex-pop-next-search-point (match-end 0)) | |
1334 | (setq bibtex-pop-previous-search-point (match-beginning 0)) | |
1335 | (bibtex-flash-head) | |
1336 | ; Go back to where we started, delete old text, and pop new. | |
1337 | (goto-char stop-old-text) | |
1338 | (delete-region start-old-text stop-old-text) | |
1339 | (insert new-text)) | |
1340 | (t ; search failed | |
1341 | (error "No next matching BibTeX field.")))))) | |
1342 | (setq this-command 'bibtex-pop-next)) | |
1343 | ||
1344 | (defun bibtex-flash-head () | |
1345 | "Flash at BibTeX reference head before point, if exists. (Moves point)." | |
1346 | (let ((flash)) | |
1347 | (cond ((re-search-backward bibtex-reference-head (point-min) t) | |
1348 | (goto-char (match-beginning bibtex-type-in-head)) | |
1349 | (setq flash (match-end bibtex-key-in-reference))) | |
1350 | (t | |
1351 | (end-of-line) | |
1352 | (skip-chars-backward " \t") | |
1353 | (setq flash (point)) | |
1354 | (beginning-of-line) | |
1355 | (skip-chars-forward " \t"))) | |
1356 | (if (pos-visible-in-window-p (point)) | |
1357 | (sit-for 1) | |
1358 | (message "From: %s" | |
1359 | (buffer-substring (point) flash))))) | |
1360 | ||
1361 | ||
1362 | \f | |
1363 | (defun bibtex-enclosing-field () | |
1364 | "Search for BibTeX field enclosing point. | |
1365 | Point moves to end of field; also, use match-beginning and match-end | |
1366 | to parse the field." | |
9ae11a89 ER |
1367 | ;; sct@dcs.edinburgh.ac.uk |
1368 | (let ((old-point (point))) | |
1369 | (condition-case errname | |
1370 | (bibtex-enclosing-regexp bibtex-field) | |
1371 | (search-failed | |
1372 | (goto-char old-point) | |
1373 | (error "Can't find enclosing BibTeX field."))))) | |
745bc783 JB |
1374 | |
1375 | (defun bibtex-enclosing-reference () | |
1376 | "Search for BibTeX reference enclosing point. | |
1377 | Point moves to end of reference; also, use match-beginning and match-end | |
1378 | to parse the reference." | |
9ae11a89 ER |
1379 | ;; sct@dcs.edinburgh.ac.uk |
1380 | (let ((old-point (point))) | |
1381 | (condition-case errname | |
1382 | (bibtex-enclosing-regexp bibtex-reference) | |
1383 | (search-failed | |
1384 | (goto-char old-point) | |
1385 | (error "Can't find enclosing BibTeX reference."))))) | |
745bc783 JB |
1386 | |
1387 | (defun bibtex-enclosing-regexp (regexp) | |
1388 | "Search for REGEXP enclosing point. | |
1389 | Point moves to end of REGEXP. See also match-beginning and match-end. | |
1390 | If an enclosing REGEXP is not found, signals search-failed; point is left in | |
1391 | an undefined location. | |
1392 | ||
1393 | [Doesn't something like this exist already?]" | |
1394 | ||
1395 | (interactive "sRegexp: ") | |
1396 | ; compute reasonable limits for the loop | |
1397 | (let* ((initial (point)) | |
1398 | (right (if (re-search-forward regexp (point-max) t) | |
1399 | (match-end 0) | |
1400 | (point-max))) | |
1401 | (left | |
1402 | (progn | |
1403 | (goto-char initial) | |
1404 | (if (re-search-backward regexp (point-min) t) | |
1405 | (match-beginning 0) | |
1406 | (point-min))))) | |
1407 | ; within the prescribed limits, loop until a match is found | |
1408 | (goto-char left) | |
1409 | (re-search-forward regexp right nil 1) | |
1410 | (if (> (match-beginning 0) initial) | |
1411 | (signal 'search-failed (list regexp))) | |
e5167999 | 1412 | (while (<= (match-end 0) initial) |
745bc783 JB |
1413 | (re-search-forward regexp right nil 1) |
1414 | (if (> (match-beginning 0) initial) | |
1415 | (signal 'search-failed (list regexp)))) | |
1416 | )) | |
1417 | ||
1418 | (defun bibtex-clean-entry () | |
1419 | "For all optional fields of current BibTeX entry: if empty, kill the whole field; otherwise, remove the \"OPT\" string in the name; if text numerical, remove double-quotes. For all mandatory fields: if empty, signal error." | |
1420 | (interactive) | |
9ae11a89 | 1421 | (beginning-of-bibtex-entry) |
745bc783 JB |
1422 | (let ((start (point))) |
1423 | (save-restriction | |
9ae11a89 | 1424 | (narrow-to-region start (save-excursion (end-of-bibtex-entry) (point))) |
745bc783 JB |
1425 | (while (re-search-forward bibtex-field (point-max) t 1) |
1426 | (let ((begin-field (match-beginning 0)) | |
1427 | (end-field (match-end 0)) | |
1428 | (begin-name (match-beginning bibtex-name-in-field)) | |
1429 | (end-name (match-end bibtex-name-in-field)) | |
1430 | (begin-text (match-beginning bibtex-text-in-field)) | |
1431 | (end-text (match-end bibtex-text-in-field)) | |
1432 | ) | |
1433 | (goto-char begin-name) | |
1434 | (cond ((and | |
1435 | (looking-at "OPT") | |
1436 | bibtex-clean-entry-zap-empty-opts) | |
1437 | (goto-char begin-text) | |
e5167999 | 1438 | (if (looking-at "\"\"") ; empty: delete whole field |
745bc783 | 1439 | (delete-region begin-field end-field) |
e5167999 | 1440 | ; otherwise: not empty, delete "OPT" |
745bc783 JB |
1441 | (goto-char begin-name) |
1442 | (delete-char (length "OPT")) | |
9ae11a89 ER |
1443 | (progn |
1444 | ;; fixup alignment. [alarson:19920309.2047CST] | |
1445 | (search-forward "=") | |
1446 | (delete-horizontal-space) | |
1447 | (indent-to-column bibtex-text-alignment)) | |
745bc783 JB |
1448 | (goto-char begin-field) ; and loop to go through next test |
1449 | )) | |
1450 | (t | |
1451 | (goto-char begin-text) | |
1452 | (cond ((looking-at "\"[0-9]+\"") ; if numerical, | |
1453 | (goto-char end-text) | |
1454 | (delete-char -1) ; delete enclosing double-quotes | |
1455 | (goto-char begin-text) | |
1456 | (delete-char 1) | |
1457 | (goto-char end-field) ; go to end for next search | |
1458 | (forward-char -2) ; to compensate for the 2 quotes deleted | |
1459 | ) | |
1460 | ((looking-at "\"\"") ; if empty quotes, complain | |
1461 | (forward-char 1) | |
1462 | (if (not (or (equal (buffer-substring | |
1463 | begin-name | |
1464 | (+ begin-name 3)) | |
1465 | "OPT") | |
1466 | (equal (buffer-substring | |
1467 | begin-name | |
1468 | (+ begin-name 3)) | |
e5167999 | 1469 | "opt"))) |
745bc783 JB |
1470 | (error "Mandatory field ``%s'' is empty" |
1471 | (buffer-substring begin-name end-name)))) | |
1472 | (t | |
1473 | (goto-char end-field)))))))) | |
1474 | (goto-char start) | |
9ae11a89 ER |
1475 | (end-of-bibtex-entry) |
1476 | ;; sct@dcs.edinburgh.ac.uk | |
1477 | (save-excursion | |
1478 | (previous-line 1) | |
1479 | (end-of-line) | |
1480 | (if (eq (preceding-char) ?,) | |
1481 | (backward-delete-char 1))) | |
1482 | (skip-whitespace-and-comments))) | |
745bc783 JB |
1483 | |
1484 | \f | |
2798dfd6 RS |
1485 | ;;; Menus for bibtex mode |
1486 | ||
1487 | (define-key bibtex-mode-map [menu-bar entry-types] | |
93d35499 | 1488 | (cons "Entry Types" (make-sparse-keymap "Entry Types"))) |
2798dfd6 RS |
1489 | |
1490 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-InProceedings] | |
1491 | '(" article in conference Proceedings " . bibtex-InProceedings)) | |
1492 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-Article] | |
1493 | '(" Article in journal " . bibtex-Article)) | |
1494 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-Book] | |
1495 | '(" Book " . bibtex-Book)) | |
1496 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-Booklet] | |
1497 | '(" Booklet " . bibtex-Booklet)) | |
1498 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-InProceedings] | |
1499 | '(" Conference " . bibtex-InProceedings)) | |
1500 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-MastersThesis] | |
1501 | '(" Master's Thesis " . bibtex-MastersThesis)) | |
1502 | ;define-key bibtex-mode-map [menu-bar entry-types bibtex-DEAthesis] | |
93d35499 | 1503 | ;'((" DEA Thesis " . bibtex-DEAthesis)) |
2798dfd6 RS |
1504 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-PhdThesis] |
1505 | '(" Phd. Thesis " . bibtex-PhdThesis)) | |
1506 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-TechReport] | |
1507 | '(" Technical Report " . bibtex-TechReport)) | |
1508 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-Manual] | |
1509 | '(" technical Manual " . bibtex-Manual)) | |
1510 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-Proceedings] | |
1511 | '(" conference Proceedings " . bibtex-Proceedings)) | |
1512 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-InBook] | |
1513 | '(" a chapter in a Book " . bibtex-InBook)) | |
1514 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-InCollection] | |
1515 | '(" an article in a Collection " . bibtex-InCollection)) | |
1516 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-Misc] | |
1517 | '(" miscellaneous " . bibtex-Misc)) | |
1518 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-Unpublished] | |
1519 | '(" unpublished " . bibtex-Unpublished)) | |
1520 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-string] | |
1521 | '(" string " . bibtex-string)) | |
1522 | (define-key bibtex-mode-map [menu-bar entry-types bibtex-preamble] | |
1523 | '(" preamble " . bibtex-preamble)) | |
1524 | ||
1525 | (define-key bibtex-mode-map [menu-bar move/edit] | |
93d35499 | 1526 | (cons "Bibtex Edit" (make-sparse-keymap "Bibtex Edit"))) |
2798dfd6 RS |
1527 | |
1528 | (define-key bibtex-mode-map [menu-bar move/edit bibtex-next-field] | |
1529 | '(" next field " . bibtex-next-field)) | |
1530 | (define-key bibtex-mode-map [menu-bar move/edit bibtex-find-text] | |
1531 | '(" to end of field " . bibtex-find-text)) | |
1532 | (define-key bibtex-mode-map [menu-bar move/edit bibtex-pop-previous] | |
1533 | '("snatch from similar preceding field" . bibtex-pop-previous)) | |
1534 | (define-key bibtex-mode-map [menu-bar move/edit bibtex-pop-next] | |
1535 | '("snatch from similar following field" . bibtex-pop-next)) | |
1536 | (define-key bibtex-mode-map [menu-bar move/edit bibtex-remove-OPT] | |
93d35499 | 1537 | '(" remove OPT " . bibtex-remove-OPT)) |
2798dfd6 RS |
1538 | (define-key bibtex-mode-map [menu-bar move/edit bibtex-remove-double-quotes] |
1539 | '(" remove quotes " . bibtex-remove-double-quotes)) | |
1540 | (define-key bibtex-mode-map [menu-bar move/edit bibtex-clean-entry] | |
1541 | '(" clean up entry " . bibtex-clean-entry)) | |
93d35499 RS |
1542 | (define-key bibtex-mode-map [menu-bar move/edit find-bibtex-duplicates] |
1543 | '(" find duplicates " . find-bibtex-duplicates)) | |
1544 | (define-key bibtex-mode-map [menu-bar move/edit sort-bibtex-entries] | |
1545 | '(" sort entries " . sort-bibtex-entries)) | |
1546 | (define-key bibtex-mode-map [menu-bar move/edit validate-bibtex-buffer] | |
1547 | '(" validate entries " . validate-bibtex-buffer)) | |
745bc783 JB |
1548 | \f |
1549 | ||
1550 | ;; Please don't send anything to bug-gnu-emacs about these Sunwindows functions | |
1551 | ;; since we aren't interested. See etc/SUN-SUPPORT for the reasons why | |
1552 | ;; we consider this nothing but a distraction from our work. | |
1553 | ||
9ae11a89 ER |
1554 | ;(defmacro eval-in-menu-window (&rest l) |
1555 | ; "Evaluates its argument in the window in which the mouse button was pressed." | |
1556 | ; (list 'eval-in-window '*menu-window* l)) | |
e5167999 ER |
1557 | |
1558 | ;(defmenu bibtex-sun-entry-menu | |
1559 | ; ("Article In Conf. Proc." eval-in-menu-window bibtex-InProceedings) | |
1560 | ; ("Article In Journal" eval-in-menu-window bibtex-Article) | |
1561 | ; ("Book" eval-in-menu-window bibtex-Book) | |
1562 | ; ("Booklet" eval-in-menu-window bibtex-Booklet) | |
1563 | ; ("Master's Thesis" eval-in-menu-window bibtex-MastersThesis) | |
1564 | ; ("PhD. Thesis" eval-in-menu-window bibtex-PhdThesis) | |
1565 | ; ("Technical Report" eval-in-menu-window bibtex-TechReport) | |
1566 | ; ("Technical Manual" eval-in-menu-window bibtex-Manual) | |
1567 | ; ("Conference Proceedings" eval-in-menu-window bibtex-Proceedings) | |
1568 | ; ("In A Book" eval-in-menu-window bibtex-InBook) | |
1569 | ; ("In A Collection" eval-in-menu-window bibtex-InCollection) | |
1570 | ; ("Miscellaneous" eval-in-menu-window bibtex-Misc) | |
1571 | ; ("Unpublished" eval-in-menu-window bibtex-Unpublished) | |
1572 | ; ("string" eval-in-menu-window bibtex-string) | |
1573 | ; ("preamble" eval-in-menu-window bibtex-preamble)) | |
1574 | ; | |
1575 | ;(defmenu bibtex-sun-menu | |
1576 | ; ("BibTeX menu") | |
1577 | ; ("add entry" . bibtex-sun-entry-menu) | |
1578 | ; ("next field" eval-in-menu-window bibtex-next-field nil) | |
1579 | ; ("to end of field" eval-in-menu-window bibtex-find-text nil) | |
1580 | ; ("snatch similar preceding field" eval-in-menu-window bibtex-pop-previous 1) | |
1581 | ; ("snatch similar following field" eval-in-menu-window bibtex-pop-next 1) | |
1582 | ; ("remove OPT" eval-in-menu-window bibtex-remove-OPT) | |
1583 | ; ("remove quotes" eval-in-menu-window bibtex-remove-double-quotes) | |
1584 | ; ("clean entry" eval-in-menu-window bibtex-clean-entry) | |
1585 | ; ("describe BibTeX mode" eval-in-menu-window describe-mode) | |
1586 | ; ("Main Emacs menu" . emacs-menu)) | |
745bc783 | 1587 | |
9ae11a89 ER |
1588 | ;(defun bibtex-sun-menu-eval (window x y) |
1589 | ; "Pop-up menu of BibTeX commands." | |
1590 | ; (sun-menu-evaluate window (1+ x) (1- y) 'bibtex-sun-menu)) | |
1591 | ; | |
1592 | ;(defun bibtex-sun-environment () | |
1593 | ; "Set up sun menus for BibTeX mode. Call it as bibtex-mode-hook, or | |
1594 | ;interactively" | |
1595 | ; (interactive) | |
1596 | ; (local-set-mouse '(text right) 'bibtex-sun-menu-eval)) | |
1597 | ; | |
745bc783 | 1598 | |
9ae11a89 | 1599 | ;;; bibtex.el ends here |