;;; Geometry Literature Database BibTeX mode for GNU Emacs
;;; Otfried Schwarzkopf 93-01-19
;;; This is a modified version of the bibtex-mode included with the 
;;; GNU Emacs-distribution. It is not based on the bibtex+ mode by
;;; Marc Shapiro, not only because the latter seems to have problems with
;;; long entries, but mainly for historical reasons.

;;; includes work by
;;; Bengt Martensson 87-06-28
;;; Marc Shapiro 19-oct-1987
;;; Skip Montanaro 7-dec-87
;;; Tim Lambert 94-09-23 (automatic key creation)

;; To use geombib-mode you need to do two things: get this file loaded
;; into your emacs sessions at the right time; and tell emacs what
;; type of files are geombib-files.  To do the former, make sure that
;; geombib.el{c} is on your load-path, and add the following lines to
;; your .emacs file:
;; (autoload 'geombib-mode "geombib" nil t)
;; 
;; To do the latter, set up your auto-mode-alist file to recognize geombib
;; file extensions. For example, if you want to use geombib-mode exclusively 
;; to edit the geometry data base, add this to your .emacs file:
;; (setq auto-mode-alist
;; (append '(("geom\\.bib$"  . geombib-mode))
;;         auto-mode-alist))
;;
;; If you like geombib-mode and you want to use it for all your 
;; bibtex files, use the following lines instead:
;; (setq auto-mode-alist
;; (append '(("\\.bib$"  . geombib-mode))
;;         auto-mode-alist))
;;
;; Note that you should customize the value of "geombib-directory", and
;; possibly "geombib-show-documentation", below.  Again, you can do this
;; in your .emacs file by specifying the local directory:
;; (setq geombib-directory "~/biblios/geombib/" )

(defvar geombib-directory "/public/biblios/geombib/"
  "*Directory (/-terminated) where README and authority files can be found." )

(defvar geombib-mode-syntax-table nil "")
(defvar geombib-mode-abbrev-table nil "")
(define-abbrev-table 'geombib-mode-abbrev-table ())
(defvar geombib-mode-map (make-sparse-keymap) "")
(defvar geombib-is-geom nil
  "*Non-nil if current file should be considered the Geometry Literature
Database.")
(defvar geombib-show-documentation t
  "*Non-nil means show documentation for current field automagically")
(defvar geombib-authority-letters 
  '( ( "keywords" . ?K )
     ( "journal" . ?J)
     ( "booktitle" . ?B)
     ( "publisher" . ?I)
     ( "address" . ?a)
     ( "institution" . ?i)))

;;;---------------------------------------------------------------------
(defun geombib-mode () 
  "Major mode for editing bibtex files, especially the Geometry Literature 
Database.
\\[geombib-entry] asks for an entry type (with completion) and will outline
the fields for the BibTeX entry.
There are shortcuts for article, inproceedings, incollection, and techreport
(the entry types most common in the geometry database).

Optional fields are preceded by \"OPT\", or \"ENC\" or \"DIS\" when a field is
particularly ENCouraged or DIScouraged. You can use \\[geombib-remove-opt] to remove \"OPT\"
on the current line. Note, however, that this is not strictly necessary, since
you will finish entering an entry by \\[geombib-clean-entry], and that command automatically
removes the OPT from all non-empty fields. Required fields are those which are
mandatory or strongly recommended, according to the current guidelines, i.e.
those you should be able to supply easily when working from a title page.

Use \\[geombib-find-it] to position point at the end of the string on the same line.
Use \\[geombib-next-position] to move to the next position to fill in.  
You can use \\[geombib-kill-whole-line] to kill the whole line. Note again that this
is rarely necessary, since \\[geombib-clean-entry] removes all empty optional fields.
However, you can use it to get rid of an inappropriate \"required\" field
(for example, author and editor fields were both made \"required\" in the
Book type, where a correct entry needs one or the other but probably not
both).

\\[geombib-pop-previous] can be used to copy the field from the previous entry in the
database. This is very useful when entering a whole conference worth of papers.

This mode was designed for the geometry literature database, but can be used
for any BibTeX-file adhering to the same conventions.  (Especially, the leading
comma is essential.  Also, it doesn't really support fields spanning more than
one line).  Therefore, on entry to geombib-mode the filename is compared to
\"geom.bib\".  It it is equal then it will not be possible to use any BibTeX
entry types not presently permitted in the geometry database.
This can be overridden by setting geombib-is-geom to nil.

If the variable geombib-show-documentation is non-nil, then the commands \\[geombib-find-it]
and \\[geombib-next-position] will automagically display information about the current field
by consulting the file README of the geometry literature database. 

For fields Journal, Publisher, Booktitle, and Keywords, the key
\\[geombib-complete] completes the current field contents by looking 
it up in the geometry literature authority file. 
To get a list of all entries in the authority file of a specific type,
move on a field of that type and complete the empty field.
The authority file can also be viewed directly using \\[geombib-view-authority].
Completion is also available for Institution and Address. Here, the list of
possible completions is generated by merging all entries of this type present
in the database. 

\\[geombib-clean-entry] (geombib-clean-entry) should be used after finishing
an entry. It creates a key for the new entry if none is given.
It checks whether the key of the new entry is unique, whether there
are any accents not directly enclosed in brackets, removes all empty 
OPT-fields, removes the OPT from all fields that are not empty, and the
quotation marks from all entries that contain only digits.

Full list of commands:
\\{geombib-mode-map}

Variables:
geombib-directory
geombib-is-geom
geombib-show-documentation

Entry to this mode calls the value of geombib-mode-hook
if that value is non-nil."
  (interactive)
  (kill-all-local-variables)
  (if (not geombib-mode-syntax-table)
      (setq geombib-mode-syntax-table (copy-syntax-table)))
  (set-syntax-table geombib-mode-syntax-table)
  (modify-syntax-entry ?\$ "$$  ")
  (modify-syntax-entry ?\% "<   ")
  (modify-syntax-entry ?\f ">   ")
  (modify-syntax-entry ?\n ">   ")
  (modify-syntax-entry ?'  "w   ")
  (modify-syntax-entry ?@  "w   ")
  (use-local-map geombib-mode-map)
  (setq major-mode 'geombib-mode)

  (setq mode-name "GeomBib")
  (set-syntax-table geombib-mode-syntax-table)
  (setq local-abbrev-table geombib-mode-abbrev-table)
  (make-local-variable 'paragraph-start)
  (setq paragraph-start "^[ \f\n\t]*$")

  (define-key geombib-mode-map "\t" 'geombib-find-it)
  (define-key geombib-mode-map "\n" 'geombib-next-position)
  (define-key geombib-mode-map "\C-k" 'geombib-kill-line)
  (define-key geombib-mode-map "\C-c\"" 'geombib-remove-double-quotes)
  (define-key geombib-mode-map "\C-c\C-k" 'geombib-kill-whole-line)
  (define-key geombib-mode-map "\C-c\C-a" 'geombib-Article)
  (define-key geombib-mode-map "\C-c\C-b" 'geombib-Book)
  (define-key geombib-mode-map "\C-ci" 'geombib-InCollection)
  (define-key geombib-mode-map "\C-c\C-i" 'geombib-InProceedings)
  (define-key geombib-mode-map "\C-c\C-o" 'geombib-remove-opt)
  (define-key geombib-mode-map "\C-c\C-s" 'geombib-string)
  (define-key geombib-mode-map "\C-c\C-t" 'geombib-TechReport)
  (define-key geombib-mode-map "\C-c\C-e" 'geombib-entry)
  (define-key geombib-mode-map "\e\C-e" 'geombib-end-of-entry)
  (define-key geombib-mode-map "\e\C-a" 'geombib-beginning-of-entry)
  (define-key geombib-mode-map "\e\t"   'geombib-complete)
  (define-key geombib-mode-map "\C-c\C-d" 'geombib-empty-field)
  (define-key geombib-mode-map "\C-c\C-p" 'geombib-pop-previous)
  (define-key geombib-mode-map "\C-c\C-c" 'geombib-clean-entry)
  (define-key geombib-mode-map "\C-c\C-h" 'geombib-find-documentation)
  (define-key geombib-mode-map "\C-c\C-y" 'geombib-view-authority)
  (define-key geombib-mode-map "\C-c?" 'describe-mode)

  (auto-fill-mode 0)
  (if (equal (file-name-nondirectory (buffer-file-name)) "geom.bib")
      (progn
	(setq geombib-is-geom t)
	(message "Treating this file as Geometry Literature Database.")))
  (run-hooks 'geombib-mode-hook))

(defun geombib-entry (entry-type &optional required optional)
  (interactive (let* ((completion-ignore-case t)
		      (e-t (completing-read "Entry Type: "
					    geombib-entry-field-alist
					    nil t)))
		 (list e-t)))
  (if (and (null required) (null optional))
      (let* ((e (assoc entry-type geombib-entry-field-alist))
	     (tlist geombib-geom-permitted-entry-types))
	(if (null e)
	    (error "Bibtex entry type %s not defined!" entry-type))
	(if geombib-is-geom
	    (while (not (equal entry-type (car tlist)))
	      (setq tlist (cdr tlist))
	      (if (null tlist)
		  (error "Entry type %s not permitted in Database!"
			 entry-type))))
	(setq required (elt e 1)
	      optional (elt e 2))))
  (geombib-move-outside-of-entry)
  (insert (concat "@" entry-type "{\n\n}\n\n"))
  (previous-line 3)
  (insert (mapconcat 'geombib-make-entry required "\n"))
  (if required (insert "\n"))
  (setq geombib-required-warned nil)
  (insert (mapconcat 'geombib-make-opt-entry optional "\n"))
  (if optional (insert "\n"))
  (insert (mapconcat 'geombib-make-opt-entry geombib-general-optional-fields
		     "\n"))
  (up-list -1)
  (forward-char 1)
  (geombib-next-position))

(defun geombib-move-outside-of-entry ()
   "Make sure we are outside of a bib entry"
   (if (or
	(= (point) (point-max))
	(= (point) (point-min))
	(looking-at "[ \n]*@")
	)
	t
	(progn
	  (backward-paragraph)
	  (forward-paragraph)))
   (re-search-forward "[ \t\n]*" (point-max) t))

(defun geombib-make-entry (str)
  (concat ", " str " =\t\"\""))

(defun geombib-make-opt-entry (str)
  (concat ", OPT" str " =\t\"\""))
    
(defun geombib-Article ()
  (interactive)
  (geombib-entry "article"))

(defun geombib-Book ()
  (interactive)
  (geombib-entry "book"))

(defun geombib-InCollection ()
  (interactive)
  (geombib-entry "incollection"))

(defun geombib-InProceedings ()
  (interactive)
  (geombib-entry "inproceedings"))

(defun geombib-TechReport ()
  (interactive)
  (geombib-entry "techreport"))

(defvar geombib-geom-permitted-entry-types
  '( "article" "book" "inbook" "incollection" "inproceedings" "mastersthesis" "phdthesis" "techreport" ))

(defvar geombib-general-optional-fields
  '( "keywords" "comments" "succeeds" "precedes" "cites" "annote" "abstract" ))

(defvar geombib-entry-field-alist
  '(
    ("article"
     ("author" "title" "journal" "volume" "DISnumber" "DISmonth" "year" "pages" )
     ("note" ))
    ("book"
     ("author" "editor" "title" "ENCseries" "ENCvolume" "ENCedition" "publisher" "ENCaddress" "year" "DISisbn" )
     ("note" ))
    ("booklet"
     ("title" "year" )
     ("author" "howpublished" "address" "month" "note" ))
    ("inbook"
     ("author" "chapter" "title" "ENCeditor" "ENCseries" "ENCvolume" "ENCedition" "publisher" "DISaddress" "year" )
     ("note" ))
    ("incollection"
     ("author" "title" "ENCchapter" "ENCeditor" "booktitle" "ENCseries" "ENCvolume" "publisher" "DISaddress" "year" "pages" )
     ("note" ))
    ("inproceedings"
     ("author" "title" "booktitle" "ENCseries" "ENCvolume" "DISpublisher" "DISaddress" "year" "pages" )
     ("note" ))
    ("manual"
     ("title" )
     ("author" "organization" "address" "edition" "year" "month" "note" ))
    ("mastersthesis"
     ("author" "title" "ENCtype" "school" "address" "ENCmonth" "year" )
     ("note" ))
    ("misc"
     nil
     ("author" "title" "howpublished" "year" "month" "note" ))
    ("phdthesis"
     ("author" "title" "ENCtype" "school" "address" "ENCmonth" "year" )
     ("note" ))
    ("proceedings"
     ("title" "year" )
     ("editor" "publisher" "organization" "address" "month" "note" ))
    ("techreport"
     ("author" "title" "ENCtype" "number" "institution" "ENCaddress" "ENCmonth" "year" )
     ("note" ))
    ("unpublished"
     ("author" "title" "note" )
     ("month" "year" ))))

(defun geombib-string ()
  (interactive)
  (geombib-move-outside-of-entry)
  (insert "@string{ = \"\"}\n")
  (previous-line 1)
  (forward-char 8))

(defun geombib-next-position ()
  "Finds next position to write in."
  (interactive)
  (forward-line 1)
  (geombib-find-it))

(defun geombib-find-it ()
  (interactive)
  "Find position on current line (if possible) to add entry text."
  (beginning-of-line)
  (let ((beg (point)))
    (end-of-line)
    (backward-char 1)
;    (if (looking-at "\"\"")
;	t
;      (forward-char 1))
    )
  (if geombib-show-documentation
      (geombib-find-documentation)))
    

(defun geombib-looking-at-opt ()
  "Test whether looking at an optional field."
  (or
   (looking-at "ENC")
   (looking-at "OPT")
   (looking-at "DIS")
  ))

(defun geombib-equals-opt (str)
  "Test whether string is an optional prefix."
  (or
   (equal str "ENC")
   (equal str "OPT")
   (equal str "DIS")
  ))

(defun geombib-remove-opt ()
  "Removes the 'OPT' starting optional arguments."
  (interactive)
  (beginning-of-line)
  (forward-char 2)
  (if (geombib-looking-at-opt)
      (delete-char 3))
  (geombib-find-it))

(defun geombib-kill-whole-line ()
  "Kills the current line."
  (interactive)
  (beginning-of-line)
  (kill-line 1))

(defun geombib-remove-double-quotes ()
  "Removes \"\" around string."
  (interactive)
  (geombib-find-it)
  (let
      ((here (point))
       (eol (progn (end-of-line) (point))))
    (beginning-of-line)
    (if (search-forward "\"\"" eol t)
	(progn
	  (delete-char -1)
	  (if (search-forward "\"\"" eol t)
	      (delete-char -1)
	    ))
      (goto-char here))
    )
  )

(defun geombib-grab-from-geom-bib (mnemonic)
  "Grab an entry from the geometry data base"
  (interactive "sGrab Entry with Mnemonic: ")
  (let (beg entry)
    (save-excursion
      (set-buffer (find-file-noselect
		   (expand-file-name (concat geombib-directory
					     "geom.bib"))))
      (save-excursion
	(goto-char (point-min))
	(re-search-forward (concat "^@[a-z]* *{ *"
				   (regexp-quote mnemonic)
				   "$"))
	(setq beg (match-beginning 0))
	(re-search-forward "^}")
	(setq entry (buffer-substring beg (match-end 0)))))
    (insert entry "\n")))

(defun geombib-indent-line ()
  (interactive)
  (if (save-excursion
	(forward-line -1)
	(looking-at ", \\|\t\t "))
      (insert "\t\t ")))

(defun geombib-empty-field ()
  "Delete the text part of the current field, replace with empty text"
  (interactive)
  (beginning-of-line)
  (let ((eol (save-excursion (end-of-line) (point))))
    (re-search-forward "^, [a-z]+[ \t]*=[ \t]+" eol)
    (delete-region (point) eol)
    (insert "\"\"")
    (backward-char 1)))

(defun geombib-beginning-of-entry ()
  (interactive)
  (re-search-backward "^@" nil 'move))

; TL 26-09-94 fixed so closing brace at end of line inside an entry does not confuse it
(defun geombib-end-of-entry ()
  (interactive)
  (if (re-search-forward "}$" nil 'move)
      (progn 
	(geombib-beginning-of-entry)
	(forward-sexp 2)
	t)
    ))

(defun geombib-pop-previous ()
  "Replace text of current field with the text of same field in previous entry."
  (interactive)
  (geombib-remove-opt)
  (let ((epos (progn (end-of-line)
		     (point)))
	(bpos (progn (beginning-of-line)
		     (point)))
	field str)
    (re-search-forward "^, \\([a-z]+\\)[ \t]")
    (setq field (buffer-substring (match-beginning 1) (match-end 1)))
    (goto-char bpos)
    (re-search-backward (concat "^, " field "[ \t]+=[ \t]+\\(.*\\)$"))
    (delete-region bpos epos)
    (goto-char bpos)
    (insert (buffer-substring (match-beginning 0) (match-end 0)))
    (geombib-find-it)))

(defun geombib-find-documentation ()
  "Find documentation for field on current line by looking it up in the
README-file of the Geometry literature database."
  (interactive)
  (let ((hbuf (find-file-noselect
	       (expand-file-name (concat geombib-directory "README"))))
	field)
    (save-excursion
      (beginning-of-line)
      (re-search-forward ", \\([a-z]+\\)[ \t]")
      (setq field (buffer-substring (match-beginning 1) (match-end 1)))
      (if (geombib-equals-opt (substring field 0 3))
	  (setq field (substring field 3)))
      (if (or (string= field "precedes")
	      (string= field "succeeds"))
	  (setq field "precedes/succeeds"))
      (set-buffer hbuf)
      (if (equal "README" (buffer-name))
	  (rename-buffer "*GeomBib Documentation*"))
      (goto-char (point-min))
      (re-search-forward (concat "^" field ":"))
      (display-buffer hbuf)
      (let* ((win (get-buffer-window hbuf))
	     (cwin (selected-window))
	     (bpos (match-beginning 0))
	     (epos (progn
		     (re-search-forward "\n\n")
		     (match-end 0)))
	     (nlines (count-lines bpos epos))
	     (nlines (max nlines 4))
	     (ht (window-height win)))
	(select-window win)
	(enlarge-window (- nlines ht))
	(select-window cwin)
	(goto-char bpos)
	(set-window-start win bpos)))))
	
(defun geombib-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.
Create BibTeX key if not present.  Test whether BibTeX key is unique.
Locate sequences such as \\"", \\v and test whether they are within brackets (We require that there is an opening bracket directly before the backslash)."
;; should do empty checks first, accents second, key last
  (interactive)
  (geombib-beginning-of-entry)
  (let ((start (point))
	(endry (save-excursion (geombib-end-of-entry) (point-marker)))
	(mykey (geombib-make-citekey))
	skey
	fieldname)
    (if (re-search-forward "^@[a-z]*[ \t]*{[ \t]*\\([^\n\t ,]+\\)"
		       (save-excursion (end-of-line) (point)) t)
	(progn
          (setq skey (buffer-substring (match-beginning 1) (match-end 1)))
	  (if (not (string= skey mykey))
	      (if (y-or-n-p (concat "Shall I change " skey " to " mykey " "))
		  (progn
		    (delete-region (match-beginning 1) (match-end 1))
		    (insert mykey)
		    (setq skey mykey)))))
      (end-of-line)
      (insert mykey)
      (setq skey mykey)
      )
    (goto-char start)
    (insert "@")
    (goto-char (point-min))
    (if (re-search-forward (concat "^@[a-z]*[ \t]*{[ \t]*"
				   (regexp-quote skey) "[\n\t ,]")
			   nil t)
	(progn
	  (goto-char start)
	  (delete-char 1)
	  (error "Key %s already exists!" skey)))
    (goto-char start)
    (delete-char 1)
    (while (re-search-forward "[^{]\\\\\\(['`^~\"=.]\\|[uvHtcdb][ \t]\\)"
			      (marker-position endry) t)
      (error "Illegal use of accent escape!"))
    (goto-char start)
    (while (re-search-forward "^, \\([a-zA-Z]+\\)[ \t]*=[ \t]*\\(.*\\)$"
			      (marker-position endry) t)
      (let ((begin-field (match-beginning 0))
	    (end-field (match-end 0))
	    (begin-name (match-beginning 1))
	    (end-name (match-end 1))
	    (begin-text (match-beginning 2))
	    (end-text (match-end 2))
	    )
	(goto-char begin-name)
	(cond
	 ((geombib-looking-at-opt)
	  (goto-char begin-text)
	  (if (looking-at "\"\"") ; empty: delete whole field
	      (geombib-kill-whole-line)
	    (geombib-remove-opt))
	  (goto-char begin-field))
	 (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 2))) ; go to end for next search
;; should complain once about each, go to next
	   ((looking-at "\"\"")       ; if empty quotes, complain once
	    (if (null geombib-required-warned)
             (progn
	      (setq geombib-required-warned t)
	      (setq fieldname (buffer-substring begin-name end-name))
	      (error "Required field ``%s'' is empty" fieldname))))
	   (t
	    (goto-char end-field)))))))
    (goto-char start)
    (geombib-end-of-entry)))

;;;This is the start of the code that calculates cite keys
;;Return the position of the text associated with a field
(defun geombib-get-text (fieldname)
  (save-excursion
    (if (re-search-forward (concat "^, " (regexp-quote fieldname) "[ \t]*=[ \t]*\"?\\(.*\\)$")
			   (save-excursion (geombib-end-of-entry) (point-marker)) t)
	(let ((begin-text (match-beginning 1))
	      (end-text (match-end 1))
	      )
	  (if (string= (buffer-substring (1- end-text) end-text) "\"")
	      (setq end-text (1- end-text)))
	  (cons begin-text end-text)))))

(defun geombib-make-citekey ()
    (concat 
     (save-excursion (geombib-get-citekey-authorpart))
     "-"
     (save-excursion (geombib-get-citekey-titlepart))
     "-"
     (save-excursion (geombib-get-citekey-yearpart))
     ))

;;it is easier to parse the author list backwards...
(defun geombib-get-citekey-authorpart ()
  (let ((authors (or (geombib-get-text "author")
		     (geombib-get-text "editor")))
	(citekey)
	)
    (if authors
	(progn 
	  (goto-char (cdr authors))
	  (setq citekey (geombib-get-authorinitial))
	  (while (search-backward " and " (car authors) t)
	    (setq citekey (concat (geombib-get-authorinitial) citekey)))
	  (downcase citekey)))))

(defun geombib-get-authorinitial ()
  (let ((end (point))
	(case-fold-search nil))
    (save-excursion 
      (while (not (member (preceding-char) '(?\ ?\")))
	(backward-sexp 1)
	)
      (backward-char)
      (if (or (re-search-forward "[ {\"][A-Z]" end t)
	      (re-search-forward "[A-Za-z]" end t)) ;maybe the name does not start with a capital
	  (char-to-string (preceding-char))
	""))))


(defvar geombib-title-syntax-table nil "")

(defun geombib-get-citekey-titlepart ()
  (let ((title (or (geombib-get-text "title")
		   (geombib-get-text "booktitle")))
	(citekey "")
	(word)
	(start)
	(end)
	(rom)
	)
    (if title
	(progn				
	  (if (not geombib-title-syntax-table)
	      ;;syntax table to treat "-" as whitespace so "iso-line" gets
	      ;; abbreviated "il"
	      (progn (setq geombib-title-syntax-table
			   (copy-syntax-table geombib-mode-syntax-table))
		     (set-syntax-table geombib-title-syntax-table)
		     (modify-syntax-entry ?\- "    ")
		     (modify-syntax-entry ?\, "    ")
		     (modify-syntax-entry ?\: "    ")
		     (modify-syntax-entry ?\; "    ")
		     (modify-syntax-entry ?\. "    ")
		     (modify-syntax-entry ?\) "    ")
		     (modify-syntax-entry ?\( "    ")
		     (modify-syntax-entry ?\] "    ")
		     (modify-syntax-entry ?\[ "    ")
		     (modify-syntax-entry ?\/ "    ")
		     ))
	  (set-syntax-table geombib-title-syntax-table)
	  (goto-char (car title))
	  (while (< (point) (cdr title))
	    (setq start (point))
	    (forward-sexp 1)
	    (while (and (< (point) (cdr title))
			(not (eq (char-syntax (following-char)) ?\ )))
	      (forward-sexp 1)
	      )
	    (setq end (min (point) (cdr title)))
	    ;; collect word, leaving out grouping characters {}$
	    (setq word "")
	    (goto-char start)
	    (if (looking-at "[^A-Za-z0-9]*\\\\\\(rm\\|it\\|v\\|c\\)[^A-Za-z]") ;ignore initial \rm and \it
		(re-search-forward "[^A-Za-z0-9]*\\\\[A-Za-z]*"))
	    (if (looking-at " *on-line") ;kludge so "On-line" becomes "ol"
		(setq word "on-")
	      (if (re-search-forward "[A-Za-z0-9]" end t)
		  (progn
		    (setq word (char-to-string (preceding-char)))
		    (while (re-search-forward "[^{}$]" end t)
		      (setq word (concat word (char-to-string (preceding-char))))
		      )
		    )
		)
	      )
	    (goto-char end)
	    (if (not (member (downcase word) geombib-elide))
		(setq
		 citekey
		 (concat
		  citekey
		  (cond
		   ((string= word "") "") ;nothing in the word
		    ((setq rom (assoc word geombib-special)) (cdr rom))
		    ((string< word "A") (int-to-string ( string-to-int word))) 
					;if numeric strip of trailing alphas
		    (t (substring word 0 1)) ;first letter of a word
			)))
	      )
	    )
	  (set-syntax-table geombib-mode-syntax-table)
	  (downcase (substring citekey 0 (min 5 (length citekey))))
	  ))))

;; year part of cite key is last two digits or question marks of year field
(defun geombib-get-citekey-yearpart ()
   (let ((year (geombib-get-text "year"))
	 (yearpart)
	 )
     (if year
	 (progn
	   (goto-char (- (cdr year) 2))
	   (if (looking-at "[0-9\\?][0-9\\?]")
	       (buffer-substring (point) (cdr year)))))))
 
(defvar geombib-special
  '(("I"."1") ("II"."2") ("III"."3") ("IV"."4") ("V"."5")
    ("varepsilon"."e")
    ("online"."ol") ("Online"."ol")
    ("1d"."1d") ("1D"."1d")
    ("2d"."2d") ("2D"."2d")
    ("3d"."3d") ("3D"."3d")
    ("4d"."4d") ("4D"."4d"))
  "Abbreviations of special title words.")

(defvar geombib-elide
  '("of" "the" "a" "for" "and" "in" "on" "an" "to" "with" "by" "from" 
    "among" "into" "as" "under" "over" "or" "via" "at" "than")
    "Title words to ignore when forming a key."
)

; end of code to compute cite keys

(defvar geombib-completion-alist nil)

(defun geombib-add-completion-alias (char str)
  (let* ((charcel (assoc char geombib-completion-alist))
	 (charcel (if charcel
		      charcel
		    (setq geombib-completion-alist
			  (cons (cons char nil) geombib-completion-alist))
		    (car geombib-completion-alist)))
	 (strcel  (assoc str (cdr charcel))))
    (if (null strcel)
	(rplacd charcel (cons (list str) (cdr charcel))))))


(defun geombib-make-completion-alist ()
  (message "Creating completion alists ... ")
  (save-excursion
    (set-buffer (find-file-noselect
		 (expand-file-name (concat geombib-directory "authority"))))
    (if (equal "authority" (buffer-name))
	(rename-buffer "*GeomBib Authority*"))
    (goto-char (point-min))
    (setq geombib-completion-alist nil)
    (while (re-search-forward
	    "^%\\([A-Z]\\)[ \t]+\\(.*\\)$" nil t)
      (geombib-add-completion-alias
       (string-to-char (buffer-substring (match-beginning 1) (match-end 1)))
       (buffer-substring (match-beginning 2) (match-end 2)))))
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "^, institution[ \t]*=[ \t]*\"\\(.*\\)\"[ \t]*$"
			      nil t)
      (geombib-add-completion-alias
       ?i (buffer-substring (match-beginning 1) (match-end 1)))))
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "^, address[ \t]*=[ \t]*\"\\(.*\\)\"[ \t]*$"
			      nil t)
      (geombib-add-completion-alias
       ?a (buffer-substring (match-beginning 1) (match-end 1)))))
  (let ((l geombib-completion-alist))
    (while l
      (rplacd (car l) (sort (cdr (car l))
			    (function (lambda (a b)
					(string< (car a) (car b))))))
      (setq l (cdr l))))
  (message "Creating completion alists ... Done"))
			      
(defun geombib-complete ()
  "Try to complete text in field before point, using the information in 
the authority file and the field type."
  (interactive)
  (if (null geombib-completion-alist)
      (geombib-make-completion-alist))
  (let ((cp (point)))
    (beginning-of-line)
    (re-search-forward "^, \\([a-z]+\\)[ \t]*=[ \t]*\"\\(.*\\)$")
    (goto-char cp)
    (let* ((fieldname (buffer-substring (match-beginning 1) (match-end 1)))
	   (fieldname (if (geombib-equals-opt (substring fieldname 0 3))
			  (substring fieldname 3)
			fieldname))
	   (btxt (match-beginning 2))
	   (text (buffer-substring btxt cp))
	   (text (if (equal fieldname "keywords")
		     (if (string-match ",[ \t]*\\([^,]*\\)$" text)
			 (progn
			   (setq btxt (+ btxt (match-beginning 1)))
			   (substring text (match-beginning 1)))
		       text)
		   text))
	   (key (cdr (assoc fieldname geombib-authority-letters)))
	   (completion-ignore-case t)
	   (alist (cdr (assoc key geombib-completion-alist)))
	   (compl (try-completion text alist))
	   (all  (all-completions text alist)))
      (cond
       ((null compl)
	(error "Cannot complete %s" text))
       ((eq compl t))
       ((<  (length text) (length compl))
	(delete-region btxt cp)
	(goto-char btxt)
	(insert compl))
       (t
	(with-output-to-temp-buffer "*Help*"
	  (while all
	    (princ (concat (car all) "\n"))
	    (setq all (cdr all)))))))))

(defun geombib-view-authority ()
  "View the authority file in another window."
  (interactive)
  (if (null geombib-completion-alist)
      (geombib-make-completion-alist))
  (switch-to-buffer-other-window "*GeomBib Authority*"))

; Made it smarter 26-09-94 Tim Lambert
(defun geombib-kill-line ()
  "Like kill-line, but leave trailing quotation mark on line alone."
  (interactive)
  (if (looking-at "[^\"]*\"$")
      (progn
	(save-restriction
	  (narrow-to-region
	   (save-excursion (1+ (search-backward "\"")))
	   (save-excursion (1- (search-forward "\""))))
	  (kill-line current-prefix-arg)))
    (kill-line current-prefix-arg)
    )
  )

;; end of geombib.el
