diff lisp/textmodes/bibtex.el @ 257:e5ba2ba35226

Initial revision
author Jim Blandy <jimb@redhat.com>
date Thu, 09 May 1991 21:50:45 +0000
parents
children a819dc25b9e7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/textmodes/bibtex.el	Thu May 09 21:50:45 1991 +0000
@@ -0,0 +1,1020 @@
+;;; BibTeX mode for GNU Emacs
+;; Copyright (C) 1985, 1986, 1987, 1990 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 1, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Mike Newton (newton@gumby.cs.caltech.edu) 91.1.20
+;;;  * bibtex.el/bibtex-mode : updated comments to indicate new use of 
+;;;    address, add minor explanations and fix small omissions.
+;;;  * bibtex.el/bibtex-entry : fixed spelling of variable
+
+;;; Mike Newton (newton@gumby.cs.caltech.edu) 90.11.17
+;;;  * Handle items like
+;;;          title = poft # "Fifth Tri-quaterly" # random-conf,
+;;;    and   title = {This title is inside curlies}
+;;;  * added user settable, always present, optional fields
+;;;  * fixed 'bibtex-find-it's doc string's location
+;;;  * bibtex-field-text made more general (it wouldnt handle the # construct)
+;;;		and it now handles a small subset of the {} cases
+;;;  * put DEA thesis back in (why get rid of good code?) 
+;;;  * merged into release 19 version code
+;;;  * if cross-ref'ing is on, put 'pages' near top of OPTs, as the other
+;;;             entries are unlikely to be used.
+;;;  * skip-whitespace replaced by skip-chars-forward (also done 
+;;;             by Marc Shairo)
+
+;;; Bengt Martensson, March 6
+;;;   Adapted to Bibtex 0.99 by updating the optional fields according
+;;;   to the document BibTeXing, Oren Patashnik, dated January 31, 1988.
+;;;   Updated documentation strings accordingly.  Added (provide 'bibtex).
+;;;   If bibtex-include-OPT-crossref is non-nil, every entry will have
+;;;   an OPTcrossref field, analogously for bibtex-include-OPTkey and
+;;;   bibtex-include-OPTannote.  Added bibtex-preamble, bound to ^C^EP,
+;;;   and also found in X- and sun-menus.  Cleaned up the sun-menu
+;;;   stuff, and made it more uniform with the X-menu stuff.  Marc: I
+;;;   strongly suspect that I broke your parsing...  (Or, more
+;;;   correctly, BibTeX 0.99 broke it.)
+;;;   Added bibtex-clean-entry-zap-empty-opts, defvar'd to t.  If it
+;;;   is nil, bibtex-clean-entry will leave empty optional fields alone.
+  
+;;; Marc Shapiro 1-feb-89: integrated changes by Bengt Martensson 88-05-06:
+;;;   Added Sun menu support.  Locally bound to right mouse button in 
+;;;   bibtex-mode.  Emacs 18.49 allows local mouse bindings!!
+;;;   Commented out DEAthesis.
+
+;;; Marc Shapiro 6-oct-88
+;;;  * use indent-to-column instead of inserting tabs (changes to 
+;;;    bibtex-entry, bibtex-make-entry, bibtex-make-OPT-entry, renamed to
+;;;    bibtex-make-optional-entry)
+;;;  * C-c C-k deletes the current OPT entry entirely
+;;;  * C-c C-d replaces text of field with ""
+;;;  * renamed bibtex-find-it to bibtex-find-text.  With arg, now goes to
+;;;    start of text.  Fixed bugs in it.
+
+;;; Marc Shapiro 23-sep-88
+;;;  * bibtex-clean-entry moves past end of entry.
+;;;  * bibtex-clean-entry signals mandatory fields left empty.
+
+;;; Marc Shapiro 18-jul-88
+;;;  * Moved all the entry type keystrokes to "C-c C-e something" (instead of
+;;;    "C-c something" previously) to make room for more.  C-c C-e is
+;;;    supposed to stand for "entry" [idea taken from mail-mode].  Moved
+;;;    bibtex-pop-previous to C-c C-p and bibtex-pop-next to C-c C-n.
+;;;  * removed binding for "\e[25~"
+;;;  * replaced bibtex-clean-optionals by bibtex-clean-entry, bound to
+;;;    C-c C-c
+
+;;; Marc Shapiro 13-jul-88 [based on ideas by Sacha Krakowiak of IMAG]
+;;;  * bibtex-pop-previous replaces current field with value of
+;;;    similar field in previous entry.  May be called n times in a row
+;;;    (or with arg n) to pop similar field of n'th previous entry.
+;;;    There is also a bibtex-pop-next to get similar field of next
+;;;    entry.
+;;;  * C-c C-k now kills all empty optional fields of current entry, and
+;;;    removes "OPT" for those optional fields which have text. 
+
+;;; Marc Shapiro 14-dec-87
+;;;   Cosmetic fixes.  Fixed small bug in bibtex-move-outside-of-entry.
+;;; Skip Montanaro <steinmetz!sprite!montanaro> 7-dec-87, Shapiro 10-dec-87
+;;;   before inserting an entry, make sure we are outside of a bib entry
+;;; Marc Shapiro 3-nov-87
+;;;   addition for France: DEAthesis
+;;; Marc Shapiro 19-oct-1987
+;;;   add X window menu option; bug fixes. TAB, LFD, C-c " and C-c C-o now
+;;;   behave consistently; deletion never occurs blindly.
+;;; Marc Shapiro <shapiro@inria.inria.fr> 15-oct-1986
+;;;    align long lines nicely; C-c C-o checks for the "OPT" string;
+;;;    TAB goes to the end of the string; use lower case; use
+;;;    run-hooks
+
+;;; Bengt Martensson <ubrinf!mond!bengt> 87-06-28
+;;; (Bengt Martensson <bengt@mathematik.uni-Bremen.de> 87-06-28)
+;;;   Original version
+
+;;; NOTE by Marc Shapiro, 14-dec-87:
+;;; (bibtex-x-environment) binds an X menu for bibtex mode to x-button-c-right.
+;;; Trouble is, in Emacs 18.44 you can't have a mode-specific mouse binding,
+;;; so it will remain active in all windows.  Yuck!
+
+(provide 'bibtex)
+
+(defvar bibtex-mode-syntax-table nil "")
+(defvar bibtex-mode-abbrev-table nil "")
+(define-abbrev-table 'bibtex-mode-abbrev-table ())
+(defvar bibtex-mode-map (make-sparse-keymap) "")
+(defvar bibtex-pop-previous-search-point nil
+  "Next point where `bibtex-pop-previous' should start looking for a similar
+entry.")
+(defvar bibtex-pop-next-search-point nil
+  "Next point where `bibtex-pop-next' should start looking for a similar
+entry.")
+
+(defvar bibtex-clean-entry-zap-empty-opts t
+  "*If non-nil, `bibtex-clean-entry' will delete all empty optional fields.")
+(defvar bibtex-include-OPTcrossref t
+  "*If non-nil, all entries will have an `OPTcrossref' field.")
+(defvar bibtex-include-OPTkey t
+  "*If non-nil, all entries will have an `OPTkey' field.")
+(defvar bibtex-include-OPTannote t
+  "*If non-nil, all entries will have an `OPTannote' field.")
+
+;; note: the user should be allowed to have their own list of always
+;;       available optional fields.  exs: "keywords" "categories"
+(defvar bibtex-mode-user-optional-fields nil		;no default value
+  "*List of optional fields that user always wants present in a bibtex entry.
+One possibility is for ``keywords''")
+
+
+;;; A bibtex file is a sequence of entries, either string definitions
+;;; or reference entries.  A reference entry has a type part, a
+;;; key part, and a comma-separated sequence of fields.  A string
+;;; entry has a single field.  A field has a left and right part,
+;;; separated by a '='.  The left part is the name, the right part is
+;;; the text.  Here come the definitions allowing to create and/or parse
+;;; entries and fields:
+
+;;; fields
+(defun bibtex-cfield (name text)
+  "Create a regexp for a bibtex field of name NAME and text TEXT."
+  (concat ",[ \t\n]*\\("
+	  name
+	  "\\)[ \t\n]*=[ \t\n]*\\("
+	  text
+	  "\\)"))
+(defconst bibtex-name-in-cfield 1
+  "The regexp subexpression number of the name part in `bibtex-cfield'.")
+(defconst bibtex-text-in-cfield 2
+  "The regexp subexpression number of the text part in `bibtex-cfield'.")
+
+(defconst bibtex-field-name "[A-Za-z][---A-Za-z0-9:_+]*"
+  "Regexp defining the name part of a bibtex field.")
+
+;; bibtex-field-text must be able to handle
+;;   title = "Proc. Fifteenth Annual" # STOC,
+;;   month = "10~" # jan,
+;;   year = "{\noopsort{1973c}}1981",
+;;   month = apr # "-" # may,
+;;   key = {Volume-2},
+;;   note = "Volume~2 is listed under Knuth \cite{book-full}"
+;; i have added a few of these, but not all! -- MON
+
+(defconst bibtex-field-const
+  "[0-9A-Za-z][---A-Za-z0-9:_+]*"
+  "Format of a bibtex field constant.")
+(defconst bibtex-field-string
+  (concat
+    "\"[^\"]*[^\\\\]\"\\|\"\"")
+  "Match either a string or an empty string.")
+(defconst bibtex-field-string-or-const
+  (concat bibtex-field-const "\\|" bibtex-field-string)
+  "Match either `bibtex-field-string' or `bibtex-field-const'.")
+
+;(defconst bibtex-field-text
+;  "\"[^\"]*[^\\\\]\"\\|\"\"\\|[0-9A-Za-z][---A-Za-z0-9:_+]*"
+;  "Regexp defining the text part of a bibtex field: either a string, or an empty string, or a constant.")
+
+(defconst bibtex-field-text
+  (concat
+    "\\(" bibtex-field-string-or-const "\\)"
+        "\\([ \t\n]+#[ \t\n]+\\(" bibtex-field-string-or-const "\\)\\)*\\|"
+    "{[^{}]*[^\\\\]}")
+  "Regexp defining the text part of a bibtex field: either a string, or
+an empty string, or a constant followed by one or more # / constant pairs.
+Also matches simple {...} patterns.")
+
+(defconst bibtex-field
+  (bibtex-cfield bibtex-field-name bibtex-field-text)
+  "Regexp defining the format of a bibtex field")
+
+(defconst bibtex-name-in-field bibtex-name-in-cfield
+  "The regexp subexpression number of the name part in `bibtex-field'.")
+(defconst bibtex-text-in-field bibtex-text-in-cfield
+  "The regexp subexpression number of the text part in `bibtex-field'.")
+
+;;; references
+(defconst bibtex-reference-type
+  "@[A-Za-z]+"
+  "Regexp defining the type part of a bibtex reference entry.")
+(defconst bibtex-reference-head
+  (concat "^[ \t]*\\("
+	  bibtex-reference-type
+	  "\\)[ \t]*[({]\\("
+	  bibtex-field-name
+	  "\\)")
+  "Regexp defining format of the header line of a bibtex reference entry.")
+(defconst bibtex-type-in-head 1
+  "The regexp subexpression number of the type part in `bibtex-reference-head'.")
+(defconst bibtex-key-in-head 2
+  "The regexp subexpression number of the key part in `bibtex-reference-head'.")
+
+(defconst bibtex-reference
+  (concat bibtex-reference-head
+	  "\\([ \t\n]*" bibtex-field "\\)*"
+	  "[ \t\n]*[})]")
+  "Regexp defining the format of a bibtex reference entry.")
+(defconst bibtex-type-in-reference bibtex-type-in-head
+  "The regexp subexpression number of the type part in `bibtex-reference'.")
+(defconst bibtex-key-in-reference bibtex-key-in-head
+  "The regexp subexpression number of the key part in `bibtex-reference'.")
+
+;;; strings
+(defconst bibtex-string
+  (concat "^[ \t]*@[sS][tT][rR][iI][nN][gG][ \t\n]*[({][ \t\n]*\\("
+	  bibtex-field-name
+	  "\\)[ \t\n]*=[ \t\n]*\\("
+	  bibtex-field-text
+	  "\\)[ \t\n]*[})]")
+  "Regexp defining the format of a bibtex string entry.")
+(defconst bibtex-name-in-string 1
+  "The regexp subexpression of the name part in `bibtex-string'.")
+(defconst bibtex-text-in-string 2
+  "The regexp subexpression of the text part in `bibtex-string'.")
+
+(defconst bibtex-name-alignement 2
+  "Alignment for the name part in BibTeX fields.
+Chosen on aesthetic grounds only.")
+
+(defconst bibtex-text-alignment (length "  organization = ")
+  "Alignment for the text part in BibTeX fields.
+Equal to the space needed for the longest name part.")
+
+;;; bibtex mode:
+
+;;;###autoload
+(defun bibtex-mode () 
+  "Major mode for editing bibtex files.
+
+\\{bibtex-mode-map}
+
+A command such as \\[bibtex-Book] will outline the fields for a BibTeX book entry.
+
+The optional fields start with the string OPT, and thus ignored by BibTeX.
+The OPT string may be removed from a field with \\[bibtex-remove-OPT].
+\\[bibtex-kill-optional-field] kills the current optional field entirely.
+\\[bibtex-remove-double-quotes] removes the double-quotes around the text of
+the current field.  \\[bibtex-empty-field] replaces the text of the current
+field with the default \"\".
+
+The command \\[bibtex-clean-entry] cleans the current entry, i.e. (i) removes
+double-quotes from entirely numerical fields, (ii) removes OPT from all
+non-empty optional fields, (iii) removes all empty optional fields, and (iv)
+checks that no non-optional fields are empty.
+
+Use \\[bibtex-find-text] to position the dot at the end of the current field.
+Use \\[bibtex-next-field] to move to end of the next field.
+
+\\[bibtex-x-environment] binds a mode-specific X menu to control+right
+mouse button.
+\\[bibtex-sun-environment] binds a mode-specific Sun menu to right
+mouse button.
+
+Fields:
+    address
+           Publisher's address, or for conference, location held
+    annote
+           Long annotation used for annotated bibliographies (begins sentence)
+    author
+           Name(s) of author(s), in BibTeX name format
+    booktitle
+           Book title when the thing being referenced isn't the whole book.
+           For book entries, the title field should be used instead.
+    chapter
+           Chapter number (or section or whatever).
+    crossref
+	   The database key of the entry being cross referenced.
+    edition
+           Edition of a book (e.g., \"second\")
+    editor
+           Name(s) of editor(s), in BibTeX name format.
+           If there is also an author field, then the editor field should be
+           for the book or collection that the work appears in
+    howpublished
+            How something strange has been published (begins sentence)
+    institution
+           Sponsoring institution
+    journal
+           Journal name (macros are provided for many)
+    key
+           Alphabetizing, labeling and cross-refing key (needed when no 
+	   author or editor)
+    month
+           Month (macros are provided)
+    note
+           To help the reader find a reference (begins sentence)
+    number
+           Number of a journal or technical report
+    organization
+           Organization (sponsoring a conference)
+    pages
+           Page number or numbers (use `--' to separate a range)
+    publisher
+           Publisher name
+    school
+           School name (for theses)
+    series
+           The name of a series or set of books.
+           An individual book will will also have it's own title
+    title
+           The title of the thing being referenced
+    type
+           Type of a technical report (e.g., \"Research Note\") to be used
+           instead of the default \"Technical Report\"
+    volume
+           Volume of a journal or multivolume work
+    year
+           Year---should contain only numerals
+---------------------------------------------------------
+Entry to this mode calls the value of bibtex-mode-hook if that value is
+non-nil."
+  (interactive)
+  (kill-all-local-variables)
+  (if bibtex-mode-syntax-table
+      (set-syntax-table bibtex-mode-syntax-table)
+     (setq bibtex-mode-syntax-table (make-syntax-table))
+     (set-syntax-table bibtex-mode-syntax-table)
+     (modify-syntax-entry ?\" ".")
+     (modify-syntax-entry ?$ "$$  ")
+     (modify-syntax-entry ?% "<   ")
+     (modify-syntax-entry ?'  "w   ")
+     (modify-syntax-entry ?@  "w   ")
+     (modify-syntax-entry ?\\ "\\")
+     (modify-syntax-entry ?\f ">   ")
+     (modify-syntax-entry ?\n ">   ")
+     (modify-syntax-entry ?~ " "))
+  (use-local-map bibtex-mode-map)
+  (setq major-mode 'bibtex-mode)
+
+
+  (setq mode-name "BibTeX")
+  (set-syntax-table bibtex-mode-syntax-table)
+  (setq local-abbrev-table bibtex-mode-abbrev-table)
+  (make-local-variable 'paragraph-start)
+  (setq paragraph-start "^[ \f\n\t]*$")
+
+  (define-key bibtex-mode-map "\t" 'bibtex-find-text)
+  (define-key bibtex-mode-map "\n" 'bibtex-next-field)
+  (define-key bibtex-mode-map "\C-c\"" 'bibtex-remove-double-quotes)
+  (define-key bibtex-mode-map "\C-c\C-c" 'bibtex-clean-entry)
+  (define-key bibtex-mode-map "\C-c?" 'describe-mode)
+  (define-key bibtex-mode-map "\C-c\C-p" 'bibtex-pop-previous)
+  (define-key bibtex-mode-map "\C-c\C-n" 'bibtex-pop-next)
+  (define-key bibtex-mode-map "\C-c\C-k" 'bibtex-kill-optional-field)
+  (define-key bibtex-mode-map "\C-c\C-d" 'bibtex-empty-field)
+
+  (define-key bibtex-mode-map "\C-c\C-e\C-a" 'bibtex-Article)
+  (define-key bibtex-mode-map "\C-c\C-e\C-b" 'bibtex-Book)
+  (define-key bibtex-mode-map "\C-c\C-e\C-d" 'bibtex-DEAthesis)
+  (define-key bibtex-mode-map "\C-c\C-e\C-c" 'bibtex-InProceedings)
+  (define-key bibtex-mode-map "\C-c\C-e\C-i" 'bibtex-InBook)
+  (define-key bibtex-mode-map "\C-c\C-ei" 'bibtex-InCollection)
+  (define-key bibtex-mode-map "\C-c\C-eI" 'bibtex-InProceedings)
+  (define-key bibtex-mode-map "\C-c\C-e\C-m" 'bibtex-Manual)
+  (define-key bibtex-mode-map "\C-c\C-em" 'bibtex-MastersThesis)
+  (define-key bibtex-mode-map "\C-c\C-eM" 'bibtex-Misc)
+  (define-key bibtex-mode-map "\C-c\C-o" 'bibtex-remove-OPT)
+  (define-key bibtex-mode-map "\C-c\C-e\C-p" 'bibtex-PhdThesis)
+  (define-key bibtex-mode-map "\C-c\C-ep" 'bibtex-Proceedings)
+  (define-key bibtex-mode-map "\C-c\C-eP" 'bibtex-preamble)
+  (define-key bibtex-mode-map "\C-c\C-e\C-t" 'bibtex-TechReport)
+  (define-key bibtex-mode-map "\C-c\C-e\C-s" 'bibtex-string)
+  (define-key bibtex-mode-map "\C-c\C-e\C-u" 'bibtex-Unpublished)
+
+  (auto-fill-mode 1)			; nice alignements
+  (setq left-margin (+ bibtex-text-alignment 1))
+
+  (run-hooks 'bibtex-mode-hook))
+
+(defun bibtex-move-outside-of-entry ()
+  "Make sure we are outside of a bib entry"
+  (cond ((or
+	  (= (point) (point-max))
+	  (= (point) (point-min))
+	  (looking-at "[ \n]*@")
+	  )
+	 t)
+	(t
+	 (backward-paragraph)
+	 (forward-paragraph)))
+  (re-search-forward "[ \t\n]*" (point-max) t))
+
+;;
+;; note: this should really take lists of strings OR of lists.  in the
+;;       second case, one can use either list.  (ie:
+;;                "name" (("crossref") ("journal" "year"))     )
+;;
+
+(defun bibtex-entry (entry-type required optional)
+  (bibtex-move-outside-of-entry)
+  (insert "@" entry-type "{")
+  (mapcar 'bibtex-make-field required)
+  (if bibtex-include-OPTcrossref
+      (bibtex-make-optional-field "crossref"))
+  (if bibtex-include-OPTkey
+      (bibtex-make-optional-field "key"))
+  (mapcar 'bibtex-make-optional-field optional)
+  (if bibtex-mode-user-optional-fields		;MON...
+      (mapcar 'bibtex-make-optional-field
+	      bibtex-mode-user-optional-fields))
+  (if bibtex-include-OPTannote
+      (bibtex-make-optional-field "annote"))
+  (insert "\n}\n\n")
+  (forward-char -3)
+  (up-list -1)
+  (forward-char 1))  
+
+(defun bibtex-make-field (str)
+  (interactive "sBibTeX entry type: ")
+  (insert ",\n")
+  (indent-to-column bibtex-name-alignement)
+  (insert str " = ")
+  (indent-to-column bibtex-text-alignment)
+  (insert "\"\"")
+  nil)
+
+(defun bibtex-make-optional-field (str)
+  (interactive "sOptional BibTeX entry type: ")
+  (insert ",\n")
+  (indent-to-column bibtex-name-alignement)
+  (insert "OPT" str " = ")
+  (indent-to-column bibtex-text-alignment)
+  (insert "\"\"")
+  nil)
+
+;; What to do about crossref?  if present, journal and year are 
+;; both optional.  Due to this, i move all of them into optional. -- MON
+
+(defun bibtex-Article ()
+  (interactive)
+  (if bibtex-include-OPTcrossref
+      (bibtex-entry "Article" '("author" "title")
+		    '("journal" "year" "volume" "number" "pages"
+		      "month" "note"))
+    (bibtex-entry "Article" '("author" "title" "journal" "year")
+		  '("volume" "number" "pages" "month" "note"))))
+
+(defun bibtex-Book ()
+  (interactive)
+  (bibtex-entry "Book" '("author" "title" "publisher" "year")
+ 		'("editor" "volume" "number" "series" "address"
+		  "edition" "month" "note")))
+
+(defun bibtex-Booklet ()
+  (interactive)
+  (bibtex-entry "Booklet" '("title")
+		'("author" "howpublished" "address" "month" "year" "note")))
+
+;; France: Dipl\^{o}me d'Etudes Approfondies (similar to Master's)
+(defun bibtex-DEAthesis ()
+  (interactive)
+  (bibtex-entry "DEAthesis" '("author" "title" "school" "year")
+		'("address" "month" "note")))
+
+(defun bibtex-InBook ()
+  (interactive)
+  (if bibtex-include-OPTcrossref
+      (bibtex-entry "InBook" '("author" "title" "chapter")
+		    '("publisher" "year" "editor" "pages" "volume" "number"
+		      "series" "address" "edition" "month" "type" "note"))
+    (bibtex-entry "InBook" '("author" "title" "chapter" "publisher" "year")
+		  '("editor" "pages" "volume" "number" "series" "address"
+		    "edition" "month" "type" "note"))))
+
+;; In next 2, for crossref case, put pages near beginning of 
+;; optionals as it will be used most often  -- MON
+(defun bibtex-InCollection ()
+  (interactive)
+  (if bibtex-include-OPTcrossref
+      (bibtex-entry "InCollection" '("author" "title")
+		    '("pages" "booktitle" "publisher" "year"
+		      "editor" "volume" "number" "series" "type" "chapter"
+		      "address" "edition" "month" "note"))
+    (bibtex-entry "InCollection" '("author" "title"
+				   "booktitle" "publisher" "year")
+		  '("editor" "volume" "number" "series" "type" "chapter"
+		    "pages" "address" "edition" "month" "note"))))
+
+(defun bibtex-InProceedings ()
+  (interactive)
+  (if bibtex-include-OPTcrossref
+      (bibtex-entry "InProceedings" '("author" "title")
+		    '( "pages" "editor" "volume" "number" "series"
+		       "booktitle" "year"
+		       "organization" "publisher" "address" "month" "note"))
+    (bibtex-entry "InProceedings" '("author" "title" "booktitle" "year")
+		  '("editor" "volume" "number" "series" "pages"
+		    "organization" "publisher" "address" "month" "note"))))
+
+(defun bibtex-Manual ()
+  (interactive)
+  (bibtex-entry "Manual" '("title")
+		'("author" "organization" "address" "edition" "year"
+			   "month" "note")))
+
+(defun bibtex-MastersThesis ()
+  (interactive)
+  (bibtex-entry "MastersThesis" '("author" "title" "school" "year")
+		'("address" "month" "note" "type")))
+
+(defun bibtex-Misc ()
+  (interactive)
+  (bibtex-entry "Misc" '()
+		'("author" "title" "howpublished" "year" "month" "note")))
+
+(defun bibtex-PhdThesis ()
+  (interactive)
+  (bibtex-entry "PhdThesis" '("author" "title" "school" "year")
+		'("address" "month" "type" "note")))
+
+(defun bibtex-Proceedings ()
+  (interactive)
+  (bibtex-entry "Proceedings" '("title" "year")
+		'("editor" "volume" "number" "series" "publisher"
+		  "organization" "address" "month" "note")))
+
+(defun bibtex-TechReport ()
+  (interactive)
+  (bibtex-entry "TechReport" '("author" "title" "institution" "year")
+		'("type" "number" "address" "month" "note")))
+
+
+(defun bibtex-Unpublished ()
+  (interactive)
+  (bibtex-entry "Unpublished" '("author" "title" "note")
+		'("year" "month")))
+
+(defun bibtex-string ()
+  (interactive)
+  (bibtex-move-outside-of-entry)
+  (insert "@string{ = """"}\n")
+  (previous-line 1)
+  (forward-char 8))
+
+(defun bibtex-preamble ()
+  (interactive)
+  (bibtex-move-outside-of-entry)
+  (insert "@Preamble{}\n")
+  (previous-line 1)
+  (forward-char 10))
+
+(defun bibtex-next-field (arg)
+  "Finds end of text of next BibTeX field; with arg, to its beginning"
+  (interactive "P")
+  (bibtex-inside-field)
+  (let ((start (point)))
+    (condition-case ()
+	(progn
+	  (bibtex-enclosing-field)
+	  (goto-char (match-end 0))
+	  (forward-char 2))
+      (error
+       (goto-char start)
+       (end-of-line)
+       (forward-char 1))))
+  (bibtex-find-text arg))
+
+(defun bibtex-find-text (arg)
+  "Go to end of text of current field; with arg, go to beginning."
+  (interactive "P")
+  (bibtex-inside-field)
+  (bibtex-enclosing-field)
+  (if arg
+      (progn
+	(goto-char (match-beginning bibtex-text-in-field))
+	(if (looking-at "\"")
+	    (forward-char 1)))
+    (goto-char (match-end bibtex-text-in-field))
+    (if (= (preceding-char) ?\")
+	(forward-char -1))))
+
+(defun bibtex-remove-OPT ()
+  "Removes the 'OPT' starting optional arguments and goes to end of text"
+  (interactive)
+  (bibtex-inside-field)
+  (bibtex-enclosing-field)
+  (save-excursion
+    (goto-char (match-beginning bibtex-name-in-field))
+    (if (looking-at "OPT")
+	(delete-char (length "OPT"))))
+  (bibtex-inside-field))
+
+(defun bibtex-inside-field ()
+  "Try to avoid point being at end of a bibtex field."
+  (interactive)
+  (end-of-line)
+  (skip-chars-backward " \t")		;delete these chars? -- MON
+  (cond ((= (preceding-char) ?,)
+	 (forward-char -1)))
+  (cond ((= (preceding-char) ?\")
+	 (forward-char -1))))		;only go back if quote
+
+
+(defun bibtex-remove-double-quotes ()
+  "Removes """" around string."
+  (interactive)
+  (save-excursion
+    (bibtex-inside-field)
+    (bibtex-enclosing-field)
+    (let ((start (match-beginning bibtex-text-in-field))
+	  (stop (match-end  bibtex-text-in-field)))
+      (goto-char stop)
+      (forward-char -1)
+      (if (looking-at "\"")
+	  (delete-char 1))
+      (goto-char start)
+      (if (looking-at "\"")
+	  (delete-char 1)))))
+
+(defun bibtex-kill-optional-field ()
+  "Kill the entire enclosing optional BibTeX field"
+  (interactive)
+  (bibtex-inside-field)
+  (bibtex-enclosing-field)
+  (goto-char (match-beginning bibtex-name-in-field))
+  (let ((the-end (match-end 0))
+	(the-beginning (match-beginning 0)))
+    (if (looking-at "OPT")
+	(progn
+	  (goto-char the-end)
+	  (skip-chars-forward " \t\n,")
+	  (kill-region the-beginning the-end))
+      (error "Mandatory fields can't be killed"))))
+
+(defun bibtex-empty-field ()
+  "Delete the text part of the current field, replace with empty text"
+  (interactive)
+  (bibtex-inside-field)
+  (bibtex-enclosing-field)
+  (goto-char (match-beginning bibtex-text-in-field))
+  (kill-region (point) (match-end bibtex-text-in-field))
+  (insert "\"\"")
+  (bibtex-find-text t))
+
+
+(defun bibtex-pop-previous (arg)
+  "Replace text of current field with the text of similar field in previous entry.
+With arg, go up ARG entries.  Repeated, goes up so many times.  May be
+intermixed with \\[bibtex-pop-next] (bibtex-pop-next)."
+  (interactive "p")
+  (bibtex-inside-field)
+  (save-excursion
+    ; parse current field
+    (bibtex-enclosing-field)
+    (let ((start-old-text (match-beginning bibtex-text-in-field))
+	  (stop-old-text  (match-end bibtex-text-in-field))
+	  (start-name (match-beginning bibtex-name-in-field))
+	  (stop-name (match-end bibtex-name-in-field))
+	  (new-text))
+      (goto-char start-name)
+      ; construct regexp for previous field with same name as this one
+      (let ((matching-entry
+	     (bibtex-cfield
+	      (buffer-substring (if (looking-at "OPT")
+				    (+ (point) (length "OPT"))
+				  (point))
+				stop-name)
+	      bibtex-field-text)))
+	
+	; if executed several times in a row, start each search where the
+	; last one finished
+	(cond ((or (eq last-command 'bibtex-pop-previous)
+		   (eq last-command 'bibtex-pop-next))
+	       t
+	       )
+	      (t
+	       (bibtex-enclosing-reference)
+	       (setq bibtex-pop-previous-search-point (match-beginning 0))
+	       (setq bibtex-pop-next-search-point (match-end 0))))
+	(goto-char bibtex-pop-previous-search-point)
+	
+	; Now search for arg'th previous similar field
+	(cond
+	 ((re-search-backward matching-entry (point-min) t arg)
+	  (setq new-text
+		(buffer-substring (match-beginning bibtex-text-in-cfield)
+				  (match-end bibtex-text-in-cfield)))
+	  ; Found a matching field. Remember boundaries.
+	  (setq bibtex-pop-next-search-point (match-end 0))
+	  (setq bibtex-pop-previous-search-point (match-beginning 0))
+	  (bibtex-flash-head)
+	  ; Go back to where we started, delete old text, and pop new.
+	  (goto-char stop-old-text)
+	  (delete-region start-old-text stop-old-text)
+	  (insert new-text))
+	 (t				; search failed
+	  (error "No previous matching BibTeX field."))))))
+  (setq this-command 'bibtex-pop-previous))
+
+(defun bibtex-pop-next (arg)
+  "Replace text of current field with the text of similar field in next entry.
+With arg, go up ARG entries.  Repeated, goes up so many times.  May be
+intermixed with \\[bibtex-pop-previous] (bibtex-pop-previous)."
+  (interactive "p")
+  (bibtex-inside-field)
+  (save-excursion
+    ; parse current field
+    (bibtex-enclosing-field)
+    (let ((start-old-text (match-beginning bibtex-text-in-field))
+	  (stop-old-text  (match-end bibtex-text-in-field))
+	  (start-name (match-beginning bibtex-name-in-field))
+	  (stop-name (match-end bibtex-name-in-field))
+	  (new-text))
+      (goto-char start-name)
+      ; construct regexp for next field with same name as this one,
+      ; ignoring possible OPT's
+      (let ((matching-entry
+	     (bibtex-cfield
+	      (buffer-substring (if (looking-at "OPT")
+				    (+ (point) (length "OPT"))
+				  (point))
+				stop-name)
+	      bibtex-field-text)))
+	
+	; if executed several times in a row, start each search where the
+	; last one finished
+	(cond ((or (eq last-command 'bibtex-pop-next)
+		   (eq last-command 'bibtex-pop-previous))
+	       t
+	       )
+	      (t
+	       (bibtex-enclosing-reference)
+	       (setq bibtex-pop-previous-search-point (match-beginning 0))
+	       (setq bibtex-pop-next-search-point (match-end 0))))
+	(goto-char bibtex-pop-next-search-point)
+	
+	; Now search for arg'th next similar field
+	(cond
+	 ((re-search-forward matching-entry (point-max) t arg)
+	  (setq new-text
+		(buffer-substring (match-beginning bibtex-text-in-cfield)
+				  (match-end bibtex-text-in-cfield)))
+	  ; Found a matching field. Remember boundaries.
+	  (setq bibtex-pop-next-search-point (match-end 0))
+	  (setq bibtex-pop-previous-search-point (match-beginning 0))
+	  (bibtex-flash-head)
+	  ; Go back to where we started, delete old text, and pop new.
+	  (goto-char stop-old-text)
+	  (delete-region start-old-text stop-old-text)
+	  (insert new-text))
+	 (t				; search failed
+	  (error "No next matching BibTeX field."))))))
+  (setq this-command 'bibtex-pop-next))
+
+(defun bibtex-flash-head ()
+  "Flash at BibTeX reference head before point, if exists.  (Moves point)."
+  (let ((flash))
+    (cond ((re-search-backward bibtex-reference-head (point-min) t)
+	   (goto-char (match-beginning bibtex-type-in-head))
+	   (setq flash (match-end bibtex-key-in-reference)))
+	  (t
+	   (end-of-line)
+	   (skip-chars-backward " \t")
+	   (setq flash (point))
+	   (beginning-of-line)
+	   (skip-chars-forward " \t")))
+    (if (pos-visible-in-window-p (point))
+	(sit-for 1)
+      (message "From: %s"
+	       (buffer-substring (point) flash)))))
+
+
+
+(defun bibtex-enclosing-field ()
+  "Search for BibTeX field enclosing point.
+Point moves to end of field; also, use match-beginning and match-end
+to parse the field."
+  (condition-case errname
+      (bibtex-enclosing-regexp bibtex-field)
+    (search-failed
+     (error "Can't find enclosing BibTeX field."))))
+
+(defun bibtex-enclosing-reference ()
+  "Search for BibTeX reference enclosing point.
+Point moves to end of reference; also, use match-beginning and match-end
+to parse the reference."
+  (condition-case errname
+      (bibtex-enclosing-regexp bibtex-reference)
+    (search-failed
+     (error "Can't find enclosing BibTeX reference."))))
+
+(defun bibtex-enclosing-regexp (regexp)
+  "Search for REGEXP enclosing point.
+Point moves to end of REGEXP.  See also match-beginning and match-end.
+If an enclosing REGEXP is not found, signals search-failed; point is left in
+an undefined location.
+
+[Doesn't something like this exist already?]"
+  
+  (interactive "sRegexp: ")
+  ; compute reasonable limits for the loop
+  (let* ((initial (point))
+	 (right (if (re-search-forward regexp (point-max) t)
+		    (match-end 0)
+		  (point-max)))
+	 (left
+	  (progn
+	    (goto-char initial)
+	    (if (re-search-backward regexp (point-min) t)
+		(match-beginning 0)
+	      (point-min)))))
+    ; within the prescribed limits, loop until a match is found
+    (goto-char left)
+    (re-search-forward regexp right nil 1)
+    (if (> (match-beginning 0) initial)
+	(signal 'search-failed (list regexp)))	  
+    (while (<= (match-end 0) initial)
+      (re-search-forward regexp right nil 1)
+      (if (> (match-beginning 0) initial)
+	  (signal 'search-failed (list regexp))))
+    ))
+
+(defun bibtex-clean-entry ()
+  "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."
+  (interactive)
+  (bibtex-enclosing-reference)
+  (goto-char (match-beginning 0))
+  (let ((start (point)))
+    (save-restriction
+      (narrow-to-region start (match-end 0))
+      (while (re-search-forward bibtex-field (point-max) t 1)
+	(let ((begin-field (match-beginning 0))
+	      (end-field (match-end 0))
+	      (begin-name (match-beginning bibtex-name-in-field))
+	      (end-name (match-end  bibtex-name-in-field))
+	      (begin-text (match-beginning bibtex-text-in-field))
+	      (end-text (match-end bibtex-text-in-field))
+	      )
+	  (goto-char begin-name)
+	  (cond ((and
+		  (looking-at "OPT")
+		  bibtex-clean-entry-zap-empty-opts)
+		 (goto-char begin-text)
+		 (if (looking-at "\"\"") ; empty: delete whole field
+		     (delete-region begin-field end-field)
+		   ; otherwise: not empty, delete "OPT"
+		   (goto-char begin-name)
+		   (delete-char (length "OPT"))
+		   (goto-char begin-field) ; and loop to go through next test
+		   ))
+		(t
+		 (goto-char begin-text)
+		 (cond ((looking-at "\"[0-9]+\"") ; if numerical,
+			(goto-char end-text)
+			(delete-char -1) ; delete enclosing double-quotes
+			(goto-char begin-text)
+			(delete-char 1)
+			(goto-char end-field) ; go to end for next search
+			(forward-char -2) ; to compensate for the 2 quotes deleted
+			)
+		       ((looking-at "\"\"") ; if empty quotes, complain
+			(forward-char 1)
+			(if (not (or (equal (buffer-substring
+					     begin-name
+					     (+ begin-name 3))
+					    "OPT")
+				     (equal (buffer-substring
+					     begin-name
+					     (+ begin-name 3))
+					    "opt")))
+			    (error "Mandatory field ``%s'' is empty"
+				   (buffer-substring begin-name end-name))))
+		       (t
+			(goto-char end-field))))))))
+    (goto-char start)
+    (skip-chars-forward "@a-zA-Z")
+    (bibtex-enclosing-reference)
+    (goto-char (match-end 0))
+    (skip-chars-forward " \t\n")))
+
+
+
+;;; X window menus for bibtex mode
+
+(defun bibtex-x-help (arg)
+  "Mouse commands for BibTeX mode"
+  
+  (let ((selection
+	 (x-popup-menu
+	  arg
+	  '("BibTeX commands"
+	    ("BibTeX entry types"
+	     (" article in conference Proceedings " . bibtex-InProceedings)
+	     ("        Article in journal         " . bibtex-Article)
+	     ("               Book                " . bibtex-Book)
+	     ("             Booklet               " . bibtex-Booklet)
+	     ("            Conference	          " . bibtex-InProceedings)
+	     ("         Master's Thesis           " . bibtex-MastersThesis)
+	     ("            DEA Thesis             " . bibtex-DEAthesis)
+	     ("            Phd. Thesis            " . bibtex-PhdThesis)
+	     ("         Technical Report          " . bibtex-TechReport)
+	     ("         technical Manual          " . bibtex-Manual)
+	     ("      conference Proceedings       " . bibtex-Proceedings)
+	     ("        a chapter in a Book        " . bibtex-InBook)
+	     ("    an article in a Collection     " . bibtex-InCollection)
+	     ("           miscellaneous           " . bibtex-Misc)
+	     ("            unpublished            " . bibtex-Unpublished)
+	     ("              string               " . bibtex-string)
+	     ("             preamble              " . bibtex-preamble)
+	     )
+	    ("Moving around and editing"
+	     ("            next field             " . bibtex-next-field)
+	     ("          to end of field          " . bibtex-find-text)
+	     ("snatch from similar preceding field" . bibtex-pop-previous)
+	     ("snatch from similar following field" . bibtex-pop-next)
+	     ("            remove OPT             " . bibtex-remove-OPT)
+	     ("           remove quotes           "
+	      . bibtex-remove-double-quotes)
+	     ("          clean up entry           " . bibtex-clean-entry)
+	     )
+	    ("help"
+	     ("       describe BibTeX mode        " . describe-mode)
+	     )))))
+    (and selection (call-interactively selection))))
+
+(defun bibtex-x-environment ()
+  "Set up X menus for BibTeX mode.  Call it as bibtex-mode-hook, or interactively"
+  (interactive)
+  (require 'x-mouse)
+  (define-key mouse-map x-button-c-right 'bibtex-x-help)
+  )
+
+
+
+;; Please don't send anything to bug-gnu-emacs about these Sunwindows functions
+;; since we aren't interested.  See etc/SUN-SUPPORT for the reasons why
+;; we consider this nothing but a distraction from our work.
+
+(if (fboundp 'defmenu)
+    (progn
+
+(defmenu bibtex-sun-entry-menu 
+  ("Article In Conf. Proc."
+   (lambda () (eval-in-window *menu-window* (bibtex-InProceedings))))
+  ("Article In Journal"
+   (lambda () (eval-in-window *menu-window* (bibtex-Article))))
+  ("Book"
+   (lambda () (eval-in-window *menu-window* (bibtex-Book))))
+  ("Booklet"
+   (lambda () (eval-in-window *menu-window* (bibtex-Booklet))))
+  ("Master's Thesis"
+   (lambda () (eval-in-window *menu-window* (bibtex-MastersThesis))))
+  ;;("DEA Thesis" bibtex-DEAthesis)
+  ("PhD. Thesis"
+   (lambda () (eval-in-window *menu-window* (bibtex-PhdThesis))))
+  ("Technical Report"
+   (lambda () (eval-in-window *menu-window* (bibtex-TechReport))))
+  ("Technical Manual"
+   (lambda () (eval-in-window *menu-window* (bibtex-Manual))))
+  ("Conference Proceedings"
+   (lambda () (eval-in-window *menu-window* (bibtex-Proceedings))))
+  ("In A Book"
+   (lambda () (eval-in-window *menu-window* (bibtex-InBook))))
+  ("In A Collection"
+   (lambda () (eval-in-window *menu-window* (bibtex-InCollection))))
+  ("Miscellaneous"
+   (lambda () (eval-in-window *menu-window* (bibtex-Misc))))
+  ("Unpublished"
+   (lambda () (eval-in-window *menu-window* (bibtex-Unpublished)))))
+
+(defmenu bibtex-sun-menu
+  ("BibTeX menu")
+  ("add entry" . bibtex-sun-entry-menu)
+  ("add string"
+   (lambda () (eval-in-window *menu-window* (bibtex-string))))
+  ;("next field" bibtex-next-position)
+  ;("to end of field" bibtex-find-it)
+;  ("remove OPT"
+;   (lambda () (eval-in-window *menu-window* (bibtex-remove-opt))))
+;  ("remove quotes"
+;   (lambda () (eval-in-window *menu-window* (bibtex-remove-double-quotes))))
+;  ("remove this line"
+;   (lambda () (eval-in-window *menu-window* (kill-current-line))))
+  ("describe BibTeX mode"
+   (lambda () (eval-in-window *menu-window* (describe-mode))))
+  ("Main Emacs menu" . emacs-menu))
+ 
+(defun bibtex-sun-menu-eval (window x y)
+  "Pop-up menu of BibTeX commands."
+  (sun-menu-evaluate window (1+ x) (1- y) 'bibtex-sun-menu))
+
+(defun bibtex-sun-environment ()
+  "Set up sun menus for BibTeX mode.  Call it as bibtex-mode-hook, or interactively"
+  (interactive)
+  (local-set-mouse  '(text right) 'bibtex-sun-menu-eval))
+
+))  ; matches (if...
+
+;;; ------------- end bibtex-mode.el -------------------------------