0
|
1 ;;; bibtex.el --- BibTeX mode for GNU Emacs
|
|
2
|
|
3 ;; Copyright (C) 1992 Free Software Foundation, Inc.
|
|
4
|
|
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>
|
|
9 ;; Version: 1.3.1
|
|
10 ;; Maintainer:Aaron Larson <alarson@src.honeywell.com>
|
|
11 ;; Adapted-By: ESR
|
|
12 ;; Keywords: tex, bib
|
|
13
|
|
14 ;; This file is part of XEmacs.
|
|
15
|
|
16 ;; XEmacs is free software; you can redistribute it and/or modify it
|
|
17 ;; under the terms of the GNU General Public License as published by
|
|
18 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
19 ;; any later version.
|
|
20
|
|
21 ;; XEmacs is distributed in the hope that it will be useful, but
|
|
22 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
24 ;; General Public License for more details.
|
|
25
|
|
26 ;; You should have received a copy of the GNU General Public License
|
|
27 ;; along with XEmacs; see the file COPYING. If not, write to the Free
|
|
28 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
29
|
|
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
|
|
38 ;;; Commentary:
|
|
39
|
|
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)
|
|
52
|
|
53 ;;; Change Log:
|
|
54
|
|
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 ;;;
|
|
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:
|
|
141 ;;; " tex-insert-quote
|
|
142 ;;; C-c$ ispell-bibtex-entry
|
|
143 ;;; M-C-a beginning-of-bibtex-entry
|
|
144 ;;; M-C-e end-of-bibtex-entry
|
|
145 ;;; Mike Newton (newton@gumby.cs.caltech.edu) 90.11.17
|
|
146 ;;; * Handle items like
|
|
147 ;;; title = poft # "Fifth Tri-quarterly" # random-conf,
|
|
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
|
|
151 ;;; * bibtex-field-text made more general (it wouldn't handle the # construct)
|
|
152 ;;; and it now handles a small subset of the {} cases
|
|
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.
|
|
157 ;;; Updated documentation strings accordingly. Added (provide 'bibtex).
|
|
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.
|
|
167
|
|
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
|
|
174 ;;; * skip-whitespace replaced by skip-chars-forward
|
|
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
|
|
188 ;;; * Fixed bug in bibtex-flash-entry
|
|
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
|
|
221 ;;; Bengt Martensson <bengt@mathematik.uni-Bremen.de> 87-06-28
|
|
222 ;;; Original version
|
|
223
|
|
224 ;;; Code:
|
|
225
|
|
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
|
|
231 (provide 'bibtex)
|
|
232
|
|
233 ;;; these guys typically don't have autoloads...[alarson:19920131.1548CST]
|
|
234 ;;; Check for fboundp first so that if user autoloads them from non standard
|
|
235 ;;; places, the users bindings will take precedence.
|
|
236 (if (not (fboundp 'tex-insert-quote))
|
|
237 (autoload 'tex-insert-quote "tex-mode"))
|
|
238 (if (not (fboundp 'sort-subr))
|
|
239 (autoload 'sort-subr "sort"))
|
|
240
|
|
241 ;;; These should be in a more generally accessible location.
|
|
242
|
|
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))
|
|
258
|
|
259
|
|
260
|
|
261
|
|
262 (defvar bibtex-clean-entry-zap-empty-opts t
|
|
263 "*If non-nil, bibtex-clean-entry will delete all empty optional fields.")
|
|
264
|
|
265 (defvar bibtex-include-OPTcrossref t
|
|
266 "*If non-nil, all entries will have an OPTcrossref field.")
|
|
267 (defvar bibtex-include-OPTkey t
|
|
268 "*If non-nil, all entries will have an OPTkey field.")
|
|
269 (defvar bibtex-include-OPTannote t
|
|
270 "*If non-nil, all entries will have an OPTannote field.")
|
|
271
|
|
272 ;; note: the user should be allowed to have their own list of always
|
|
273 ;; available optional fields. exs: "keywords" "categories"
|
|
274
|
|
275 (defvar bibtex-mode-user-optional-fields nil ;no default value
|
|
276 "*List of optional fields that user want to have as always present
|
|
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]
|
|
311 (define-key km "\"" 'tex-insert-quote)
|
|
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-c\C-b" '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
|
|
336 (define-key km 'button3 'bibtex-menu)
|
|
337 km))
|
|
338
|
|
339 (defvar bibtex-pop-previous-search-point nil
|
|
340 "Next point where bibtex-pop-previous should start looking for a similar
|
|
341 entry.")
|
|
342
|
|
343 (defvar bibtex-pop-next-search-point nil
|
|
344 "Next point where bibtex-pop-next should start looking for a similar
|
|
345 entry.")
|
|
346
|
|
347 (defvar bibtex-entry-field-alist
|
|
348 '(
|
|
349 ("Article" . ((("author" "title" "journal" "year")
|
|
350 ("volume" "number" "pages" "month" "note"))
|
|
351 (("author" "title")
|
|
352 ("journal" "year" "volume" "number" "pages"
|
|
353 "month" "note"))))
|
|
354 ("Book" . ((("author" "title" "publisher" "year")
|
|
355 ("editor" "volume" "number" "series" "address"
|
|
356 "edition" "month" "note"))))
|
|
357 ("Booklet" . ((("title")
|
|
358 ("author" "howpublished" "address" "month" "year" "note"))))
|
|
359
|
|
360 ;; France: Dipl\^{o}me d'Etudes Approfondies (similar to Master's)
|
|
361 ; ("DEAthesis" . ((("author" "title" "school" "year")
|
|
362 ; ("address" "month" "note"))))
|
|
363
|
|
364 ("InBook" . ((("author" "title" "chapter" "publisher" "year")
|
|
365 ("editor" "pages" "volume" "number" "series" "address"
|
|
366 "edition" "month" "type" "note"))
|
|
367 (("author" "title" "chapter")
|
|
368 ("publisher" "year" "editor" "pages" "volume" "number"
|
|
369 "series" "address" "edition" "month" "type" "note"))))
|
|
370
|
|
371
|
|
372 ("InCollection" . ((("author" "title"
|
|
373 "booktitle" "publisher" "year")
|
|
374 ("editor" "volume" "number" "series" "type" "chapter"
|
|
375 "pages" "address" "edition" "month" "note"))
|
|
376 (("author" "title")
|
|
377 ("booktitle" "publisher" "year"
|
|
378 "editor" "volume" "number" "series" "type" "chapter"
|
|
379 "pages" "address" "edition" "month" "note"))))
|
|
380
|
|
381
|
|
382 ("InProceedings" . ((("author" "title" "booktitle" "year")
|
|
383 ("editor" "volume" "number" "series" "pages"
|
|
384 "organization" "publisher" "address" "month" "note"))
|
|
385 (("author" "title")
|
|
386 ("editor" "volume" "number" "series" "pages"
|
|
387 "booktitle" "year"
|
|
388 "organization" "publisher" "address" "month" "note"))))
|
|
389
|
|
390
|
|
391 ("Manual" . ((("title")
|
|
392 ("author" "organization" "address" "edition" "year"
|
|
393 "month" "note"))))
|
|
394
|
|
395 ("MastersThesis" . ((("author" "title" "school" "year")
|
|
396 ("address" "month" "note" "type"))))
|
|
397
|
|
398 ("Misc" . ((()
|
|
399 ("author" "title" "howpublished" "year" "month" "note"))))
|
|
400
|
|
401 ("PhdThesis" . ((("author" "title" "school" "year")
|
|
402 ("address" "month" "type" "note"))))
|
|
403
|
|
404 ("Proceedings" . ((("title" "year")
|
|
405 ("editor" "volume" "number" "series" "publisher"
|
|
406 "organization" "address" "month" "note"))))
|
|
407
|
|
408 ("TechReport" . ((("author" "title" "institution" "year")
|
|
409 ("type" "number" "address" "month" "note"))))
|
|
410
|
|
411 ("Unpublished" . ((("author" "title" "note")
|
|
412 ("year" "month"))))
|
|
413 )
|
|
414
|
|
415 "List of (entry-name (required optional) (crossref-required crossref-optional))
|
|
416 tripples. If the third element is nil, then the first pair can be used. Required
|
|
417 and optional are lists of strings. All entry creation functions use this variable
|
|
418 to generate entries, and bibtex-entry ensures the entry type is valid. This
|
|
419 variable can be used for example to make bibtex manipulate a different set of entry
|
|
420 types, e.g. a crossreference document of organization types.")
|
|
421
|
|
422
|
|
423 ;;; A bibtex file is a sequence of entries, either string definitions
|
|
424 ;;; or reference entries. A reference entry has a type part, a
|
|
425 ;;; key part, and a comma-separated sequence of fields. A string
|
|
426 ;;; entry has a single field. A field has a left and right part,
|
|
427 ;;; separated by a '='. The left part is the name, the right part is
|
|
428 ;;; the text. Here come the definitions allowing to create and/or parse
|
|
429 ;;; entries and fields:
|
|
430
|
|
431 ;;; fields
|
|
432 (defun bibtex-cfield (name text)
|
|
433 "Create a regexp for a bibtex field of name NAME and text TEXT"
|
|
434 (concat ",[ \t\n]*\\("
|
|
435 name
|
|
436 "\\)[ \t\n]*=[ \t\n]*\\("
|
|
437 text
|
|
438 "\\)"))
|
|
439 (defconst bibtex-name-in-cfield 1
|
|
440 "The regexp subexpression number of the name part in bibtex-cfield.")
|
|
441 (defconst bibtex-text-in-cfield 2
|
|
442 "The regexp subexpression number of the text part in bibtex-cfield.")
|
|
443
|
|
444 ;;; KAWATA Yasuro <yasuro@qqqq.maekawa.is.uec.ac.jp> reported bug that "/"
|
|
445 ;;; was not premitted in field names. The old value of this var was:
|
|
446 ;;; "[A-Za-z][---A-Za-z0-9:_+]*"
|
|
447 ;;; According to the LaTeX manual, page 71, the legal values are letters,
|
|
448 ;;; digits, and punctuation other than comma. Section 2.1 defines
|
|
449 ;;; punctuation as:
|
|
450 ;;; .:;,?!`'()[]-/*@
|
|
451 ;;; and says that += can be used in normal text. Specifically #$%&~_^\{}
|
|
452 ;;; are called out as special chars. Some experimentation with LaTeX
|
|
453 ;;; indicates that # and ~ definitely don't work, but that the following
|
|
454 ;;; citation does! \cite{a0.:;?!`'()[]-/*@_&$^+=|<>}. I chose here to
|
|
455 ;;; permit _ since it was previously allowed, but otherwise to only handle
|
|
456 ;;; punc and +=
|
|
457 ;;; Amendment: I couldn't get a regexp with both "[]"'s and hyphen to
|
|
458 ;;; work. It looks like you need them both to be the first entries in a
|
|
459 ;;; regexp pattern. [alarson:19930315.0900CST]
|
|
460
|
|
461 (defconst bibtex-field-name "[A-Za-z][---A-Za-z0-9.:;?!`'()/*@_+=]*"
|
|
462 "Regexp defining the name part of a bibtex field.")
|
|
463
|
|
464 ;; bibtex-field-text must be able to handle
|
|
465 ;; title = "Proc. Fifteenth Annual" # STOC,
|
|
466 ;; month = "10~" # jan,
|
|
467 ;; year = "{\noopsort{1973c}}1981",
|
|
468 ;; month = apr # "-" # may,
|
|
469 ;; key = {Volume-2},
|
|
470 ;; note = "Volume~2 is listed under Knuth \cite{book-full}"
|
|
471 ;; i have added a few of these, but not all! -- MON
|
|
472
|
|
473 (defconst bibtex-field-const
|
|
474 "[0-9A-Za-z][---A-Za-z0-9:_+]*"
|
|
475 "Format of a bibtex field constant.")
|
|
476
|
|
477 (defconst bibtex-field-string
|
|
478 (concat
|
|
479 "\"[^\"]*[^\\\\]\"\\|\"\"")
|
|
480 "Match either a string or an empty string.")
|
|
481
|
|
482 (defconst bibtex-field-string-or-const
|
|
483 (concat bibtex-field-const "\\|" bibtex-field-string)
|
|
484 "Match either bibtex-field-string or bibtex-field-const.")
|
|
485
|
|
486 (defconst bibtex-field-text
|
|
487 (concat
|
|
488 "\\(" bibtex-field-string-or-const "\\)"
|
|
489 "\\([ \t\n]+#[ \t\n]+\\(" bibtex-field-string-or-const "\\)\\)*\\|"
|
|
490 "{[^{}]*[^\\\\]}")
|
|
491 "Regexp defining the text part of a bibtex field: either a string, or
|
|
492 an empty string, or a constant followed by one or more # / constant pairs.
|
|
493 Also matches simple {...} patterns.")
|
|
494
|
|
495 ;(defconst bibtex-field-text
|
|
496 ; "\"[^\"]*[^\\\\]\"\\|\"\"\\|[0-9A-Za-z][---A-Za-z0-9:_+]*"
|
|
497 ; "Regexp defining the text part of a bibtex field: either a string, or an empty string, or a constant.")
|
|
498
|
|
499 (defconst bibtex-field
|
|
500 (bibtex-cfield bibtex-field-name bibtex-field-text)
|
|
501 "Regexp defining the format of a bibtex field")
|
|
502
|
|
503 (defconst bibtex-name-in-field bibtex-name-in-cfield
|
|
504 "The regexp subexpression number of the name part in bibtex-field")
|
|
505 (defconst bibtex-text-in-field bibtex-text-in-cfield
|
|
506 "The regexp subexpression number of the text part in bibtex-field")
|
|
507
|
|
508 ;;; references
|
|
509 (defconst bibtex-reference-type
|
|
510 "@[A-Za-z]+"
|
|
511 "Regexp defining the type part of a bibtex reference entry")
|
|
512 (defconst bibtex-reference-head
|
|
513 (concat "^[ \t]*\\("
|
|
514 bibtex-reference-type
|
|
515 "\\)[ \t]*[({]\\("
|
|
516 bibtex-field-name
|
|
517 "\\)")
|
|
518 "Regexp defining format of the header line of a bibtex reference entry")
|
|
519 (defconst bibtex-type-in-head 1
|
|
520 "The regexp subexpression number of the type part in bibtex-reference-head")
|
|
521 (defconst bibtex-key-in-head 2
|
|
522 "The regexp subexpression number of the key part in
|
|
523 bibtex-reference-head")
|
|
524
|
|
525 (defconst bibtex-reference
|
|
526 (concat bibtex-reference-head
|
|
527 "\\([ \t\n]*" bibtex-field "\\)*"
|
|
528 "[ \t\n]*[})]")
|
|
529 "Regexp defining the format of a bibtex reference entry")
|
|
530 (defconst bibtex-type-in-reference bibtex-type-in-head
|
|
531 "The regexp subexpression number of the type part in bibtex-reference")
|
|
532 (defconst bibtex-key-in-reference bibtex-key-in-head
|
|
533 "The regexp subexpression number of the key part in
|
|
534 bibtex-reference")
|
|
535
|
|
536 ;;; strings
|
|
537 (defconst bibtex-string
|
|
538 (concat "^[ \t]*@[sS][tT][rR][iI][nN][gG][ \t\n]*[({][ \t\n]*\\("
|
|
539 bibtex-field-name
|
|
540 "\\)[ \t\n]*=[ \t\n]*\\("
|
|
541 bibtex-field-text
|
|
542 "\\)[ \t\n]*[})]")
|
|
543 "Regexp defining the format of a bibtex string entry")
|
|
544 (defconst bibtex-name-in-string 1
|
|
545 "The regexp subexpression of the name part in bibtex-string")
|
|
546 (defconst bibtex-text-in-string 2
|
|
547 "The regexp subexpression of the text part in bibtex-string")
|
|
548
|
|
549 (defconst bibtex-name-alignment 2
|
|
550 "Alignment for the name part in BibTeX fields.
|
|
551 Chosen on aesthetic grounds only.")
|
|
552
|
|
553 (defconst bibtex-text-alignment (length " organization = ")
|
|
554 "Alignment for the text part in BibTeX fields.
|
|
555 Equal to the space needed for the longest name part.")
|
|
556
|
|
557 (defun bibtex-current-entry-label (&optional include-cite kill)
|
|
558 "Return the label of the bibtex entry containing, or preceding point.
|
|
559 Optional argument INCLUDE-CITE, if true means put a '\\cite{}' around the
|
|
560 returned value. Second optional argument KILL, if true, means place the
|
|
561 returned value in the kill buffer. Interactively; providing prefix
|
|
562 argument makes INCLUDE-CITE true, and kill is true by default.
|
|
563
|
|
564 Rationale:
|
|
565 The intention is that someone will write a function that can be bound to
|
|
566 a mouse key so that people entering TeX can just mouse on the bibtex entry
|
|
567 and have the citation key inserted at the current point (which will almost
|
|
568 certainly be in some other buffer). In the interim this function is
|
|
569 marginally useful for keyboard binding and is not bound by default.
|
|
570 Suggested binding is ^C-k."
|
|
571 (interactive (list current-prefix-arg t))
|
|
572 (save-excursion
|
|
573 (beginning-of-bibtex-entry)
|
|
574 (re-search-forward bibtex-reference-head (save-excursion (end-of-bibtex-entry) (point)))
|
|
575 (let* ((key (buffer-substring (match-beginning bibtex-key-in-head)
|
|
576 (match-end bibtex-key-in-head)))
|
|
577 (val (if include-cite
|
|
578 (format "\\cite{%s}" key)
|
|
579 key)))
|
|
580 (if kill
|
|
581 (put-string-on-kill-ring val))
|
|
582 val)))
|
|
583
|
|
584 ;;; bibtex mode:
|
|
585
|
|
586 ;;;###autoload
|
|
587 (defun bibtex-mode ()
|
|
588 "Major mode for editing bibtex files.
|
|
589
|
|
590 \\{bibtex-mode-map}
|
|
591
|
|
592 A command such as \\[bibtex-Book] will outline the fields for a BibTeX book entry.
|
|
593
|
|
594 The optional fields start with the string OPT, and thus ignored by BibTeX.
|
|
595 The OPT string may be removed from a field with \\[bibtex-remove-OPT].
|
|
596 \\[bibtex-kill-optional-field] kills the current optional field entirely.
|
|
597 \\[bibtex-remove-double-quotes] removes the double-quotes around the text of
|
|
598 the current field. \\[bibtex-empty-field] replaces the text of the current
|
|
599 field with the default \"\".
|
|
600
|
|
601 The command \\[bibtex-clean-entry] cleans the current entry, i.e. (i) removes
|
|
602 double-quotes from entirely numerical fields, (ii) removes OPT from all
|
|
603 non-empty optional fields, (iii) removes all empty optional fields, and (iv)
|
|
604 checks that no non-optional fields are empty.
|
|
605
|
|
606 Use \\[bibtex-find-text] to position the dot at the end of the current field.
|
|
607 Use \\[bibtex-next-field] to move to end of the next field.
|
|
608
|
|
609 The following may be of interest as well:
|
|
610
|
|
611 Functions:
|
|
612 find-bibtex-duplicates
|
|
613 find-bibtex-entry-location
|
|
614 hide-bibtex-entry-bodies
|
|
615 sort-bibtex-entries
|
|
616 validate-bibtex-buffer
|
|
617
|
|
618 Variables:
|
|
619 bibtex-clean-entry-zap-empty-opts
|
|
620 bibtex-entry-field-alist
|
|
621 bibtex-include-OPTannote
|
|
622 bibtex-include-OPTcrossref
|
|
623 bibtex-include-OPTkey
|
|
624 bibtex-maintain-sorted-entries
|
|
625 bibtex-mode-user-optional-fields
|
|
626
|
|
627 Fields:
|
|
628 address
|
|
629 Publisher's address
|
|
630 annote
|
|
631 Long annotation used for annotated bibliographies (begins sentence)
|
|
632 author
|
|
633 Name(s) of author(s), in BibTeX name format
|
|
634 booktitle
|
|
635 Book title when the thing being referenced isn't the whole book.
|
|
636 For book entries, the title field should be used instead.
|
|
637 chapter
|
|
638 Chapter number
|
|
639 crossref
|
|
640 The database key of the entry being cross referenced.
|
|
641 edition
|
|
642 Edition of a book (e.g., \"second\")
|
|
643 editor
|
|
644 Name(s) of editor(s), in BibTeX name format.
|
|
645 If there is also an author field, then the editor field should be
|
|
646 for the book or collection that the work appears in
|
|
647 howpublished
|
|
648 How something strange has been published (begins sentence)
|
|
649 institution
|
|
650 Sponsoring institution
|
|
651 journal
|
|
652 Journal name (macros are provided for many)
|
|
653 key
|
|
654 Alphabetizing and labeling key (needed when no author or editor)
|
|
655 month
|
|
656 Month (macros are provided)
|
|
657 note
|
|
658 To help the reader find a reference (begins sentence)
|
|
659 number
|
|
660 Number of a journal or technical report
|
|
661 organization
|
|
662 Organization (sponsoring a conference)
|
|
663 pages
|
|
664 Page number or numbers (use `--' to separate a range)
|
|
665 publisher
|
|
666 Publisher name
|
|
667 school
|
|
668 School name (for theses)
|
|
669 series
|
|
670 The name of a series or set of books.
|
|
671 An individual book will will also have it's own title
|
|
672 title
|
|
673 The title of the thing being referenced
|
|
674 type
|
|
675 Type of a technical report (e.g., \"Research Note\") to be used
|
|
676 instead of the default \"Technical Report\"
|
|
677 volume
|
|
678 Volume of a journal or multivolume work
|
|
679 year
|
|
680 Year---should contain only numerals
|
|
681 ---------------------------------------------------------
|
|
682 Entry to this mode calls the value of bibtex-mode-hook if that value is
|
|
683 non-nil."
|
|
684 (interactive)
|
|
685 (kill-all-local-variables)
|
|
686 (set-syntax-table bibtex-mode-syntax-table)
|
|
687 (use-local-map bibtex-mode-map)
|
|
688 (setq major-mode 'bibtex-mode)
|
|
689 (setq mode-name "BibTeX")
|
|
690 (set-syntax-table bibtex-mode-syntax-table)
|
|
691 (setq local-abbrev-table bibtex-mode-abbrev-table)
|
|
692 (make-local-variable 'paragraph-start)
|
|
693 (setq paragraph-start "^[ \f\n\t]*$")
|
|
694 (auto-fill-mode 1) ; nice alignments
|
|
695 (setq left-margin (+ bibtex-text-alignment 1))
|
|
696
|
|
697 (run-hooks 'bibtex-mode-hook))
|
|
698
|
|
699 (defun bibtex-move-outside-of-entry ()
|
|
700 "Make sure we are outside of a bib entry"
|
|
701 (cond ((or
|
|
702 (= (point) (point-max))
|
|
703 (= (point) (point-min))
|
|
704 (looking-at "[ \n]*@")
|
|
705 )
|
|
706 t)
|
|
707 (t
|
|
708 (backward-paragraph)
|
|
709 (forward-paragraph)))
|
|
710 (re-search-forward "[ \t\n]*" (point-max) t))
|
|
711
|
|
712 (defun ispell-abstract ()
|
|
713 (interactive)
|
|
714 (beginning-of-bibtex-entry)
|
|
715 (re-search-forward "^[ \t]*[OPT]*abstract[ \t]*=")
|
|
716 (ispell-region (point)
|
|
717 (save-excursion (forward-sexp) (point))))
|
|
718
|
|
719 (defun beginning-of-bibtex-entry ()
|
|
720 (interactive)
|
|
721 (re-search-backward "^@" nil 'move))
|
|
722
|
|
723 (defun skip-whitespace-and-comments ()
|
|
724 ;; It might be a good idea to have forward-sexp with argument 0 do what
|
|
725 ;; this function tries to do, namely skip whitespace and comments.
|
|
726 ;; Maybe a better name for this would be skip-to-next-sexp.
|
|
727 ;; alternative implementation:
|
|
728 ;; (let ((parse-sexp-ignore-comments t))
|
|
729 ;; (forward-sexp 1)
|
|
730 ;; (forward-sexp -1))
|
|
731 ;; but I've had problems with this not getting the parse of comments
|
|
732 ;; right going backward if they contain unbalanced expressions or string
|
|
733 ;; quotes. [alarson:19920217.1021CST]
|
|
734 (let ((md (match-data)))
|
|
735 (unwind-protect
|
|
736 (while (cond ((looking-at "\\s>+\\|\\s +")
|
|
737 ;; was whitespace
|
|
738 ;; NOTE: also checked end-comment. In latex and
|
|
739 ;; lisp modes, newline is an end comment, but it
|
|
740 ;; should also be a whitespace char.
|
|
741 (goto-char (match-end 0)))
|
|
742 ;; If looking at beginning of comment, skip to end.
|
|
743 ((looking-at "\\s<")
|
|
744 (re-search-forward "\\s>"))))
|
|
745 (store-match-data md))))
|
|
746
|
|
747 ;;; [alarson:19920214.1007CST]
|
|
748 (defun end-of-bibtex-entry ()
|
|
749 "If inside an entry, move to the end of it, otherwise move to the end
|
|
750 of the next entry."
|
|
751 (interactive)
|
|
752 ;; if point was previously at the end of an entry, this puts us
|
|
753 ;; inside the next entry, otherwise we remain in the current one.
|
|
754 (progn
|
|
755 (skip-whitespace-and-comments)
|
|
756 ;;; (skip-chars-forward " \t\n")
|
|
757 (end-of-line))
|
|
758 (beginning-of-bibtex-entry)
|
|
759 (let ((parse-sexp-ignore-comments t))
|
|
760 (forward-sexp) ; skip entry type
|
|
761 (forward-sexp) ; skip entry body
|
|
762 ))
|
|
763 ;(defun end-of-bibtex-entry ()
|
|
764 ; (interactive)
|
|
765 ; (re-search-forward "}$" nil 'move))
|
|
766
|
|
767 (defun ispell-bibtex-entry ()
|
|
768 (interactive)
|
|
769 (ispell-region (progn (beginning-of-bibtex-entry) (point))
|
|
770 (progn (end-of-bibtex-entry) (point))))
|
|
771
|
|
772 (defun narrow-to-bibtex-entry ()
|
|
773 (interactive)
|
|
774 (save-excursion
|
|
775 (narrow-to-region (progn (beginning-of-bibtex-entry) (point))
|
|
776 (progn (end-of-bibtex-entry) (point)))))
|
|
777
|
|
778
|
|
779 (defun beginning-of-first-bibtex-entry ()
|
|
780 (goto-char (point-min))
|
|
781 (cond
|
|
782 ((re-search-forward "^@" nil 'move)
|
|
783 (beginning-of-line))
|
|
784 ((and (bobp) (eobp))
|
|
785 nil)
|
|
786 (t
|
|
787 (message "Warning: No bibtex entries found!"))))
|
|
788
|
|
789 (defun hide-bibtex-entry-bodies (&optional arg)
|
|
790 "Hide all lines between first and last bibtex entries not beginning with @.
|
|
791 With argument, show all text."
|
|
792 (interactive "P")
|
|
793 (save-excursion
|
|
794 (beginning-of-first-bibtex-entry)
|
|
795 ;; subst-char-in-region modifies the buffer, despite what the
|
|
796 ;; documentation says...
|
|
797 (let ((modifiedp (buffer-modified-p))
|
|
798 (buffer-read-only nil))
|
|
799 (if arg
|
|
800 (subst-char-in-region (point) (point-max) ?\r ?\n t)
|
|
801 (while (save-excursion (re-search-forward "\n[^@]" (point-max) t))
|
|
802 (save-excursion (replace-regexp "\n\\([^@]\\)" "\r\\1"))))
|
|
803 (setq selective-display (not arg))
|
|
804 (set-buffer-modified-p modifiedp))))
|
|
805
|
|
806 (defvar bibtex-sort-ignore-string-entries nil
|
|
807 "*If true, bibtex @STRING entries are ignored when determining ordering
|
|
808 of the buffer (e.g. sorting, locating alphabetical position for new entries,
|
|
809 etc.)")
|
|
810
|
|
811 (defun sort-bibtex-entries ()
|
|
812 "Sort bibtex entries alphabetically by key.
|
|
813 Text before the first bibtex entry, and following the last is not affected.
|
|
814 If bibtex-sort-ignore-string-entries is true, @string entries will be ignored.
|
|
815
|
|
816 Bugs:
|
|
817 1. Text between the closing brace ending one bibtex entry, and the @ starting
|
|
818 the next, is considered part of the PRECEDING entry. Perhaps it should be
|
|
819 part of the following entry."
|
|
820 (interactive)
|
|
821 (save-restriction
|
|
822 (beginning-of-first-bibtex-entry)
|
|
823 (narrow-to-region (point)
|
|
824 (save-excursion
|
|
825 (goto-char (point-max))
|
|
826 (beginning-of-bibtex-entry)
|
|
827 (end-of-bibtex-entry)
|
|
828 (point)))
|
|
829 (sort-subr nil ; reversep
|
|
830 ;; beginning of record function
|
|
831 'forward-line
|
|
832 ;; end of record function
|
|
833 (function (lambda () (and (re-search-forward "}\\s-*\n[\n \t]*@" nil 'move)
|
|
834 (forward-char -2))))
|
|
835 ;; start of key function
|
|
836 (if bibtex-sort-ignore-string-entries
|
|
837 (function (lambda ()
|
|
838 (while (and (re-search-forward "^\\s-*\\([@a-zA-Z]*\\)\\s-*{\\s-*")
|
|
839 (string-equalp "@string"
|
|
840 (buffer-substring (match-beginning 1)
|
|
841 (match-end 1)))))
|
|
842 nil))
|
|
843 (function (lambda () (re-search-forward "{\\s-*") nil)))
|
|
844 ;; end of key function
|
|
845 (function (lambda () (search-forward ",")))
|
|
846 )))
|
|
847
|
|
848 (defun map-bibtex-entries (fun)
|
|
849 "Call FUN for each bibtex entry starting with the current, to the end of the file.
|
|
850 FUN is called with one argument, the key of the entry, and with point inside the entry.
|
|
851 If bibtex-sort-ignore-string-entries is true, FUN will not be called for @string entries."
|
|
852 (beginning-of-bibtex-entry)
|
|
853 (while (re-search-forward "^@[^{]*{[ \t]*\\([^, ]*\\)" nil t)
|
|
854 (if (and bibtex-sort-ignore-string-entries
|
|
855 (string-equalp "@string{"
|
|
856 (buffer-substring (match-beginning 0)
|
|
857 (match-beginning 1))))
|
|
858 nil ; ignore the @string entry.
|
|
859 (funcall fun (buffer-substring (match-beginning 1) (match-end 1))))))
|
|
860
|
|
861 (defun find-bibtex-entry-location (entry-name)
|
|
862 "Searches from beginning of current buffer looking for place to put the
|
|
863 bibtex entry named ENTRY-NAME. Buffer is assumed to be in sorted order,
|
|
864 without duplicates (see \\[sort-bibtex-entries]), if it is not, an error will
|
|
865 be signalled."
|
|
866 (interactive "sBibtex entry key: ")
|
|
867 (let ((previous nil)
|
|
868 point)
|
|
869 (beginning-of-first-bibtex-entry)
|
|
870 (or (catch 'done
|
|
871 (map-bibtex-entries (function (lambda (current)
|
|
872 (cond
|
|
873 ((string-equal entry-name current)
|
|
874 (error "Entry duplicates existing!"))
|
|
875 ((or (null previous)
|
|
876 (string< previous current))
|
|
877 (setq previous current
|
|
878 point (point))
|
|
879 (if (string< entry-name current)
|
|
880 (progn
|
|
881 (beginning-of-bibtex-entry)
|
|
882 ;; Many schemes append strings to
|
|
883 ;; existing entries to resolve them,
|
|
884 ;; so initial substring matches may
|
|
885 ;; indicate a duplicate entry.
|
|
886 (let ((idx (string-match (regexp-quote entry-name) current)))
|
|
887 (if (and (integerp idx)
|
|
888 (zerop idx))
|
|
889 (progn
|
|
890 (message "Warning: Entry %s may be a duplicate of %s!"
|
|
891 entry-name current)
|
|
892 (ding t))))
|
|
893 (throw 'done t))))
|
|
894 ((string-equal previous current)
|
|
895 (error "Duplicate here with previous!"))
|
|
896 (t (error "Entries out of order here!")))))))
|
|
897 (end-of-bibtex-entry))))
|
|
898
|
|
899 (defun validate-bibtex-buffer ()
|
|
900 "Find some typical errors in bibtex files.
|
|
901 1. At signs (@) not as first char of a line.
|
|
902 2. Double quotes (\") inside strings.
|
|
903 3. Closing braces (}) not the last character of a line."
|
|
904 (interactive)
|
|
905 (let ((point (point)))
|
|
906 (while (re-search-forward ".@" nil t)
|
|
907 (let* ((foo (parse-partial-sexp (save-excursion (beginning-of-bibtex-entry)
|
|
908 (point))
|
|
909 (point)))
|
|
910 (in-a-string (nth 3 foo)))
|
|
911 (if (not in-a-string)
|
|
912 (error "At sign (@) out of place!"))))
|
|
913 (goto-char point)
|
|
914 (while (search-forward "\"" nil t)
|
|
915 (or (looking-at "[,}][ \t]*$")
|
|
916 (char-equal (preceding-char) ?\")
|
|
917 ;; some versions put closing brace on separate line.
|
|
918 (looking-at "[ \t]*\n}")
|
|
919 (save-excursion
|
|
920 (save-restriction
|
|
921 (narrow-to-region (point)
|
|
922 (progn (beginning-of-line) (point)))
|
|
923 (looking-at "^[ \t]*[a-zA-Z]+[ \t]*=[ \t]*\"$")))
|
|
924 (error "Quote out of place, or missing \",\" or \"}\"!")))
|
|
925 (goto-char point)
|
|
926 ;; This is only approximate, should actually search for close braces,
|
|
927 ;; then see if they are inside a string, or at the end of a line.
|
|
928 ;; This just gets the typical case of whitespace after a closing brace.
|
|
929 (while (search-forward "}[ \t]+$" nil t)
|
|
930 (error "Brace not last char of line!"))
|
|
931 (goto-char point)
|
|
932 (message "Bibtex buffer appears o.k.")))
|
|
933
|
|
934 (defun find-bibtex-duplicates ()
|
|
935 "Searches forward in current buffer looking for duplicate bibtex entries.
|
|
936 Buffer is assumed to be sorted, see \\[sort-bibtex-entries]"
|
|
937 (interactive)
|
|
938 (let ((point (point)))
|
|
939 ;; errors if things are not right...
|
|
940 (find-bibtex-entry-location (make-string 10 255))
|
|
941 (goto-char point)
|
|
942 (message "No duplicates found!")))
|
|
943
|
|
944
|
|
945 ;;; assoc doesn't ignore case, so we need an assoc that does...
|
|
946 (defun assoc-string-equalp (thing alist)
|
|
947 (or (assoc thing alist)
|
|
948 (while (and alist
|
|
949 (not (string-equalp thing (car (car alist)))))
|
|
950 (setq alist (cdr alist)))
|
|
951 (car alist)))
|
|
952
|
|
953 (defvar bibtex-maintain-sorted-entries nil
|
|
954 "*If true, bibtex-mode will attempt to maintain all bibtex entries in
|
|
955 sorted order.
|
|
956
|
|
957 Note that this is more a property of a file than a personal preference and
|
|
958 as such should normally be set via a file local variable entry.")
|
|
959
|
|
960 (defun bibtex-entry (entry-type &optional required optional)
|
|
961 (interactive (let* ((completion-ignore-case t)
|
|
962 (e-t (completing-read "Entry Type: " bibtex-entry-field-alist
|
|
963 nil t)))
|
|
964 (list e-t)))
|
|
965 (if (and (null required) (null optional))
|
|
966 (let* ((e (assoc-string-equalp entry-type bibtex-entry-field-alist))
|
|
967 (r-n-o (elt e 1))
|
|
968 (c-ref (elt e 2)))
|
|
969 (if (null e)
|
|
970 (error "Bibtex entry type %s not defined!"))
|
|
971 (if (and bibtex-include-OPTcrossref c-ref)
|
|
972 (setq required (elt c-ref 0)
|
|
973 optional (elt c-ref 1))
|
|
974 (setq required (elt r-n-o 0)
|
|
975 optional (elt r-n-o 1)))))
|
|
976 (let ((key (if bibtex-maintain-sorted-entries
|
|
977 (read-string (format "%s key: " entry-type)))))
|
|
978 (if key
|
|
979 (find-bibtex-entry-location key))
|
|
980 (bibtex-move-outside-of-entry)
|
|
981 (insert "@" entry-type "{")
|
|
982 (if key
|
|
983 (insert key))
|
|
984 (save-excursion
|
|
985 (mapcar 'bibtex-make-field required)
|
|
986 (if bibtex-include-OPTcrossref
|
|
987 (bibtex-make-optional-field "crossref"))
|
|
988 (if bibtex-include-OPTkey
|
|
989 (bibtex-make-optional-field "key"))
|
|
990 (mapcar 'bibtex-make-optional-field optional)
|
|
991 (mapcar 'bibtex-make-optional-field
|
|
992 bibtex-mode-user-optional-fields)
|
|
993 (if bibtex-include-OPTannote
|
|
994 (bibtex-make-optional-field "annote"))
|
|
995 (insert "\n}\n\n"))
|
|
996 (if key
|
|
997 (bibtex-next-field t))
|
|
998 (run-hooks 'bibtex-add-entry-hook)))
|
|
999
|
|
1000 ;; (defun bibtex-entry (entry-type required optional)
|
|
1001 ;; (bibtex-move-outside-of-entry)
|
|
1002 ;; (insert (concat "@" entry-type "{,\n\n}\n\n"))
|
|
1003 ;; (previous-line 3)
|
|
1004 ;; (insert (mapconcat 'bibtex-make-entry required ",\n"))
|
|
1005 ;; (if required
|
|
1006 ;; (if optional
|
|
1007 ;; (insert ",\n")))
|
|
1008 ;; (insert (mapconcat 'bibtex-make-OPT-entry optional ",\n"))
|
|
1009 ;; (if bibtex-mode-user-optional-fields ;MON...
|
|
1010 ;; (progn
|
|
1011 ;; (if optional
|
|
1012 ;; (insert ",\n"))
|
|
1013 ;; (insert (mapconcat 'bibtex-make-OPT-entry
|
|
1014 ;; bibtex-mode-user-optional-fields
|
|
1015 ;; ",\n")))) ;MON
|
|
1016 ;; (up-list -1)
|
|
1017 ;; (forward-char 1))
|
|
1018
|
|
1019
|
|
1020 (defun bibtex-make-field (e-t)
|
|
1021 (interactive "sBibTeX entry type: ")
|
|
1022 (let ((name (if (consp e-t) (car e-t) e-t))
|
|
1023 (value (if (consp e-t) (cdr e-t) "")))
|
|
1024 (insert ",\n")
|
|
1025 (indent-to-column bibtex-name-alignment)
|
|
1026 (insert name " = ")
|
|
1027 (indent-to-column bibtex-text-alignment)
|
|
1028 ;; lucid emacs prin1-to-string breaks the undo chain. When they fix
|
|
1029 ;; that, the hack can be removed. [alarson:19930316.0805CST]
|
|
1030 ; (insert (prin1-to-string value))
|
|
1031 ;; begin hack
|
|
1032 (insert (format (if (stringp value) "\"%s\"" "%s")
|
|
1033 value))
|
|
1034 ;; end hack
|
|
1035 nil))
|
|
1036
|
|
1037 (defun bibtex-make-optional-field (e-t)
|
|
1038 (interactive "sOptional BibTeX entry type: ")
|
|
1039 (if (consp e-t)
|
|
1040 (setq e-t (cons (concat "OPT" (car e-t)) (cdr e-t)))
|
|
1041 (setq e-t (concat "OPT" e-t)))
|
|
1042 (bibtex-make-field e-t))
|
|
1043
|
|
1044 ;; What to do about crossref? if present, journal and year are
|
|
1045 ;; both optional. Due to this, i move all of them into optional. -- MON
|
|
1046
|
|
1047 (defun bibtex-Article ()
|
|
1048 (interactive)
|
|
1049 (bibtex-entry "Article"))
|
|
1050
|
|
1051 (defun bibtex-Book ()
|
|
1052 (interactive)
|
|
1053 (bibtex-entry "Book"))
|
|
1054
|
|
1055 (defun bibtex-Booklet ()
|
|
1056 (interactive)
|
|
1057 (bibtex-entry "Booklet"))
|
|
1058
|
|
1059 ;(defun bibtex-DEAthesis ()
|
|
1060 ; (interactive)
|
|
1061 ; (bibtex-entry "DEAthesis"))
|
|
1062
|
|
1063 (defun bibtex-InBook ()
|
|
1064 (interactive)
|
|
1065 (bibtex-entry "InBook"))
|
|
1066
|
|
1067 (defun bibtex-InCollection ()
|
|
1068 (interactive)
|
|
1069 (bibtex-entry "InCollection"))
|
|
1070
|
|
1071 (defun bibtex-InProceedings ()
|
|
1072 (interactive)
|
|
1073 (bibtex-entry "InProceedings"))
|
|
1074
|
|
1075 (defun bibtex-Manual ()
|
|
1076 (interactive)
|
|
1077 (bibtex-entry "Manual"))
|
|
1078
|
|
1079 (defun bibtex-MastersThesis ()
|
|
1080 (interactive)
|
|
1081 (bibtex-entry "MastersThesis"))
|
|
1082
|
|
1083 (defun bibtex-Misc ()
|
|
1084 (interactive)
|
|
1085 (bibtex-entry "Misc"))
|
|
1086
|
|
1087 (defun bibtex-PhdThesis ()
|
|
1088 (interactive)
|
|
1089 (bibtex-entry "PhdThesis"))
|
|
1090
|
|
1091 (defun bibtex-Proceedings ()
|
|
1092 (interactive)
|
|
1093 (bibtex-entry "Proceedings"))
|
|
1094
|
|
1095 (defun bibtex-TechReport ()
|
|
1096 (interactive)
|
|
1097 (bibtex-entry "TechReport"))
|
|
1098
|
|
1099 (defun bibtex-Unpublished ()
|
|
1100 (interactive)
|
|
1101 (bibtex-entry "Unpublished"))
|
|
1102
|
|
1103 (defun bibtex-string ()
|
|
1104 (interactive)
|
|
1105 (bibtex-move-outside-of-entry)
|
|
1106 (insert "@string{ = \"\"}\n")
|
|
1107 (previous-line 1)
|
|
1108 (forward-char 8))
|
|
1109
|
|
1110 (defun bibtex-preamble ()
|
|
1111 (interactive)
|
|
1112 (bibtex-move-outside-of-entry)
|
|
1113 (insert "@Preamble{}\n")
|
|
1114 (previous-line 1)
|
|
1115 (forward-char 10))
|
|
1116
|
|
1117 (defun bibtex-next-field (arg)
|
|
1118 "Finds end of text of next BibTeX field; with arg, to its beginning"
|
|
1119 (interactive "P")
|
|
1120 (bibtex-inside-field)
|
|
1121 (let ((start (point)))
|
|
1122 (condition-case ()
|
|
1123 (progn
|
|
1124 (bibtex-enclosing-field)
|
|
1125 (goto-char (match-end 0))
|
|
1126 (forward-char 2))
|
|
1127 (error
|
|
1128 (goto-char start)
|
|
1129 (end-of-line)
|
|
1130 (forward-char 1))))
|
|
1131 (bibtex-find-text arg))
|
|
1132
|
|
1133 ;; (defun bibtex-next-field ()
|
|
1134 ;; "Finds end of text of next field."
|
|
1135 ;; (interactive)
|
|
1136 ;; (condition-case ()
|
|
1137 ;; (progn
|
|
1138 ;; (bibtex-inside-field)
|
|
1139 ;; (re-search-forward ",[ \t\n]*" (point-max) 1)
|
|
1140 ;; (bibtex-enclosing-field)
|
|
1141 ;; (bibtex-inside-field))
|
|
1142 ;; (error nil)))
|
|
1143
|
|
1144 (defun bibtex-find-text (arg)
|
|
1145 "Go to end of text of current field; with arg, go to beginning."
|
|
1146 (interactive "P")
|
|
1147 (bibtex-inside-field)
|
|
1148 (bibtex-enclosing-field)
|
|
1149 (if arg
|
|
1150 (progn
|
|
1151 (goto-char (match-beginning bibtex-text-in-field))
|
|
1152 (if (looking-at "\"")
|
|
1153 (forward-char 1)))
|
|
1154 (goto-char (match-end bibtex-text-in-field))
|
|
1155 (if (= (preceding-char) ?\")
|
|
1156 (forward-char -1))))
|
|
1157
|
|
1158 ;; (defun bibtex-find-text ()
|
|
1159 ;; "Go to end of text of current field."
|
|
1160 ;; (interactive)
|
|
1161 ;; (condition-case ()
|
|
1162 ;; (progn
|
|
1163 ;; (bibtex-inside-field)
|
|
1164 ;; (bibtex-enclosing-field)
|
|
1165 ;; (goto-char (match-end bibtex-text-in-field))
|
|
1166 ;; (bibtex-inside-field))
|
|
1167 ;; (error nil)))
|
|
1168
|
|
1169 (defun bibtex-remove-OPT ()
|
|
1170 "Removes the 'OPT' starting optional arguments and goes to end of text"
|
|
1171 (interactive)
|
|
1172 (bibtex-inside-field)
|
|
1173 (bibtex-enclosing-field)
|
|
1174 (save-excursion
|
|
1175 (goto-char (match-beginning bibtex-name-in-field))
|
|
1176 (if (looking-at "OPT")
|
|
1177 ;; sct@dcs.edinburgh.ac.uk
|
|
1178 (progn
|
|
1179 (delete-char (length "OPT"))
|
|
1180 (search-forward "=")
|
|
1181 (delete-horizontal-space)
|
|
1182 (indent-to-column bibtex-text-alignment))))
|
|
1183 (bibtex-inside-field))
|
|
1184
|
|
1185 (defun bibtex-inside-field ()
|
|
1186 "Try to avoid point being at end of a bibtex field."
|
|
1187 (interactive)
|
|
1188 (end-of-line)
|
|
1189 (skip-chars-backward " \t") ;MON - maybe delete these chars?
|
|
1190 (cond ((= (preceding-char) ?,)
|
|
1191 (forward-char -2))) ; -1 --> -2 sct@dcs.edinburgh.ac.uk
|
|
1192 (cond ((= (preceding-char) ?\")
|
|
1193 (forward-char -1)))) ;MON - only go back if quote
|
|
1194
|
|
1195 (defun bibtex-remove-double-quotes ()
|
|
1196 "Removes \"\" around string."
|
|
1197 (interactive)
|
|
1198 (save-excursion
|
|
1199 (bibtex-inside-field)
|
|
1200 (bibtex-enclosing-field)
|
|
1201 (let ((start (match-beginning bibtex-text-in-field))
|
|
1202 (stop (match-end bibtex-text-in-field)))
|
|
1203 (goto-char stop)
|
|
1204 (forward-char -1)
|
|
1205 (if (looking-at "\"")
|
|
1206 (delete-char 1))
|
|
1207 (goto-char start)
|
|
1208 (if (looking-at "\"")
|
|
1209 (delete-char 1)))))
|
|
1210
|
|
1211 (defun bibtex-kill-optional-field ()
|
|
1212 "Kill the entire enclosing optional BibTeX field"
|
|
1213 (interactive)
|
|
1214 (bibtex-inside-field)
|
|
1215 (bibtex-enclosing-field)
|
|
1216 (goto-char (match-beginning bibtex-name-in-field))
|
|
1217 (let ((the-end (match-end 0))
|
|
1218 (the-beginning (match-beginning 0)))
|
|
1219 (if (looking-at "OPT")
|
|
1220 (progn
|
|
1221 (goto-char the-end)
|
|
1222 (skip-chars-forward " \t\n,")
|
|
1223 (kill-region the-beginning the-end))
|
|
1224 (error "Mandatory fields can't be killed"))))
|
|
1225
|
|
1226 (defun bibtex-empty-field ()
|
|
1227 "Delete the text part of the current field, replace with empty text"
|
|
1228 (interactive)
|
|
1229 (bibtex-inside-field)
|
|
1230 (bibtex-enclosing-field)
|
|
1231 (goto-char (match-beginning bibtex-text-in-field))
|
|
1232 (kill-region (point) (match-end bibtex-text-in-field))
|
|
1233 (insert "\"\"")
|
|
1234 (bibtex-find-text t))
|
|
1235
|
|
1236
|
|
1237 (defun bibtex-pop-previous (arg)
|
|
1238 "Replace text of current field with the text of similar field in previous entry.
|
|
1239 With arg, go up ARG entries. Repeated, goes up so many times. May be
|
|
1240 intermixed with \\[bibtex-pop-next] (bibtex-pop-next)."
|
|
1241 (interactive "p")
|
|
1242 (bibtex-inside-field)
|
|
1243 (save-excursion
|
|
1244 ; parse current field
|
|
1245 (bibtex-enclosing-field)
|
|
1246 (let ((start-old-text (match-beginning bibtex-text-in-field))
|
|
1247 (stop-old-text (match-end bibtex-text-in-field))
|
|
1248 (start-name (match-beginning bibtex-name-in-field))
|
|
1249 (stop-name (match-end bibtex-name-in-field))
|
|
1250 (new-text))
|
|
1251 (goto-char start-name)
|
|
1252 ; construct regexp for previous field with same name as this one
|
|
1253 (let ((matching-entry
|
|
1254 (bibtex-cfield
|
|
1255 (buffer-substring (if (looking-at "OPT")
|
|
1256 (+ (point) (length "OPT"))
|
|
1257 (point))
|
|
1258 stop-name)
|
|
1259 bibtex-field-text)))
|
|
1260
|
|
1261 ; if executed several times in a row, start each search where the
|
|
1262 ; last one finished
|
|
1263 (cond ((or (eq last-command 'bibtex-pop-previous)
|
|
1264 (eq last-command 'bibtex-pop-next))
|
|
1265 t
|
|
1266 )
|
|
1267 (t
|
|
1268 (bibtex-enclosing-reference)
|
|
1269 (setq bibtex-pop-previous-search-point (match-beginning 0))
|
|
1270 (setq bibtex-pop-next-search-point (match-end 0))))
|
|
1271 (goto-char bibtex-pop-previous-search-point)
|
|
1272
|
|
1273 ; Now search for arg'th previous similar field
|
|
1274 (cond
|
|
1275 ((re-search-backward matching-entry (point-min) t arg)
|
|
1276 (setq new-text
|
|
1277 (buffer-substring (match-beginning bibtex-text-in-cfield)
|
|
1278 (match-end bibtex-text-in-cfield)))
|
|
1279 ; Found a matching field. Remember boundaries.
|
|
1280 (setq bibtex-pop-next-search-point (match-end 0))
|
|
1281 (setq bibtex-pop-previous-search-point (match-beginning 0))
|
|
1282 (bibtex-flash-head)
|
|
1283 ; Go back to where we started, delete old text, and pop new.
|
|
1284 (goto-char stop-old-text)
|
|
1285 (delete-region start-old-text stop-old-text)
|
|
1286 (insert new-text))
|
|
1287 (t ; search failed
|
|
1288 (error "No previous matching BibTeX field."))))))
|
|
1289 (setq this-command 'bibtex-pop-previous))
|
|
1290
|
|
1291 (defun bibtex-pop-next (arg)
|
|
1292 "Replace text of current field with the text of similar field in next entry.
|
|
1293 With arg, go up ARG entries. Repeated, goes up so many times. May be
|
|
1294 intermixed with \\[bibtex-pop-previous] (bibtex-pop-previous)."
|
|
1295 (interactive "p")
|
|
1296 (bibtex-inside-field)
|
|
1297 (save-excursion
|
|
1298 ; parse current field
|
|
1299 (bibtex-enclosing-field)
|
|
1300 (let ((start-old-text (match-beginning bibtex-text-in-field))
|
|
1301 (stop-old-text (match-end bibtex-text-in-field))
|
|
1302 (start-name (match-beginning bibtex-name-in-field))
|
|
1303 (stop-name (match-end bibtex-name-in-field))
|
|
1304 (new-text))
|
|
1305 (goto-char start-name)
|
|
1306 ; construct regexp for next field with same name as this one,
|
|
1307 ; ignoring possible OPT's
|
|
1308 (let ((matching-entry
|
|
1309 (bibtex-cfield
|
|
1310 (buffer-substring (if (looking-at "OPT")
|
|
1311 (+ (point) (length "OPT"))
|
|
1312 (point))
|
|
1313 stop-name)
|
|
1314 bibtex-field-text)))
|
|
1315
|
|
1316 ; if executed several times in a row, start each search where the
|
|
1317 ; last one finished
|
|
1318 (cond ((or (eq last-command 'bibtex-pop-next)
|
|
1319 (eq last-command 'bibtex-pop-previous))
|
|
1320 t
|
|
1321 )
|
|
1322 (t
|
|
1323 (bibtex-enclosing-reference)
|
|
1324 (setq bibtex-pop-previous-search-point (match-beginning 0))
|
|
1325 (setq bibtex-pop-next-search-point (match-end 0))))
|
|
1326 (goto-char bibtex-pop-next-search-point)
|
|
1327
|
|
1328 ; Now search for arg'th next similar field
|
|
1329 (cond
|
|
1330 ((re-search-forward matching-entry (point-max) t arg)
|
|
1331 (setq new-text
|
|
1332 (buffer-substring (match-beginning bibtex-text-in-cfield)
|
|
1333 (match-end bibtex-text-in-cfield)))
|
|
1334 ; Found a matching field. Remember boundaries.
|
|
1335 (setq bibtex-pop-next-search-point (match-end 0))
|
|
1336 (setq bibtex-pop-previous-search-point (match-beginning 0))
|
|
1337 (bibtex-flash-head)
|
|
1338 ; Go back to where we started, delete old text, and pop new.
|
|
1339 (goto-char stop-old-text)
|
|
1340 (delete-region start-old-text stop-old-text)
|
|
1341 (insert new-text))
|
|
1342 (t ; search failed
|
|
1343 (error "No next matching BibTeX field."))))))
|
|
1344 (setq this-command 'bibtex-pop-next))
|
|
1345
|
|
1346 (defun bibtex-flash-head ()
|
|
1347 "Flash at BibTeX reference head before point, if exists. (Moves point)."
|
|
1348 (let ((flash))
|
|
1349 (cond ((re-search-backward bibtex-reference-head (point-min) t)
|
|
1350 (goto-char (match-beginning bibtex-type-in-head))
|
|
1351 (setq flash (match-end bibtex-key-in-reference)))
|
|
1352 (t
|
|
1353 (end-of-line)
|
|
1354 (skip-chars-backward " \t")
|
|
1355 (setq flash (point))
|
|
1356 (beginning-of-line)
|
|
1357 (skip-chars-forward " \t")))
|
|
1358 (if (pos-visible-in-window-p (point))
|
|
1359 (sit-for 1)
|
|
1360 (message "From: %s"
|
|
1361 (buffer-substring (point) flash)))))
|
|
1362
|
|
1363
|
|
1364
|
|
1365 (defun bibtex-enclosing-field ()
|
|
1366 "Search for BibTeX field enclosing point.
|
|
1367 Point moves to end of field; also, use match-beginning and match-end
|
|
1368 to parse the field."
|
|
1369 ;; sct@dcs.edinburgh.ac.uk
|
|
1370 (let ((old-point (point)))
|
|
1371 (condition-case errname
|
|
1372 (bibtex-enclosing-regexp bibtex-field)
|
|
1373 (search-failed
|
|
1374 (goto-char old-point)
|
|
1375 (error "Can't find enclosing BibTeX field.")))))
|
|
1376
|
|
1377 (defun bibtex-enclosing-reference ()
|
|
1378 "Search for BibTeX reference enclosing point.
|
|
1379 Point moves to end of reference; also, use match-beginning and match-end
|
|
1380 to parse the reference."
|
|
1381 ;; sct@dcs.edinburgh.ac.uk
|
|
1382 (let ((old-point (point)))
|
|
1383 (condition-case errname
|
|
1384 (bibtex-enclosing-regexp bibtex-reference)
|
|
1385 (search-failed
|
|
1386 (goto-char old-point)
|
|
1387 (error "Can't find enclosing BibTeX reference.")))))
|
|
1388
|
|
1389 (defun bibtex-enclosing-regexp (regexp)
|
|
1390 "Search for REGEXP enclosing point.
|
|
1391 Point moves to end of REGEXP. See also match-beginning and match-end.
|
|
1392 If an enclosing REGEXP is not found, signals search-failed; point is left in
|
|
1393 an undefined location.
|
|
1394
|
|
1395 [Doesn't something like this exist already?]"
|
|
1396
|
|
1397 (interactive "sRegexp: ")
|
|
1398 ; compute reasonable limits for the loop
|
|
1399 (let* ((initial (point))
|
|
1400 (right (if (re-search-forward regexp (point-max) t)
|
|
1401 (match-end 0)
|
|
1402 (point-max)))
|
|
1403 (left
|
|
1404 (progn
|
|
1405 (goto-char initial)
|
|
1406 (if (re-search-backward regexp (point-min) t)
|
|
1407 (match-beginning 0)
|
|
1408 (point-min)))))
|
|
1409 ; within the prescribed limits, loop until a match is found
|
|
1410 (goto-char left)
|
|
1411 (re-search-forward regexp right nil 1)
|
|
1412 (if (> (match-beginning 0) initial)
|
|
1413 (signal 'search-failed (list regexp)))
|
|
1414 (while (<= (match-end 0) initial)
|
|
1415 (re-search-forward regexp right nil 1)
|
|
1416 (if (> (match-beginning 0) initial)
|
|
1417 (signal 'search-failed (list regexp))))
|
|
1418 ))
|
|
1419
|
|
1420 (defun bibtex-clean-entry ()
|
|
1421 "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."
|
|
1422 (interactive)
|
|
1423 (beginning-of-bibtex-entry)
|
|
1424 (let ((start (point)))
|
|
1425 (save-restriction
|
|
1426 (narrow-to-region start (save-excursion (end-of-bibtex-entry) (point)))
|
|
1427 (while (re-search-forward bibtex-field (point-max) t 1)
|
|
1428 (let ((begin-field (match-beginning 0))
|
|
1429 (end-field (match-end 0))
|
|
1430 (begin-name (match-beginning bibtex-name-in-field))
|
|
1431 (end-name (match-end bibtex-name-in-field))
|
|
1432 (begin-text (match-beginning bibtex-text-in-field))
|
|
1433 (end-text (match-end bibtex-text-in-field))
|
|
1434 )
|
|
1435 (goto-char begin-name)
|
|
1436 (cond ((and
|
|
1437 (looking-at "OPT")
|
|
1438 bibtex-clean-entry-zap-empty-opts)
|
|
1439 (goto-char begin-text)
|
|
1440 (if (looking-at "\"\"") ; empty: delete whole field
|
|
1441 (delete-region begin-field end-field)
|
|
1442 ; otherwise: not empty, delete "OPT"
|
|
1443 (goto-char begin-name)
|
|
1444 (delete-char (length "OPT"))
|
|
1445 (progn
|
|
1446 ;; fixup alignment. [alarson:19920309.2047CST]
|
|
1447 (search-forward "=")
|
|
1448 (delete-horizontal-space)
|
|
1449 (indent-to-column bibtex-text-alignment))
|
|
1450 (goto-char begin-field) ; and loop to go through next test
|
|
1451 ))
|
|
1452 (t
|
|
1453 (goto-char begin-text)
|
|
1454 (cond ((looking-at "\"[0-9]+\"") ; if numerical,
|
|
1455 (goto-char end-text)
|
|
1456 (delete-char -1) ; delete enclosing double-quotes
|
|
1457 (goto-char begin-text)
|
|
1458 (delete-char 1)
|
|
1459 (goto-char end-field) ; go to end for next search
|
|
1460 (forward-char -2) ; to compensate for the 2 quotes deleted
|
|
1461 )
|
|
1462 ((looking-at "\"\"") ; if empty quotes, complain
|
|
1463 (forward-char 1)
|
|
1464 (if (not (or (equal (buffer-substring
|
|
1465 begin-name
|
|
1466 (+ begin-name 3))
|
|
1467 "OPT")
|
|
1468 (equal (buffer-substring
|
|
1469 begin-name
|
|
1470 (+ begin-name 3))
|
|
1471 "opt")))
|
|
1472 (error "Mandatory field ``%s'' is empty"
|
|
1473 (buffer-substring begin-name end-name))))
|
|
1474 (t
|
|
1475 (goto-char end-field))))))))
|
|
1476 (goto-char start)
|
|
1477 (end-of-bibtex-entry)
|
|
1478 ;; sct@dcs.edinburgh.ac.uk
|
|
1479 (save-excursion
|
|
1480 (previous-line 1)
|
|
1481 (end-of-line)
|
|
1482 (if (eq (preceding-char) ?,)
|
|
1483 (backward-delete-char 1)))
|
|
1484 (skip-whitespace-and-comments)))
|
|
1485
|
|
1486
|
|
1487 ;;; Menus for bibtex mode
|
|
1488
|
|
1489 (defconst bibtex-menu
|
|
1490 '("BibTeX Commands"
|
|
1491 "Entry Types"
|
|
1492 "---"
|
|
1493 ["Article in Conference Proceedings" bibtex-InProceedings t]
|
|
1494 ["Article in Journal" bibtex-Article t]
|
|
1495 ["Book" bibtex-Book t]
|
|
1496 ["Booklet" bibtex-Booklet t]
|
|
1497 ["Conference" bibtex-InProceedings t]
|
|
1498 ["Master's Thesis" bibtex-MastersThesis t]
|
|
1499 ["DEA Thesis" bibtex-DEAthesis t]
|
|
1500 ["Phd. Thesis" bibtex-PhdThesis t]
|
|
1501 ["Technical Report" bibtex-TechReport t]
|
|
1502 ["Technical Manual" bibtex-Manual t]
|
|
1503 ["Conference Proceedings" bibtex-Proceedings t]
|
|
1504 ["A Chapter in a Book" bibtex-InBook t]
|
|
1505 ["An Article in a Collection" bibtex-InCollection t]
|
|
1506 ["Miscellaneous" bibtex-Misc t]
|
|
1507 ["Unpublished" bibtex-Unpublished t]
|
|
1508 ["String" bibtex-string t]
|
|
1509 ["Preamble" bibtex-preamble t]
|
|
1510 "---"
|
|
1511 "Bibtex Edit"
|
|
1512 "---"
|
|
1513 ["Next Field" bibtex-next-field t]
|
|
1514 ["To End of Field" bibtex-find-text t]
|
|
1515 ["Snatch From Similar Preceding Field" bibtex-pop-previous t]
|
|
1516 ["Snatch From Similar Following Field" bibtex-pop-next t]
|
|
1517 ["Remove OPT" bibtex-remove-OPT t]
|
|
1518 ["Remove Quotes" bibtex-remove-double-quotes t]
|
|
1519 ["Clean Up Entry" bibtex-clean-entry t]
|
|
1520 ["Find Duplicates" find-bibtex-duplicates t]
|
|
1521 ["Sort Entries" sort-bibtex-entries t]
|
|
1522 ["Validate Entries" validate-bibtex-buffer t]
|
|
1523 ))
|
|
1524
|
|
1525 (defun bibtex-menu ()
|
|
1526 (interactive)
|
|
1527 (let ((popup-menu-titles nil))
|
|
1528 (popup-menu bibtex-menu)))
|
|
1529
|
|
1530 ;;; bibtex.el ends here
|