[net.sources] TeX/LaTeX/BibTeX support for Emacs-264

dmj@uw-beaver (David Jacobson) (02/24/86)

Quite some time ago I sent a message to net.emacs that I had an extensive
TeX/LaTex/BibTeX support package that ran under Goslings Emacs-264.
Here it is. 

First there are 3 mlisp files:  TeX-mode.ml, TeX-justify.ml, and
bibTeX.ml.  The bibTeX system requires that you install somewhere
a directory, which I have called "bibshells" that contians a whole
collection of files telling bibTeX how to make article,
techreport, etc., entries.  The 4th big chunk of this file is that
directory, collected together in "ar" format.  The installer must
create this directory, cd to it, and use "ar x" to decompose the
4th portion of this file into the things that go into bibshells.
(Or just do it with an editor.  It's not that big.)  Then s/he
must find the first few lines of bibTeX.ml right after the opening
comments and change them according to where the bibshells
directory is created.

The beginning of each .ml file contains instructions for how to
use the stuff implemented in it.  

Long rows of ===== separate the portions of this message.

=========================================================
TeX-mode.ml
=========================================================
;  Originally from somewhere.  Extensively modified by dmj@uw-june
;  Last edited Feb. 19, 1986.
; 
; The following extensions/modifications to the original TeX-mode 
; have been made:
; 
; 1.  Since double-quotes are normalling illegal in TeX, unless the
;     variable TeX-expand-quote is set, typing a '"' issues a warning.
; 2.  The function "TeX-$" and its subsidiary "in-math-mode" were recoded
;     for greater speed, at least on Emacs-264.
; 3.  ESC-\ makes prompts for a LaTeX environment (?) name.  Say you
;     type "foo".  It inserts \begin{foo}   \end{foo}, in a (hopefully)
;     pleasing arrangement.  The mark is left right after the \begin{foo}
;     so you can use ^X-^X (exchange-dot-and-mark) to insert parameters
;     and return to your former place.
; 4.  Suppose the last braced command you typed was "{\foo ... }"
;     The next time you type "{", simply typing a space will insert \foo.
;     Note, the string foo is captured when its closing "}" was typed.
;     As an experimental feature, it forgets the string if you don't
;     use it for a while (twice, right now).
; 5.  ESC-m on a word will surround the word with "{\em ... }"
; 6.  ESC-j will justify a paragraph.  It works very hard to do this right.
;     Paragraphs are bounded by blanks or by \begin or \end or by
;     TeX comments ("% ...").   It will not break a \verb+ ... +.  (+ 
;     is not special.  Any character except blank will do.)  Neither
;     "\%" nor "\verb+  %  +" will be considered comments.
;     It uses the following to determine the right margin, in order of
;     increasing priority: current right margin - 10, the buffer specific 
;     variable "justify-right-margin", a ^U prefix. TeX-justify is in
;     a separate file, TeX-justify.ml.
; 7.  If the text is like "\cite{Knuth84}", with the cursor on Knuth84, the
;     bibTeX.ml function "describe-cite-in-buffer" will be invoked to
;     display the citation in another window.
; 
; As for as the original TeX-mode code goes, I (dmj) am not even sure
; what some of it is supposed to do.  Here is what some of the stuff
; not mentioned above does.
; 
; $ is bound to TeX-$ which at the end of a math mode region bounces to 
; the matching $ at the beginning of the math region.  Since the beginning
; ending are both delimited by $, it has to search from the beginning of the
; file.  This can get slow, so somewhere where you are sure you are not in
; math mode, hit ESC-$, which is bound to TeX-end-math-region.  This will put
; in the string "%emacs-mathOK".  TeX-$ only searches back as far as the
; nearest occurance of this.
; 
; TeX-brace is what "}" was formerly bound to.  

(if (! (is-bound TeX-cmd-string))
    (progn (declare-global TeX-cmd-string)
	   (setq TeX-cmd-string ""))
)

(declare-global TeX-cmd-cnt)

(defun 
    
    (TeX-warn-character
	(insert-character (last-key-struck))
	(error-message "Really?")
    )
    
    (TeX-double-quote lpos rpos
	(if (= '\134' (preceding-char))
	    (insert-character '"')
	    (progn 
		   (save-excursion 
		       (setq lpos 0)
		       (setq rpos 0)
		       (set-mark)
		       (error-occurred 
			   (search-reverse "``")
			   (setq lpos (dot))
			   (exchange-dot-and-mark)
			   (search-reverse "''")
			   (setq rpos (dot)))
		   )
		   (if (> lpos rpos)
		       (insert-string "''")
		       (insert-string "``"))))
    )
    
    (insert-TeX-aux-macros
	(beginning-of-line)
	(insert-string (concat "% \\noflash{...text...} makes a box as wide"
			       " as its arg, but which is whitespace\n"
			       "\\def\\noflash#1{\\setbox0=\\hbox{#1}\\hbox"
			       " to 1\\wd0{\\hfill}}\n"))
    )
    
    
    (skip-white-space
	(re-search-forward "[^	 ]")
	(backward-character)
    )
    
    (setup-indented-TeX-display prior nfl-ins padding col
	(save-excursion 
	    (delete-region-to-buffer "TeX indent temp")
	    (temp-use-buffer "TeX indent temp")
	    (beginning-of-file)
	    (setq padding "                    ")
	    (setq prior padding)
	    (while (! (eobp))
		   (skip-white-space)
		   (setq col (current-column))
		   (delete-white-space)
		   (if (eolp)
		       (insert-string "\\vskip 5pt")
		       (progn 
			      (setq nfl-ins (substr prior 1 (- col 1)))
			      (if (= (length nfl-ins) 0)
				  (insert-string "\\hbox{")
				  (insert-string (concat "\\hbox{\\noflash{"
							 nfl-ins "}")))
			      (set-mark)
			      (end-of-line)
			      (setq prior (concat nfl-ins (region-to-string)
						  padding))
			      (insert-character '}'))
		   )
		   (next-line)
		   (beginning-of-line)
	    )
	    (insert-character '}')
	    (beginning-of-file)
	    (insert-string "\\vbox{")
	)
	(yank-buffer "TeX indent temp")
	(novalue)
    )
    
    
    (unsetup-indented-TeX-display
	(search-reverse "\\vbox{")
	(set-mark)
	(forward-paren)
	(save-excursion 
	    (delete-region-to-buffer "TeX indent temp")
	    (temp-use-buffer "TeX indent temp")
	    (end-of-file)
	    (delete-previous-character)
	    (beginning-of-file)
	    (provide-prefix-argument 6 (delete-next-character))
	    (while (! (eobp))
		   (delete-next-character)
		   (if (!= 'h' (following-char))
		       ; a \vskip line (blank)
		       (kill-to-end-of-line)
		       ; an \hbox line
		       (progn
			     (provide-prefix-argument 5
				 (delete-next-character))
			     (if (= '\134' (following-char)); backslash
				 (replace-noflash))
			     (end-of-line)
			     (delete-previous-character)
		       )
		   )
		   (next-line)
		   (beginning-of-line)
	    )
	)
	(yank-buffer "TeX indent temp")
	(novalue)
    )
    
    (replace-noflash col
	(set-mark)
	(search-forward "}")
	(setq col (current-column))
	(delete-to-killbuffer)
	(to-col (- col 10))
    )
    
    
    (in-math-mode  mm-count 
	(save-excursion 
	    (insert-character ' ')
	    (set-mark)
	    (if (error-occurred (search-reverse "%emacs-mathOK"))
		(beginning-of-file))
	    (save-restriction 
		(narrow-region)
		(if (= '\$' (following-char))
		    (setq mm-count 1)
		    (setq mm-count 0))
		(while (! (error-occurred 
			      (re-search-forward "[^\\\$]\$\$*[^\$]")
			      (backward-character))
		       )
		       (setq mm-count (+ mm-count 1))
		)
		(end-of-file)
		(delete-previous-character); kill space
	    ) 			;  end of save-restriction
	)			;  end of save-excursion
	(% mm-count 2)
    )
    
    
    (TeX-end-math-region
	(if (in-math-mode)
	    (error-message "You're still in math mode!")
	    (progn 
		   (if (! (bolp))
		       (insert-character '\n'))
		   (insert-string "%emacs-mathOK\n")
	    )
	)
    )
    
    (check-too-many-$ l$
	; Checks if 3 $s are just before cursor.
	; Complains in \$$$ case as well.
	(save-excursion 
	    (setq l$ (dot))
	    (while (= (preceding-char) '$')
		   (backward-character))
	    (if (> (- l$ (dot)) 2)
		(error-message "Too many '$'s"))
	)
    )
    
    (rev-find-mm$
	(error-occurred 
	    (re-search-reverse "[^\\\$]\$\$*[^\$]")
	    (forward-character))
    )
    
    (TeX-$ c
	   (setq c (preceding-char))
	   (insert-character (last-key-struck))
	   (if (& (!= c '\134') (! (in-math-mode))) ; \134 = backslash
	       (save-excursion 
		   (if (! (eobp))
		       (re-search-reverse "[^\\\$]\$\$*[^\$]"))
		   (if (error-occurred 
			   (re-search-reverse "[^\\\$]\$\$*[^\$]")
			   (forward-character))
		       (beginning-of-file))		      
		   (if (dot-is-visible)
		       (sit-for 5)
		       (progn
			     (beginning-of-line)
			     (set-mark)
			     (end-of-line)
			     (message (region-to-string)))
		   )
	       )
	   )
	   (check-too-many-$) 
    )
    
    
    (c-paren
	    (insert-character (last-key-struck))
	    (save-excursion
		(backward-paren)
		(if (dot-is-visible)
		    (sit-for 5)
		    (progn
			  (beginning-of-line)
			  (set-mark)
			  (end-of-line)
			  (message (region-to-string)))
		)
	    )
    )
    
    (TeX-brace
	(if (= (preceding-char) '\134'); backslash
	    (insert-character (last-key-struck))
	    (c-paren)
	)
    )
    
    ; TeX-begin leaves the mark at the end of \begin{...} 
    ; the dot on the next line
    ; and \end{...} after that.  Hence you can add parameters by simply doing 
    ; ^X-^X and get back to the text area with another ^X-^X.
    
    (TeX-begin env-name current-col 
	(setq env-name (arg 1 "\\begin: "))
	(setq current-col (current-column))
	(insert-string "\\begin{")
	(insert-string env-name)
	(insert-character '}')
	(set-mark)
	(newline)
	(to-col current-col)
	(save-excursion 
	    (newline)
	    (to-col current-col)
	    (insert-string "\\end{")
	    (insert-string env-name)
	    (insert-character '}')
	    (if (| (! (eolp)) (eobp)) 
		(progn (newline)
		       (to-col current-col)
		)
	    )
	    (if (! (dot-is-visible)) (sit-for 0))
	)
    )
    
    (TeX-left-brace char prevchar
	(setq prevchar (preceding-char))
	(insert-character (last-key-struck))
	(if (& (!= TeX-cmd-string "")
	       (> TeX-cmd-cnt 0)
	       (!= prevchar '\134')  ; backslash
	    )
	    (progn 
		   (message "<space> => " TeX-cmd-string)
		   (setq char (get-tty-character))
		   (if (= char ' ')
		       (progn 
			      (insert-string TeX-cmd-string)
			      (setq TeX-cmd-cnt 2)
		       )
		       (setq TeX-cmd-cnt (- TeX-cmd-cnt 1))
		   )
		   (push-back-character char)
	    )
	)
    )
    
    (TeX-right-brace
	(if (= (preceding-char) '\134');  backslash
	    (insert-character (last-key-struck))
	    (progn 
		   (save-excursion 
		       (backward-paren)
		       (forward-character)
		       (if (= (following-char) '\134'); backslash
			   (progn (set-mark)
				  (forward-word)
				  (setq TeX-cmd-string (region-to-string))
				  (setq TeX-cmd-cnt 2)
			   )
		       )
		   )
		   (c-paren)
	    )
	)
    )
    
    (TeX-emphasize-word word-beg
	(error-occurred (forward-character))
	(backward-word)
	(setq word-beg (dot))
	(backward-word)
	(forward-word)
	(if (& (= (following-char) '}')
	       (save-excursion 
		   (forward-character)
		   (backward-paren)
		   (looking-at "{\\\\em"))
	    )
	    (progn (delete-next-character)
		   (goto-character word-beg))
	    (progn (goto-character word-beg)
		   (insert-string "{\\em "))
	)
	(forward-word)
	(insert-character '}')
	(forward-word)
	(if (! (eobp)) (backward-word))
    )
    
    (TeX-mode
	(local-bind-to-key "TeX-justify-paragraph" (+ 128 'j'))
	(local-bind-to-key "TeX-end-math-region" (+ 128 '$'))
	(local-bind-to-key "TeX-right-brace" '}')
	(local-bind-to-key "TeX-left-brace" '{')
	(local-bind-to-key "TeX-begin" "\e\134"); ESC-backslash
	(local-bind-to-key "TeX-emphasize-word" "\em"); pun?
	(local-bind-to-key "describe-cite-in-buffer" "\^X\^D")
	(if (! (is-bound TeX-inhibit-$))
	    (local-bind-to-key "TeX-$" '$'))
	(if (is-bound TeX-expand-quote)
	    (local-bind-to-key "TeX-double-quote" '\"')
	    (local-bind-to-key "TeX-warn-character" '\"'))
	(setq right-margin 77)
	(setq mode-string "TeX")
	(setq case-fold-search 1)
	(use-syntax-table "TeX-mode")
	(modify-syntax-entry "()   (")
	(modify-syntax-entry "(]   [")
	(modify-syntax-entry "(}   {")
	(modify-syntax-entry ")(   )")  
	(modify-syntax-entry ")[   ]")
	(modify-syntax-entry "){   }")
	(modify-syntax-entry "\\    \134")
	(use-abbrev-table "text-mode")
	(setq left-margin 1)
	(if (is-bound TeX-mode-hook)
	    (execute-mlisp-line TeX-mode-hook)
	)
	(novalue)
    )
)

(autoload "TeX-justify-paragraph" "TeX-justify.ml")
(autoload "describe-cite-in-buffer" "bibTeX.ml")
(novalue)
==========================================================
TeX-justify.ml
==========================================================
; Written by dmj@june.
; Last edited Feb. 19, 1986
; 
; By defining and assigning to the variable 
; justify-right-margin you can make it leave more right margin on the
; right than it normally would.  This is convenient, since maximum
; readability, at least for me, occurs at about 66 columns.  But I would
; like to keep the right margin at the default (77) so it will not break 
; long lines while I am trying to type in equations, tables, and the like.
; 
; 
; 
; KNOWN BUGS AND DEFICIENCIES:
; 
; For some unknown reason it sometimes scrolls the window a little.
; 
; Lines with \verbs come out a little short.
; This is because before justification \verbs are expanded by ceiling log10 n 
; characters plus one more if the first character is a space, comma, or 
; digit.  
; 
; There may be trouble if the character immediately following \verb is white.
; 


(defun
    (sentence-end ch 
	(save-excursion 
	    (while (| (= (setq ch (preceding-char)) ')')
		      (= ch '"')
		      (= ch '\'')
		      (= ch ']')
		      (= ch '}'))
		   (if (! (bobp)) (backward-character))
	    )
	    (setq ch (preceding-char))
	    (| (= ch '.')
	       (= ch '?')
	       (= ch ':')
	       (= ch '!'))
	)
    )
    
    (TeX-j-bndy
	(& (looking-at "[ \t]*$\\|%\\|.*[^\n\\]%\\|\\\\begin\\|\\\\end")
	   ; a fast, although too permisive, condition
	   (| (looking-at "[ \t]*$\\|%\\|\\\\begin\\|\\\\end")
	      ; white or leading %, \begin, or \end 
	      (save-excursion found-% delim-str search-str
		  (setq found-% 0)
		  (set-mark)
		  (end-of-line)
		  (exchange-dot-and-mark)
		  (save-restriction 
		      (narrow-region)
		      (while (& (! found-%)
				(! (error-occurred 
				       (re-search-forward 
					   "\\=%\\|[^\n\\]%\\|\\\\verb")))
			     )
			     (if (= (preceding-char) '%')
				 (setq found-% 1)
				 (error-occurred 
				     (setq delim-str 
					   (char-to-string (following-char)))
				     (forward-character)
				     (search-forward delim-str))
				 (end-of-line)
			     )
		      )
		  )
		  found-%
	      )
	   )
	)
    )


; The length of the actual verbatim string is placed right after the opening
; dilimiter.  A comma is added if the first character is a comma, a space,
; or a digit.  Then all spaces are replaced by the delimiter.

    (TeX-encode-verbs delim-char found-some size
	(setq found-some 0)
	(save-restriction 
	    (narrow-region)
	    (save-excursion 
		(beginning-of-file)
		(while (! (error-occurred 
			      (search-forward "\\verb")))
		       (setq found-some 1)
		       (setq delim-char (following-char))
		       (forward-character)
		       (set-mark)
		       (search-forward (char-to-string delim-char))
		       (backward-character)
		       (exchange-dot-and-mark)
		       (setq size (- (mark) (dot)))
		       (insert-string size)
		       (if (looking-at "[ ,0-9]") (insert-character ','))
		       (save-restriction 
			   (narrow-region)
			   (error-occurred 
			       (replace-string " " 
				   (char-to-string  delim-char)))
			   (end-of-file)
		       )
		)
	    )
	)
	found-some
    )
    
    
    (TeX-decode-verbs delim-char size
	(save-restriction 
	    (narrow-region)
	    (save-excursion 
		(beginning-of-file)
		(while (! (error-occurred 
			      (search-forward "\\verb")))
		       (setq delim-char (following-char))
		       (forward-character)
		       (set-mark)
		       (re-search-forward "[0-9]*")
		       (setq size (+ (region-to-string) 0))
		       (erase-region)
		       (if (= (following-char) ',') (delete-next-character))
		       (set-mark)
		       (goto-character (+ (dot) size))
		       (exchange-dot-and-mark)
		       (save-restriction 
			   (narrow-region)
			   (error-occurred 
			       (replace-string 
				   (char-to-string delim-char) " "))
			   (end-of-file)
		       )
		)
	    )
	)
    )
    
    
    
    (TeX-justify-paragraph old-right-margin did-move dot-char msg 
	(setq old-right-margin right-margin)
	(if prefix-argument-provided
	    (setq right-margin prefix-argument)
	    (& (is-bound justify-right-margin) (> justify-right-margin 0))
	    (setq right-margin justify-right-margin)
	)
	(setq dot-char (following-char))
	(save-excursion
	    (beginning-of-line)
	    ; kludge so that if we have just finished a paragraph we still 
	    ; justify it
	    (if (looking-at "[ \t]*$") ; white line pattern also matches eob
		(progn (previous-line)(beginning-of-line)))
	    ; find beginning of paragraph
	    (setq did-move 0)
	    (while (& (! (bobp))
		      (! (TeX-j-bndy)))
		   (progn (previous-line)
			  (beginning-of-line)
			  (setq did-move 1))
	    )
	    (if (& did-move (TeX-j-bndy))
		(progn (next-line)(beginning-of-line)))
	    
	    ; now we are at the beginning of the paragraph 
	    ; and beginning of line
	    
	    (set-mark)		; only used in fixing verbs
	    
	    (if (! (TeX-j-bndy))
		(progn last-col c-col need-to-decode-verbs
		       (setq need-to-decode-verbs 0)
		       (delete-white-space)
		       ; get first line to come out right if left margin 
		       ; is not 1
		       (to-col left-margin)
		       
		       ; make the whole paragraph into one long line
		       
		       (end-of-line)
		       (error-occurred (forward-character))
		       ; loop invariant is beginning of line following long 
		       ; line or end of buffer
		       (while  (! (TeX-j-bndy))
			       ; this will also match end-of-buffer
			       ; delete the new-line to make a longer line
			       (delete-previous-character)
			       (delete-white-space)
			       ; check for end-of-sentence.  
			       ; If so, add an extra space.
			       (if (sentence-end)
				   (insert-character ' '))
			       (insert-character ' ')
			       (end-of-line)
			       (error-occurred (forward-character))
		       )
		       ; reassemble into lines of the right length
		       ; but first get back to end of the real line
		       (if (bolp) (backward-character))
		       
		       (setq need-to-decode-verbs (TeX-encode-verbs))
		       
		       (setq c-col (current-column))
		       (while (progn
				    (setq last-col c-col)
				    (insert-character '!')
				    (delete-previous-character)
				    (end-of-line)
				    (setq c-col (current-column))
				    (< c-col last-col))
		       )
		       
		       (if need-to-decode-verbs (TeX-decode-verbs))
		       
		       (setq msg "Done!")
		)  		; end of giant progn
		(setq msg "Nothing to justify")
	    )			; end of giant if
	    
	)			; end of save-excursion
	
	; save-excursion uses sticky pointers.  We delete white space at 
	; end of lines and then re-insert it, which leaves the sticky 
	; pointer to the left of the space rather that to the right if 
	; that was where it was originally was.  So here we fix it up.
	; If there was nothing to justify, this will just be a no-op anyway.
	
	(if (& (!= dot-char (following-char))
	       (!= dot-char ' ')
	       (!= dot-char '\t')
	       (!= dot-char '\n'))
	    (error-occurred 
		(search-forward (char-to-string dot-char))
		(backward-character)
	    )
	)
	(setq right-margin old-right-margin)
	(message msg)
	(novalue)
    )
)
================================================================
bibTeX.ml
================================================================
; BibTeX-mode, by David Jacobson, dmj@uw-june
; Last edited Feb. 19, 1986
; This provides help for editing .bib files for BibTeX.  
; Several functions are provided:
; 
; find-key will find a specified key in a sorted .bib file or find the place 
; where that key should be inserted.  
; 
; @article will insert a shell with all the possible fields for an article
; @<entry-type> will do the same for the other legal entry-types.
; 
; next-field (ESC-n) will move to the next un-filled-in field and announce 
; whether it is required, optional, etc.  If next-field is invoked from
; the text portion of an empty field (typically dot is inside ""), 
; that field is deleted, except on the key, in which case the last value 
; used in a find-key will be inserted.
; 
; justify-field (ESC-j) will justify a field.
; 
; forward-entry and backward-entry do the obvious.  They are bound to ESC-] 
; and ESC-[
; 
; If the global varible bibliography-shell-directory is defined, 
; the shells will be taken from there.
; 
; If the global variable extra-bib-fields-file is defined, the contents of 
; the named file will be added after the last field;  commas are fixed.
; 
; The function describe-abbrev-in-buffer (^X-^D) describes the bibTeX 
; abbreviation under the cursor.  Once it has been invoked there will be a 
; buffer named Bib-Abbrevs.  It can be perused to see all abbreviations.
; 
; The function describe-cite-in-buffer is intended to be invoked in another
; buffer.  (It is bound to ^X-^D in TeX-mode buffers.)  It finds the
; bibliography entry corresponding to the citation under the dot and
; displays it in another window.  If the same directory as the current
; file contains a file named .bibfile, the name of the bibliography
; file is taken from there.  (No shell metacharacters like ~ or .., please.)
; If no .bibfile exists, the user is prompted for a file name.
; To change the bibfile used by a buffer set the buffer specific
; variable bibliography-file to the name of the desired file.
; 
; 
; BUGS and LIMITATIONS:
;
; justify-field requires the field be delimited by '"' marks.  
; 
; find-key is based on collating sequence rather than alphabetical order.
; 
; The @<entry-type> functions are not undoable, neither is the first
; invocation of describe-abbrev-in-buffer or describe-cite-in-buffer.
; 
; The @<entry-type> functions conflict with the same ones in Scribe-mode.  
; Loading both packages at once will make one of them inoperative.
; 
; When saving a file after invoking any @<entry-type> function, the system
; will often give a warning approximately "File has been modified, do you
; want to overwrite it?"  This is because of an emacs bug.  Reply yes.
; 
; Describe-cite-in-buffer malfunctions when invoked in its own bibfile.
; 
; The re's that describe the beginning of an entry are not all consistent.
; It's sloppiness, not a feature.
; 
; NOTE TO INSTALLERS:
; 
; Hard coded is the directory ~dmj/latex/bibshells/ just below.  If this 
; is installed on machines other than uw-june, that entire directory must be
; copied and the new name must replace that below.  
; 

(defun 
    
    (insert-bib-shell bibshelldir
	(setq bibshelldir "~dmj/latex/bibshells")
	(if (is-bound bibliography-shell-directory)
	    (setq bibshelldir bibliography-shell-directory))
	(insert-file (concat bibshelldir "/" 
			     (arg 1 "Bibliography type: ")))
	(newline)
	(if (is-bound extra-bib-fields-file)
	    (save-excursion 
		(re-search-forward "[ \t\n]*)")
		(region-around-match 0)
		(exchange-dot-and-mark)
		(insert-character ',')
		(end-of-line)	; probably is already there, but make sure
		(forward-character)
		(insert-file extra-bib-fields-file)
	    )
	)
	(undo-boundary)
	(next-field)
    )
    
    (@article (insert-bib-shell "article"))
    (@book (insert-bib-shell "book"))
    (@booklet (insert-bib-shell "booklet"))
    (@conference (insert-bib-shell "inproceedings"))
    (@inbook (insert-bib-shell "inbook"))
    (@incollection (insert-bib-shell "incollection"))
    (@inproceedings (insert-bib-shell "inproceedings"))
    (@manual (insert-bib-shell "manual"))
    (@mastersthesis (insert-bib-shell "mastersthesis"))
    (@misc (insert-bib-shell "misc"))
    (@phdthesis (insert-bib-shell "phdthesis"))
    (@proceedings (insert-bib-shell "proceedings"))
    (@techreport (insert-bib-shell "techreport"))
    (@unpublished (insert-bib-shell "unpublished"))
    
    
    (next-field newdot string end-of-entry
	(if (! (is-bound Key-Search-String))
	    (progn 
		   (declare-buffer-specific Key-Search-String)
		   (setq Key-Search-String "")
	    )
	)
	(setq end-of-entry 0)
	(if (& (! (bobp))
	       (save-excursion
		   (backward-character)
		   (looking-at "\"\"\\|=,\\|=[ \t\n]*)"))
	       ; "" or =, or =<white-space><rt. paren>
	    )
	    (save-excursion
		(if (= (following-char) '"')
		    (forward-character))
		(set-mark)
		(search-reverse ",")
		(erase-region)
		(setq end-of-entry (looking-at "[ \t\n]*)"))
	    )
	    (& 
	       (= (following-char) ',')
	       (save-excursion 
		   (beginning-of-line)
		   (looking-at "@[A-Za-z]*(,[ \t]*$")
	       )
	    )
	    (insert-string Key-Search-String)
	)
	(if end-of-entry
	    (message "Last field deleted")
	    (progn 
		   (save-excursion
		       (re-search-forward "[*?@&|+]*>>")
		       (region-around-match 0)
		       (setq string (region-to-string))
		       (erase-region)
		       (setq newdot (dot))
		   )
		   
		   (goto-character newdot)
		   
		   (if (= string ">>") (message "Required")
		       (= string "?>>")(message "Optional")
		       (= string "|>>")(message "Or the following")
		       (= string "&|>>")(message "And/Or the following")
		       (= string "@>>") (message "Alternative")
		       (= string "*>>") (message "Required only if no author or editor is specified")
		       (= string "+>>") (message "Required: (" 
					    Key-Search-String ")")
		       (message string " is unknown -- see a local expert")
		       ; local expert: if the bibshell file is 
		       ; not corrupted, send a bug report to
		       ; dmj@uw-june or
		       ; ...ihnp4!uw-beaver!uw-june!dmj
		   )
	    )
	)
    )
    
    (next-key new-dot key
	(save-excursion 
	    (re-search-forward "^@.*(\\(.*\\),[ \t]*")
	    (region-around-match 1)
	    (setq key (region-to-string))
	    (setq new-dot (mark))
	)
	(goto-character new-dot)
	key
    )
    
    (forward-entry 
	(if (looking-at "^@.*(.*,")
	    (end-of-line))
	(if (error-occurred (next-key))
	    (end-of-file)
	    (beginning-of-line)
	)
	(novalue)
    )
    
    (previous-key new-dot key
	(save-excursion 
	    (beginning-of-line)	; emacs rev-searching finds the pattern if
	    ; dot is anywhere in it.  This prevents that.
	    (re-search-reverse "^@.*(\\(.*\\),[ \t]*")
	    (region-around-match 1)
	    (setq key (region-to-string))
	    (setq new-dot (mark))
	)
	(goto-character new-dot)
	key
    )
    
    (backward-entry
	(previous-key)
	(beginning-of-line)
    )
    
    (find-key temp-key not-found
	(declare-buffer-specific Key-Search-String)
	(setq Key-Search-String (arg 1 ": find-key Key: "))
	(beginning-of-file)
	(if (error-occurred 
		(while (progn 
			      (setq temp-key (next-key))
			      (< temp-key Key-Search-String))
		)
		; key we are on is >= Key-Search-String
		(if (!= temp-key Key-Search-String) ;  must be >
		    (progn 
			   (error-occurred 
			       (beginning-of-line)
			       (previous-line))
		    )
		)
	    )
	    (end-of-file) 	; pattern was not found
	)
	(novalue) 
	
    )
    
    (fast-find-key		; not same semantics as find-key
	(re-search-forward
	    (concat "^@[0-9A-Za-z]*(" (quote (arg 1 "Key: ")) ",")
	)
    )
    
    (justify-field key-loc eq-loc c-col last-col start-col dot-col dot-char
	no-quote
	(setq dot-char (following-char))
	(setq dot-col (current-column))
	(save-excursion 
	    (previous-key)
	    (setq key-loc (dot))
	)
	(save-excursion 
	    (if (looking-at ".*="); there is an = ahead
		(search-forward "=")
		(progn (search-reverse "=")
		       (if (< (dot) key-loc)
			   (error-message "Cannot find field"))
		       (forward-character)
		)
	    )
	    (setq eq-loc (dot))
	    (if (! (looking-at "[ \t]*\""))
		(error-message "Not a quoted string")
	    )
	    (search-forward "\"")
	    ;       close space between '=' and '"'
	    ;	    (backward-character)
	    ;	    (delete-white-space)
	    ;	    (forward-character)
	    (setq start-col (current-column))
	    ; find end of region to justify
	    (if (error-occurred 
		    (re-search-forward "\"\\|^[ \t]*\n\\|^[ \t][ \t]*)[ \t]*$\\|^@.*("))
		(progn 
		       (end-of-file)
		       (setq no-quote 1)
		)
		(progn 
		       (re-search-reverse "")
		       (if (setq no-quote (! (looking-at "\"")))
			   (previous-line)
		       )
		)
	    )
	    
	    ; make it one big line		       
	    (while (progn 
			  (beginning-of-line)
			  (> (dot) eq-loc)
		   )
		   (delete-previous-character)
		   (delete-white-space)
		   (insert-character ' ')
	    )
	    ; reassemble into lines of the right length
	    (setq left-margin start-col)
	    (end-of-line)		       
	    (setq c-col (current-column))
	    (while (progn
			 (setq last-col c-col)
			 (insert-character '!')
			 (delete-previous-character)
			 (end-of-line)
			 (setq c-col (current-column))
			 (< c-col last-col))
	    )
	    (setq left-margin 1)
	)
	; save-excursion uses sticky pointers.  We delete white space at 
	; end of lines and then re-insert it, which leaves the sticky 
	; pointer to the left of the space rather that to the right if 
	; that was where it was originally was.  So here we fix it up.
	; If there was nothing to justify, this will just be a no-op anyway.
	
	(if (& (!= dot-char (following-char))
	       (!= dot-char ' ')
	       (!= dot-char '\t')
	       (!= dot-char '\n'))
	    (error-occurred 
		(search-forward (char-to-string dot-char))
		(backward-character)
	    )
	)
	
	;when the dot is out in the left margin it winds up at the end of the 
	;previous line.  We would like it to be the case that if no text 
	;moves, then neither does the cursor.  But 
	;as a temporary hack we will just do the following: 
	
	(if (& (eolp) (! (eobp))) (forward-character)) 	;hack
	
	(if no-quote (message "Warning: no closing quote"))
	(novalue)
    )
    
    (fetch&use-Bib-Abbrevs-buffer full-name abbrev
	(temp-use-buffer "Bib-Abbrevs")
	(setq needs-checkpointing 0)
	(setq case-fold-search 1)
	(if (= (buffer-size) 0)
	    (progn 
		   (insert-file "/usr/lib/tex/macros/alpha.bst")
		   (beginning-of-file)
		   (search-forward "MACRO")
		   (beginning-of-line)
		   (set-mark)
		   (beginning-of-file)
		   (erase-region)
		   (end-of-file)
		   (set-mark)
		   (search-reverse "MACRO")
		   (next-line)
		   (next-line)
		   (erase-region)
		   (beginning-of-file)
		   (while (! (eobp))
			  (if (looking-at 
				  "^MACRO[ \t]*{\\([a-z]*\\)}[ \t\n]*{\\(.*\\)}.*$"
			      )
			      (progn (region-around-match 1)
				     (setq abbrev (region-to-string))
				     (region-around-match 2)
				     (setq full-name (region-to-string))
				     (region-around-match 0)
				     (erase-region)
				     (insert-string abbrev)
				     (insert-character '\t')
				     (insert-string full-name)
				     (beginning-of-line)
				     (next-line)
			      )
			      (progn
				    (set-mark)
				    (next-line)
				    (erase-region)
			      )
			  )
		   )
		   
	    )
	)
    )
    
    (describe-abbrev-in-buffer abbrev expanded
	(save-excursion
	    (error-occurred (forward-character))
	    (backward-word)
	    (set-mark)
	    (forward-word)
	    (setq abbrev (region-to-string))
	    (fetch&use-Bib-Abbrevs-buffer)
	    (beginning-of-file)
	    (search-forward (concat abbrev "\t"))
	    (set-mark)
	    (end-of-line)
	    (setq expanded (region-to-string))
	)
	(message expanded)
    )
    
    (current-file-directory fname
	(setq fname (current-file-name))
	(save-excursion 
	    (temp-use-buffer "Bibfilename Buffer")
	    (erase-buffer)
	    (insert-string fname)
	    (search-reverse "/")
	    (set-mark)
	    (end-of-line)
	    (erase-region)
	    (beginning-of-line)
	    (region-to-string)
	)
    )
    
    
    
    (describe-cite-in-buffer bib-key filename indirectbibfile currentdir
	(if (| (! (is-bound bibliography-file))
	       (= bibliography-file "")
	    )
	    (progn 
		   (declare-buffer-specific bibliography-file)
		   (setq currentdir (current-file-directory))
		   (setq indirectbibfile (concat currentdir "/.bibfile"))
		   (if (file-exists indirectbibfile)
		       (save-excursion
			   (temp-use-buffer "Bibfile Name")
			   (erase-buffer)
			   (insert-file indirectbibfile)
			   (beginning-of-file)
			   (set-mark)
			   (if (!= (following-char) '/')
			       (progn (insert-string currentdir)
				      (insert-character '/')
			       )
			   )
			   (end-of-line)
			   (delete-white-space)
			   (setq filename (region-to-string))
		       )
		       (setq filename (get-tty-file "Bibliography file: "))
		   )
		   (setq bibliography-file "") 
		   (if (= filename "") (error-message "No file name"))
		   (if (! (file-exists filename))
		       (if (!= 'y' (string-to-char (get-tty-string (concat "\"" filename "\" does not exist.  Should I go on? "))))
			   (error-message "Aborted.")
		       )
		   )
	    )
	    (setq filename bibliography-file)
	)
	(save-excursion  orig-buffer first-time
	    (setq orig-buffer (dot))
	    (re-search-reverse 
		"[{, \t\n]\\([^,} \t\n]*\\)[,} \t\n]\\|[{, \t\n]\\([^,} \t\n]*\\)\\'")
	    (region-around-match 1)
	    ; re-search-reverse == back up 1 char at a time, do looking-at
	    (setq bib-key (region-to-string))
	    (if (= bib-key "")
		(progn (region-around-match 2)
		       (setq bib-key (region-to-string)))
	    )
	    (setq first-time (= bibliography-file ""))
	    (error-occurred (visit-file filename))
	    (if (& first-time
		   (!= mode-string "BibTeX")
		)
		(if (= 'y' (string-to-char (get-tty-string 
					       (concat (current-buffer-name) " not in BibTeX mode.  Should I set it? "))))
		    (bibTeX-mode)
		)
	    )
	    (setq filename (current-file-name))
	    (save-excursion 
		(temp-use-buffer orig-buffer)
		(setq bibliography-file filename)
	    )
	    (beginning-of-file)
	    (if (error-occurred (fast-find-key bib-key))
		(progn 
		       (find-key bib-key)
		       (error-message "\""bib-key "\" not found")
		)
		(line-to-top-of-window)
	    )
	)
    )
    
    
    (bibTeX-mode
	(TeX-mode)
	(local-bind-to-key "next-field" "\en")
	(local-bind-to-key "justify-field" "\ej")
	(local-bind-to-key "forward-entry" "\e]")
	(if (| (= (global-binding-of "\e[") "backward-paragraph")
	       (= (global-binding-of "\e[") "nothing")
	    )
	    (local-bind-to-key "backward-entry" "\e["))
	; vt100's and vt2xx's use ESC-[ for their special keys.  
	; If it gets locally bound to backward-entry real havoc ensues.
	(local-bind-to-key "describe-abbrev-in-buffer" "\^X\^D")
	(remove-local-binding '"')
	(setq mode-string "BibTeX")
	(declare-buffer-specific Key-Search-String)
	(setq Key-Search-String "")
	(novalue)
    )
    
)
====================================================================
bibshells directory.  Unpack using ar x
====================================================================
!<arch>
article         484283606   428   10    100644  133       `
@Article(+>>,
	Author=">>",
	Title=">>",
	Journal=>>,
	Volume="?>>",
	Number=?>>,
	Month=?>>,
	Year=>>,
	Pages="?>>",
	Note="?>>"
	)

book            484004779   428   10    100644  170       `
@Book(+>>,
	Author="|>>",
	Editor="@>>",
	Title=">>",
	Edition="?>>",
	Publisher=">>",
	Address="?>>",
	Volume="?>>",
	Series="?>>",
	Month=?>>,
	Year=>>,
	Note="?>>"
	)
booklet         484004779   428   10    100644  108       `
@Booklet(+>>,
	Author="?>>",
	Key="*>>",
	Title=">>",
	Address="?>>",
	Month=?>>,
	Year=?>>,
	Note="?>>"
	)
inbook          484004778   428   10    100644  203       `
@InBook(+>>,
	Author="|>>",
	Editor="@>>",
	Title=">>",
	Chapter="&|>>",
	Pages="@>>",
	Edition="?>>",
	Publisher=">>",
	Address="?>>",
	Volume="?>>",
	Series="?>>",
	Month=?>>,
	Year=>>,
	Note="?>>"
	)

incollection    484004778   428   10    100644  178       `
@InCollection(+>>,
	Author=">>",
	Title=">>",
	Booktitle=">>",
	Editor="?>>",
	Chapter="?>>",
	Pages="?>>",
	Publisher=">>",
	Address="?>>",
	Month=?>>,
	Year=>>,
	Note="?>>"
	)
inproceedings   484004778   428   10    100644  185       `
@InProceedings(+>>,
	Author=">>",
	Title=">>",
	Booktitle=">>",
	Editor="?>>",
	Pages="?>>",
	Organization="?>>",
	Publisher="?>>",
	Address="?>>",
	Month=?>>,
	Year=>>,
	Note="?>>"
	)

manual          484004777   428   10    100644  144       `
@Manual(+>>,
	Title=">>",
	Edition="?>>",
	Author="?>>",
	Key="*>>",
	Organization="?>>",
	Address="?>>",
	Month=?>>,
	Year=?>>,
	Note="?>>"
	)
mastersthesis   484004777   428   10    100644  114       `
@MastersThesis(+>>,
	Author=">>",
	Title=">>",
	School=">>",
	Address="?>>",
	Month=?>>,
	Year=>>,
	Note="?>>"
	)
misc            484004776   428   10    100644  111       `
@Misc(+>>,
	Author="?>>",
	Key="*>>",
	Title="?>>",
	HowPublished="?>>",
	Month=?>>,
	Year=?>>,
	Note="?>>"
	)

phdthesis       484004774   428   10    100644  110       `
@PhDThesis(+>>,
	Author=">>",
	Title=">>",
	School=">>",
	Address="?>>",
	Month=?>>,
	Year=>>,
	Note="?>>"
	)
proceedings     484004773   428   10    100644  149       `
@Proceedings(+>>,
	Title=">>",
	Editor="?>>",
	Key="*>>",
	Organization="?>>",
	Publisher=">>",
	Address="?>>",
	Month=?>>,
	Year=>>,
	Note="?>>"
	)

techreport      484004772   428   10    100644  144       `
@TechReport(+>>,
	Author=">>",
	Title=">>",
	Type="?>>",
	Number="?>>",
	Institution=">>",
	Address="?>>",
	Month=?>>,
	Year=>>,
	Note="?>>"
	)
unpublished     484004771   428   10    100644  82        `
@Unpublished(+>>,
	Author=">>",
	Title=">>",
	Month=?>>,
	Year=?>>,
	Note=">>"
	)
============================================================