summaryrefslogtreecommitdiff
path: root/support/emacs-modes
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/emacs-modes
Initial commit
Diffstat (limited to 'support/emacs-modes')
-rw-r--r--support/emacs-modes/00readme.txt45
-rw-r--r--support/emacs-modes/aux-renum.el299
-rw-r--r--support/emacs-modes/bibtex-mode.el1566
-rw-r--r--support/emacs-modes/cweave.ch77
-rw-r--r--support/emacs-modes/fweave.ch88
-rw-r--r--support/emacs-modes/inspec2bibtex.el836
-rw-r--r--support/emacs-modes/limbo.material38
-rw-r--r--support/emacs-modes/meta-mode.el1099
-rw-r--r--support/emacs-modes/minor-map.el126
-rw-r--r--support/emacs-modes/outline-m.el184
-rw-r--r--support/emacs-modes/swiftex/hilit-swiftex.el314
-rw-r--r--support/emacs-modes/swiftex/swiftex-doc.txt548
-rw-r--r--support/emacs-modes/swiftex/swiftex.el2170
-rw-r--r--support/emacs-modes/texheader.tex2
-rw-r--r--support/emacs-modes/textrailer.tex1
-rw-r--r--support/emacs-modes/u8tex.el536
-rw-r--r--support/emacs-modes/weave.ch626
-rw-r--r--support/emacs-modes/web-mode-manual.tex1526
-rw-r--r--support/emacs-modes/web-mode.el5162
19 files changed, 15243 insertions, 0 deletions
diff --git a/support/emacs-modes/00readme.txt b/support/emacs-modes/00readme.txt
new file mode 100644
index 0000000000..aa19fa0e95
--- /dev/null
+++ b/support/emacs-modes/00readme.txt
@@ -0,0 +1,45 @@
+This directory contains GNU Emacs Lisp files which enhance that
+environment for TeX Users.
+
+Modes for TeX handling:
+ *AUC TeX mode
+ auc-tex.el is an enhanced TeX mode which provides the following
+ features:
+ - Intelligent macros for often used controls:
+ {\em }, \section{ }, etc.
+ - Invoking and debugging TeX/LaTeX from within
+ Emacs
+ - Help for errors while debugging (includes all
+ TeX and LaTeX errors)
+ - Indentation by environments
+ - support for outline minor-mode
+ Some features use the following additional emacs-lisp
+ files:
+ minor-map.el Keymaps for EMACS minor modes
+ outline-m.el Outlining as a minor mode.
+ Also, the following files are used in constructing a LaTeX
+ file:
+ texheader.tex Lines for beginning of LaTeX file.
+ textrailer.tex Lines for ending of LaTeX file.
+
+ A mailing list is available for discussions etc. regarding the
+ AUC TeX modes. You may joint the auc-tex mailinglist by sending
+ subscriptions to
+ auc-tex-request@iesd.auc.dk
+ Articles should be sent to
+ auc-tex@iesd.auc.dk
+
+Modes for BibTeX handling
+ bibtex-mode.el BibTeX mode for inputting/editing .bib files.
+
+Modes for WEB
+ web-mode.el WEB mode for working with web/cweb/fweb
+ web-mode-manual.tex Documentation for the mode.
+ cweave.ch Change file to adapt cweave to the web mode
+ fweave.ch Change file to adapt fweave to the web mode
+ weave.ch Change file to adapt weave to the web mode
+ limbo.material Extra material for the web mode
+
+Modes for LaTeX doc files
+ swiftex.el Emacs mode for .dtx files (by Mathew Swift)
+
diff --git a/support/emacs-modes/aux-renum.el b/support/emacs-modes/aux-renum.el
new file mode 100644
index 0000000000..c87dd2cedc
--- /dev/null
+++ b/support/emacs-modes/aux-renum.el
@@ -0,0 +1,299 @@
+;;; aux-renum.el --- renumber labels in LaTeX documents
+
+;; Copyright (C) 1995, 1996 Ulrik Vieth.
+
+;; Author: Ulrik Vieth <vieth@thphy.uni-duesseldorf.de>
+;; Keywords: tex, maint
+;; Version: 0.5
+
+;;; This file is *not* part of GNU Emacs.
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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.
+
+;;; Commentary:
+
+;; Description:
+;;
+;; This package provides two functions `aux-renumber-single' and
+;; `aux-renumber-multi' to renumber equation labels and references
+;; in LaTeX documents so that they match their representation in
+;; the ".aux" file(s) and the formatted document.
+;;
+;; Why would you want to do that? Well, consider a manuscript of
+;; a book containing several hundreds of equations spread across
+;; a dozen or more files. Since it is impossible to give reasonable
+;; names to so many equations, they may have been given some ad-hoc
+;; labels when the manuscript was typed. After completing some
+;; intermediate or final version that will be printed and possibly
+;; distributed, it may be convenient to renumber the labels so that
+;; you can directly refer to the equation numbers in the printed
+;; version without having to figure out what cryptic label to type
+;; to produce the desired equation number in subsequent edits.
+;;
+;; Another appilcation might be a manuscript of a paper that will
+;; be submitted electronically to a journal. To avoid confusion
+;; in subsequent correspondence with the journal editor, it might
+;; be advantageous if the labels match their representation in the
+;; paper copy submitted to the publisher.
+;;
+
+;; Usage:
+;;
+;; 1. Load or autoload this file:
+;;
+;; (load-library "aux-renum")
+;;
+;; or
+;; (autoload 'aux-renumber-single "aux-renum"
+;; "Renumber labels in a single-file LaTeX document." t)
+;; (autoload 'aux-renumber-multi "aux-renum"
+;; "Renumber labels in a multi-file LaTeX document." t)
+;;
+;; 2. Run it interactively:
+;;
+;; M-x aux-renumber-single
+;; M-x aux-renumber-multi
+;;
+
+
+;; Known Problems:
+;;
+;; - Operation is restricted to files in the current directory.
+;; This isn't easy to fix because the list of include files is
+;; constructed from the information in the master ".aux" file
+;; which doesn't include any directory information.
+;;
+;; - There are no checks to ensure that the replacement strings
+;; are unique. This shouldn't be a problem if the ".aux" files
+;; are correct and up-to-date, but it could mess up your files
+;; if several (presumably incorrectly placed) labels have the
+;; same representation, e.g. if they refer to a section number
+;; instead of an equation number. Check your ".aux" files or
+;; take your chances!
+;;
+;; - It is silently assumed that the labels in your ".aux" file
+;; follow certain conventions. This means that every label is
+;; considered an equation label unless it starts with a known
+;; prefix. The list of prefixes of labels that should be left
+;; unchaged is specified by the regexp `aux-exclude-regexp'.
+;;
+;; - The replacement function in `aux-process-tex-file' uses the
+;; high-level functions `find-file-noselect' and `save-buffer'
+;; to load and save ".tex" files, which perform all sorts of
+;; checks. This might lead to some unexpected user interaction
+;; if some safety checks need to be answered. This might be
+;; somewhat irritating, but it's only to be on the safe side.
+;;
+
+;; History:
+;;
+;; v 0.0 -- 1995/12/31 created
+;; v 0.1 -- 1995/01/01 first preliminary version tested
+;; v 0.2 -- 1996/01/02 first complete version tested
+;; v 0.3 -- 1996/01/03 documentation added and clean up
+;; v 0.4 -- 1996/01/27 minor doucmentation touch-up
+;; v 0.5 -- 1196/01/28 improved search regexp for labels
+
+
+;;; Code:
+
+;; User-visible variables:
+
+(defvar aux-translation-alist nil
+ "Translation table used to renumber labels and references
+in LaTeX documents. Initialized in \\[aux-prepare-table].")
+
+(defvar aux-exclude-regexp "\\(chap\\|sec\\|fig\\|pic\\|note\\|page\\)"
+ "Regexp containing prefixes of labels to be left unchanged
+when preparing `aux-translation-alist' in \\[aux-prepare-table].")
+
+
+;; these variables could (or perhaps should) be local, but it's easier
+;; to check their values in case something goes wrong if they're global
+;;
+(defvar aux-match-string nil
+ "String containing the last match for a label or reference replaced
+in \\[aux-prepare-tex-file].")
+(defvar aux-replace-string nil
+ "String containing the last replacement text for a label or reference
+in \\[aux-prepare-tex-file].")
+
+
+;; User-visible functions:
+
+(defun aux-renumber-single (base-name)
+ "Renumber labels and references in a single-file LaTeX document
+so that they match their representation in the printed document.
+
+Expects a string argument BASE-NAME, which is used to construct
+the file names of the \".tex\" and \".aux\" file to operate on."
+
+ (interactive "sFile name (without extension): ")
+ (let* ((tex-file-name (concat base-name ".tex"))
+ (aux-file-name (concat base-name ".aux"))
+ (aux-file-list (list aux-file-name)))
+
+ ;; prepare translation table and process the ".tex" file
+ ;;
+ (aux-prepare-table aux-file-list)
+
+ (auto-save-mode -1) ; turn off auto-saving
+ (message "Processing file \"%s\"" tex-file-name)
+ (aux-process-tex-file tex-file-name)
+ (message "Done")
+ (auto-save-mode 1) ; turn on auto-saving
+ )
+ )
+
+
+(defun aux-renumber-multi (base-name)
+ "Renumber labels and references in a multi-file LaTeX document
+so that they match their representation in the printed document.
+
+Expects a string argument BASE-NAME, which is used to construct
+the file names of the main \".tex\" and \".aux\" file to operate on.
+The list of file names of the included \".tex\" and \".aux\" files
+is determined automatically."
+
+ (interactive "sMaster file name (without extension): ")
+ (let* (lab-buffer ; buffer to operate on
+ (tex-file-list '())
+ (aux-file-list '())
+ (main-aux-file-name (concat base-name ".aux")))
+
+ ;; get scratch buffer to operate on
+ ;;
+ (setq lab-buffer (get-buffer-create "*aux-scratch*"))
+ (set-buffer lab-buffer)
+ (erase-buffer) ; erase left-over from previous run
+
+ ;; insert contents of main ".aux" file
+ ;;
+ (if (file-readable-p main-aux-file-name)
+ (insert-file-contents-literally main-aux-file-name)
+ (error "I can't find file \"%s\"" main-aux-file-name))
+
+ ;; extract file names of included ".aux" and ".tex" files
+ ;;
+ (delete-non-matching-lines "\\\\@input")
+ (while (re-search-forward "\\\\@input{\\(.*\\)\\.aux}" nil t)
+ (let ((file-name (match-string 1)))
+ (setq aux-file-list
+ (cons (concat file-name ".aux") aux-file-list))
+ (setq tex-file-list
+ (cons (concat file-name ".tex") tex-file-list))))
+ (setq aux-file-list (reverse aux-file-list))
+ (setq tex-file-list (reverse tex-file-list))
+
+ ;; prepare translation table and process all ".tex" files
+ ;;
+ (aux-prepare-table aux-file-list)
+
+ (auto-save-mode -1) ; turn off auto-saving
+ (while tex-file-list
+ (let ((tex-file-name (car tex-file-list)))
+ (message "Processing file \"%s\"" tex-file-name)
+ (aux-process-tex-file tex-file-name))
+ (setq tex-file-list (cdr tex-file-list)))
+ (message "Done")
+ (auto-save-mode 1) ; turn on auto-saving
+ )
+ )
+
+
+(defun aux-prepare-table (aux-file-list)
+ "Prepare a translation table for renumbering LaTeX documents.
+
+Expects an argument AUX-FILE-LIST specifying the list of files
+to operate on. Operates by extracting the information from
+`\\newlabel' commands in the specified LaTeX \".aux\" file(s).
+
+Stores the extracted information in suitable form in a scratch
+buffer `*aux-scratch*' and evaluates the final buffer contents
+to initialize the translation table `aux-translation-alist'."
+
+ (let (lab-buffer) ; buffer to operate on
+
+ ;; get scratch buffer to operate on
+ ;;
+ (setq lab-buffer (get-buffer-create "*aux-scratch*"))
+ (set-buffer lab-buffer)
+ (erase-buffer) ; erase left-over from previous run
+
+ ;; insert contents of ".aux" file(s)
+ ;;
+ (goto-char (point-min))
+ (while aux-file-list
+ (let ((file-name (car aux-file-list)))
+ (if (file-readable-p file-name)
+ (insert-file-contents-literally file-name)
+ (error "I can't find file \"%s\"" file-name)))
+ (goto-char (point-max))
+ (setq aux-file-list (cdr aux-file-list)))
+
+ ;; extract all `\newlabel' commands from the ".aux" files
+ ;; and discard irrelevant lines for those kinds of labels
+ ;; that shouldn't be modified (e.g. sections, figures, notes)
+ ;;
+ (goto-char (point-min))
+ ;; these functions don't move point
+ (delete-non-matching-lines "\\\\newlabel")
+ (delete-matching-lines aux-exclude-regexp)
+
+ ;; convert `\newlabel' commands into suitable table form
+ ;; that can be used to construct aux-translation-alist
+ ;;
+ (goto-char (point-min))
+ (while (re-search-forward
+ "\\\\newlabel{\\(.*\\)}{{\\(.*\\)}{\\(.*\\)}}" nil t)
+ (replace-match "(\"\\1\" . \"\\2\")" nil nil))
+
+ ;; add framework for a simple lisp function
+ (goto-char (point-min))
+ (insert "(setq aux-translation-alist '(\n")
+ (goto-char (point-max))
+ (insert "))\n")
+
+ ;; and evaluate the buffer contents in lisp
+ (eval-buffer)
+ )
+ )
+
+
+(defun aux-process-tex-file (tex-file-name)
+ "Substitute arguments of `\\label' and `\\ref' commands in
+a LaTeX file TEX-FILE-NAME according to the translation table
+`aux-translation-alist' initialized in \\[aux-prepare-table]."
+
+ (let (tex-buffer) ; buffer to operate on
+
+ (setq tex-buffer (find-file-noselect tex-file-name))
+ (set-buffer tex-buffer)
+
+ ;; replace all ocurrences of `\label' and `\ref' according
+ ;; to the translation table where applicable, or else leave
+ ;; them unchanged by re-inserting the original match-string
+ ;;
+ (goto-char (point-min))
+ (while (re-search-forward
+ "\\\\\\(label\\|ref\\)[ ]*{\\([^}]+\\)}" nil t)
+ (setq aux-match-string (match-string 2))
+ (setq aux-replace-string
+ (or (cdr (assoc aux-match-string aux-translation-alist))
+ aux-match-string))
+ (replace-match "\\\\\\1" nil nil)
+ (insert "{" aux-replace-string "}"))
+
+ (save-buffer)
+ )
+ )
+
+;;; aux-renum.el ends here
diff --git a/support/emacs-modes/bibtex-mode.el b/support/emacs-modes/bibtex-mode.el
new file mode 100644
index 0000000000..f6b9e51f09
--- /dev/null
+++ b/support/emacs-modes/bibtex-mode.el
@@ -0,0 +1,1566 @@
+;;; Copyright (C) 1992 Free Software Foundation, Inc.
+
+;;; This file is NOT part of GNU Emacs.
+
+;;; GNU Emacs is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY. No author or distributor
+;;; accepts responsibility to anyone for the consequences of using it
+;;; or for whether it serves any particular purpose or works at all,
+;;; unless he says so in writing. Refer to the GNU Emacs General Public
+;;; License for full details.
+
+;;; Everyone is granted permission to copy, modify and redistribute
+;;; GNU Emacs, but only under the conditions described in the
+;;; GNU Emacs General Public License. A copy of this license is
+;;; supposed to have been given to you along with GNU Emacs so you
+;;; can know your rights and responsibilities. It should be in a
+;;; file named COPYING. Among other things, the copyright notice
+;;; and this notice must be preserved on all copies.
+
+;;; TODO distribute texinfo file.
+
+;;; BibTeX mode for GNU Emacs
+
+;;; LCD Archive Entry:
+;;; bibtex-mode|Bengt Martensson, Marc Shapiro, Aaron Larson|
+;;; alarson@src.honeywell.com|
+;;; Support for maintaining BibTeX format bibliography databases|
+;;; 92-04-01|version 1.2|~/modes/bibtex-mode.el.Z|
+
+;;; BUGS:
+;;; 1. using regular expressions to match the entire bibtex entry dies
+;;; on long bibtex entires (e.g. those containing abstracts) since
+;;; the length of regular expression matches is fairly limited.
+;;; 2. When inserting a string (with \C-C\C-E\s) hitting a TAB results
+;;; in the error message "Can't find enclosing Bibtex field" instead
+;;; of moving to the empty string. [reported by gernot@cs.unsw.oz.au]
+;;; 3. Function string-equalp should be in a library file, not in this
+;;; file.
+
+;;; (current keeper: alarson@src.honeywell.com
+;;; previous: shapiro@corto.inria.fr)
+
+;;; alarson@src.honeywell.com (begin V1.2)
+;;; 1. Fixed placement of "interactive specification" in find-bibtex-
+;;; entry-location and bibtex-make-field. [Bug report from mernst@
+;;; theory.lcs.mit.edu]
+;;; 2. Fixed problem where bibtex-entry would fail if user typed entry
+;;; name in wrong case.
+;;; 3. Merged in patches from sct@dcs.edinburgh.ac.uk:
+;;; A) bibtex-inside-field now positions the cursor _before_ the last comma
+;;; on a line (the comma is not necessarily "inside" the field); this
+;;; does not seem to break any existing code... (touch wood)
+;;; B) bibtex-enclosing-field and bibtex-enclosing-reference now leave
+;;; point unmoved if no enclosing field/reference is found.
+;;; C) As a result of changes (A) and (B)... bibtex-next-field works
+;;; properly, even when called from the entry key position.
+;;; D) bibtex-remove-OPT realigns the '=' after removing the 'opt'.
+;;; E) bibtex-clean-entry now always removes any trailing comma from the
+;;; end of a bibtex entry (these commas get stripped automatically when
+;;; optional fields are killed by bibtex-kill-optional-field, but can be
+;;; left if optional fields are removed by other means).
+;;; 4. Fixed some minor problems with X menu support as noted by
+;;; khera@cs.duke.edu
+;;; 5. Added bibtex-refile-entry (from brannon@jove.cs.caltech.edu)
+;;; 6. Added variable bibtex-sort-ignore-string-entries as requested by
+;;; gernot@cs.unsw.oz.au
+;;; 7. Added bibtex-current-entry-label at request of
+;;; yasuro@maekawa.is.uec.ac.jp
+;;; 8. Deleted DEAthesis per shapiro@corto.inria.fr
+;;; 9. Moved narrow-to-bibtex-entry from C-c C-n to C-c n (the previous
+;;; binding was in conflict with the binding for bibtex-pop-next.
+;;; bug report from [shapiro@corto.inria.fr]
+;;;
+;;; alarson@src.honeywell.com 92-Feb-13
+;;; 1. Made bibtex-entry user callable, now prompts for entry type (e.g.
+;;; Article), with completion, and bound it to a key. This is now my
+;;; preferred way to add most entries.
+;;; 2. Made fields of a bibtex entry derived from the alist bibtex-entry-
+;;; field-alist.
+;;; 3. Fixed handling of escaped double quotes, e.g. "Schr{\"o}dinger".
+;;; 4. Fixed bug where unhiding bibtex entries moved point.
+;;; 5. Made "field name" specs permit (name . value) for defaulting. E.g.
+;;; (setq bibtex-mode-user-optional-fields '(("library" . "alarson")))
+;;; will generate the field:
+;;; library = "alarson",
+;;; 6. Added binding for narrow-to-bibtex-entry
+;;; 7. Adding a bibtex entry now runs hook: bibtex-add-entry-hook
+;;; 8. Made bibtex-clean-entry fixup text alignment, and eliminated the
+;;; dependency on bibtex-enclosing-reference which has a problem with
+;;; long entries (e.g. those containing abstracts).
+;;;
+;;; alarson@src.honeywell.com 92-Jan-31
+;;; Added support for: ispell, beginning/end of entry movement, a simple
+;;; outline like mode (hide the bodies of bibtex entries), support for
+;;; sorting bibtex entries, and maintaining them in sorted order, and
+;;; simple buffer validation.
+;;; User visible functions added:
+;;; ispell-{abstract,bibtex-entry}, {beginning,end}-of-bibtex-entry
+;;; hide-bibtex-entry-bodies, sort-bibtex-entries, validate-bibtex-
+;;; buffer, find-bibtex-duplicates
+;;; user visible variables added:
+;;; bibtex-maintain-sorted-entries
+;;; new local keybindings:
+;;; " TeX-insert-quote
+;;; C-c$ ispell-bibtex-entry
+;;; M-C-a beginning-of-bibtex-entry
+;;; M-C-e end-of-bibtex-entry
+;;; 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
+
+;;; 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
+;;; * skip-whitespace replaced by skip-chars-forward
+;;; * 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
+;;; * Fixed bug in bibtex-flash-entry
+;;; * 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)
+
+;;; these guys typically don't have autoloads...[alarson:19920131.1548CST]
+(if (not (fboundp 'TeX-insert-quote))
+ (autoload 'TeX-insert-quote "tex-mode"))
+(if (not (fboundp 'sort-subr))
+ (autoload 'sort-subr "sort"))
+
+;;; These should be in a more generally accessible location.
+
+(defun string-equalp (s1 s2)
+ "Like string= except differences in case are ignored."
+ (let ((ss1 (if (symbolp s1) (symbol-name s1) s1))
+ (ss2 (if (symbolp s2) (symbol-name s2) s2)))
+ (and (= (length ss1) (length ss2))
+ (string-equal (upcase ss1) (upcase ss2)))))
+
+;;; This should be moved into simple.el, and the functions there modified
+;;; to call it rather than doing it themselves.
+(defun put-string-on-kill-ring (string)
+ "Make STRING be the first element of the kill ring."
+ (setq kill-ring (cons string kill-ring))
+ (if (> (length kill-ring) kill-ring-max)
+ (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
+ (setq kill-ring-yank-pointer kill-ring))
+
+
+
+
+(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 want to have as always present
+when making a bibtex entry. One possibility is for ``keywords''.
+Entries can be either strings or conses, in which case the car should be
+string and the cdr the value to be inserted.")
+
+(defvar bibtex-mode-syntax-table
+ (let ((st (make-syntax-table)))
+ ;; [alarson:19920214.1004CST] make double quote a string quote
+ (modify-syntax-entry ?\" "\"" st)
+ (modify-syntax-entry ?$ "$$ " st)
+ (modify-syntax-entry ?% "< " st)
+ (modify-syntax-entry ?' "w " st)
+ (modify-syntax-entry ?@ "w " st)
+ (modify-syntax-entry ?\\ "\\" st)
+ (modify-syntax-entry ?\f "> " st)
+ (modify-syntax-entry ?\n "> " st)
+ (modify-syntax-entry ?~ " " st)
+ st))
+
+(defvar bibtex-mode-abbrev-table nil "")
+(define-abbrev-table 'bibtex-mode-abbrev-table ())
+(defvar bibtex-mode-map
+ (let ((km (make-sparse-keymap)))
+
+ (define-key km "\t" 'bibtex-find-text)
+ (define-key km "\n" 'bibtex-next-field)
+ (define-key km "\C-c\"" 'bibtex-remove-double-quotes)
+ (define-key km "\C-c\C-c" 'bibtex-clean-entry)
+ (define-key km "\C-c?" 'describe-mode)
+ (define-key km "\C-c\C-p" 'bibtex-pop-previous)
+ (define-key km "\C-c\C-n" 'bibtex-pop-next)
+ (define-key km "\C-c\C-k" 'bibtex-kill-optional-field)
+ (define-key km "\C-c\C-d" 'bibtex-empty-field)
+
+ ;; [alarson:19920131.1543CST]
+ (define-key km "\"" 'TeX-insert-quote)
+ (define-key km "\C-c$" 'ispell-bibtex-entry)
+ (define-key km "\M-\C-a" 'beginning-of-bibtex-entry)
+ (define-key km "\M-\C-e" 'end-of-bibtex-entry)
+ (define-key km "\C-ce" 'bibtex-entry)
+ (define-key km "\C-cn" 'narrow-to-bibtex-entry)
+
+ (define-key km "\C-c\C-e\C-a" 'bibtex-Article)
+ (define-key km "\C-c\C-e\C-b" 'bibtex-Book)
+; (define-key km "\C-c\C-e\C-d" 'bibtex-DEAthesis)
+ (define-key km "\C-c\C-e\C-c" 'bibtex-InProceedings)
+ (define-key km "\C-c\C-e\C-i" 'bibtex-InBook)
+ (define-key km "\C-c\C-ei" 'bibtex-InCollection)
+ (define-key km "\C-c\C-eI" 'bibtex-InProceedings)
+ (define-key km "\C-c\C-e\C-m" 'bibtex-Manual)
+ (define-key km "\C-c\C-em" 'bibtex-MastersThesis)
+ (define-key km "\C-c\C-eM" 'bibtex-Misc)
+ (define-key km "\C-c\C-o" 'bibtex-remove-OPT)
+ (define-key km "\C-c\C-e\C-p" 'bibtex-PhdThesis)
+ (define-key km "\C-c\C-ep" 'bibtex-Proceedings)
+ (define-key km "\C-c\C-eP" 'bibtex-preamble)
+ (define-key km "\C-c\C-e\C-t" 'bibtex-TechReport)
+ (define-key km "\C-c\C-e\C-s" 'bibtex-string)
+ (define-key km "\C-c\C-e\C-u" 'bibtex-Unpublished)
+ km))
+
+(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.")
+
+
+;;; 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
+ (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-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
+ (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.")
+
+(defun bibtex-current-entry-label (&optional include-cite kill)
+ "Return the label of the bibtex entry containing, or preceeding point.
+Optional argument INCLUDE-CITE, if true means put a '\\cite{}' around the
+returned value. Second optional argument KILL, if true, means place the
+returned value in the kill buffer. Interactively; providing prefix
+argument makes INCLUDE-CITE true, and kill is true by default.
+
+Rationale:
+The intention is that someone will write a function that can be bound to
+a mouse key so that people entering TeX can just mouse on the bibtex entry
+and have the citation key inserted at the current point (which will almost
+certainly be in some other bufer). In the interim this function is
+marginally useful for keyboard binding and is not bound by default.
+Suggested binding is ^C-k."
+ (interactive (list current-prefix-arg t))
+ (save-excursion
+ (beginning-of-bibtex-entry)
+ (re-search-forward bibtex-reference-head (save-excursion (end-of-bibtex-entry) (point)))
+ (let* ((key (buffer-substring (match-beginning bibtex-key-in-head)
+ (match-end bibtex-key-in-head)))
+ (val (if include-cite
+ (format "\\cite{%s}" key)
+ key)))
+ (if kill
+ (put-string-on-kill-ring val))
+ val)))
+
+;;; bibtex mode:
+
+(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.
+
+The following may be of interest as well:
+
+ Functions:
+ find-bibtex-duplicates
+ find-bibtex-entry-location
+ hide-bibtex-entry-bodies
+ sort-bibtex-entries
+ validate-bibtex-buffer
+
+ Variables:
+ bibtex-clean-entry-zap-empty-opts
+ bibtex-entry-field-alist
+ bibtex-include-OPTannote
+ bibtex-include-OPTcrossref
+ bibtex-include-OPTkey
+ bibtex-maintain-sorted-entries
+ bibtex-mode-user-optional-fields
+
+Fields:
+ address
+ Publisher's address
+ 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
+ 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 and labeling 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)
+ (set-syntax-table bibtex-mode-syntax-table)
+ (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]*$")
+ (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))
+
+(defun ispell-abstract ()
+ (interactive)
+ (beginning-of-bibtex-entry)
+ (re-search-forward "^[ \t]*[OPT]*abstract[ \t]*=")
+ (ispell-region (point)
+ (save-excursion (forward-sexp) (point))))
+
+(defun beginning-of-bibtex-entry ()
+ (interactive)
+ (re-search-backward "^@" nil 'move))
+
+(defun skip-whitespace-and-comments ()
+ ;; It might be a good idea to have forward-sexp with argument 0 do what
+ ;; this function tries to do, namely skip whitespace and comments.
+ ;; Maybe a better name for this would be skip-to-next-sexp.
+ ;; alternative implementation:
+ ;; (let ((parse-sexp-ignore-comments t))
+ ;; (forward-sexp 1)
+ ;; (forward-sexp -1))
+ ;; but I've had problems with this not getting the parse of comments
+ ;; right going backward if they contain unbalanced expressions or string
+ ;; quotes. [alarson:19920217.1021CST]
+ (let ((md (match-data)))
+ (unwind-protect
+ (while (cond ((looking-at "\\s>+\\|\\s +")
+ ;; was whitespace
+ ;; NOTE: also checked end-comment. In latex and
+ ;; lisp modes, newline is an end comment, but it
+ ;; should also be a whitespace char.
+ (goto-char (match-end 0)))
+ ;; If looking at beginning of comment, skip to end.
+ ((looking-at "\\s<")
+ (re-search-forward "\\s>"))))
+ (store-match-data md))))
+
+;;; [alarson:19920214.1007CST]
+(defun end-of-bibtex-entry ()
+ "If inside an entry, move to the end of it, otherwise move to the end
+of the next entry."
+ (interactive)
+ ;; if point was previously at the end of an entry, this puts us
+ ;; inside the next entry, otherwise we remain in the current one.
+ (progn
+ (skip-whitespace-and-comments)
+;;; (skip-chars-forward " \t\n")
+ (end-of-line))
+ (beginning-of-bibtex-entry)
+ (let ((parse-sexp-ignore-comments t))
+ (forward-sexp) ; skip entry type
+ (forward-sexp) ; skip entry body
+ ))
+;(defun end-of-bibtex-entry ()
+; (interactive)
+; (re-search-forward "}$" nil 'move))
+
+(defun ispell-bibtex-entry ()
+ (interactive)
+ (ispell-region (progn (beginning-of-bibtex-entry) (point))
+ (progn (end-of-bibtex-entry) (point))))
+
+(defun narrow-to-bibtex-entry ()
+ (interactive)
+ (save-excursion
+ (narrow-to-region (progn (beginning-of-bibtex-entry) (point))
+ (progn (end-of-bibtex-entry) (point)))))
+
+
+(defun beginning-of-first-bibtex-entry ()
+ (goto-char (point-min))
+ (cond
+ ((re-search-forward "^@" nil 'move)
+ (beginning-of-line))
+ ((and (bobp) (eobp))
+ nil)
+ (t
+ (message "Warning: No bibtex entries found!"))))
+
+(defun hide-bibtex-entry-bodies (&optional arg)
+ "Hide all lines between first and last bibtex entries not beginning with @.
+With argument, show all text."
+ (interactive "P")
+ (save-excursion
+ (beginning-of-first-bibtex-entry)
+ ;; subst-char-in-region modifies the buffer, despite what the
+ ;; documentation says...
+ (let ((modifiedp (buffer-modified-p))
+ (buffer-read-only nil))
+ (if arg
+ (subst-char-in-region (point) (point-max) ?\r ?\n t)
+ (while (save-excursion (re-search-forward "\n[^@]" (point-max) t))
+ (save-excursion (replace-regexp "\n\\([^@]\\)" "\r\\1"))))
+ (setq selective-display (not arg))
+ (set-buffer-modified-p modifiedp))))
+
+(defvar bibtex-sort-ignore-string-entries nil
+ "*If true, bibtex @STRING entries are ignored when determining ordering
+of the buffer (e.g. sorting, locating alphabetical position for new entries,
+etc.)")
+
+(defun sort-bibtex-entries ()
+ "Sort bibtex entries alphabetically by key.
+Text before the first bibtex entry, and following the last is not affected.
+If bibtex-sort-ignore-string-entries is true, @string entries will be ignored.
+
+Bugs:
+ 1. Text between the closing brace ending one bibtex entry, and the @ starting
+ the next, is considered part of the PRECEEDING entry. Perhaps it should be
+ part of the following entry."
+ (interactive)
+ (save-restriction
+ (beginning-of-first-bibtex-entry)
+ (narrow-to-region (point)
+ (save-excursion
+ (goto-char (point-max))
+ (beginning-of-bibtex-entry)
+ (end-of-bibtex-entry)
+ (point)))
+ (sort-subr nil ; reversep
+ ;; begining of record function
+ 'forward-line
+ ;; end of record function
+ (function (lambda () (and (re-search-forward "}\\s-*\n[\n \t]*@" nil 'move)
+ (forward-char -2))))
+ ;; start of key function
+ (if bibtex-sort-ignore-string-entries
+ (function (lambda ()
+ (while (and (re-search-forward "^\\s-*\\([@a-zA-Z]*\\)\\s-*{\\s-*")
+ (string-equalp "@string"
+ (buffer-substring (match-beginning 1)
+ (match-end 1)))))
+ nil))
+ (function (lambda () (re-search-forward "{\\s-*") nil)))
+ ;; end of key function
+ (function (lambda () (search-forward ",")))
+ )))
+
+(defun map-bibtex-entries (fun)
+ "Call FUN for each bibtex entry starting with the current, to the end of the file.
+FUN is called with one argument, the key of the entry, and with point inside the entry.
+If bibtex-sort-ignore-string-entries is true, FUN will not be called for @string entries."
+ (beginning-of-bibtex-entry)
+ (while (re-search-forward "^@[^{]*{[ \t]*\\([^, ]*\\)" nil t)
+ (if (and bibtex-sort-ignore-string-entries
+ (string-equalp "@string{"
+ (buffer-substring (match-beginning 0)
+ (match-beginning 1))))
+ nil ; ignore the @string entry.
+ (funcall fun (buffer-substring (match-beginning 1) (match-end 1))))))
+
+(defun find-bibtex-entry-location (entry-name)
+ "Searches from beginning of current buffer looking for place to put the
+bibtex entry named ENTRY-NAME. Buffer is assumed to be in sorted order,
+without duplicates (see \\[sort-bibtex-entries]), if it is not, an error will
+be signalled."
+ (interactive "sBibtex entry key: ")
+ (let ((previous nil)
+ point)
+ (beginning-of-first-bibtex-entry)
+ (or (catch 'done
+ (map-bibtex-entries (function (lambda (current)
+ (cond
+ ((string-equal entry-name current)
+ (error "Entry duplicates existing!"))
+ ((or (null previous)
+ (string< previous current))
+ (setq previous current
+ point (point))
+ (if (string< entry-name current)
+ (progn
+ (beginning-of-bibtex-entry)
+ ;; Many schemes append strings to
+ ;; existing entries to resolve them,
+ ;; so initial substring matches may
+ ;; indicate a duplicate entry.
+ (let ((idx (string-match (regexp-quote entry-name) current)))
+ (if (and (integerp idx)
+ (zerop idx))
+ (progn
+ (message "Warning: Entry %s may be a duplicate of %s!"
+ entry-name current)
+ (ding t))))
+ (throw 'done t))))
+ ((string-equal previous current)
+ (error "Duplicate here with previous!"))
+ (t (error "Entries out of order here!")))))))
+ (end-of-bibtex-entry))))
+
+(defun validate-bibtex-buffer ()
+ "Find some typical errors in bibtex files.
+ 1. At signs (@) not as first char of a line.
+ 2. Double quotes (\") inside strings.
+ 3. Closing braces (}) not the last character of a line."
+ (interactive)
+ (let ((point (point)))
+ (while (re-search-forward ".@" nil t)
+ (let* ((foo (parse-partial-sexp (save-excursion (beginning-of-bibtex-entry)
+ (point))
+ (point)))
+ (in-a-string (nth 3 foo)))
+ (if (not in-a-string)
+ (error "At sign (@) out of place!"))))
+ (goto-char point)
+ (while (search-forward "\"" nil t)
+ (or (looking-at "[,}][ \t]*$")
+ (char-equal (preceding-char) ?\")
+ ;; some versions put closing brace on separate line.
+ (looking-at "[ \t]*\n}")
+ (save-excursion
+ (save-restriction
+ (narrow-to-region (point)
+ (progn (beginning-of-line) (point)))
+ (looking-at "^[ \t]*[a-zA-Z]+[ \t]*=[ \t]*\"$")))
+ (error "Quote out of place, or missing \",\" or \"}\"!")))
+ (goto-char point)
+ ;; This is only approximate, should actually search for close braces,
+ ;; then see if they are inside a string, or at the end of a line.
+ ;; This just gets the typical case of whitespace after a closing brace.
+ (while (search-forward "}[ \t]+$" nil t)
+ (error "Brace not last char of line!"))
+ (goto-char point)
+ (message "Bibtex buffer appears o.k.")))
+
+(defun find-bibtex-duplicates ()
+ "Searches forward in current buffer looking for duplicate bibtex entries.
+Buffer is assumed to be sorted, see \\[sort-bibtex-entries]"
+ (interactive)
+ (let ((point (point)))
+ ;; errors if things are not right...
+ (find-bibtex-entry-location (make-string 10 255))
+ (goto-char point)
+ (message "No duplicates found!")))
+
+
+;;; assoc doesn't ignore case, so we need an assoc that does...
+(defun assoc-string-equalp (thing alist)
+ (or (assoc thing alist)
+ (while (and alist
+ (not (string-equalp thing (car (car alist)))))
+ (setq alist (cdr alist)))
+ (car alist)))
+
+(defvar bibtex-maintain-sorted-entries nil
+ "*If true, bibtex-mode will attempt to maintain all bibtex entries in
+sorted order.
+
+Note that this is more a property of a file than a personal preference and
+as such should normally be set via a file local variable entry.")
+
+(defun bibtex-entry (entry-type &optional required optional)
+ (interactive (let* ((completion-ignore-case t)
+ (e-t (completing-read "Entry Type: " bibtex-entry-field-alist
+ nil t)))
+ (list e-t)))
+ (if (and (null required) (null optional))
+ (let* ((e (assoc-string-equalp entry-type bibtex-entry-field-alist))
+ (r-n-o (elt e 1))
+ (c-ref (elt e 2)))
+ (if (null e)
+ (error "Bibtex entry type %s not defined!"))
+ (if (and bibtex-include-OPTcrossref c-ref)
+ (setq required (elt c-ref 0)
+ optional (elt c-ref 1))
+ (setq required (elt r-n-o 0)
+ optional (elt r-n-o 1)))))
+ (let (key)
+ (if bibtex-maintain-sorted-entries
+ (progn
+ (setq key (read-string (format "%s key: " entry-type)))
+ (find-bibtex-entry-location key)))
+ (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)
+ (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)
+ (if key
+ (progn
+ (insert key)
+ (search-forward "\"\",")
+ (backward-char 2)
+ ;; this doesn't handle the first field right! [alarson:19920213.1830CST]
+ ;;(bibtex-next-field t)
+ ))
+ (run-hooks 'bibtex-add-entry-hook)))
+
+;; (defun bibtex-entry (entry-type required optional)
+;; (bibtex-move-outside-of-entry)
+;; (insert (concat "@" entry-type "{,\n\n}\n\n"))
+;; (previous-line 3)
+;; (insert (mapconcat 'bibtex-make-entry required ",\n"))
+;; (if required
+;; (if optional
+;; (insert ",\n")))
+;; (insert (mapconcat 'bibtex-make-OPT-entry optional ",\n"))
+;; (if bibtex-mode-user-optional-fields ;MON...
+;; (progn
+;; (if optional
+;; (insert ",\n"))
+;; (insert (mapconcat 'bibtex-make-OPT-entry
+;; bibtex-mode-user-optional-fields
+;; ",\n")))) ;MON
+;; (up-list -1)
+;; (forward-char 1))
+
+
+(defun bibtex-make-field (e-t)
+ (interactive "sBibTeX entry type: ")
+ (let ((name (if (consp e-t) (car e-t) e-t))
+ (value (if (consp e-t) (cdr e-t) "")))
+ (insert ",\n")
+ (indent-to-column bibtex-name-alignement)
+ (insert name " = ")
+ (indent-to-column bibtex-text-alignment)
+ (insert (prin1-to-string value))
+ nil))
+
+(defun bibtex-make-optional-field (e-t)
+ (interactive "sOptional BibTeX entry type: ")
+ (if (consp e-t)
+ (setq e-t (cons (concat "OPT" (car e-t)) (cdr e-t)))
+ (setq e-t (concat "OPT" e-t)))
+ (bibtex-make-field e-t))
+
+;; What to do about crossref? if present, journal and year are
+;; both optional. Due to this, i move all of them into optional. -- MON
+
+(defvar bibtex-entry-field-alist
+ '(
+ ("Article" . ((("author" "title" "journal" "year")
+ ("volume" "number" "pages" "month" "note"))
+ (("author" "title")
+ ("journal" "year" "volume" "number" "pages"
+ "month" "note"))))
+ ("Book" . ((("author" "title" "publisher" "year")
+ ("editor" "volume" "number" "series" "address"
+ "edition" "month" "note"))))
+ ("Booklet" . ((("title")
+ ("author" "howpublished" "address" "month" "year" "note"))))
+
+ ;; France: Dipl\^{o}me d'Etudes Approfondies (similar to Master's)
+; ("DEAthesis" . ((("author" "title" "school" "year")
+; ("address" "month" "note"))))
+
+ ("InBook" . ((("author" "title" "chapter" "publisher" "year")
+ ("editor" "pages" "volume" "number" "series" "address"
+ "edition" "month" "type" "note"))
+ (("author" "title" "chapter")
+ ("publisher" "year" "editor" "pages" "volume" "number"
+ "series" "address" "edition" "month" "type" "note"))))
+
+
+ ("InCollection" . ((("author" "title"
+ "booktitle" "publisher" "year")
+ ("editor" "volume" "number" "series" "type" "chapter"
+ "pages" "address" "edition" "month" "note"))
+ (("author" "title")
+ ("booktitle" "publisher" "year"
+ "editor" "volume" "number" "series" "type" "chapter"
+ "pages" "address" "edition" "month" "note"))))
+
+
+ ("InProceedings" . ((("author" "title" "booktitle" "year")
+ ("editor" "volume" "number" "series" "pages"
+ "organization" "publisher" "address" "month" "note"))
+ (("author" "title")
+ ("editor" "volume" "number" "series" "pages"
+ "booktitle" "year"
+ "organization" "publisher" "address" "month" "note"))))
+
+
+ ("Manual" . ((("title")
+ ("author" "organization" "address" "edition" "year"
+ "month" "note"))))
+
+ ("MastersThesis" . ((("author" "title" "school" "year")
+ ("address" "month" "note" "type"))))
+
+ ("Misc" . ((()
+ ("author" "title" "howpublished" "year" "month" "note"))))
+
+ ("PhdThesis" . ((("author" "title" "school" "year")
+ ("address" "month" "type" "note"))))
+
+ ("Proceedings" . ((("title" "year")
+ ("editor" "volume" "number" "series" "publisher"
+ "organization" "address" "month" "note"))))
+
+ ("TechReport" . ((("author" "title" "institution" "year")
+ ("type" "number" "address" "month" "note"))))
+
+ ("Unpublished" . ((("author" "title" "note")
+ ("year" "month"))))
+ )
+
+ "List of (entry-name (required optional) (crossref-required crossref-optional))
+tripples. If the third element is nil, then the first pair can be used. Required
+and optional are lists of strings. All entry creation functions use this variable
+to generate entries, and bibtex-entry ensures the entry type is valid. This
+variable can be used for example to make bibtex manipulate a different set of entry
+types, e.g. a crossreference document of organization types.")
+
+
+(defun bibtex-Article ()
+ (interactive)
+ (bibtex-entry "Article"))
+
+(defun bibtex-Book ()
+ (interactive)
+ (bibtex-entry "Book"))
+
+(defun bibtex-Booklet ()
+ (interactive)
+ (bibtex-entry "Booklet"))
+
+;(defun bibtex-DEAthesis ()
+; (interactive)
+; (bibtex-entry "DEAthesis"))
+
+(defun bibtex-InBook ()
+ (interactive)
+ (bibtex-entry "InBook"))
+
+(defun bibtex-InCollection ()
+ (interactive)
+ (bibtex-entry "InCollection"))
+
+(defun bibtex-InProceedings ()
+ (interactive)
+ (bibtex-entry "InProceedings"))
+
+(defun bibtex-Manual ()
+ (interactive)
+ (bibtex-entry "Manual"))
+
+(defun bibtex-MastersThesis ()
+ (interactive)
+ (bibtex-entry "MastersThesis"))
+
+(defun bibtex-Misc ()
+ (interactive)
+ (bibtex-entry "Misc"))
+
+(defun bibtex-PhdThesis ()
+ (interactive)
+ (bibtex-entry "PhdThesis"))
+
+(defun bibtex-Proceedings ()
+ (interactive)
+ (bibtex-entry "Proceedings"))
+
+(defun bibtex-TechReport ()
+ (interactive)
+ (bibtex-entry "TechReport"))
+
+(defun bibtex-Unpublished ()
+ (interactive)
+ (bibtex-entry "Unpublished"))
+
+(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-next-field ()
+;; "Finds end of text of next field."
+;; (interactive)
+;; (condition-case ()
+;; (progn
+;; (bibtex-inside-field)
+;; (re-search-forward ",[ \t\n]*" (point-max) 1)
+;; (bibtex-enclosing-field)
+;; (bibtex-inside-field))
+;; (error nil)))
+
+(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-find-text ()
+;; "Go to end of text of current field."
+;; (interactive)
+;; (condition-case ()
+;; (progn
+;; (bibtex-inside-field)
+;; (bibtex-enclosing-field)
+;; (goto-char (match-end bibtex-text-in-field))
+;; (bibtex-inside-field))
+;; (error nil)))
+
+(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")
+ ;; sct@dcs.edinburgh.ac.uk
+ (progn
+ (delete-char (length "OPT"))
+ (search-forward "=")
+ (delete-horizontal-space)
+ (indent-to-column bibtex-text-alignment))))
+ (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") ;MON - maybe delete these chars?
+ (cond ((= (preceding-char) ?,)
+ (forward-char -2))) ; -1 --> -2 sct@dcs.edinburgh.ac.uk
+ (cond ((= (preceding-char) ?\")
+ (forward-char -1)))) ;MON - 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."
+ ;; sct@dcs.edinburgh.ac.uk
+ (let ((old-point (point)))
+ (condition-case errname
+ (bibtex-enclosing-regexp bibtex-field)
+ (search-failed
+ (goto-char old-point)
+ (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."
+ ;; sct@dcs.edinburgh.ac.uk
+ (let ((old-point (point)))
+ (condition-case errname
+ (bibtex-enclosing-regexp bibtex-reference)
+ (search-failed
+ (goto-char old-point)
+ (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)
+ (beginning-of-bibtex-entry)
+ (let ((start (point)))
+ (save-restriction
+ (narrow-to-region start (save-excursion (end-of-bibtex-entry) (point)))
+ (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"))
+ (progn
+ ;; fixup alignment. [alarson:19920309.2047CST]
+ (search-forward "=")
+ (delete-horizontal-space)
+ (indent-to-column bibtex-text-alignment))
+ (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)
+ (end-of-bibtex-entry)
+ ;; sct@dcs.edinburgh.ac.uk
+ (save-excursion
+ (previous-line 1)
+ (end-of-line)
+ (if (eq (preceding-char) ?,)
+ (backward-delete-char 1)))
+ (skip-whitespace-and-comments)))
+
+;;; Addition by: terrence brannon <brannon@jove.cs.caltech.edu>
+;;; slightly modified; alarson to use file-writable-p and to be more
+;;; careful about what other buffers might be visible on the screen at the
+;;; current time.
+(defun bibtex-refile-entry (to-file)
+ "Move the current bibtex entry to the end of a different bibtex file.
+For example; You might record the bibtex entry for documents you want the
+library to obtain in a requested.bib file. After the document comes in,
+move it to a permanent file based on the category of the bibliography entry."
+
+ (interactive (list (read-file-name "Move to what bib file? "
+ nil default-directory nil)))
+ (save-excursion
+ (let ((start (progn (beginning-of-bibtex-entry) (point)))
+ (end (progn (end-of-bibtex-entry) (point))))
+
+ (if (file-writable-p (expand-file-name to-file))
+ (save-excursion
+ (kill-region start end)
+ (unwind-protect
+ (progn
+ (let ((b (find-file-noselect (expand-file-name to-file))))
+ (goto-char (point-max))
+ (insert "\n")
+ (set-buffer b)))
+ (yank))
+ (save-buffer))
+ (error "file not accessible")))))
+
+
+
+
+
+;;; 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.
+
+;(defmacro eval-in-menu-window (&rest l)
+; "Evaluates its argument in the window in which the mouse button was pressed."
+; (list 'eval-in-window '*menu-window* l))
+
+;(defmenu bibtex-sun-entry-menu
+; ("Article In Conf. Proc." eval-in-menu-window bibtex-InProceedings)
+; ("Article In Journal" eval-in-menu-window bibtex-Article)
+; ("Book" eval-in-menu-window bibtex-Book)
+; ("Booklet" eval-in-menu-window bibtex-Booklet)
+; ("Master's Thesis" eval-in-menu-window bibtex-MastersThesis)
+; ("PhD. Thesis" eval-in-menu-window bibtex-PhdThesis)
+; ("Technical Report" eval-in-menu-window bibtex-TechReport)
+; ("Technical Manual" eval-in-menu-window bibtex-Manual)
+; ("Conference Proceedings" eval-in-menu-window bibtex-Proceedings)
+; ("In A Book" eval-in-menu-window bibtex-InBook)
+; ("In A Collection" eval-in-menu-window bibtex-InCollection)
+; ("Miscellaneous" eval-in-menu-window bibtex-Misc)
+; ("Unpublished" eval-in-menu-window bibtex-Unpublished)
+; ("string" eval-in-menu-window bibtex-string)
+; ("preamble" eval-in-menu-window bibtex-preamble))
+;
+;(defmenu bibtex-sun-menu
+; ("BibTeX menu")
+; ("add entry" . bibtex-sun-entry-menu)
+; ("next field" eval-in-menu-window bibtex-next-field nil)
+; ("to end of field" eval-in-menu-window bibtex-find-text nil)
+; ("snatch similar preceding field" eval-in-menu-window bibtex-pop-previous 1)
+; ("snatch similar following field" eval-in-menu-window bibtex-pop-next 1)
+; ("remove OPT" eval-in-menu-window bibtex-remove-OPT)
+; ("remove quotes" eval-in-menu-window bibtex-remove-double-quotes)
+; ("clean entry" eval-in-menu-window bibtex-clean-entry)
+; ("describe BibTeX mode" eval-in-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))
+;
+
+;;; ------------- end bibtex-mode.el -------------------------------
diff --git a/support/emacs-modes/cweave.ch b/support/emacs-modes/cweave.ch
new file mode 100644
index 0000000000..38c4050e07
--- /dev/null
+++ b/support/emacs-modes/cweave.ch
@@ -0,0 +1,77 @@
+%
+% cweave.ch by Mark Motl for the purpose of separating the index
+% and module names into files INDEX.tex and MODULE_NAMES.tex
+% respectively. These are used in the web-mode for gnu-emacs.
+
+@x
+@* Introduction.
+The ``banner line'' defined here should be changed whenever \.{CWEAVE}
+is modified.
+
+@d banner "This is CWEAVE ($Revision: 1.9 $)\n"
+@y
+@* Introduction.
+The ``banner line'' defined here should be changed whenever \.{CWEAVE}
+is modified.
+
+@d banner "CWEAVE ($Rev: 1.9 $), writes INDEX.tex and MODULE_NAMES.tex\n"
+@z
+
+
+@x
+@ @c phase_three() {
+if (no_xref) {
+ finish_line();
+ out_str("\\vfill\\end");
+ finish_line();
+}
+else {
+ phase=3; printf("\nWriting the index...");
+ if (change_exists) {
+ finish_line(); @<Tell about changed modules@>;
+ }
+ finish_line(); out_str("\\inx"); finish_line();
+@.\\inx@>
+ @<Do the first pass of sorting@>;
+ @<Sort and output the index@>;
+ out_str("\\fin"); finish_line();
+@.\\fin@>
+ @<Output all the module names@>;
+ out_str("\\con"); finish_line();
+@.\\con@>
+}
+printf("Done.");
+check_complete(); /* was all of the change file used? */
+}
+@y
+@ @c phase_three() {
+if (no_xref) {
+ finish_line();
+ out_str("\\vfill\\end");
+ finish_line();
+}
+else {
+ phase=3; printf("\nWriting the index...");
+ finish_line();
+ out_str("\\input INDEX"); finish_line(); finish_line();
+ out_str("\\input MODULE_NAMES"); finish_line(); fclose(tex_file);
+ if ((tex_file=fopen("INDEX.tex","w"))==NULL)
+ fatal("! Cannot open ouput file ","INDEX.tex");
+ if (change_exists) { @<Tell about changed modules@>;
+ finish_line(); finish_line(); }
+ out_str("\\inx"); finish_line();
+@.\\inx@>
+ @<Do the first pass of sorting@>;
+ @<Sort and output the index@>;
+ out_str("\\fin"); finish_line(); fclose(tex_file);
+@.\\fin@>
+ if ((tex_file=fopen("MODULE_NAMES.tex","w"))==NULL)
+ fatal("! Cannot open ouput file ","MODULE_NAMES.tex");
+ @<Output all the module names@>;
+ out_str("\\con"); finish_line(); fclose(tex_file);
+@.\\con@>
+}
+printf("Done.");
+check_complete(); /* was all of the change file used? */
+}
+@z
diff --git a/support/emacs-modes/fweave.ch b/support/emacs-modes/fweave.ch
new file mode 100644
index 0000000000..23482dcec6
--- /dev/null
+++ b/support/emacs-modes/fweave.ch
@@ -0,0 +1,88 @@
+@x
+@ This is the third phase.
+
+@a
+SRTN phase_three(VOID)
+{
+if (no_xref)
+ {
+ finish_line();
+ out_str("\\vfill\\end"); @+ finish_line();
+ }
+else
+ {
+ phase=3; printf("\nWriting the index...");
+
+ if (change_exists)
+ {
+ finish_line(); @<Tell about changed modules@>;
+ }
+
+ finish_line();
+out_str(w_style.indx.preamble); @+ finish_line();
+@.\\Winx@>
+
+ @<Do the first pass of sorting@>;
+ @<Sort and output the index@>;
+ out_str(w_style.indx.postamble); @+ finish_line();
+@.\\Wfin@>
+
+@<Print the command line, etc.@>;
+ @<Output all the module names@>;
+ out_str("\\Wcon"); @+ finish_line();
+@.\\Wcon@>
+ }
+
+printf("Done.");
+check_complete(); /* Was all of the change file used? */
+}
+@y
+@ This is the third phase.
+
+@a
+SRTN phase_three(VOID)
+
+{
+if (no_xref) {
+ finish_line();
+ out_str("\\vfill\\end"); @+ finish_line();
+ }
+else
+ {
+ phase=3; printf("\nWriting the index...");
+ finish_line();
+ out_str("\\input INDEX"); finish_line(); finish_line();
+ out_str("\\input MODULE_NAMES"); finish_line();
+ out_str("\\bigskip");
+ @<Print the command line, etc.@>;
+ out_str("\\Wcon"); @+ finish_line();
+@.\\Wcon@>
+
+ fclose(tex_file);
+ if ((tex_file=fopen("INDEX.tex","w"))==NULL)
+ fatal("! Cannot open ouput file ","INDEX.tex");
+
+ if (change_exists) {
+ @<Tell about changed modules@>;
+ finish_line(); finish_line(); }
+
+ out_str(w_style.indx.preamble); @+ finish_line();
+@.\\Winx@>
+
+ @<Do the first pass of sorting@>;
+ @<Sort and output the index@>;
+ out_str(w_style.indx.postamble); @+ finish_line();
+@.\\Wfin@>
+
+ fclose(tex_file);
+ if ((tex_file=fopen("MODULE_NAMES.tex","w"))==NULL)
+ fatal("! Cannot open ouput file ","MODULE_NAMES.tex");
+
+ @<Output all the module names@>;
+
+ fclose(tex_file); }
+
+printf("Done. aTm 1.00");
+check_complete(); /* Was all of the change file used? */
+}
+@z
diff --git a/support/emacs-modes/inspec2bibtex.el b/support/emacs-modes/inspec2bibtex.el
new file mode 100644
index 0000000000..11c2c683e9
--- /dev/null
+++ b/support/emacs-modes/inspec2bibtex.el
@@ -0,0 +1,836 @@
+;; INSPEC to BibTeX bibliography conversion routine.
+;; Copyright 1990 Ralph P. Sobek
+;; inspect2bibtex.el version 1.2
+;;
+;;; This program 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.
+;;;
+;;; This program 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.
+;;;
+;;; A copy of the GNU General Public License can be obtained from this
+;;; program's author (send electronic mail to ralph@laas.fr) or from
+;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+;;; 02139, USA.
+;;;
+;;; Send bug reports, suggestions, or improvements to ralph@laas.fr.
+
+(autoload 'bibtex-move-outside-of-entry "bibtex-mode")
+(provide 'inspec2)
+
+(defvar *INSPEC-msg-buffer* (get-buffer-create "*INSPEC Output*"))
+
+(defvar *INSPEC-msg-flag* nil)
+
+(defvar *INSPEC-buffer* nil)
+
+(defvar *BibTeX-buffer* nil)
+
+(defvar *INSPEC-last-id* "")
+
+;; INSPEC REGEXPs
+
+(defconst INSPEC-header
+ "^Quest Accession Number : \\([0-9]+\\)\n \\(.*\\) INSPEC \\(.*\\) Issue.*$")
+
+(defconst INSPEC-beginning "^ ")
+(defconst INSPEC-end "\\(^ \\|\\'\\)")
+
+(defconst INSPEC-blank "[ \n] *")
+(defconst INSPEC-sep
+ (concat "\n?,"
+ INSPEC-blank))
+
+(defconst INSPEC-tail-sep
+ (concat "\n?,\\("
+ INSPEC-blank
+ "\\|\\'\\)"))
+
+(defconst INSPEC-tail "Treatment: \\(.+\n\\)+\n")
+
+(defconst INSPEC-year "\\([0-9][0-9][0-9][0-9]\\)")
+
+(defconst INSPEC-refs
+ (concat "\\([0-9]+"
+ INSPEC-blank
+ "Refs\\)"))
+
+(defconst INSPEC-ref-refs
+ (concat INSPEC-refs
+ INSPEC-tail-sep))
+
+(defconst INSPEC-day "[0-9][0-9]?")
+
+(defconst INSPEC-month
+ "\\(Jan\\.\\|Feb\\.\\|March\\|April\\|May\\|June\\|July\\|Aug\\.\\|Sept\\.\\|Oct\\.\\|Nov\\.\\|Dec\\.\\)")
+
+(defconst INSPEC-dates
+ (concat "\\(\\(.*\\)"
+ INSPEC-blank
+ "\\)?"
+ INSPEC-year))
+
+(defconst INSPEC-ref-dates
+ (concat INSPEC-dates
+ INSPEC-tail-sep))
+
+(defconst INSPEC-d-month-flag 1)
+(defconst INSPEC-d-month-index 2)
+(defconst INSPEC-d-year 3)
+
+(defconst INSPEC-volume "vol\\.\\([^ ,]+\\)")
+
+(defconst INSPEC-ref-volume
+ (concat INSPEC-volume
+ INSPEC-tail-sep))
+
+(defconst INSPEC-pages "p\\.\n?\\([---0-9+]+\\)")
+
+;; INSPEC Conference Paper REGEXPs
+
+(defconst INSPEC-ref-pages
+ (concat INSPEC-pages
+ "\\("
+ INSPEC-blank
+ "\\(pp\\|supl\\)\\.\\)?\\( "
+ INSPEC-volume
+ "\\)?"
+ INSPEC-tail-sep
+ ))
+
+(defconst INSPEC-ref-pages-index 1)
+(defconst INSPEC-ref-pp-index 2)
+(defconst INSPEC-ref-volume-index 5)
+
+(defconst INSPEC-country
+ (concat "\\("
+ INSPEC-sep
+ ".*\\)*Country"
+ INSPEC-blank
+ "of"
+ INSPEC-blank
+ "Publ\\.:"
+ INSPEC-blank
+ "\\(.*\\)$"))
+
+(defconst INSPEC-conference-address "\\(\\([^,]+, \\)?.*\\) ")
+
+(defconst INSPEC-conference-address&date
+ (concat INSPEC-conference-address
+ "\\("
+ INSPEC-dates
+ "\\)$"))
+
+(defconst INSPEC-c-address-index 1)
+(defconst INSPEC-c-dates-index 3)
+(defconst INSPEC-c-month-flag 4)
+(defconst INSPEC-c-month-index 5)
+
+;; INSPEC Journal Paper REGEXPs
+
+(defconst INSPEC-journal-abbrev "\\(.+\\) (\\(.+\\))$")
+
+(defconst INSPEC-journal-name
+ (concat "\\(\\<[^.]+\\>\\)"
+ INSPEC-blank))
+
+(defconst INSPEC-journal-number "no\\.\\([^ ,]+\\)")
+
+(defconst INSPEC-ref-number
+ (concat INSPEC-journal-number
+ INSPEC-tail-sep))
+
+(defconst INSPEC-journal-reference-header
+ (concat "\\("
+ INSPEC-journal-name
+ "\\)?"
+ INSPEC-volume))
+
+(defconst INSPEC-j-name-flag 1)
+(defconst INSPEC-j-name-index 2)
+
+;; INSPEC Report REGEXPs
+
+(defconst INSPEC-report "Rep No\\. \\([0-9A-Za-z---#.]+\\)")
+
+(defconst INSPEC-report-info
+ (concat INSPEC-report
+ " \\([A-Z0-9][^,]*\\)"
+ INSPEC-sep
+ "\\(\\(.+\n\\)+\\)"
+ INSPEC-end))
+
+;; INSPEC Match Functions
+
+(defun match-quest ()
+ "Function to match the next INSPEC quest."
+ (interactive)
+ (let (num type start end (last (point)) begin)
+ (cond ((re-search-forward INSPEC-header nil 'skip 1)
+ (setq num (buffer-substring (match-beginning 2) (match-end 2)))
+ (setq type (buffer-substring (match-beginning 3) (match-end 3)))
+ (setq start (match-end 0))
+ (INSPEC-dump-junk last (match-beginning 0))
+ (re-search-forward paragraph-start)
+ (setq end (match-beginning 0))
+
+ (save-excursion
+ (save-restriction
+ (re-search-backward "^ Treatment:" start t 1)
+ (narrow-to-region start (match-beginning 0))
+ (goto-char start)
+ (cond ((string= "Conference Paper" type)
+ (match-conference-entry))
+ ((string= "Journal Paper" type)
+ (match-journal-entry))
+ ((string= "Report Section" type)
+ (match-in-collection-entry))
+ ((string= "Report" type)
+ (match-report-entry))
+ ((string= "Conference Proceedings" type)
+ (match-proceedings-entry))
+ ((string= "Book Chapter" type)
+ (match-in-book-entry))
+ (t (error "Unknown INSPEC type encountered: %s" type))))))
+ (t (INSPEC-dump-junk last (point-max))))
+))
+
+(defun match-conference-entry ()
+ "Function to match INSPEC Conference Paper."
+ (let ((title (c2string(match-field)))
+ (authors (match-field))
+ (authors-address (match-field))
+ conference
+ conference-ref publisher editors organization address dates volume
+ annote journal-name number month year pages note
+ assoc-value)
+
+
+ (setq authors (squeeze (convert-names (car authors) (car (cdr authors)))))
+
+ (re-search-forward INSPEC-end nil t 1)
+
+ (cond ((match-conf-address&dates (point) (match-field-end))
+ (setq conference (c2string authors-address))
+ (setq authors-address nil)
+ (re-search-forward INSPEC-end nil t 1))
+ (t (setq conference (buffer-substring (point) (match-field-end)))
+ (re-search-forward INSPEC-end nil t 1)
+
+ (if (match-conf-address&dates (point) (match-field-end))
+ (re-search-forward INSPEC-end nil t 1)
+ (INSPEC-msg num
+ "Missing proceedings address or dates in \"%s\"."
+ (buffer-substring (point) (point-max))))))
+
+
+ (cond ((looking-at INSPEC-journal-abbrev)
+ (setq journal-abbrev (list (match-beginning 1) (match-end 1)))
+ (re-search-forward INSPEC-end nil t 1)
+
+ (if (match-INSPEC-reference-field (point) (match-field-end))
+ (re-search-forward INSPEC-end nil t 1)
+ (INSPEC-msg num "Missing journal citation in \"%s\"."
+ (buffer-substring (point) (point-max))))
+
+ (setq note (concat "In "
+ (squeeze conference)
+ ". "
+ (squeeze dates)
+ ", "
+ (squeeze address)))
+
+ (match-language-field)
+ (match-sponsor-field)
+
+ (add-annotation num)
+
+ (add-entry "annote" (squeeze annote))
+ (add-entry "note" note)
+ (add-entry "organization" (squeeze organization))
+ (add-entry "pages" (squeeze pages))
+ (add-entry "number" (squeeze number))
+ (add-entry "volume" (squeeze volume))
+ (add-entry "month" (squeeze month))
+ (add-entry "year" year)
+ (add-entry "journal" (squeeze (cond ((and (stringp journal-name)
+ (not (string= journal-name
+ "")))
+ journal-name)
+ (t (c2string journal-abbrev)))))
+ (add-entry "title" (squeeze title))
+ (add-entry "author" authors)
+ (cons "Article" (cons (make-key authors) assoc-value)))
+
+ ((match-INSPEC-reference-field (point) (match-field-end))
+
+ (re-search-forward INSPEC-end nil t 1)
+
+ (match-language-field)
+ (match-publisher-field t)
+ (match-pages-field)
+ (match-isbn-field)
+ (match-editors-field)
+ (match-sponsor-field)
+
+ (add-annotation num)
+
+ (add-entry "annote" (squeeze annote))
+ (add-entry "note" note)
+ (add-entry "volume" (squeeze volume))
+ (add-entry "address" (squeeze address))
+ (add-entry "publisher" (squeeze publisher))
+ (add-entry "organization" (squeeze organization))
+ (add-entry "pages" (squeeze pages))
+ (add-entry "editor" (squeeze editors))
+ (add-entry "month" (squeeze month))
+ (add-entry "year" year)
+ (add-entry "booktitle" (squeeze conference))
+ (add-entry "title" (squeeze title))
+ (add-entry "author" authors)
+ (cons "InProceedings" (cons (make-key authors) assoc-value)))
+ (t (INSPEC-msg num "Missing conference citation in \"%s\"."
+ (buffer-substring (point) (point-max))))))
+ )
+
+(defun match-journal-entry ()
+ "Function to match INSPEC Journal Paper."
+ (let ((title (c2string(match-field)))
+ (authors (match-field))
+ authors-address journal-abbrev journal-name volume number
+ month year pages note annote assoc-value)
+
+ (re-search-forward INSPEC-end nil t 1)
+ (cond ((not (looking-at INSPEC-journal-abbrev))
+ (setq authors-address (list (point) (match-field-end)))
+ (re-search-forward INSPEC-end nil t 1)
+ (cond ((not (looking-at INSPEC-journal-abbrev))
+ (INSPEC-msg num "Missing journal abbrev. in \"%s\"."
+ (buffer-substring (point) (point-max))))
+ (t
+ (setq journal-abbrev (list (match-beginning 1)
+ (match-end 1)))
+ (re-search-forward INSPEC-end nil t 1))))
+
+ (t (setq journal-abbrev (list (match-beginning 1) (match-end 1)))
+ (re-search-forward INSPEC-end nil t 1)))
+
+ (cond ((match-INSPEC-reference-field (point) (match-field-end))
+ (re-search-forward INSPEC-end nil t 1))
+ (t (INSPEC-msg num "Missing journal citation in \"%s\"."
+ (buffer-substring (point) (point-max)))))
+
+ (match-language-field)
+
+ (add-annotation num)
+
+ (setq authors (squeeze (convert-names (car authors) (car (cdr authors)))))
+
+ (add-entry "annote" (squeeze annote))
+ (add-entry "note" note)
+ (add-entry "pages" (squeeze pages))
+ (add-entry "number" (squeeze number))
+ (add-entry "volume" (squeeze volume))
+ (add-entry "month" (squeeze month))
+ (add-entry "year" (squeeze year))
+ (add-entry "journal" (squeeze (cond ((and (stringp journal-name)
+ (not (string= journal-name
+ "")))
+ journal-name)
+ (t (c2string journal-abbrev)))))
+ (add-entry "title" (squeeze title))
+ (add-entry "author" authors)
+ (cons "Article" (cons (make-key authors) assoc-value))))
+
+(defun match-proceedings-entry ()
+ "Function to match INSPEC Conference Proceedings."
+ (let ((title (c2string(match-field)))
+ booktitle year volume number date publisher organization annote
+ journal-name month pages note assoc-value)
+
+ (re-search-forward INSPEC-end nil t 1)
+ (if (match-conf-address&dates (point) (match-field-end))
+ (re-search-forward INSPEC-end nil t 1)
+ (INSPEC-msg num
+ "Missing proceedings address or dates in \"%s\"."
+ (buffer-substring (point) (point-max))))
+
+
+ (cond ((looking-at INSPEC-journal-abbrev)
+ (setq booktitle (buffer-substring (match-beginning 1) (match-end 1)))
+ (re-search-forward INSPEC-end nil t 1)))
+
+ (cond ((match-INSPEC-reference-field (point) (match-field-end))
+ (re-search-forward INSPEC-end nil t 1))
+ (t (INSPEC-msg num "Missing proceedings citation in \"%s\"."
+ (buffer-substring (point) (+ (point) 30)))))
+
+ (match-language-field)
+ (match-publisher-field)
+ (match-pages-field)
+ (match-sponsor-field)
+
+ (add-annotation num)
+
+ (add-entry "annote" (squeeze annote))
+ ;; (add-entry "note" note)
+ (add-entry "address" (squeeze address))
+ (add-entry "organization" (squeeze organization))
+ (add-entry "publisher" (squeeze publisher))
+ ;; (add-entry "editor" (squeeze editors))
+ ;; (add-entry "author" (squeeze authors))
+ (add-entry "month" (squeeze month))
+ (add-entry "year" (squeeze year))
+ (add-entry "booktitle" (squeeze booktitle))
+ (add-entry "title" (squeeze title))
+ (cons "Proceedings" (cons
+ (make-key (or organization publisher "Unknown"))
+ assoc-value)))
+ )
+
+(defun match-report-entry ()
+ "Function to match INSPEC Report."
+ (let ((title (c2string(match-field)))
+ (authors (match-field))
+ number institution address year month annote note journal-name volume
+ assoc-value)
+
+ (re-search-forward INSPEC-end nil t 1)
+
+ (if (match-INSPEC-reference-field (point) (match-field-end))
+ (re-search-forward INSPEC-end nil t 1)
+ (INSPEC-msg num "Missing report date in \"%s\"."
+ (buffer-substring (point) (point-max))))
+
+ (match-language-field)
+ (match-pages-field)
+ (cond ((looking-at INSPEC-report-info)
+ (setq number (buffer-substring (match-beginning 1) (match-end 1)))
+ (setq institution (buffer-substring (match-beginning 2)
+ (match-end 2)))
+ (setq address (buffer-substring (match-beginning 3) (match-end 3)))
+ (re-search-forward INSPEC-end nil t 1))
+ (t (INSPEC-msg num "Missing Report ref. in \"%s\"."
+ (buffer-substring (point) (point-max)))))
+
+
+ (add-annotation num)
+
+ (setq authors (squeeze (convert-names (car authors) (car (cdr authors)))))
+
+ (add-entry "annote" (squeeze annote))
+ (add-entry "note" note)
+ (add-entry "month" (squeeze month))
+ (add-entry "address" (squeeze address))
+ (add-entry "number" (squeeze number))
+ (add-entry "year" year)
+ (add-entry "institution" (squeeze institution))
+ (add-entry "title" (squeeze title))
+ (add-entry "author" authors)
+ (cons "TechReport" (cons (make-key authors) assoc-value)))
+ )
+
+(defun match-in-collection-entry ()
+ "Function to match INSPEC Report Section."
+ (let ((title (c2string(match-field)))
+ (authors (match-field))
+ (authors-address (match-field))
+ booktitle note volume number date pages month year annote
+ journal-name assoc-value)
+
+ (re-search-forward INSPEC-end nil t 1)
+ (cond ((not (match-INSPEC-reference-field (point) (match-field-end)))
+ (setq booktitle (buffer-substring (point) (match-field-end)))
+ (re-search-forward INSPEC-end nil t 1)
+
+ (if (match-INSPEC-reference-field (point) (match-field-end))
+ (re-search-forward INSPEC-end nil t 1)
+ (INSPEC-msg num "Missing in-collection citation in \"%s\"."
+ (buffer-substring (point) (point-max)))))
+
+ (t (setq booktitle (c2string authors-address))
+ (setq authors-address nil)
+ (re-search-forward INSPEC-end nil t 1)))
+
+ (add-annotation num)
+
+ (setq authors (squeeze (convert-names (car authors) (car (cdr authors)))))
+
+ (match-language-field)
+
+ (add-entry "note" note)
+ (add-entry "annote" (squeeze annote))
+ ;; (add-entry "publisher" (squeeze publisher))
+ ;; (add-entry "editor" (squeeze editor))
+ (add-entry "year" (squeeze year))
+ (add-entry "booktitle" (squeeze booktitle))
+ (add-entry "pages" (squeeze month))
+ (add-entry "title" (squeeze title))
+ (add-entry "author" authors)
+ (cons "InCollection" (cons (make-key authors) assoc-value))))
+
+(defun match-in-book-entry ()
+ "Function to match INSPEC Book Chapter."
+ (let ((title (c2string(match-field)))
+ (authors (match-field))
+ (authors-address (match-field))
+ booktitle publisher editors year month pages note annote
+ journal-name volume number assoc-value)
+
+ (re-search-forward INSPEC-end nil t 1)
+ (cond ((not (match-INSPEC-reference-field (point) (match-field-end)))
+ (setq booktitle (buffer-substring (point) (match-field-end)))
+ (re-search-forward INSPEC-end nil t 1)
+
+ (if (match-INSPEC-reference-field (point) (match-field-end))
+ (re-search-forward INSPEC-end nil t 1)
+ (INSPEC-msg num "Missing in-book citation in \"%s\"."
+ (buffer-substring (point) (point-max)))))
+
+ (t (setq booktitle (c2string authors-address))
+ (setq authors-address nil)
+ (re-search-forward INSPEC-end nil t 1)))
+
+ (match-language-field)
+ (match-publisher-field t)
+ (match-pages-field)
+ (match-isbn-field)
+ (match-editors-field)
+
+ (add-annotation num)
+
+ (setq authors (squeeze (convert-names (car authors) (car (cdr authors)))))
+
+ (add-entry "annote" (squeeze annote))
+ (add-entry "note" note)
+ (add-entry "pages" (squeeze pages))
+ (add-entry "editor" (squeeze editors))
+ (add-entry "month" (squeeze month))
+ (add-entry "year" year)
+ (add-entry "publisher" (squeeze publisher))
+ (add-entry "booktitle" (squeeze booktitle))
+ (add-entry "title" (squeeze title))
+ (add-entry "author" authors)
+ (cons "InBook" (cons (make-key authors) assoc-value))))
+
+(defun match-INSPEC-reference-field (start end)
+ "Function to match the INSPEC reference field in all INSPEC documents."
+ (interactive "r")
+ (let (flag journal-flag)
+ (save-excursion
+ (save-restriction
+ (narrow-to-region start end)
+ (goto-char start)
+ (cond ((looking-at INSPEC-journal-reference-header)
+
+ ;; Journal Papers, Conference Papers, and Conference
+ ;; Proceedings may fall through this branch.
+;;(/= start (match-beginning 0))
+ (cond (
+ (match-beginning INSPEC-j-name-flag)
+ (setq journal-name (buffer-substring
+ (match-beginning INSPEC-j-name-index)
+ (match-end INSPEC-j-name-index)))
+;; (buffer-substring start (1- (match-beginning 0)))
+ (goto-char (match-end INSPEC-j-name-flag))))
+
+ (cond ((looking-at INSPEC-ref-volume)
+ (setq volume (buffer-substring
+ (match-beginning 1) (match-end 1)))
+ (goto-char (match-end 0))))
+
+ (cond ((looking-at INSPEC-ref-number)
+ (setq number (buffer-substring (match-beginning 1)
+ (match-end 1)))
+ (goto-char (match-end 0))))
+ (setq flag t journal-flag t)))
+
+ (cond ((looking-at INSPEC-ref-dates)
+
+ ;; Conference Papers, Conference Proceedings, Reports,
+ ;; Report Sections, Book Chapters, and also Journal
+ ;; Papers may fall through this branch.
+
+ (if (and (or (not month) journal-flag)
+ (match-beginning INSPEC-d-month-flag)
+ (/= (match-beginning INSPEC-d-month-index)
+ (match-end INSPEC-d-month-index)))
+ (setq month (buffer-substring
+ (match-beginning INSPEC-d-month-index)
+ (match-end INSPEC-d-month-index))))
+ (setq year (buffer-substring
+ (match-beginning INSPEC-d-year)
+ (match-end INSPEC-d-year)))
+ (goto-char (match-end 0))
+ (setq flag t)))
+
+ (cond ((looking-at INSPEC-ref-pages)
+ (setq pages (buffer-substring
+ (match-beginning INSPEC-ref-pages-index)
+ (if (match-beginning INSPEC-ref-pp-index)
+ (match-end INSPEC-ref-pp-index)
+ (match-end INSPEC-ref-pages-index))))
+ (if (match-beginning INSPEC-ref-volume-index)
+ (setq volume (buffer-substring
+ (match-beginning INSPEC-ref-volume-index)
+ (match-end INSPEC-ref-volume-index))))
+ (goto-char (match-end 0))
+ (setq flag t)))
+
+ (cond ((looking-at INSPEC-ref-refs)
+ ;; flag is just a temporary variable here
+ (setq flag (buffer-substring (match-beginning 1)
+ (match-end 1)))
+ (if (/= 0 (string-to-int flag)) (add-annotation flag))
+ (setq flag t)))))
+ (if flag (goto-char (1+ end)))
+ flag))
+
+(defun match-language-field ()
+ (cond ((looking-at "\\(In .*\\)$")
+ (add-note (buffer-substring (match-beginning 1) (match-end 1)))
+ (re-search-forward INSPEC-end nil t 1))))
+
+(defun match-publisher-field (&optional errorflag)
+ (cond ((looking-at "Publisher: \\(.+\\)\\.")
+ (setq publisher (buffer-substring (match-beginning 1)
+ (match-end 1)))
+ (re-search-forward INSPEC-end nil t 1))
+ (errorflag (INSPEC-msg num "Missing \"Publisher:\" field at \"%s\"."
+ (buffer-substring (point)
+ (min (+(point) 20)
+ (point-max)))))))
+
+(defun match-pages-field ()
+ (cond ((looking-at "Pages: ")
+ (re-search-forward INSPEC-end nil t 1))))
+
+(defun match-isbn-field ()
+ (cond ((looking-at "ISBN: ")
+ (re-search-forward INSPEC-end nil t 1))))
+
+(defun match-editors-field ()
+ (cond ((looking-at "\\(.*\\) (Editors)$")
+ (setq editors (convert-names (match-beginning 1)
+ (match-end 1)))
+ (re-search-forward INSPEC-end nil t 1))))
+
+(defun match-sponsor-field ()
+ (let (start)
+ (cond ((looking-at "Sponsor: ")
+ (setq start (match-end 0))
+ (re-search-forward INSPEC-end nil t 1)
+ (setq organization (buffer-substring start
+ (1- (match-beginning 0))))))))
+
+(defun match-conf-address&dates (start end)
+ (save-excursion
+ (save-restriction
+ (narrow-to-region start end)
+ (goto-char start)
+ (cond ((looking-at INSPEC-conference-address&date)
+ (setq address (buffer-substring
+ (match-beginning INSPEC-c-address-index)
+ (match-end INSPEC-c-address-index)))
+ (setq dates (buffer-substring
+ (match-beginning INSPEC-c-dates-index)
+ (match-end INSPEC-c-dates-index)))
+
+ (if (and (match-beginning INSPEC-c-month-flag)
+ (/= (match-beginning INSPEC-c-month-index)
+ (match-end INSPEC-c-month-index)))
+
+ (setq month (buffer-substring
+ (match-beginning INSPEC-c-month-index)
+ (match-end INSPEC-c-month-index))))
+ 't)))))
+
+
+(defun match-field-end ()
+ (save-excursion (re-search-forward INSPEC-end nil t 1)
+ (1- (match-beginning 0))))
+
+(defun match-field ()
+ (re-search-forward INSPEC-beginning)
+ (list (point)
+ (match-field-end))
+)
+
+(defun convert-names (start end)
+ "Function to convert list of names in INSPEC format (separated by
+ `;'s) to BibTeX format (separated by ` and '). The INSPEC names are
+ in the buffer between START and END."
+ (save-excursion
+ (save-restriction
+ (let (names)
+ (narrow-to-region start end)
+ (goto-char start)
+ (while (and (/= (point) end)
+ (re-search-forward "\\([^;]*\\)\\(;\\|\\'\\)" end t 1))
+ (setq names (nconc names (list(list (match-beginning 1)
+ (match-end 1))))))
+ (mapconcat (function(lambda (l) (buffer-substring (car l)
+ (car (cdr l)))))
+ names
+ " and "))))
+)
+
+(defun INSPEC-msg (num string &rest args)
+ "Function to send an error message to the `*INSPEC-msg-buffer*'.
+ The message consits of the INSPEC identity NUM, the formatting
+ STRING and the ARGS to be formatted."
+ (save-excursion
+ (set-buffer *INSPEC-msg-buffer*)
+ (if (string= num *INSPEC-last-id*)
+ (insert-char ? 9)
+ (setq *INSPEC-last-id* num)
+ (insert (format "
+In Ref. %s " num)))
+ (insert (format string args) ?\n)
+ (goto-char (point-max))))
+
+(defun INSPEC-dump-junk (start end)
+ "Function to check for extraneous junk and dump it to the
+`*INSPEC-msg-buffer*'."
+ (save-excursion
+ (save-restriction
+ (goto-char end)
+ ;; There's an extra line before the INSPEC header
+ (forward-line -1)
+ (skip-chars-backward " \t\n" start)
+ (if (/= start (point))
+ (progn
+ (setq end (point))
+ (goto-char start)
+ (skip-chars-forward " \t\n" end)
+ (beginning-of-line)
+ (if (/= end (point))
+ (let ((flag *INSPEC-msg-flag*))
+ (narrow-to-region (point) end)
+ (set-buffer *INSPEC-msg-buffer*)
+ (or flag (progn
+ (insert
+ (format "%s:\n\n"
+ (buffer-file-name *INSPEC-buffer*)))
+ (goto-char (point-max))))
+ (insert-buffer *INSPEC-buffer*)
+ (goto-char (point-max))
+ (insert-char ?\n 2))))))))
+
+(defun c2string (lst)
+ "Function to convert a list of 2 buffer indices into a string."
+ (buffer-substring (car lst) (car (cdr lst))))
+
+(defun squeeze (string)
+ "Function to squeeze all white-space in a string to individual
+ spaces. White-space at the beginnig or the end of the string is
+ eliminated."
+ (and string
+ (let (start (oldpos 0) newstring (len (length string)))
+ (save-excursion
+ (while (setq start (string-match "[ \n]+" string start))
+ (cond ((= start 0))
+ ((= len (match-end 0))
+ (setq newstring (concat newstring
+ (substring string oldpos start))))
+ (t (setq newstring (concat newstring
+ (substring string oldpos start)
+ " "))))
+ (setq oldpos (setq start (match-end 0)))))
+ (if (/= oldpos len) (concat newstring (substring string oldpos))
+ newstring))))
+
+(defun add-annotation (string)
+ (setq annote (if (stringp annote)
+ (concat annote ", " string)
+ string)))
+
+(defun add-note (string)
+ (setq note (if (stringp note)
+ (concat note ", " string)
+ string)))
+
+(defun add-entry (type entry)
+ (if (and (stringp entry)
+ (/= 0 (length entry)))
+ (setq assoc-value (cons (cons type entry) assoc-value))))
+
+;; BibTex conversion functions
+
+(defun make-key (string)
+ "Function to create a BibTeX key based upon STRING and dynamic
+ `year' of the form <string>-nn."
+ (string-match "\\<\\([^ ,]+\\)\\>[, ]?" string)
+ (concat (substring string (match-beginning 1) (match-end 1))
+ "-"
+ (if (and year (stringp year) (= (length year) 4))
+ (substring year 2)
+ "??")))
+
+(defun make-bibtex (entry-type key assoc-list)
+ "Function to create a filled BibTeX entry from the ENTRY-TYPE,
+ author KEY, and association list, ASSOC-LIST, of BibTeX field keys
+ and their associated values."
+ (bibtex-move-outside-of-entry)
+ (insert (concat "@" entry-type "{" key ",\n\n}\n\n"))
+ (previous-line 3)
+ (insert (mapconcat (function make-bibtex-entry) assoc-list ",\n"))
+ (re-search-forward "}\n\n" nil t 1))
+
+(defun make-bibtex-entry (assoc)
+ "Function to build BibTeX entry field from ASSOC's field key and
+ value."
+ (concat " " (car assoc) " = \"" (cdr assoc) "\""))
+
+(defun convert-entry ()
+ "Function to convert an INSPEC entry to its corresponding BibTeX
+ entry."
+ (let (quest)
+ (setq quest (match-quest))
+ (if (consp quest)
+ (save-excursion
+ (set-buffer *BibTeX-buffer*)
+ (make-bibtex (car quest) (car (cdr quest)) (cdr (cdr quest)))))))
+
+(defun inspec2bibtex (f1 f2)
+ "Interactive function to convert an INSPEC file, F1, to the
+ corresponding BibTeX file, F2."
+ (interactive "fINSPEC file:\nFBibTeX file:")
+ (find-file-read-only f1)
+ (setq *INSPEC-buffer* (current-buffer))
+ (setq *BibTeX-buffer* (find-file-noselect f2))
+ (inspec2bibtex-region-1 (point-min) (point-max)))
+
+(defun inspec2bibtex-region (start end f2)
+ "Function to convert the region from START to END in the `*INSPEC
+ buffer*' to BibTeX file F2."
+ (interactive "r\nFBibTeX file:")
+ (setq *INSPEC-buffer* (current-buffer))
+ (setq *BibTeX-buffer* (find-file-noselect f2))
+ (set-buffer *BibTeX-buffer*)
+ (goto-char (point-max))
+ (set-buffer *INSPEC-buffer*)
+ (inspec2bibtex-region-1 start end))
+
+
+(defun inspec2bibtex-region-1 (start end)
+ (let ((max-msg (save-excursion (set-buffer *INSPEC-msg-buffer*)
+ (point-max))))
+ (make-local-variable 'paragraph-start)
+ (make-local-variable '*INSPEC-msg-flag*)
+ (setq paragraph-start "^[ \f\n\t]*$")
+
+ (save-excursion
+ (save-restriction
+ (narrow-to-region start end)
+ (goto-char start)
+ (while (< (point) end)
+ (convert-entry))))
+
+ (if (/= max-msg (save-excursion (set-buffer *INSPEC-msg-buffer*)
+ (point-max)))
+ (pop-to-buffer *INSPEC-msg-buffer*))))
diff --git a/support/emacs-modes/limbo.material b/support/emacs-modes/limbo.material
new file mode 100644
index 0000000000..1833c25d34
--- /dev/null
+++ b/support/emacs-modes/limbo.material
@@ -0,0 +1,38 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% LIMBO MATERIAL
+%
+\font\ninerm=cmr9
+\font\mc\ninerm % medium caps for names like UNIX
+\def\PASCAL{Pascal}
+\def\<{$\langle\,$}
+\def\>{$\,\rangle$}
+\def\C{{\bf C}}
+\def\Unix{{\mc UNIX}} \let\unix=\Unix
+\def\today{\ifcase\month\or
+ January\or February\or March\or April\or
+ May\or June\or July\or August\or
+ September\or October\or November\or December\fi
+ \space\number\day, \number\year}
+\def\title{{\tt }}
+\def\topofcontents{\hsize 6in
+ \vglue -30pt plus 1fil minus 1.5in
+ \centerline{\title}
+ \vskip 15pt
+ \centerline{\today}
+ \vfil
+ \def\?##1]{\hbox to 1in{\hfil##1.\ }}}
+\def\botofcontents{\vskip 0pt plus 1fil minus 1.5in}
+%
+% These are added by Bart for handy use in programming languages
+\font\ninett=cmtt9
+\def\WEB{{\ninett WEB}}% use like \WEB{} to make space significant
+\font\sc=cmcsc10 % Computer Modern Computer Small Caps
+\def\Fortran{{\sc Fortran}}
+%
+% END OF LIMBO MATERIAL
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% BEGINNING OF WEB
+%
diff --git a/support/emacs-modes/meta-mode.el b/support/emacs-modes/meta-mode.el
new file mode 100644
index 0000000000..b615862cc5
--- /dev/null
+++ b/support/emacs-modes/meta-mode.el
@@ -0,0 +1,1099 @@
+;;; meta-mode.el --- major mode for editing Metafont or MetaPost sources.
+
+;; Copyright (C) 1997 by Ulrik Vieth.
+
+;; Author: Ulrik Vieth <vieth@thphy.uni-duesseldorf.de>
+;; Version: 1.0
+;; Keywords: Metafont, MetaPost, tex, languages
+
+;;; This file is *not* part of GNU Emacs.
+
+;; This program 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 2, or (at your option)
+;; any later version.
+
+;; This program 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, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Description:
+;;
+;; This Emacs Lisp package provides a major mode for editing Metafont
+;; or MetaPost sources. It includes all the necessary code to set up
+;; a major mode including an approriate syntax table, keymap, and a
+;; mode-specific pull-down menu. It also provides a sophisticated set
+;; of font-lock patterns, a fancy indentation function adapted from
+;; AUC-TeX's latex.el, and some basic mode-specific editing functions
+;; such as functions to move to the beginning or end of the enclosing
+;; environment, or to mark, re-indent, or comment-out environments.
+;; On the other hand, it doesn't yet provide any functionality for
+;; running Metafont or MetaPost in a shell buffer form within Emacs,
+;; but such functionality might be added later, either as part of this
+;; package or as a separate Emacs Lisp package.
+
+;; Installation:
+;;
+;; Install this file (meta-mode.el) in your personal or system-wide
+;; Emacs Lisp directory and add these lines to your startup files:
+;;
+;; (autoload 'metafont-mode "meta-mode" "Metafont editing mode." t)
+;; (autoload 'metapost-mode "meta-mode" "MetaPost editing mode." t)
+;;
+;; (setq auto-mode-alist
+;; (append '(("\\.mf\\'" . metafont-mode)
+;; ("\\.mp\\'" . metapost-mode)) auto-mode-alist))
+;;
+;; An interface to running Metafont or MetaPost as a shell process
+;; from within Emacs is currently under development as a separate
+;; Emacs Lisp package (meta-buf.el). In order to have that package
+;; loaded automatically when first entering Metafont or MetaPost mode,
+;; you might use the load-hook provided in this package by adding
+;; these lines to your startup file:
+;;
+;; (add-hook 'meta-mode-load-hook
+;; '(lambda () (require 'meta-buf)))
+;;
+;; The add-on package loaded this way may in turn make use of the
+;; mode-hooks provided in this package to activate additional features
+;; when entering Metafont or MetaPost mode.
+
+;; Font Lock Support:
+;;
+;; If you are using global-font-lock-mode (introduced in Emacs 19.31),
+;; fontification in Metafont and/or MetaPost mode will be activated
+;; automatically. To speed up fontification for the rather complex
+;; patterns used in these modes, it may be a good idea to activate
+;; lazy-lock as a font-lock-support-mode (introduced in Emacs 19.32)
+;; by adding these lines to your startup file:
+;;
+;; (global-font-lock-mode t)
+;; (setq font-lock-support-mode 'lazy-lock-mode)
+;;
+;; If you are using an older version of Emacs, which doesn't provide
+;; global-font-lock-mode or font-lock-support-mode, you can also
+;; activate fontification in Metafont and/or MetaPost mode by adding
+;; the following lines to your startup file:
+;;
+;; (add-hook 'meta-common-mode-hook 'turn-on-font-lock)
+;; (add-hook 'meta-common-mode-hook 'turn-on-lazy-lock)
+
+;; Customization:
+;;
+;; Following the usual Emacs Lisp coding conventions, the major modes
+;; defined in this package provide several hook variables to allow for
+;; local customization when entering the modes. In particular, there
+;; is a `meta-common-mode-hook' which applies to both modes as well as
+;; `metafont-mode-hook' and `metapost-mode-hook' which apply to the
+;; individual modes. In addition, there are several variables and
+;; regexps controlling e.g. the behavior of the indentation function,
+;; which may be customized via `edit-options'. Please refer to the
+;; docstrings in the code below for details.
+
+;; Availability:
+;;
+;; This package is currently available via my "TeX Software" WWW page:
+;;
+;; http://www.thphy.uni-duesseldorf.de/~vieth/subjects/tex/software.html
+;;
+;; As of this version 1.0, this package will be uploaded to CTAN
+;; archives, where it shall find a permanent home, presumably in
+;; tex-archive/support/emacs-modes. It will also be submitted for
+;; integration into the GNU Emacs distribution at that time.
+;;
+;; History:
+;;
+;; v 0.0 -- 1997/02/01 UV Started writing meta-mode.el.
+;; v 0.1 -- 1997/02/02 UV Added preliminary set of font-lock patterns.
+;; v 0.2 -- 1997/02/03 UV Improved and debugged font-lock patterns.
+;; Added indent-line-function for TAB.
+;; v 0.3 -- 1997/02/17 UV Improved font-lock patterns and syntax table.
+;; Improved and debbuged indentation function.
+;; v 0.4 -- 1997/02/18 UV Added functions to indent regions for M-C-q,
+;; also added a preliminary mode-specific menu.
+;; v 0.5 -- 1997/02/19 UV Added functions to skip to next or previous
+;; defun and to re-indent or comment-out defuns.
+;; v 0.6 -- 1997/02/20 UV More debugging, testing and clean-up.
+;; v 0.7 -- 1997/02/22 UV Use easymenu to define mode-specific menu.
+;; v 0.8 -- 1997/02/24 UV Added completion function for M-TAB.
+;; v 0.9 -- 1997/03/08 UV Added fill-paragraph function for comments.
+;; Also fixed a few remaining font-lock problems.
+;; Added meta-mode-load-hook to load meta-buf.el.
+;; v 1.0 -- 1997/04/07 UV Cleanup for official public release.
+;;
+;; Historical Footnote:
+;;
+;; This package was begun on February 1, 1997, exactly 20 years after
+;; the genesis of TeX took place according to Don Knuth's own account
+;; (cf. ``The Errors of TeX'', reprinted in ``Literate Programming'',
+;; Chapter 10, p. 249). What better date could there be to choose?
+;;
+
+
+;;; Code:
+
+(require 'easymenu)
+
+;;; Fontification.
+
+(defvar meta-font-lock-keywords
+ (let ((input-keywords
+ "\\(input\\|generate\\)")
+ (begin-keywords
+ (concat "\\(begin\\(char\\|fig\\|graph\\|logochar\\)\\|"
+ "\\cmchar\\|dcchar\\|ecchar\\)"))
+ (end-keywords
+ "\\(end\\(char\\|fig\\|graph\\)\\)")
+ (macro-keywords-1
+ "\\(def\\|let\\|mode_def\\|vardef\\)")
+ (macro-keywords-2
+ "\\(primarydef\\|secondarydef\\|tertiarydef\\)")
+;(make-regexp
+; '("expr" "suffix" "text" "primary" "secondary" "tertiary") t)
+ (args-keywords
+ (concat "\\(expr\\|primary\\|s\\(econdary\\|uffix\\)\\|"
+ "te\\(rtiary\\|xt\\)\\)"))
+;(make-regexp
+; '("boolean" "color" "numeric" "pair" "path" "pen" "picture"
+; "string" "transform" "newinternal") t)
+ (type-keywords
+ (concat "\\(boolean\\|color\\|n\\(ewinternal\\|umeric\\)\\|"
+ "p\\(a\\(ir\\|th\\)\\|en\\|icture\\)\\|string\\|"
+ "transform\\)"))
+;(make-regexp
+; '("for" "forever" "forsuffixes" "endfor"
+; "step" "until" "upto" "downto" "thru" "within"
+; "iff" "if" "elseif" "else" "fi" "exitif" "exitunless"
+; "let" "def" "vardef" "enddef" "mode_def"
+; "true" "false" "known" "unknown" "and" "or" "not"
+; "save" "interim" "inner" "outer" "relax"
+; "begingroup" "endgroup" "expandafter" "scantokens"
+; "generate" "input" "endinput" "end" "bye"
+; "message" "errmessage" "errhelp" "special" "numspecial"
+; "readstring" "readfrom" "write") t)
+ (syntactic-keywords
+ (concat "\\(and\\|b\\(egingroup\\|ye\\)\\|"
+ "d\\(ef\\|ownto\\)\\|e\\(lse\\(\\|if\\)"
+ "\\|nd\\(\\|def\\|for\\|group\\|input\\)"
+ "\\|rr\\(help\\|message\\)"
+ "\\|x\\(it\\(if\\|unless\\)\\|pandafter\\)\\)\\|"
+ "f\\(alse\\|i\\|or\\(\\|ever\\|suffixes\\)\\)\\|"
+ "generate\\|i\\(ff?\\|n\\(ner\\|put\\|terim\\)\\)\\|"
+ "known\\|let\\|m\\(essage\\|ode_def\\)\\|"
+ "n\\(ot\\|umspecial\\)\\|o\\(r\\|uter\\)\\|"
+ "re\\(ad\\(from\\|string\\)\\|lax\\)\\|"
+ "s\\(ave\\|cantokens\\|pecial\\|tep\\)\\|"
+ "t\\(hru\\|rue\\)\\|"
+ "u\\(n\\(known\\|til\\)\\|pto\\)\\|"
+ "vardef\\|w\\(ithin\\|rite\\)\\)"))
+ )
+ (list
+ ;; embedded TeX code in btex ... etex
+ (cons (concat "\\(btex\\|verbatimtex\\)"
+ "[ \t]+\\(.*\\)[ \t]+"
+ "\\(etex\\)")
+ '((1 font-lock-keyword-face)
+ (2 font-lock-string-face)
+ (3 font-lock-keyword-face)))
+ ;; unary macro definitions: def, vardef, let
+ (cons (concat "\\<" macro-keywords-1 "\\>"
+ "[ \t]+\\(\\sw+\\|\\s_+\\|\\s.+\\)")
+ '((1 font-lock-keyword-face)
+ (2 font-lock-function-name-face)))
+ ;; binary macro defintions: <leveldef> x operator y
+ (cons (concat "\\<" macro-keywords-2 "\\>"
+ "[ \t]+\\(\\sw+\\)"
+ "[ \t]*\\(\\sw+\\|\\s.+\\)"
+ "[ \t]*\\(\\sw+\\)")
+ '((1 font-lock-keyword-face)
+ (2 font-lock-variable-name-face nil t)
+ (3 font-lock-function-name-face nil t)
+ (4 font-lock-variable-name-face nil t)))
+ ;; variable declarations: numeric, pair, color, ...
+ (cons (concat "\\<" type-keywords "\\>"
+ "\\([ \t]+\\(\\sw+\\)\\)*")
+ '((1 font-lock-type-face)
+ (font-lock-match-meta-declaration-item-and-skip-to-next
+ (goto-char (match-end 1)) nil
+ (1 font-lock-variable-name-face nil t))))
+ ;; argument declarations: expr, suffix, text, ...
+ (cons (concat "\\<" args-keywords "\\>"
+ "\\([ \t]+\\(\\sw+\\|\\s_+\\)\\)*")
+ '((1 font-lock-type-face)
+ (font-lock-match-meta-declaration-item-and-skip-to-next
+ (goto-char (match-end 1)) nil
+ (1 font-lock-variable-name-face nil t))))
+ ;; special case of arguments: expr x of y
+ (cons (concat "\\(expr\\)[ \t]+\\(\\sw+\\)"
+ "[ \t]+\\(of\\)[ \t]+\\(\\sw+\\)")
+ '((1 font-lock-type-face)
+ (2 font-lock-variable-name-face)
+ (3 font-lock-keyword-face nil t)
+ (4 font-lock-variable-name-face nil t)))
+ ;; syntactic keywords
+ (cons (concat "\\<" syntactic-keywords "\\>")
+ 'font-lock-keyword-face)
+ ;; beginchar, beginfig
+ (cons (concat "\\<" begin-keywords "\\>")
+ 'font-lock-keyword-face)
+ ;; endchar, endfig
+ (cons (concat "\\<" end-keywords "\\>")
+ 'font-lock-keyword-face)
+ ;; input, generate
+ (cons (concat "\\<" input-keywords "\\>"
+ "[ \t]+\\(\\sw+\\)")
+ '((1 font-lock-keyword-face)
+ (2 font-lock-reference-face)))
+ ;; embedded Metafont/MetaPost code in comments
+ (cons "|\\([^|]+\\)|"
+ '(1 font-lock-reference-face t))
+ ))
+ "Default expressions to highlight in Metafont or MetaPost mode.")
+
+
+(defun font-lock-match-meta-declaration-item-and-skip-to-next (limit)
+ ;; Match and move over Metafont/MetaPost declaration item after point.
+ ;;
+ ;; The expected syntax of an item is either "word" or "symbol",
+ ;; possibly ending with optional whitespace. Everything following
+ ;; the item (but belonging to it) is expected to by skipable by
+ ;; `forward-sexp'. The list of items is expected to be separated
+ ;; by commas and terminated by semicolons or equals signs.
+ ;;
+ (if (looking-at "[ \t]*\\(\\sw+\\|\\s_+\\)")
+ (save-match-data
+ (condition-case nil
+ (save-restriction
+ ;; Restrict to end of line, currently guaranteed to be LIMIT.
+ (narrow-to-region (point-min) limit)
+ (goto-char (match-end 1))
+ ;; Move over any item value, etc., to the next item.
+ (while (not (looking-at "[ \t]*\\(\\(,\\)\\|;\\|=\\|$\\)"))
+ (goto-char (or (scan-sexps (point) 1) (point-max))))
+ (goto-char (match-end 2)))
+ (error t)))))
+
+
+
+;;; Completion.
+
+;; The data used to prepare the following lists of primitives and
+;; standard macros available in Metafont or MetaPost was extracted
+;; from the original sources like this:
+;;
+;; grep '^primitive' texk-7.0/web2c/{mf,mp}.web |\
+;; sed 's/primitive(\("[a-zA-Z]*"\).*/\1/' > {mf,mp}_prim.list
+;;
+;; grep '\(let\|def\|vardef\|primarydef\|secondarydef\|tertiarydef\)'
+;; texmf/meta{font,post}/plain.{mf,mp} > {mf,mp}_plain.list
+
+(defconst meta-common-primitives-list
+ '("ASCII" "addto" "also" "and" "angle" "atleast" "batchmode"
+ "begingroup" "boolean" "boundarychar" "char" "charcode" "chardp"
+ "charexists" "charext" "charht" "charic" "charlist" "charwd"
+ "contour" "controls" "cosd" "curl" "cycle" "day" "decimal" "def"
+ "delimiters" "designsize" "directiontime" "doublepath" "dump" "else"
+ "elseif" "end" "enddef" "endfor" "endgroup" "endinput" "errhelp"
+ "errmessage" "errorstopmode" "everyjob" "exitif" "expandafter"
+ "expr" "extensible" "false" "fi" "floor" "fontdimen" "fontmaking"
+ "for" "forever" "forsuffixes" "headerbyte" "hex" "if" "inner"
+ "input" "interim" "intersectiontimes" "jobname" "kern" "known"
+ "length" "let" "ligtable" "makepath" "makepen" "message" "mexp"
+ "mlog" "month" "newinternal" "nonstopmode" "normaldeviate" "not"
+ "nullpen" "nullpicture" "numeric" "oct" "odd" "of" "or" "outer"
+ "pair" "path" "pausing" "pen" "pencircle" "penoffset" "picture"
+ "point" "postcontrol" "precontrol" "primary" "primarydef" "quote"
+ "randomseed" "readstring" "reverse" "rotated" "save" "scaled"
+ "scantokens" "scrollmode" "secondary" "secondarydef" "shifted"
+ "shipout" "show" "showdependencies" "showstats" "showstopping"
+ "showtoken" "showvariable" "sind" "skipto" "slanted" "special"
+ "sqrt" "step" "str" "string" "subpath" "substring" "suffix"
+ "tension" "tertiary" "tertiarydef" "text" "time" "to"
+ "tracingcapsules" "tracingchoices" "tracingcommands"
+ "tracingequations" "tracingmacros" "tracingonline" "tracingoutput"
+ "tracingrestores" "tracingspecs" "tracingstats" "tracingtitles"
+ "transform" "transformed" "true" "turningnumber" "uniformdeviate"
+ "unknown" "until" "vardef" "warningcheck" "withpen" "xpart"
+ "xscaled" "xxpart" "xypart" "year" "ypart" "yscaled" "yxpart"
+ "yypart" "zscaled")
+ "List of primitives common to Metafont and MetaPost.")
+
+(defconst metafont-primitives-list
+ '("at" "autorounding" "chardx" "chardy" "cull" "display"
+ "dropping" "fillin" "from" "granularity" "hppp" "inwindow"
+ "keeping" "numspecial" "openwindow" "proofing" "smoothing"
+ "totalweight" "tracingedges" "tracingpens" "turningcheck" "vppp"
+ "withweight" "xoffset" "yoffset")
+ "List of primitives only defined in Metafont.")
+
+(defconst metapost-primitives-list
+ '("arclength" "arctime" "bluepart" "bounded" "btex" "clip"
+ "clipped" "color" "dashed" "dashpart" "etex" "filled" "fontpart"
+ "fontsize" "greenpart" "infont" "linecap" "linejoin" "llcorner"
+ "lrcorner" "miterlimit" "mpxbreak" "pathpart" "penpart"
+ "prologues" "readfrom" "redpart" "setbounds" "stroked" "textpart"
+ "textual" "tracinglostchars" "truecorners" "ulcorner" "urcorner"
+ "verbatimtex" "withcolor" "within" "write")
+ "List of primitives only defined in MetaPost.")
+
+(defconst meta-common-plain-macros-list
+ '( "abs" "bot" "bye" "byte" "ceiling" "clear_pen_memory"
+ "clearit" "clearpen" "clearxy" "counterclockwise" "cutdraw" "decr"
+ "dir" "direction" "directionpoint" "div" "dotprod" "downto" "draw"
+ "drawdot" "erase" "exitunless" "fill" "filldraw" "flex" "gobble"
+ "hide" "incr" "interact" "interpath" "intersectionpoint" "inverse"
+ "label" "labels" "lft" "loggingall" "magstep" "makelabel" "max"
+ "min" "mod" "numtok" "penlabels" "penpos" "penstroke" "pickup"
+ "range" "reflectedabout" "relax" "rotatedabout" "rotatedaround"
+ "round" "rt" "savepen" "shipit" "softjoin" "solve" "stop"
+ "superellipse" "takepower" "tensepath" "thru" "top" "tracingall"
+ "tracingnone" "undraw" "undrawdot" "unfill" "unfilldraw"
+ "unitvector" "upto" "whatever")
+ "List of macros common to plain Metafont and MetaPost.")
+
+(defconst metafont-plain-macros-list
+ '("beginchar" "change_width" "culldraw" "cullit" "cutoff"
+ "define_blacker_pixels" "define_corrected_pixels"
+ "define_good_x_pixels" "define_good_y_pixels"
+ "define_horizontal_corrected_pixels" "define_pixels"
+ "define_whole_blacker_pixels" "define_whole_pixels"
+ "define_whole_vertical_blacker_pixels"
+ "define_whole_vertical_pixels" "endchar" "fix_units"
+ "font_coding_scheme" "font_extra_space" "font_identifier"
+ "font_normal_shrink" "font_normal_space" "font_normal_stretch"
+ "font_quad" "font_size" "font_slant" "font_x_height" "gfcorners"
+ "good.bot" "good.lft" "good.rt" "good.top" "good.x" "good.y"
+ "grayfont" "hround" "imagerules" "italcorr" "labelfont"
+ "lowres_fix" "makebox" "makegrid" "maketicks" "mode_lowres"
+ "mode_proof" "mode_setup" "mode_smoke" "nodisplays" "notransforms"
+ "openit" "penrazor" "pensquare" "proofoffset" "proofrule"
+ "proofrulethickness" "screenchars" "screenrule" "screenstrokes"
+ "showit" "slantfont" "smode" "titlefont" "vround")
+ "List of macros only defined in plain Metafont.")
+
+(defconst metapost-plain-macros-list
+ '("arrowhead" "bbox" "beginfig" "buildcycle" "center" "cutafter"
+ "cutbefore" "dashpattern" "dotlabel" "dotlabels" "drawarrow"
+ "drawdblarrow" "drawoptions" "endfig" "image" "label" "off" "on"
+ "thelabel")
+ "List of macros only defined in plain MetaPost.")
+
+(defconst metapost-graph-macros-list
+ '("augment" "auto.x" "auto.y" "autogrid" "begingraph" "endgraph"
+ "format" "frame" "gdata" "gdotlabel" "gdraw" "gdrawarrow"
+ "gdrawdblarrow" "gfill" "glabel" "grid" "itick" "otick" "plot"
+ "setcoords" "setrange")
+ "List of macros only defined in MetaPost \"graph\" package.")
+
+(defconst metapost-boxes-macros-list
+ '("boxit" "boxjoin" "bpath" "circleit" "drawboxed" "drawboxes"
+ "drawunboxed" "fixpos" "fixsize" "pic" "rboxit")
+ "List of macros only defined in MetaPost \"boxes\" package.")
+
+
+(defvar metafont-symbol-list
+ (append meta-common-primitives-list
+ metafont-primitives-list
+ meta-common-plain-macros-list
+ metafont-plain-macros-list)
+ "List of known symbols to complete in Metafont mode.")
+
+(defvar metapost-symbol-list
+ (append meta-common-primitives-list
+ metapost-primitives-list
+ meta-common-plain-macros-list
+ metapost-plain-macros-list
+ metapost-graph-macros-list
+ metapost-boxes-macros-list)
+ "List of known symbols to complete in MetaPost mode.")
+
+
+(defvar meta-symbol-list nil
+ "List of known symbols to complete in Metafont or MetaPost mode.")
+
+(defvar meta-symbol-changed nil
+ "Flag indicating whether `meta-symbol-list' has been initialized.")
+
+(defvar meta-complete-list nil
+; (list (list "\\<\\(\\sw+\\)" 1 'meta-symbol-list)
+; (list "" 'ispell-complete-word))
+ "List of ways to perform completion in Metafont or MetaPost mode.
+
+Each entry is a list with the following elements:
+1. Regexp matching the preceding text.
+2. A number indicating the subgroup in the regexp containing the text.
+3. A function returning an alist of possible completions.
+4. Text to append after a succesful completion (if any).
+
+Or alternatively:
+1. Regexp matching the preceding text.
+2. Function to do the actual completion.")
+
+
+(defun meta-add-symbols (&rest entries)
+ "Add entries to list of known symbols in Metafont or MetaPost mode."
+ (if meta-symbol-changed
+ (setq meta-symbol-list (cons entries meta-symbol-list))
+ (setq meta-symbol-changed t)
+ (setq meta-symbol-list (cons entries meta-symbol-list))))
+
+(defun meta-symbol-list ()
+ "Return value of list of known symbols in Metafont or MetaPost mode.
+If the list was changed, sort the list and remove duplicates first."
+ (if (not meta-symbol-changed)
+ ()
+ (setq meta-symbol-changed nil)
+ (message "Preparing completion list...")
+ ;; sort list of symbols
+ (setq meta-symbol-list
+ (sort (mapcar 'meta-listify (apply 'append meta-symbol-list))
+ 'meta-car-string-lessp))
+ ;; remove duplicates
+ (let ((entry meta-symbol-list))
+ (while (and entry (cdr entry))
+ (let ((this (car entry))
+ (next (car (cdr entry))))
+ (if (not (string-equal (car this) (car next)))
+ (setq entry (cdr entry))
+ (if (> (length next) (length this))
+ (setcdr this (cdr next)))
+ (setcdr entry (cdr (cdr entry)))))))
+ (message "Preparing completion list... done"))
+ meta-symbol-list)
+
+(defun meta-listify (a)
+ ;; utility function used in `meta-add-symbols'
+ (if (listp a) a (list a)))
+
+(defun meta-car-string-lessp (a b)
+ ;; utility function used in `meta-add-symbols'
+ (string-lessp (car a) (car b)))
+
+
+(defun meta-complete-symbol ()
+ "Perform completion on Metafont or MetaPost symbol preceding point."
+ (interactive "*")
+ (let ((list meta-complete-list)
+ entry)
+ (while list
+ (setq entry (car list)
+ list (cdr list))
+ (if (meta-looking-at-backward (car entry) 200)
+ (setq list nil)))
+ (if (numberp (nth 1 entry))
+ (let* ((sub (nth 1 entry))
+ (close (nth 3 entry))
+ (begin (match-beginning sub))
+ (end (match-end sub))
+ (pattern (meta-match-buffer 0))
+ (symbol (buffer-substring begin end))
+ (list (funcall (nth 2 entry)))
+ (completion (try-completion symbol list)))
+ (cond ((eq completion t)
+ (and close
+ (not (looking-at (regexp-quote close)))
+ (insert close)))
+ ((null completion)
+ (error "Can't find completion for \"%s\"" pattern))
+ ((not (string-equal symbol completion))
+ (delete-region begin end)
+ (insert completion)
+ (and close
+ (eq (try-completion completion list) t)
+ (not (looking-at (regexp-quote close)))
+ (insert close)))
+ (t
+ (message "Making completion list...")
+ (let ((list (all-completions symbol list nil)))
+ (with-output-to-temp-buffer "*Completions*"
+ (display-completion-list list)))
+ (message "Making completion list... done"))))
+ (funcall (nth 1 entry)))))
+
+
+(defun meta-looking-at-backward (regexp &optional limit)
+ ;; utility function used in `meta-complete-symbol'
+ (let ((pos (point)))
+ (save-excursion
+ (and (re-search-backward
+ regexp (if limit (max (point-min) (- (point) limit))) t)
+ (eq (match-end 0) pos)))))
+
+(defun meta-match-buffer (n)
+ ;; utility function used in `meta-complete-symbol'
+ (if (match-beginning n)
+ (let ((str (buffer-substring (match-beginning n) (match-end n))))
+ (set-text-properties 0 (length str) nil str)
+ (copy-sequence str))
+ ""))
+
+
+
+;;; Indentation.
+
+(defvar meta-indent-level 2
+ "*Indentation of begin-end blocks in Metafont or MetaPost mode.")
+
+
+(defvar meta-left-comment-regexp "%%+"
+ "*Regexp matching comments that should be placed on the left margin.")
+
+(defvar meta-right-comment-regexp nil
+ "*Regexp matching comments that should be placed to the right margin.")
+
+(defvar meta-ignore-comment-regexp "%[^%]"
+ "*Regexp matching comments that whose indentation should not be touched.")
+
+
+(defvar meta-begin-environment-regexp
+ (concat "\\(begin\\(char\\|fig\\|gr\\(aph\\|oup\\)\\|logochar\\)\\|"
+ "def\\|for\\(\\|ever\\|suffixes\\)\\|if\\|mode_def\\|"
+ "primarydef\\|secondarydef\\|tertiarydef\\|vardef\\)")
+ "*Regexp matching the beginning of environments to be indented.")
+
+(defvar meta-end-environment-regexp
+ (concat "\\(end\\(char\\|def\\|f\\(ig\\|or\\)\\|gr\\(aph\\|oup\\)\\)"
+ "\\|fi\\)")
+ "*Regexp matching the end of environments to be indented.")
+
+(defvar meta-within-environment-regexp
+; (concat "\\(e\\(lse\\(\\|if\\)\\|xit\\(if\\|unless\\)\\)\\)")
+ (concat "\\(else\\(\\|if\\)\\)")
+ "*Regexp matching keywords within environments not to be indented.")
+
+
+(defun meta-comment-indent ()
+ "Return the indentation for a comment in Metafont or MetaPost mode."
+ (if (and meta-left-comment-regexp
+ (looking-at meta-left-comment-regexp))
+ (current-column)
+ (skip-chars-backward "\t ")
+ (max (if (bolp) 0 (1+ (current-column)))
+ comment-column)))
+
+(defun meta-indent-line ()
+ "Indent the line containing point as Metafont or MetaPost source."
+ (interactive)
+ (let ((indent (meta-indent-calculate)))
+ (save-excursion
+ (if (/= (current-indentation) indent)
+ (let ((beg (progn (beginning-of-line) (point)))
+ (end (progn (back-to-indentation) (point))))
+ (delete-region beg end)
+ (indent-to indent))))
+ (if (< (current-column) indent)
+ (back-to-indentation))))
+
+(defun meta-indent-calculate ()
+ "Return the indentation of current line of Metafont or MetaPost source."
+ (save-excursion
+ (back-to-indentation)
+ (cond
+ ;; Comments to the left margin.
+ ((and meta-left-comment-regexp
+ (looking-at meta-left-comment-regexp))
+ 0)
+ ;; Comments to the right margin.
+ ((and meta-right-comment-regexp
+ (looking-at meta-right-comment-regexp))
+ comment-column)
+ ;; Comments best left alone.
+ ((and meta-ignore-comment-regexp
+ (looking-at meta-ignore-comment-regexp))
+ (current-indentation))
+ ;; Backindent at end of environments.
+ ((looking-at
+ (concat "\\<" meta-end-environment-regexp "\\>"))
+ (- (meta-indent-calculate-last) meta-indent-level))
+ ;; Backindent at keywords within environments.
+ ((looking-at
+ (concat "\\<" meta-within-environment-regexp "\\>"))
+ (- (meta-indent-calculate-last) meta-indent-level))
+ (t (meta-indent-calculate-last)))))
+
+(defun meta-indent-calculate-last ()
+ "Return the indentation of previous line of Metafont or MetaPost source."
+ (save-restriction
+ (widen)
+ (skip-chars-backward "\n\t ")
+ (move-to-column (current-indentation))
+ ;; Ignore comments.
+ (while (and (looking-at comment-start) (not (bobp)))
+ (skip-chars-backward "\n\t ")
+ (if (not (bobp))
+ (move-to-column (current-indentation))))
+ (cond
+ ((bobp) 0)
+ (t (+ (current-indentation)
+ (meta-indent-level-count)
+ (cond
+ ;; Compensate for backindent at end of environments.
+ ((looking-at
+ (concat "\\<"meta-end-environment-regexp "\\>"))
+ meta-indent-level)
+ ;; Compensate for backindent within environments.
+ ((looking-at
+ (concat "\\<" meta-within-environment-regexp "\\>"))
+ meta-indent-level)
+ (t 0)))))
+ ))
+
+(defun meta-indent-level-count ()
+ "Count indentation change for begin-end commands in the current line."
+ (save-excursion
+ (save-restriction
+ (let ((count 0))
+ (narrow-to-region
+ (point) (save-excursion
+ (re-search-forward "[^\\\\\"]%\\|\n\\|\\'" nil t)
+ (backward-char) (point)))
+ (while (re-search-forward "\\<\\sw+\\>\\|(\\|)" nil t)
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (cond
+ ;; Count number of begin-end keywords within line.
+ ((looking-at
+ (concat "\\<" meta-begin-environment-regexp "\\>"))
+ (setq count (+ count meta-indent-level)))
+ ((looking-at
+ (concat "\\<" meta-end-environment-regexp "\\>"))
+ (setq count (- count meta-indent-level)))
+ ;; Count number of open-close parentheses within line.
+ ((looking-at "(")
+ (setq count (+ count meta-indent-level)))
+ ((looking-at ")")
+ (setq count (- count meta-indent-level)))
+ )))
+ count))))
+
+
+
+;;; Filling paragraphs.
+
+(defun meta-fill-paragraph (&optional justify)
+ "Like \\[fill-paragraph], but handle Metafont or MetaPost comments.
+If any part of the current line is a comment, fill the comment or the
+paragraph of it that point is in, preserving the comment's indentation
+and initial semicolons."
+ (interactive "P")
+ (let (has-comment ; Non-nil if line contains a comment.
+ has-code-and-comment ; Non-nil if line contains code and a comment.
+ comment-fill-prefix ; If has-comment, fill-prefix for the comment.
+ )
+ ;; Figure out what kind of comment we are looking at.
+ (save-excursion
+ (beginning-of-line)
+ (cond
+ ;; A line with nothing but a comment on it?
+ ((looking-at (concat "[ \t]*" comment-start-skip))
+ (setq has-comment t)
+ (setq comment-fill-prefix
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ ;; A line with some code, followed by a comment?
+ ((condition-case nil
+ (save-restriction
+ (narrow-to-region (point-min)
+ (save-excursion (end-of-line) (point)))
+ (while (not (looking-at (concat comment-start "\\|$")))
+ (skip-chars-forward (concat "^" comment-start "\n\"\\\\"))
+ (cond
+ ((eq (char-after (point)) ?\\) (forward-char 2))
+ ((eq (char-after (point)) ?\") (forward-sexp 1))))
+ (looking-at comment-start-skip))
+ (error nil))
+ (setq has-comment t
+ has-code-and-comment t)
+ (setq comment-fill-prefix
+ (concat (make-string (/ (current-column) 8) ?\t)
+ (make-string (% (current-column) 8) ?\ )
+ (buffer-substring (match-beginning 0) (match-end 0)))))
+ ))
+ (if (not has-comment)
+ (fill-paragraph justify)
+ ;; Narrow to include only the comment, and then fill the region.
+ (save-excursion
+ (save-restriction
+ (beginning-of-line)
+ (narrow-to-region
+ ;; Find the first line we should include in the region to fill.
+ (save-excursion
+ (while (and (zerop (forward-line -1))
+ (looking-at (concat "^[ \t]*" comment-start))))
+ (or (looking-at (concat ".*" comment-start))
+ (forward-line 1))
+ (point))
+ ;; Find the beginning of the first line past the region to fill.
+ (save-excursion
+ (while (progn (forward-line 1)
+ (looking-at (concat "^[ \t]*" comment-start))))
+ (point)))
+ (let* ((paragraph-start
+ (concat paragraph-start "\\|[ \t%]*$"))
+ (paragraph-separate
+ (concat paragraph-start "\\|[ \t%]*$"))
+ (paragraph-ignore-fill-prefix nil)
+ (fill-prefix comment-fill-prefix)
+ (after-line (if has-code-and-comment
+ (save-excursion (forward-line 1) (point))))
+ (end (progn (forward-paragraph)
+ (or (bolp) (newline 1))
+ (point)))
+ (beg (progn (backward-paragraph)
+ (if (eq (point) after-line) (forward-line -1))
+ (point)))
+ (after-pos (save-excursion
+ (goto-char beg)
+ (if (not (looking-at fill-prefix))
+ (progn
+ (re-search-forward comment-start-skip)
+ (point)))))
+ )
+ (fill-region-as-paragraph beg end justify nil after-pos))
+ )))
+ t))
+
+
+
+;;; Editing commands.
+
+(defvar meta-begin-defun-regexp
+ (concat "\\(begin\\(char\\|fig\\|logochar\\)\\|def\\|mode_def\\|"
+ "primarydef\\|secondarydef\\|tertiarydef\\|vardef\\)")
+ "*Regexp matching beginning of defuns in Metafont or MetaPost mode.")
+
+(defvar meta-end-defun-regexp
+ (concat "\\(end\\(char\\|def\\|fig\\)\\)")
+ "*Regexp matching the end of defuns in Metafont or MetaPost mode.")
+
+
+(defun meta-beginning-of-defun (&optional arg)
+ "Move backward to beginnning of a defun in Metafont or MetaPost code.
+With numeric argument, do it that many times.
+Negative arg -N means move forward to Nth following beginning of defun.
+Returns t unless search stops due to beginning or end of buffer."
+ (interactive "p")
+ (if (or (null arg) (= 0 arg)) (setq arg 1))
+ (and arg (< arg 0) (not (eobp)) (forward-char 1))
+ (and (re-search-backward
+ (concat "\\<" meta-begin-defun-regexp "\\>") nil t arg)
+ (progn (goto-char (match-beginning 0))
+ (skip-chars-backward "%")
+ (skip-chars-backward " \t") t)))
+
+(defun meta-end-of-defun (&optional arg)
+ "Move forward to end of a defun in Metafont or MetaPost code.
+With numeric argument, do it that many times.
+Negative argument -N means move back to Nth preceding end of defun.
+Returns t unless search stops due to beginning or end of buffer."
+ (interactive "p")
+ (if (or (null arg) (= 0 arg)) (setq arg 1))
+ (and (< arg 0) (not (bobp)) (forward-line -1))
+ (and (re-search-forward
+ (concat "\\<" meta-end-defun-regexp "\\>") nil t arg)
+ (progn (goto-char (match-end 0))
+ (skip-chars-forward ";")
+ (skip-chars-forward " \t")
+ (if (looking-at "\n") (forward-line 1)) t)))
+
+
+(defun meta-comment-region (beg end &optional arg)
+ "Comment out active region as Metafont or MetaPost source."
+ (interactive "r")
+ (comment-region beg end arg))
+
+(defun meta-uncomment-region (beg end)
+ "Uncomment active region as Metafont or MetaPost source."
+ (interactive "r")
+ (comment-region beg end -1))
+
+(defun meta-comment-defun (&optional arg)
+ "Comment out current environment as Metafont or MetaPost source.
+With prefix argument, uncomment the environment.
+The environment used is the one that contains point or follows point."
+ (interactive "P")
+ (save-excursion
+ (let* ((end (if (meta-end-of-defun) (point) (point-max)))
+ (beg (if (meta-beginning-of-defun) (point) (point-min))))
+ (comment-region beg end arg))))
+
+(defun meta-uncomment-defun ()
+ "Uncomment current environment as Metafont or MetaPost source."
+ (interactive)
+ (meta-comment-defun -1))
+
+
+(defun meta-indent-region (beg end)
+ "Indent the active region as Metafont or MetaPost source."
+ (interactive "r")
+ (indent-region beg end nil))
+
+(defun meta-indent-buffer ()
+ "Indent the whole buffer contents as Metafont or MetaPost source."
+ (interactive)
+ (save-excursion
+ (indent-region (point-min) (point-max) nil)))
+
+(defun meta-indent-defun ()
+ "Indent the current environment as Metafont or MetaPost source.
+The environment indented is the one that contains point or follows point."
+ (interactive)
+ (save-excursion
+ (let* ((end (if (meta-end-of-defun) (point) (point-max)))
+ (beg (if (meta-beginning-of-defun) (point) (point-min))))
+ (indent-region beg end nil))))
+
+
+(defun meta-mark-defun ()
+ "Put mark at end of the environment, point at the beginning.
+The environment marked is the one that contains point or follows point."
+ (interactive)
+ (push-mark (point))
+ (meta-end-of-defun)
+ (push-mark (point) nil t)
+ (meta-beginning-of-defun))
+
+
+
+;;; Syntax table, keymap and menu.
+
+(defvar meta-mode-abbrev-table nil
+ "Abbrev table used in Metafont or MetaPost mode.")
+(define-abbrev-table 'meta-mode-abbrev-table ())
+
+(defvar meta-mode-syntax-table nil
+ "Syntax table used in Metafont or MetaPost mode.")
+(if meta-mode-syntax-table
+ ()
+ (setq meta-mode-syntax-table (make-syntax-table))
+ ;; underscores are word constituents
+ (modify-syntax-entry ?_ "w" meta-mode-syntax-table)
+ ;; miscellaneous non-word symbols
+ (modify-syntax-entry ?# "_" meta-mode-syntax-table)
+ (modify-syntax-entry ?@ "_" meta-mode-syntax-table)
+ (modify-syntax-entry ?$ "_" meta-mode-syntax-table)
+ (modify-syntax-entry ?? "_" meta-mode-syntax-table)
+ (modify-syntax-entry ?! "_" meta-mode-syntax-table)
+ ;; binary operators
+ (modify-syntax-entry ?& "." meta-mode-syntax-table)
+ (modify-syntax-entry ?+ "." meta-mode-syntax-table)
+ (modify-syntax-entry ?- "." meta-mode-syntax-table)
+ (modify-syntax-entry ?/ "." meta-mode-syntax-table)
+ (modify-syntax-entry ?* "." meta-mode-syntax-table)
+ (modify-syntax-entry ?. "." meta-mode-syntax-table)
+ (modify-syntax-entry ?: "." meta-mode-syntax-table)
+ (modify-syntax-entry ?= "." meta-mode-syntax-table)
+ (modify-syntax-entry ?< "." meta-mode-syntax-table)
+ (modify-syntax-entry ?> "." meta-mode-syntax-table)
+ (modify-syntax-entry ?| "." meta-mode-syntax-table)
+ ;; opening and closing delimiters
+ (modify-syntax-entry ?\( "()" meta-mode-syntax-table)
+ (modify-syntax-entry ?\) ")(" meta-mode-syntax-table)
+ (modify-syntax-entry ?\[ "(]" meta-mode-syntax-table)
+ (modify-syntax-entry ?\] ")[" meta-mode-syntax-table)
+ (modify-syntax-entry ?\{ "(}" meta-mode-syntax-table)
+ (modify-syntax-entry ?\} "){" meta-mode-syntax-table)
+ ;; comment character
+ (modify-syntax-entry ?% "<" meta-mode-syntax-table)
+ (modify-syntax-entry ?\n ">" meta-mode-syntax-table)
+ ;; escape character, needed for embedded TeX code
+ (modify-syntax-entry ?\\ "\\" meta-mode-syntax-table)
+ )
+
+(defvar meta-mode-map nil
+ "Keymap used in Metafont or MetaPost mode.")
+(if meta-mode-map
+ ()
+ (setq meta-mode-map (make-sparse-keymap))
+ (define-key meta-mode-map "\t" 'meta-indent-line)
+ (define-key meta-mode-map "\C-m" 'reindent-then-newline-and-indent)
+ ;; Comment Paragraphs:
+; (define-key meta-mode-map "\M-a" 'backward-sentence)
+; (define-key meta-mode-map "\M-e" 'forward-sentence)
+; (define-key meta-mode-map "\M-h" 'mark-paragraph)
+; (define-key meta-mode-map "\M-q" 'fill-paragraph)
+ ;; Navigation:
+ (define-key meta-mode-map "\M-\C-a" 'meta-beginning-of-defun)
+ (define-key meta-mode-map "\M-\C-e" 'meta-end-of-defun)
+ (define-key meta-mode-map "\M-\C-h" 'meta-mark-defun)
+ ;; Indentation:
+ (define-key meta-mode-map "\M-\C-q" 'meta-indent-defun)
+ (define-key meta-mode-map "\C-c\C-qe" 'meta-indent-defun)
+ (define-key meta-mode-map "\C-c\C-qr" 'meta-indent-region)
+ (define-key meta-mode-map "\C-c\C-qb" 'meta-indent-buffer)
+ ;; Commenting Out:
+ (define-key meta-mode-map "\C-c%" 'meta-comment-defun)
+; (define-key meta-mode-map "\C-uC-c%" 'meta-uncomment-defun)
+ (define-key meta-mode-map "\C-c;" 'meta-comment-region)
+ (define-key meta-mode-map "\C-c:" 'meta-uncomment-region)
+ ;; Symbol Completion:
+ (define-key meta-mode-map "\M-\t" 'meta-complete-symbol)
+ ;; Shell Commands:
+; (define-key meta-mode-map "\C-c\C-c" 'meta-command-file)
+; (define-key meta-mode-map "\C-c\C-k" 'meta-kill-job)
+; (define-key meta-mode-map "\C-c\C-l" 'meta-recenter-output)
+ )
+
+(easy-menu-define
+ meta-mode-menu meta-mode-map
+ "Menu used in Metafont or MetaPost mode."
+ (list "Meta"
+ ["Forward Environment" meta-beginning-of-defun t]
+ ["Backward Environment" meta-end-of-defun t]
+ "--"
+ ["Indent Line" meta-indent-line t]
+ ["Indent Environment" meta-indent-defun t]
+ ["Indent Region" meta-indent-region
+ :active (meta-mark-active)]
+ ["Indent Buffer" meta-indent-buffer t]
+ "--"
+ ["Comment Out Environment" meta-comment-defun t]
+ ["Uncomment Environment" meta-uncomment-defun t]
+ ["Comment Out Region" meta-comment-region
+ :active (meta-mark-active)]
+ ["Uncomment Region" meta-uncomment-region
+ :active (meta-mark-active)]
+ "--"
+ ["Complete Symbol" meta-complete-symbol t]
+; "--"
+; ["Command on Buffer" meta-command-file t]
+; ["Kill Job" meta-kill-job t]
+; ["Recenter Output Buffer" meta-recenter-output-buffer t]
+ ))
+
+;; Compatibility: XEmacs doesn't have the `mark-active' variable.
+(defun meta-mark-active ()
+ "Return whether the mark and region are currently active in this buffer."
+ (or (and (boundp 'mark-active) mark-active) (mark)))
+
+
+
+;;; Hook variables.
+
+(defvar meta-mode-load-hook nil
+ "*Hook evaluated when first loading Metafont or MetaPost mode.")
+
+(defvar meta-common-mode-hook nil
+ "*Hook evaluated by both `metafont-mode' and `metapost-mode'.")
+
+(defvar metafont-mode-hook nil
+ "*Hook evaluated by `metafont-mode' after `meta-common-mode-hook'.")
+(defvar metapost-mode-hook nil
+ "*Hook evaluated by `metapost-mode' after `meta-common-mode-hook'.")
+
+
+
+;;; Initialization.
+
+(defun meta-common-initialization ()
+ "Common initialization for Metafont or MetaPost mode."
+ (kill-all-local-variables)
+
+ (make-local-variable 'paragraph-start)
+ (make-local-variable 'paragraph-separate)
+ (setq paragraph-start
+ (concat page-delimiter "\\|$"))
+ (setq paragraph-separate
+ (concat page-delimiter "\\|$"))
+
+ (make-local-variable 'paragraph-ignore-fill-prefix)
+ (setq paragraph-ignore-fill-prefix t)
+
+ (make-local-variable 'comment-start-skip)
+ (make-local-variable 'comment-start)
+ (make-local-variable 'comment-end)
+ (make-local-variable 'comment-multi-line)
+ (setq comment-start-skip "%+[ \t]*")
+ (setq comment-start "%")
+ (setq comment-end "")
+ (setq comment-multi-line nil)
+
+ (make-local-variable 'parse-sexp-ignore-comments)
+ (setq parse-sexp-ignore-comments t)
+
+ (make-local-variable 'comment-indent-function)
+ (setq comment-indent-function 'meta-comment-indent)
+ (make-local-variable 'fill-paragraph-function)
+ (setq fill-paragraph-function 'meta-fill-paragraph)
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function 'meta-indent-line)
+ ;; No need to define a mode-specific 'indent-region-function.
+ ;; Simply use the generic 'indent-region and 'comment-region.
+
+ ;; Set defaults for font-lock mode.
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults
+ '(meta-font-lock-keywords
+ nil nil ((?_ . "w")) nil
+ (font-lock-comment-start-regexp . "%")))
+
+ ;; Activate syntax table, keymap and menu.
+ (setq local-abbrev-table meta-mode-abbrev-table)
+ (set-syntax-table meta-mode-syntax-table)
+ (use-local-map meta-mode-map)
+ (easy-menu-add meta-mode-menu)
+ )
+
+
+(defun metafont-mode ()
+ "Major mode for editing Metafont sources.
+Special commands:
+\\{meta-mode-map}
+
+Turning on Metafont mode calls the value of the variables
+`meta-common-mode-hook' and `metafont-mode-hook'."
+ (interactive)
+ (meta-common-initialization)
+ (setq mode-name "Metafont")
+ (setq major-mode 'metafont-mode)
+
+ ;; Set defaults for completion function.
+ (make-local-variable 'meta-symbol-list)
+ (make-local-variable 'meta-symbol-changed)
+ (make-local-variable 'meta-complete-list)
+ (setq meta-symbol-list nil)
+ (setq meta-symbol-changed nil)
+ (apply 'meta-add-symbols metafont-symbol-list)
+ (setq meta-complete-list
+ (list (list "\\<\\(\\sw+\\)" 1 'meta-symbol-list)
+ (list "" 'ispell-complete-word)))
+ (run-hooks 'meta-common-mode-hook 'metafont-mode-hook))
+
+(defun metapost-mode ()
+ "Major mode for editing MetaPost sources.
+Special commands:
+\\{meta-mode-map}
+
+Turning on MetaPost mode calls the value of the variable
+`meta-common-mode-hook' and `metafont-mode-hook'."
+ (interactive)
+ (meta-common-initialization)
+ (setq mode-name "MetaPost")
+ (setq major-mode 'metapost-mode)
+
+ ;; Set defaults for completion function.
+ (make-local-variable 'meta-symbol-list)
+ (make-local-variable 'meta-symbol-changed)
+ (make-local-variable 'meta-complete-list)
+ (setq meta-symbol-list nil)
+ (setq meta-symbol-changed nil)
+ (apply 'meta-add-symbols metapost-symbol-list)
+ (setq meta-complete-list
+ (list (list "\\<\\(\\sw+\\)" 1 'meta-symbol-list)
+ (list "" 'ispell-complete-word)))
+ (run-hooks 'meta-common-mode-hook 'metapost-mode-hook))
+
+
+;;; Just in case ...
+
+(provide 'meta-mode)
+(run-hooks 'meta-mode-load-hook)
+
+;;; meta-mode.el ends here
diff --git a/support/emacs-modes/minor-map.el b/support/emacs-modes/minor-map.el
new file mode 100644
index 0000000000..543bd4bb0c
--- /dev/null
+++ b/support/emacs-modes/minor-map.el
@@ -0,0 +1,126 @@
+;; Minor mode keymap for Emacs
+
+;; Use minor-set-key to set a key in the minor keymap for a given
+;; minor mode.
+;;
+;; Use unbind-minor-mode to remove all key definitions for a given
+;; minor mode.
+
+;; COPYLEFT
+
+;; Created 1987 by Per Abrahamsen at University of Aalborg, Denmark.
+;; Updated 1991 by Per Abrahamsen at University of Aalborg, Denmark.
+;; This file is not part of GNU emacs (Yet... ;-)
+
+;; Everyone is granted permission to copy, modify and redistribute
+;; this file, this includes the right to remove this message.
+
+;; HOW MINOR-MAP WORKS!
+
+;; GNU Emacs minor modes may not change the keymap. This is why modes
+;; like outline-mode and indented-text-mode are major modes.
+;; Minor modes could of cause just change the local key binding on entry,
+;; and then restore it on exit. But this will fail, if some other
+;; minor mode changes the keybinding meanwhile.
+;;
+;; The idea behind minor-map is to keep a list of which minor mode has
+;; what binding for a particular key. The list is sorted
+;; chronologically, with the most recently enabled minor mode first,
+;; and the major mode last. The key will always be bound according to
+;; the head of the list, that is, the last enabled minor mode. When a
+;; minor mode is disabled, it will be removed from the list, and if it
+;; was at the head of the list the key will be bound according to the
+;; next entry in the list.
+;;
+;; When a minor mode is enabled, it should bind all its keys with
+;; minor-set-key, and, when disabled, unbound them with
+;; unbind-minor-mode.
+;;
+;; The minor mode keymaps are contained in a local variable
+;; minor-keymap, described in the documentation of make-minor-keymap.
+
+;; RESTRICTIONS
+
+;; The minor maps might fail, if the major mode (or the user) change
+;; the local key bindings after the first call to minor-set-key.
+;;
+;; Minor maps should support shared keymaps for prefix keys.
+
+;; DOES MINOR-MAP WORK?
+
+;; Please report any bug reports (or a formal proof of correctness) to
+;; abraham@iesd.auc.dk
+
+(provide 'minor-map)
+
+(make-variable-buffer-local 'minor-keymap) ;Documentation?
+(setq-default minor-keymap nil)
+
+(make-variable-buffer-local 'minor-local-keymap)
+(setq-default minor-local-keymap nil)
+
+(defun make-minor-keymap ()
+ "Construct a keymap for minor modes if none exists.
+
+The keymap is an alist of (KEY . MODE-LIST) where MODE-LIST is a list
+of (NAME . COMMAND).
+
+Each KEY represents an entry to the alist. If a key sequence have no
+entry, it mean that the KEY is bound to the default value in the
+major mode map.
+
+NAME identify a minor mode, that have bound KEY to COMMAND.
+The head of MODE-LIST represent the newest, and currently active,
+binding. The NAME of the tail is the major-mode, and COMMAND is
+the default binding. The MODE-LIST always contains at least the
+major-mode entry.
+
+Initially the alist is nil."
+
+ ;Try to make keymap buffer-local, *not* mode-local
+ (if (current-local-map)
+ (setq minor-local-keymap (copy-keymap (current-local-map)))
+ (setq minor-local-keymap (make-sparse-keymap)))
+ (use-local-map minor-local-keymap))
+
+(defun minor-set-key (key command name)
+ "Bind KEY to COMMAND in the minor keymap used by the minor mode NAME.
+NAME is a symbol that must identify the minor mode."
+
+ (if (null minor-local-keymap)
+ (make-minor-keymap))
+ (let ((map-entry (assoc key minor-keymap)))
+ (if (null map-entry)
+ (progn
+ (setq map-entry (list key
+ (cons major-mode
+ (local-key-binding key))))
+ (setq minor-keymap (cons map-entry
+ minor-keymap))))
+ (rplacd map-entry (cons (cons name command)
+ (cdr map-entry))))
+ (local-set-key key command))
+
+(defun unbind-minor-mode (name)
+ "Remove all references to minor mode NAME from the minor keymap.
+Key bindings will be updated to reflect the new content of the minor
+keymap."
+
+ (mapcar 'unbind-minor-entry minor-keymap))
+
+(defun unbind-minor-entry (entry)
+ "Remove any references to a minor mode from ENTRY. ENTRY have the
+form (KEY . MODE-LIST) where MODE-LIST is a list of (NAME . COMMAND).
+NAME is compared with the value of the variable \"name\", and the
+conscell is removed if equal. If the first entry in MODE-LIST is
+removed, KEY is rebound to the COMMAND of the next cell."
+
+ (let ((current (cdr entry))
+ (previous entry))
+ (if (eq name (car (car current)))
+ (local-set-key (car entry) (cdr (car (cdr current)))))
+ (while current
+ (if (eq name (car (car current)))
+ (rplacd previous (cdr current))
+ (setq previous current))
+ (setq current (cdr current)))))
diff --git a/support/emacs-modes/outline-m.el b/support/emacs-modes/outline-m.el
new file mode 100644
index 0000000000..a2645a29a9
--- /dev/null
+++ b/support/emacs-modes/outline-m.el
@@ -0,0 +1,184 @@
+;; Outline as minor mode.
+
+;; You need the minor keymap handler to use this file.
+
+;; To make outline-mode a minor mode, append the following to your
+;; ".emacs" file, or in a local.el:
+
+;; (make-variable-buffer-local 'outline-prefix-char)
+;; (setq-default outline-prefix-char "\C-l")
+;; (make-variable-buffer-local 'outline-regexp)
+;; (setq-default outline-regexp "[*\^l]+")
+;; (make-variable-buffer-local 'outline-level-function)
+;; (setq-default outline-level-function 'outline-level-default)
+
+;; COPYLEFT
+
+;; Created 1987 by Per Abrahamsen at University of Aalborg, Denmark.
+;; Please report improvents and bugs to abraham@iesd.auc.dk.
+
+;; Might contain code from the original outline.el, so...
+
+;; COPYRIGHT
+
+;; Outline mode commands for Emacs
+;; Copyright (C) 1986 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY. No author or distributor
+;; accepts responsibility to anyone for the consequences of using it
+;; or for whether it serves any particular purpose or works at all,
+;; unless he says so in writing. Refer to the GNU Emacs General Public
+;; License for full details.
+
+;; Everyone is granted permission to copy, modify and redistribute
+;; GNU Emacs, but only under the conditions described in the
+;; GNU Emacs General Public License. A copy of this license is
+;; supposed to have been given to you along with GNU Emacs so you
+;; can know your rights and responsibilities. It should be in a
+;; file named COPYING. Among other things, the copyright notice
+;; and this notice must be preserved on all copies.
+
+;; Jan '86, Some new features added by Peter Desnoyers and rewritten by RMS.
+
+(require 'minor-map)
+
+(if (featurep 'outline)
+ ()
+ (load-library "outline")
+ (provide 'outline))
+
+(setq minor-mode-alist (cons '(selective-display " Outline")
+ minor-mode-alist))
+
+; Changed to allow read-only buffers and to speed up nonmodified buffers
+
+(defun outline-flag-region (from to flag)
+ "Hides or shows lines from FROM to TO, according to FLAG. If FLAG
+is \\n (newline character) then text is hidden, while if FLAG is \\^M
+\(control-M) the text is shown."
+ (let ((modp (buffer-modified-p))
+ (read-only buffer-read-only))
+ (if read-only (toggle-read-only))
+ (unwind-protect
+ (subst-char-in-region from to
+ (if (= flag ?\n) ?\^M ?\n)
+ flag t)
+ (progn
+ (if read-only (toggle-read-only))
+ (set-buffer-modified-p modp)))))
+
+(defun hide-region-body (start end)
+ "Hide all body lines in the region, but not headings."
+ (save-excursion
+ (save-restriction
+ (narrow-to-region start end)
+ (goto-char (point-min))
+ (let ((modp (buffer-modified-p)))
+ (set-buffer-modified-p t)
+ (while (not (eobp))
+ (outline-flag-region (point) (progn (outline-next-preface) (point)) ?\^M)
+ (if (not (eobp))
+ (forward-char
+ (if (looking-at "[\n\^M][\n\^M]")
+ 2 1))))
+ (set-buffer-modified-p modp)))))
+
+(defun outline-level-default ()
+ "Return the depth to which a statement is nested in the outline.
+Point must be at the beginning of a header line.
+This is actually the length of whatever outline-regexp matches."
+ (save-excursion
+ (looking-at outline-regexp)
+ (- (match-end 0) (match-beginning 0))))
+
+(defun outline-level ()
+ "Return the depth to which a this heading is nested in the outline.
+This is done by a call to the value of outline-level-function, which
+default to outline-level-default."
+ (funcall outline-level-function))
+
+(if (boundp 'outline-minor-keymap)
+ ()
+ (setq outline-minor-keymap (make-keymap)) ; allocate outline keymap table
+ (define-key outline-minor-keymap "\C-n" 'outline-next-visible-heading)
+ (define-key outline-minor-keymap "\C-p" 'outline-previous-visible-heading)
+ (define-key outline-minor-keymap "\C-f" 'outline-forward-same-level)
+ (define-key outline-minor-keymap "\C-b" 'outline-backward-same-level)
+ (define-key outline-minor-keymap "\C-u" 'outline-up-heading)
+ (define-key outline-minor-keymap "\C-t" 'hide-body)
+ (define-key outline-minor-keymap "\C-a" 'show-all)
+ (define-key outline-minor-keymap "\C-o" 'outline-mode)
+ (define-key outline-minor-keymap "\C-h" 'hide-subtree)
+ (define-key outline-minor-keymap "\C-s" 'show-subtree)
+ (define-key outline-minor-keymap "\C-i" 'show-children)
+ (define-key outline-minor-keymap "\C-c" 'hide-entry)
+ (define-key outline-minor-keymap "\C-e" 'show-entry)
+ (define-key outline-minor-keymap "\C-l" 'hide-leaves)
+ (define-key outline-minor-keymap "\C-x" 'show-branches))
+
+(defun outline-minor-mode (&optional arg) "\
+Toggle outline mode.
+With arg, turn ouline mode on iff arg is positive.
+
+Minor mode for editing outlines with selective display.
+Headings are lines which start with asterisks: one for major headings,
+two for subheadings, etc. Lines not starting with asterisks are body lines.
+
+Body text or subheadings under a heading can be made temporarily
+invisible, or visible again. Invisible lines are attached to the end
+of the heading, so they move with it, if the line is killed and yanked
+back. A heading with text hidden under it is marked with an ellipsis (...).
+
+Commands:
+C-l C-n outline-next-visible-heading move by visible headings
+C-l C-p outline-previous-visible-heading
+C-l C-f outline-forward-same-level similar but skip subheadings
+C-l C-b outline-backward-same-level
+C-l C-u outline-up-heading move from subheading to heading
+
+C-l C-t hide-body make all text invisible (not headings).
+C-l C-a show-all make everything in buffer visible.
+
+C-l C-o outline-minor-mode leave outline mode.
+
+The remaining commands are used when point is on a heading line.
+They apply to some of the body or subheadings of that heading.
+
+C-l C-h hide-subtree make body and subheadings invisible.
+C-l C-s show-subtree make body and subheadings visible.
+C-l C-i show-children make direct subheadings visible.
+ No effect on body, or subheadings 2 or more levels down.
+ With arg N, affects subheadings N levels down.
+
+C-l C-c hide-entry make immediately following body invisible.
+C-l C-e show-entry make it visible.
+C-l C-l hide-leaves make body under heading and under its subheadings
+ invisible. The subheadings remain visible.
+
+C-l C-x show-branches make all subheadings at all levels visible.
+
+The prefix char (C-l) is determinated by the value of outline-prefix-char.
+If outline-minor-keymap is set, it will be used instead of the default
+keymap.
+
+The variable outline-regexp can be changed to control what is a heading.
+A line is a heading if outline-regexp matches something at the
+beginning of the line. The longer the match, the deeper the level."
+
+ (interactive "P")
+ (if (or (and (null arg) selective-display)
+ (<= (prefix-numeric-value arg) 0))
+ (progn ;Turn it off
+ (unbind-minor-mode 'outline-minor-mode)
+ (if selective-display
+ (progn
+ (show-all)
+ (setq selective-display nil))))
+ (setq selective-display t) ;Turn it on
+ (minor-set-key outline-prefix-char
+ outline-minor-keymap
+ 'outline-minor-mode))
+ (set-buffer-modified-p (buffer-modified-p))) ;No-op, but updates mode line.
diff --git a/support/emacs-modes/swiftex/hilit-swiftex.el b/support/emacs-modes/swiftex/hilit-swiftex.el
new file mode 100644
index 0000000000..cc0ae5979e
--- /dev/null
+++ b/support/emacs-modes/swiftex/hilit-swiftex.el
@@ -0,0 +1,314 @@
+;;; hilit-swiftex.el -- enhancements for highlighting swiftex and doctex
+;;; buffers using hilit19.el or hl319.el.
+;;;
+;;; This file was based on hilit-LaTeX.el v1.05 by Peter Galbraith
+;;; (rhogee@bathybius.meteo.mcgill.ca).
+
+;;; to do: we need to reset the patterns explicitly whenever we
+;;; change modes, since we need to eval variables; or can we use
+;;; functions?
+
+;;; need to distinguish doctex from swiftex.
+
+(require 'hilit19)
+(provide 'hilit-swiftex)
+
+(hilit-set-mode-patterns
+ '(doctex-mode)
+ '(
+ ;; outline heading
+ ("^\\^\\^A\\*+.*$" nil comment)
+ ;; comment
+ ("^\\^\\^A.*$" nil comment)
+ ;; label
+ ("\\\\item\\(\\[[^]]*\\]\\)?" nil label)
+ ;; formula
+ ("\\\\(" "\\\\)" formula) ; \( \)
+ ("[^\\\\]\\\\\\[" "\\\\\\]" formula) ; \[ \] but not \\[len]
+ ("[^$\\]\\($\\($[^$]*\\$\\|[^$]*\\)\\$\\)" 1 formula) ; '$...$' or '$$...$$'
+ ;; ^^ but not \$102.54 is expensive for a car wash.
+ ;; crossref
+ ("|[^|\n]*|" nil crossref)
+ (hilit-bracket-region
+ ; (\\(no\\)?cite -> changed to any cite commands that users make up.
+ "\\\\\\([^ ]*cite\\|\\(page\\)?ref\\|eqref\\|label\\|index\\|glossary\\){"
+ crossref)
+ ;; bold
+ (hilit-bracket-wysiwyg "{\\\\bfseries" bold)
+ (hilit-bracket-region "\\\\textbf{" bold)
+ ;; italic
+ (hilit-bracket-wysiwyg "{\\\\\\(em\\|itshape\\|slshape\\)" italic)
+ (hilit-bracket-region "\\\\emph{" italic)
+ (hilit-bracket-region "\\\\text\\(it\\|sl\\){" italic)
+ ;; include
+ (hilit-bracket-region "\\\\\\(include\\*?\\|input\\|bibliography\\){" include)
+ ;; defun
+ ("\\\\ReserveCS{?\\\\[a-zA-Z-@]+" defun)
+ ;; FIX, many things don't necessarily have {'s after them.
+ ;; FIX: global and long;; see doctex
+ (hilit-bracket-region "\\\\new\\(let\\|tokens\\|length\\|theorem\\|counter\\){" defun)
+ ;; FIX want to have matching braces...
+ (hilit-bracket-region "\\\\NewNameDef\\*?{" defun)
+;; causes error!
+ (hilit-bracket-region "\\(\\\\long\\|\\\\global\\)+\\\\def[^}]*{" defun)
+ ;; keyword
+ (hilit-bracket-region "\\\\\\(v\\|h\\)space\\(\*\\)?{" keyword)
+ (hilit-bracket-region "\\\\text\\(tt\\|sf\\|rm\\){" keyword)
+ (hilit-bracket-region "\\\\footnote\\(mark\\|text\\)?{" keyword)
+ (hilit-bracket-region
+ "\\\\\\(sub\\)*\\(paragraph\\|section\\)\\(\*\\|\\[.*\\]\\)?{" keyword)
+ (hilit-bracket-region
+ "\\\\\\(chapter\\|part\\)\\(\*\\|\\[.*\\]\\)?{" keyword)
+ ("\\\\[a-z]+box" nil keyword)
+ ;; define
+ ("\\\\\\(setlength\\|settowidth\\|addtolength\\|setcounter\\|addtocounter\\)" nil define)
+ (hilit-bracket-region "\\\\\\(title\\|author\\|date\\|thanks\\){" define)
+ ;; decl
+ ("\\\\\\(scshape\\|bfseries\\|em\\|itshape\\|rmfamily\\|sffamily\\|slshape\\|ttfamily\\)\\b" nil decl)
+ ("``" "''" string)
+ ("\\\\\\(raggedright\\|makeindex\\|makeglossary\\|maketitle\\)\\b" nil
+ decl)
+ (hilit-bracket-region
+ "\\\\\\(pagestyle\\|thispagestyle\\|pagenumbering\\|numberwithin\\){" decl)
+ (hilit-bracket-region "\\\\documentclass\\(\\[.*\\]\\)?{" decl)
+ (hilit-bracket-region "\\\\\\(begin\\|end\\|nofiles\\|includeonly\\){"
+ decl)
+ ("\\\\\\(normalsize\\|small\\|footnotesize\\|scriptsize\\|tiny\\|large\\|Large\\|LARGE\\|huge\\|Huge\\)\\b" nil decl)
+ ("\\\\\\(smaller\\|larger\\)\\(\\[[^]]*\\]\\)?" nil decl)
+ (hilit-bracket-region "\\\\relsize{" decl)
+ ("\\\\\\(appendix\\|tableofcontents\\|listoffigures\\|listoftables\\)\\b"
+ nil decl)
+ ;; label
+ (hilit-bracket-wysiwyg "{\\\\scshape" label)
+ (hilit-bracket-region "\\\\caption\\(\\[[^]]*\\]\\)?{" label)
+))
+
+;; avoid message while byte-compiling
+(eval-when-compile (defvar hilit-on-the-fly-in-use))
+(hilit-set-mode-patterns
+ '(swiftex-mode)
+ '(
+ ;; outline heading
+ ("^%\\*+.*$" nil comment)
+ ("\\(^\\|[^\\]\\)\\(%.*\\)$" 2 comment) ; comments
+ ;; label
+ ("\\\\item\\(\\[[^]]*\\]\\)?" nil label)
+ ;; formula
+ ("\\\\(" "\\\\)" formula) ; \( \)
+ ("[^\\\\]\\\\\\[" "\\\\\\]" formula) ; \[ \] but not \\[len]
+ ("[^$\\]\\($\\($[^$]*\\$\\|[^$]*\\)\\$\\)" 1 formula) ; '$...$' or '$$...$$'
+ ;; ^^ but not \$102.54 is expensive for a car wash.
+ ;; crossref
+ ("|[^|\n]*|" nil crossref)
+ (hilit-bracket-region
+ ; (\\(no\\)?cite -> changed to any cite commands that users make up.
+ "\\\\\\([^ ]*cite\\|\\(page\\)?ref\\|eqref\\|label\\|index\\|glossary\\){"
+ crossref)
+ ;; bold
+ (hilit-bracket-wysiwyg "{\\\\bfseries" bold)
+ (hilit-bracket-region "\\\\textbf{" bold)
+ ;; italic
+ (hilit-bracket-wysiwyg "{\\\\\\(em\\|itshape\\|slshape\\)" italic)
+ (hilit-bracket-region "\\\\emph{" italic)
+ (hilit-bracket-region "\\\\text\\(it\\|sl\\){" italic)
+ ;; include
+ (hilit-bracket-region "\\\\\\(include\\*?\\|input\\|bibliography\\){" include)
+ ;; defun
+ ("\\\\ReserveCS{?\\\\[a-zA-Z-@]+" defun)
+ ;; FIX, many things don't necessarily have {'s after them.
+ ;; FIX: global and long ; ak, all messed up.
+ (hilit-bracket-region
+ "\\\\\\(re\\)?new\\(environment\\|command\\|let\\)\\\\[.\n]*{" defun)
+ (hilit-bracket-region "\\\\new\\(let\\|tokens\\|length\\|theorem\\|counter\\){" defun)
+ ;; FIX want to have matching braces...
+ (hilit-bracket-region "\\\\NewNameDef\\*?{" defun)
+;; changed; see \\long in doctex...
+ ;; keyword
+ (hilit-bracket-region "\\\\\\(v\\|h\\)space\\(\*\\)?{" keyword)
+ (hilit-bracket-region "\\\\text\\(tt\\|sf\\|rm\\){" keyword)
+ (hilit-bracket-region "\\\\footnote\\(mark\\|text\\)?{" keyword)
+ (hilit-bracket-region
+ "\\\\\\(sub\\)*\\(paragraph\\|section\\)\\(\*\\|\\[.*\\]\\)?{" keyword)
+ (hilit-bracket-region
+ "\\\\\\(chapter\\|part\\)\\(\*\\|\\[.*\\]\\)?{" keyword)
+ ("\\\\[a-z]+box" nil keyword)
+ ;; define
+ ("\\\\\\(setlength\\|settowidth\\|addtolength\\|setcounter\\|addtocounter\\)" nil define)
+ (hilit-bracket-region "\\\\\\(title\\|author\\|date\\|thanks\\){" define)
+ ;; decl
+ ("\\\\\\(scshape\\|bfseries\\|em\\|itshape\\|rmfamily\\|sffamily\\|slshape\\|ttfamily\\)\\b" nil decl)
+ ("``" "''" string)
+ ("\\\\\\(raggedright\\|makeindex\\|makeglossary\\|maketitle\\)\\b" nil
+ decl)
+ (hilit-bracket-region
+ "\\\\\\(pagestyle\\|thispagestyle\\|pagenumbering\\|numberwithin\\){" decl)
+ (hilit-bracket-region "\\\\documentclass\\(\\[.*\\]\\)?{" decl)
+ (hilit-bracket-region "\\\\\\(begin\\|end\\|nofiles\\|includeonly\\){"
+ decl)
+ ("\\\\\\(normalsize\\|small\\|footnotesize\\|scriptsize\\|tiny\\|large\\|Large\\|LARGE\\|huge\\|Huge\\)\\b" nil decl)
+ ("\\\\\\(smaller\\|larger\\)\\(\\[[^]]*\\]\\)?" nil decl)
+ (hilit-bracket-region "\\\\relsize{" decl)
+ ("\\\\\\(appendix\\|tableofcontents\\|listoffigures\\|listoftables\\)\\b"
+ nil decl)
+ ;; label
+ (hilit-bracket-wysiwyg "{\\\\scshape" label)
+ (hilit-bracket-region "\\\\caption\\(\\[[^]]*\\]\\)?{" label)
+))
+
+;; define decl label keyword bold italic comment string include
+
+;; from the hilit-src
+ ;; and anotherone for LaTeX
+;; (crossref DarkGoldenrod Goldenrod underline)
+;; (formula Goldenrod DarkGoldenrod underline)
+;;
+
+; ;; comments
+; ("[^\\]%.*$" nil comment)
+
+; ;; the following two match \foo[xx]{xx} or \foo*{xx} or \foo{xx}
+; ("\\\\\\(sub\\)*\\(paragraph\\|section\\)\\(\*\\|\\[.*\\]\\)?{" "}"
+; keyword)
+; ("\\\\\\(chapter\\|part\\)\\(\*\\|\\[.*\\]\\)?{" "}" keyword)
+; ("\\\\footnote\\(mark\\|text\\)?{" "}" keyword)
+; ("\\\\[a-z]+box" nil keyword)
+; ("\\\\\\(v\\|h\\)space\\(\*\\)?{" "}" keyword)
+
+; ;; (re-)define new commands/environments/counters
+; ("\\\\\\(re\\)?new\\(environment\\|command\\){" "}" defun)
+; ("\\\\new\\(length\\|theorem\\|counter\\){" "}" defun)
+
+; ;; various declarations/definitions
+; ("\\\\\\(setlength\\|settowidth\\|addtolength\\|setcounter\\|addtocounter\\)" nil define)
+; ("\\\\\\(title\\|author\\|date\\|thanks\\){" "}" define)
+
+; ("\\\\documentstyle\\(\\[.*\\]\\)?{" "}" decl)
+; ("\\\\\\(begin\\|end\\|nofiles\\|includeonly\\){" "}" decl)
+; ("\\\\\\(raggedright\\|makeindex\\|makeglossary\\|maketitle\\)\\b" nil
+; decl)
+; ("\\\\\\(pagestyle\\|thispagestyle\\|pagenumbering\\){" "}" decl)
+; ("\\\\\\(normalsize\\|small\\|footnotesize\\|scriptsize\\|tiny\\|large\\|Large\\|LARGE\\|huge\\|Huge\\)\\b" nil decl)
+; ("\\\\\\(appendix\\|tableofcontents\\|listoffigures\\|listoftables\\)\\b"
+; nil decl)
+; ("\\\\\\(bf\\|em\\|it\\|rm\\|sf\\|sl\\|ss\\|tt\\)\\b" nil decl)
+
+; ;; label-like things
+; ("\\\\item\\(\\[[^]]*\\]\\)?" nil label)
+; ("\\\\caption\\(\\[[^]]*\\]\\)?{" "}" label)
+
+; ;; formulas
+; ("[^\\]\\\\(" "\\\\)" formula) ; \( \)
+; ("[^\\]\\\\\\[" "\\\\\\]" formula) ; \[ \]
+; ("[^\\$]\\($\\($[^$]*\\$\\|[^$]*\\)\\$\\)" 1 formula) ; '$...$' or '$$...$$'
+
+; ;; things that bring in external files
+; ("\\\\\\(include\\|input\\|bibliography\\){" "}" include)
+
+; ;; "wysiwyg" emphasis -- these don't work with nested expressions
+; ;; ("{\\\\\\(em\\|it\\|sl\\)" "}" italic)
+; ;; ("{\\\\bf" "}" bold)
+
+; ("``" "''" string)
+
+; ;; things that do some sort of cross-reference
+; ("\\\\\\(\\(no\\)?cite\\|\\(page\\)?ref\\|label\\|index\\|glossary\\){" "}" crossref)
+; ))
+
+ (defun hilit-bracket-region (open)
+ "Find region within curly brackets for hilit pattern.
+ARG is pattern for beginning of pattern and ends with {.
+It cannot be white space.
+Patterns ends simply at the matching closing bracket.
+
+Used for patterns like:
+ \\chapter{stuff with matching {} ending with }"
+ (if (re-search-forward open nil t)
+ (let ((here (point))
+ (the-start (match-beginning 0)))
+ (backward-char 1) ; point is on bracket
+ (if hilit-on-the-fly-in-use
+ ;; if hl319's on-the-fly hilighting is in use then we can't use
+ ;; forward-list because it uses the built-in scan-lists and will
+ ;; return an error if there is no matching bracket yet.
+ (re-search-forward "}"
+ (progn (save-excursion (end-of-line)(point)))
+ 1)
+ (forward-list 1))
+ (cons the-start (point)))))
+
+(defun hilit-inside-bracket-region (open)
+ "Find region within curly brackets for hilit pattern.
+ARG is pattern for beginning of pattern and ends with {.
+It cannot be white space.
+Patterns ends simply at the matching closing bracket.
+
+Used for patterns like:
+ \\textbf{only stuff within bracket is highlited}"
+ (if (re-search-forward open nil t)
+ (let ((the-start (point)))
+ (backward-char 1) ; point is on bracket
+ (if hilit-on-the-fly-in-use
+ (re-search-forward "}"
+ (progn (save-excursion (end-of-line)(point))) 1)
+ (forward-list 1))
+ (backward-char 1)
+ (cons the-start (point)))))
+
+(defun hilit-inside-environment (open)
+ "Find region within curly brackets for hilit pattern.
+ARG is pattern for \\begin{something}."
+ (if (re-search-forward open nil t)
+ (let ((the-start (progn (forward-line 1)(point))) ;Start on next line
+ (the-end))
+ (re-search-backward "\\\\begin{\\([^}]+\\)}" nil t)
+ (setq the-end (buffer-substring (match-beginning 1)(match-end 1)))
+ (if hilit-on-the-fly-in-use ;Search no more than 10 lines away
+ (if (search-forward (concat "\\end{" the-end "}")
+ (save-excursion (forward-line 10)(point)) t)
+ (cons the-start (progn (forward-line -1)(point)))
+ (cons the-start the-start))
+ (if (search-forward (concat "\\end{" the-end "}") nil t)
+ (cons the-start (match-beginning 0))
+ (end-of-line) ;Move off the \begin{}
+ (cons the-start the-start))))))
+
+(defun hilit-bracket-wysiwyg (open)
+ "Find region within curly brackets for hilit pattern.
+ARG is pattern for beginning of pattern and starts with {.
+Patterns ends simply at the matching closing bracket.
+
+Used for patterns like:
+ {\em stuff with matching {} ending with }"
+ (if (re-search-forward open nil t)
+ (let ((the-start (match-beginning 0)))
+ (goto-char the-start)
+ (if hilit-on-the-fly-in-use
+ (re-search-forward "}"
+ (progn (save-excursion (end-of-line)(point))) 1)
+ (forward-list 1))
+ (cons the-start (point)))))
+
+
+(defvar hilit-AmSLaTeX-commands nil
+ "*Set to t if you want to hightlight AmSLaTeX commands.")
+
+(defvar hilit-multilingual-strings nil
+ "*Set to t if you want to hightlight multilingual quoted strings.
+Highlights: \"`german\"', \"< french \">, << french >> and + 8-bit french ;.")
+
+(defvar hilit-LaTeX-commands t
+ "*Set to nil if you don't want to highlight unknown LaTeX commands")
+
+(defvar hilit-on-the-fly-in-use nil
+ "Used by hilit-LaTeX to determine if on-the-fly hilighting is in use")
+
+;; I need to modify hl319.el's on-the-fly highlighter so that it
+;; tells me on-the-fly highlighting is in use.
+(defun hilit-rehighlight-changed-lines (st en len)
+ "Quietly rehighlight just this line.
+Useful as an after change hook in VM/gnus summary buffers and dired buffers."
+ (save-match-data
+ (let ((hilit-on-the-fly-in-use t))
+ ;; (> (- en st) hilit-max-change-rehighlight)
+ (hilit-rehighlight-region st en 'quietly))))
+
diff --git a/support/emacs-modes/swiftex/swiftex-doc.txt b/support/emacs-modes/swiftex/swiftex-doc.txt
new file mode 100644
index 0000000000..30f73281a8
--- /dev/null
+++ b/support/emacs-modes/swiftex/swiftex-doc.txt
@@ -0,0 +1,548 @@
+ swiftex.el documentation
+
+I mean to turn this into .info documentation in the future, but for now, it is
+a plain text file in outline mode.
+
+
+* introduction
+
+This file defines major modes swifTeX and docTeX.
+
+swifTeX mode is for editing buffers containing normal LaTeX files, and
+provides an alternative to the LaTeX modes in the standard Emacs
+distribution and the AUC TeX package.
+
+docTeX mode is for editing buffers containing self-documenting LaTeX code
+that uses the package "doc.sty", including the document class "ltxdoc".
+For these buffers, docTeX mode is significantly more useful than the
+alternatives provided by standard Emacs and AUC TeX.
+
+These modes are derived from the LaTeX mode in "tex-mode.el" (distributed with
+GNU Emacs) using the autoloaded function `define-derived-mode' in "derived.el"
+(also part of the standard distribution). FIX: untested-by-me option to derive
+from AUC-TeX's latex-mode.
+
+The principal additions allow convenient, precise control over filling and
+outlining. There are also a few improvements to help save typing. In
+docTeX mode, functions are provided to help manage LaTeX file versions,
+dates, and CheckSums. These major modes are fully documented and
+well-tested.
+
+* installation
+
+Swiftex.el should work with GNU Emacs version 20.x. If it doesn't, tell me
+about it! I don't have the resources to ensure it works on other versions of
+Emacs. There used to be a byte-compilation problem on versions through 19.28.
+I no longer include information on it because I don't think it works on 19.x
+any more anyway.
+
+Put swiftex.el where your Emacs can find it, that is, somewhere in the
+directories in `load-path'. Byte-compile it with `M-x byte-compile-file'.
+
+You will then probably want to make some additions to your Emacs startup code
+(i.e., your .emacs file):
+
+(1) You should either load "swiftex.el" immediately or cause it to be loaded as
+ necessary. Otherwise you will have to load it manually before using it. To
+ load it immediately:
+
+ (require 'swiftex)
+
+ To load it whenever `doctex-mode' or `swiftex-mode' is called:
+
+ (autoload 'doctex-mode "swiftex" "Major mode for LaTeX doc documents.")
+ (autoload 'swiftex-mode "swiftex" "Major mode for LaTeX documents.")
+
+(2) There are two ways to have Emacs use swifTeX mode or docTeX mode
+ automatically when you work on certain documents.
+
+ (A) On a per-file basis with Emacs file variables. FIX: link to emacs.info
+ node.
+
+ Example: at the end of your file, put:
+
+ % Local Variables:
+ % mode: doctex
+ % End:
+
+ (B) By file extension by setting the Emacs variable `auto-mode-alist'. You
+ may set this variable any way you like, but a particularly convenient
+ way is to use the function `stx-merge-list' defined in "swiftex.el".
+ Here is an example using `stx-merge-list'. Each entry is independent
+ and can be omitted according to your preferences.
+
+ ;; These will only replace entries in `auto-mode-alist' with identical
+ ;; first parts; watch out for ending up with two entries that match the
+ ;; same file names, such as "\\.tex$" and "\\.tex\\'".
+ (stx-merge-list auto-mode-alist '(
+ ("\\.bbl\\'" . swiftex-mode) ("\\.aux\\'" . swiftex-mode)
+ ("\\.tex\\'" . swiftex-mode) ("\\.ins\\'" . swiftex-mode)
+ ("\\.ltx\\'" . swiftex-mode) ("\\.bbl\\'" . swiftex-mode)
+ ("\\.cls\\'" . doctex-mode) ("\\.sty\\'" . doctex-mode)
+ ("\\.dtx\\'" . doctex-mode) ("\\.fdd\\'" . doctex-mode)
+ ("\\.sto\\'" . doctex-mode) ("\\.clo\\'" . doctex-mode)
+ ("\\.cfg\\'" . doctex-mode)
+ ))
+
+ You can't use `stx-merge-list' until it is defined, so you may just
+ want to copy the definition into your .emacs file before you set
+ `auto-mode-alist':
+
+ (defun stx-merge-list (old new &optional warn)
+ "Modify a list OLD to include all NEW's elements not in OLD.
+ Compare elements with `equal'. New elements are added at the end of
+ OLD. NEW and OLD can be both lists or both alists. Returns OLD.
+
+ For alists, add NEW's keys to end of OLD if OLD does not have them.
+ If OLD does have a matching key, change its value to NEW's value for
+ that key. The key is the car of each element, the value is the cdr.
+
+ Optional WARN non-nil means print a message whenever the value of one
+ of OLD's keys is being replaced."
+ (let ((p (listp (car old))))
+ ;; check by checking first element that args are either both lists or both
+ ;; alists
+ (if (not (eq p (listp (car new))))
+ (error "Args to `merge-list' must be both lists or both alists!")
+ (if p
+ ;; `old' and `new' are alists
+ (while new
+ (let* ((new-cons (car new))
+ (old-cons (assoc (car new-cons) old)))
+ (if old-cons
+ (progn
+ (if warn
+ (message "merge-list: changing value of key %s from %s to %s"
+ (car old-cons) (cdr old-cons) (cdr new-cons)))
+ (setcdr old-cons (cdr new-cons)))
+ (nconc old (list new-cons)))
+ (setq new (cdr new))))
+ ;; `old' and `new' are regular lists
+ (while new
+ (let ((x (car new)))
+ (or (member x old)
+ (nconc old (list x)))
+ (setq new (cdr new)))))
+ old)))
+
+(3) You may want to modify some key bindings. By convention, a major mode does
+ not bind `C-c <letter>' by default, since these are reserved for users.
+ But you are a user, so bind away. Here are the bindings I like to use:
+
+ (eval-after-load "swiftex" '(swiftex-startup))
+ (defun swiftex-startup ()
+ "Onetime customization to be executed after loading \"swiftex.el\"."
+ (define-key swiftex-mode-map "\C-cm" 'stx-emphasize)
+ (define-key swiftex-mode-map "\C-ce" 'stx-close-block-from-inside)
+ (define-key swiftex-mode-map "\C-cB" 'stx-insert-block)
+ (define-key swiftex-mode-map "\C-cb" 'stx-begin-block)
+ ;; These next three are the way I like to use braces, but this is best
+ ;; left as a personal choice.
+ (define-key swiftex-mode-map "\M-{" 'self-insert-command)
+ (define-key swiftex-mode-map "\M-}" 'self-insert-command)
+ (define-key swiftex-mode-map "{" 'tex-insert-braces))
+
+* use with AUC-TeX
+
+Having swiftex and auctex both loaded causes problems for me, though you might
+want to try setting some variable (I forget which) in swiftex that will derive
+from auctex.
+
+I do the following to run AUC-TeX and swiftex in different Emacs processes. I
+put the following into my .emacs:
+
+ ;; Code in dotemacs will do the right thing with these variables.
+ (defvar dte-have-swiftex-flag t
+ "*Non-nil means swiftex.el available on system.")
+
+ (defvar dte-have-auctex-flag t
+ "*Non-nil means AUC-TeX available on system.")
+
+ ;; `dte-use-swiftex-flag' is not defined non-nil in this file. It might be
+ ;; defined on the command line, however.
+ (defvar dte-use-swiftex-flag nil
+ "Non-nil means Emacs should use swiftex.")
+
+ (defun dte-load-swiftex ()
+ "Load \"swiftex\"."
+ (require 'swiftex)
+ (merge-list auto-mode-alist '(
+ ("\\.cls\\'" . doctex-mode)
+ ("\\.sty\\'" . doctex-mode)
+ ("\\.sto\\'" . doctex-mode)
+ ("\\.clo\\'" . doctex-mode)
+ ("\\.cfg\\'" . doctex-mode)
+ ("\\.dtx\\'" . doctex-mode)
+ ("\\.fdd\\'" . doctex-mode)
+ ("\\.hlx\\'" . swiftex-mode)
+ ("\\.bbl\\'" . swiftex-mode)
+ ("\\.tex\\'" . swiftex-mode)
+ ("\\.ltx\\'" . swiftex-mode)
+ ("\\.ins\\'" . swiftex-mode)
+ ("\\.aux\\'" . swiftex-mode)
+ ("\\.cfq\\'" . swiftex-mode)
+ ("\\.stq\\'" . swiftex-mode)
+ ("\\.clq\\'" . swiftex-mode)
+ ("\\.soq\\'" . swiftex-mode)
+ ("\\.coq\\'" . swiftex-mode)
+ ("\\.tmpl\\'" . swiftex-mode)
+ ("\\.notes\\'" . swiftex-mode)
+ ) t))
+
+ (unless (boundp 'dte-no-server-flag)
+ (gnuserv-start))
+
+ (if dte-have-swiftex-flag
+ (if dte-have-auctex-flag
+ (if dte-use-swiftex-flag
+ ;; have both, use swiftex
+ (dte-load-swiftex)
+ ;; have both, don't use swiftex
+ (require 'tex-site))
+ ;; have swiftex not auctex
+ (dte-load-swiftex))
+ (when dte-have-auctex-flag
+ ;; have auctex not swiftex
+ (require 'tex-site)))
+
+
+Then I run my Emacs processes that use swiftex with a shell wrapper. Pared down:
+
+ #!/bin/sh
+
+ # Run emacs with special arguments.
+
+ # $1 is a flag.
+
+ # If this is called from a fvwm menu item, then we don't have
+ # .bashrc-interactive in the environment. We want to load .bash-dirs whether
+ # we do or not, since some of the values depend on the setting of
+ # SHELL_FOR_EMACS.
+ SHELL_FOR_EMACS=true
+ if [ -e ~/.bash-dirs ]; then
+ set -a
+ source ~/.bash-dirs
+ set +a
+ fi
+ unset SHELL_FOR_EMACS
+
+ # We remove . from PATH if it's there.
+ export PATH=$(echo $PATH | sed -e 's/^.://' -e 's/:.:/:/')
+
+ #debug=true
+
+ function runemacs () {
+ dinit=
+ if [ $debug ]; then
+ dinit=--debug-init
+ echo emacs-wrap args:
+ echo $dinit
+ let i=1
+ for x; do
+ echo $i: $x
+ let i+=1
+ done
+ fi
+ exec emacs $dinit "$@"
+ }
+
+ # Quoting is a nightmare:
+
+ # eval runemacs -q $profile_A '"$@"';;
+
+ # to get the quotes within profile_A to be understood, we need the eval, and it
+ # won't work (God knows why) if you write $(eval echo $profile_A) or
+ # $(echo $profile_A). But if you eval the "$@" (which needs the double quotes
+ # or it will expand as one word) you will screw up any quotes given on the
+ # command line, so you need to protect it from the eval with the single quotes.
+
+ # you can leave out the no-desktop flag if you like, it doesn't matter. i
+ # didn't include the code that looks at it above.
+
+ case "$1" in
+ [Ss]wiftex)
+ shift
+ # cd somewhere if you like, esp. if you use the desktop features
+ eval runemacs \
+ -q \
+ '--title="Emacs with swiftex"' \
+ --eval "'(progn
+ (setq dte-no-server-flag t
+ dte-no-desktop-flag t
+ dte-use-swiftex-flag t)
+ (load \"~/.emacs\"))'" \
+ '"$@"';;
+
+ *) shift
+ eval runemacs \
+ -q \
+ --eval "'(progn
+ (setq dte-no-desktop-flag t
+ dte-no-server-flag t)
+ (load \"~/.emacs\"))'" \
+ '"$@"';;
+ esac
+
+
+
+* user documentation
+
+The user functions are described below. Next to each one is the initial
+key binding, or a suggested one in parentheses, or both. A major mode
+should by convention not bind `C-c <letter>'; where this is my preferred
+binding, I have put the binding in the comments in the installation
+section above, and left the function unbound, or in one case bound to a
+similar key (these are given in parentheses below).
+
+** SWIFTEX MODE
+
+swifTeX mode provides all the functionality of the standard LaTeX mode,
+plus the following extensions. In the case of tab and C-c C-u, the
+standard functions have been replaced by improved ones that act similarly.
+
+*** swiftex-mode
+
+Select swifTeX major mode. See the installation section for useful ways to
+have swifTeX mode come up automatically.
+
+*** stx-tab: TAB
+
+If you have tabs in a LaTeX buffer, you will be in for some surprises when
+you use a verbatim environment, so we define a tabbing command that only
+inserts spaces. I can't imagine that the savings of file-size is at all
+significant using tabs instead of spaces. If you decide to reinstate
+normal tabbing for swifTeX mode, I strongly recommend you keep the new
+space-tabbing for docTeX mode because every macrocode environment is a
+verbatim environment.
+
+*** comment-region: C-c ;
+
+Make the region into a comment. Prefix arg means add
+that many %'s, default 1.
+
+*** stx-next-braces: M-TAB and C-c TAB
+
+Move point out of the current set of braces and just into the next.
+
+*** stx-up-block: C-c C-]
+
+Move point out of the current \begin{}-\end{} environment.
+
+*** stx-begin-block: (C-c b)
+
+Insert \begin{*} and leave point where the * is.
+
+*** OTHERS
+
+ stx-insert-block: (C-c B)
+
+Alias for standard `tex-latex-block'. Create a matching pair of
+\begin{}-\end{} lines and leave point on a blank line between them.
+
+ stx-close-block-from-inside: (C-c e)
+
+Let * be the point.
+Initial buffer contents:
+
+ \begin{text*}
+
+Final buffer contents:
+
+ \begin{text}
+ *
+ \end{text}
+
+ stx-close-block: C-c C-e
+
+Close the last unclosed \begin{}. Duplicate any legal prefix to the
+\begin{}.
+
+ stx-goto-prev-unended-begin: C-c C-u
+ stx-goto-first-unended-begin: C-c C-u
+
+Move point to the previous or first unended \begin{} above.
+
+ stx-goto-next-unbegun-end: C-c C-n
+ stx-goto-last-unbegun-end: C-c M-n
+
+Move point to the next or last unbegun \end{} below.
+
+ stx-verify-blocks: (C-c v)
+
+Move point to a mismatched \\begin .. \\end block.
+
+ stx-emphasize: (C-c m)
+
+Insert \emph{*} and leave point at *.
+
+ stx-emphasize-word: C-c C-m
+
+Surround word at point with "\emph{" and "}".
+
+ dtx-insert-change: C-c C-d g -
+ add-change-log-entry: C-c C-d l -
+ dtx-get-fileinfo: C-c C-d v -
+ dtx-update-minor-version: C-c C-d u -
+ dtx-update-major-version: C-c C-d U -
+ dtx-update-documentation-date: C-c C-d D -
+ dtx-update-checksum: C-c C-d s -
+
+All the docTeX mode commands that make sense to use in a swifTeX buffer are
+available on the same keys as in docTeX mode. See below for what these
+functions do.
+
+** DOCTEX MODE
+
+docTeX mode is intended to behave as you would want swifTeX mode to behave
+in doc.sty buffers. The argument to \CheckSum is automatically updated
+every time you save the buffer.
+
+*** doctex-mode
+
+Select docTeX major mode. See the installation section for useful ways to
+have docTeX mode come up automatically.
+
+ dtx-update-minor-version: C-c C-d u
+ dtx-update-major-version: C-c C-d U
+ dtx-update-documentation-date: C-c C-d d
+ dtx-update-checksum: C-c C-d s
+
+A <version> is any number of integers separated by dots with an optional
+prefix "v" and an optional suffix of a lowercase letter. When the version
+is updated, a "v" will always be added.
+
+The major and minor version strings will be the last two elements of the
+<version>, counting the possible suffix as a separate element if it exists.
+
+Updates are done by looking for the first line that defines \fileversion in
+the buffer (with \def or \newcommand) as a <version>. If no such line
+exists, then the line with \ProvidesPackage or \ProvidesClass is updated.
+
+When the major or minor version is updated, the date is updated. Once
+again, this is either the line defining \filedate, or the right part of the
+\ProvidesPackage (or Class) optional argument.
+
+The documentation date is similarly found on the line defining \docdate.
+
+The checksum is automatically updated whenever any of the above are
+updated, and it can be updated on its own with `dtx-update-checksum'.
+
+When the `minor-version' is a letter, the minor-version is treated a little
+differently.
+
+When the `minor-version' is a letter, doctex treats it as an indication
+consistent with the idea of a trivial revision that does not affect
+function (e.g., correcting typos in the documentation).
+
+If the minor version is a letter, updating minor-version increments the
+letter; updating major-version increments the number before it and sets the
+minor-version to null. This is fine and good.
+
+After a major update, however, there will be no letter at all, so the next
+minor update will increment the final number (i.e. the number the last
+major update incremented), and the next major update will increment the
+number BEFORE that. Examples:
+
+ VER UPDATE-TYPE NEW-VER
+======================================
+ 1.3a minor 1.3b
+ 1.3b major 1.4
+ 1.4 minor 1.5
+ 1.5 major 2
+ 2 major 3
+ 3 minor 3<prompt user>
+
+If your minor version is a letter, you should think of minor updates as
+incrementing the trivial revision and major updates as incrementing the
+minor version. If you want to increment the major version and your minor
+version is currently a letter, you need to do a major update TWICE:
+
+ 1.3a -> 1.4 -> 2.0
+
+In case you're wondering, if we DIDN'T do things this way, then there would
+be inconsistent behavior between the case where you do an update having
+already executed one previously in the same buffer in the same session of
+Emacs, and the case where you are performing the first update of the
+editing session on the buffer. Really I should build in a separate concept
+and update command for "trivial revision", but for the moment this is how
+things work, so I'm documenting it.
+
+*** dtx-get-fileinfo: C-c C-d v
+
+Display current file version, date, and documentation date in the
+minibuffer.
+
+*** OTHERS
+
+ dtx-begin-FOO
+ dtx-insert-FOO
+
+ FOO begin insert
+=======================================
+macrocode: C-c C-d c C-c C-d C
+macro: C-c C-d m C-c C-d M
+environment: C-c C-d e C-c C-d E
+bibfunction: C-c C-d f C-c C-d F
+
+The `insert' commands (on uppercase keys) begin and end the relevant
+environment, and leave point in between\; `begin' commands (on lowercase
+keys) just begin the environment. All prompt for the name of the thing in
+question.
+
+ dtx-interrupt-macrocode: C-c C-d i
+
+Interrupt a macrocode environment to add some commentary.
+
+ add-change-log-entry: C-c C-d l
+
+Make a ChangeLog entry.
+
+ dtx-insert-change: C-c C-d g
+
+Insert a LaTeX changes entry, prompting for the description of the change.
+
+
+** SYMBOL NAMES
+
+The prefixes `stx' or `dtx' begin all new symbol names, the latter being
+for symbols unique to docTeX mode.
+
+There are some exceptions that begin with `swiftex', `doctex', or `rx'.
+The actual mode functions, the mode maps, and variables holding the prefix
+keys are:
+ `swiftex-mode' `doctex-mode'
+ `swiftex-mode-map' `doctex-mode-map'
+ `swiftex-dtx-mode-map' `doctex-dtx-mode-map'
+ `swiftex-dtx-prefix-key' `doctex-dtx-prefix-key'.
+
+A group of constants have names beginning with `rx', short for "regexp".
+
+* history
+
+These major modes are the result of my own hacking over the years, adding
+to the standard LaTeX major mode.
+
+Once I got used to my developments, switching to AUC TeX seemed like too
+much of a pain in the neck. Perhaps someone will add this functionality to
+AUC TeX's one day. I don't expect many people besides me will want to use
+swifTeX mode except in its extension of docTeX mode. Do let me know if you
+like swifTeX mode.
+
+DocTeX mode began its life on 14 November 1994 when David Carlisle of the
+LaTeX 3 team gave me some Emacs lisp code written by fellow LaTeX 3 team
+members Johanes Brahms and Frank Mittelbach. That file contained functions
+for handling version control, inserting changes, and inserting the basic
+doc.sty environments. I used these functions to build a new major mode in
+parallel with swifTeX mode.
+
+The original authors have given me permission to incorporate their code in
+mine, but they do not otherwise endorse or support swiftex.el. I, Matt
+Swift <swift@alum.mit.edu>, am the sole maintainer.
+
+* future
+
+* Emacs File Variables
+
+Local Variables:
+mode: outline
+End:
diff --git a/support/emacs-modes/swiftex/swiftex.el b/support/emacs-modes/swiftex/swiftex.el
new file mode 100644
index 0000000000..8b529f2ef2
--- /dev/null
+++ b/support/emacs-modes/swiftex/swiftex.el
@@ -0,0 +1,2170 @@
+;;; swiftex.el --- major modes for LaTeX and LaTeX doc.sty documents
+
+;;;; COPYRIGHT NOTICE
+;;;
+;;; Copyright (C) 1995-1999 Matt Swift <swift@alum.mit.edu>
+;;;
+;; Author: Matt Swift <swift@alum.mit.edu>
+;; Johanes Braams
+;; Frank Mittelbach
+;; Maintainer: Matt Swift <swift@alum.mit.edu>
+;; Version: $Revision: 1.35 $
+;; Keywords: tex, latex, doc, doc.sty, ltxdoc, dtx
+;; LCD Archive Entry:
+;; swifTeX|Matt Swift|swift@alum.mit.edu|
+;; Major modes for LaTeX and LaTeX doc.sty documents|
+;; $Date: 2001/09/08 04:09:20 $|$Revision: 1.35 $|~/modes/swiftex.el.gz|
+
+;;; FIX last field above will be wrong when I have a tarball
+
+;;;
+;;; This program 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 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program 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 your Emacs program (without which this file is not useful); if not,
+;;; write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+;;; 02139, USA.
+;;;
+
+;;; Commentary:
+;;;
+;;; This file is distributed by its author with
+;;; documentation in Info format that gives an overview of
+;;; this package and describes how to install and use and
+;;; use it. It should always be available on CTAN FIX.
+
+;;;; IMPLEMENTATION
+;;; CODE:
+
+;;;;; CUSTOMIZATION GROUPS
+
+;;; :prefix "swiftex-"
+;;; :prefix "doctex-"
+;;; :prefix "rx-"
+;;; :prefix "stx-"
+;;; :prefix "dtx-"
+(defgroup swiftex nil
+ "Major mode for LaTeX files."
+ :tag "SwifTeX"
+ :group 'tex)
+(defgroup doctex nil
+ "Major mode for documented LaTeX source (.dtx) files."
+ :tag "docTeX"
+ :group 'tex
+ :group 'swiftex)
+
+;;; (defcustom
+;;; :type
+;;; :options
+;;; :version
+;;; :set
+;;; :get
+;;; :initialize
+;;; ;; customize common options
+;;; :tag
+;;; :group
+;;; :link
+;;; :load
+;;; :require
+
+;;;;; VERSION INFO
+(defconst stx-version "$Revision: 1.35 $"
+ "RCS version of Matt's master swiftex.el.")
+
+;;;;; GENERAL ACTIONS
+(provide 'swiftex)
+
+;;; Patch below from Karl Eichwalder <ke@gnu.franken.de>. I think I want to do
+;;; it differently eventually.
+;;; FIX Don't customize for now, since it may disappear.
+(defvar stx-tex-derivation t
+ "Non-nil means use Emacs standard `tex-mode' for derivation.
+Nil means use `LaTeX-mode' from the AUC TeX package.")
+(if stx-tex-derivation
+ (require 'tex-mode)
+ (require 'tex-site))
+
+;;; `concat-chars' was renamed to `string' in 20.3
+;;; thanks to Peter Møller Neergaard for noticing this
+(if (not (fboundp 'string))
+ (if (fboundp 'concat-chars)
+ (defalias 'string 'concat-chars)
+ (error
+ "I'm confused: neither `string' nor `concat-chars' are defined as functions")))
+
+;;; FIX perhaps a variable to let the user choose between old and new outlines?
+;;; do i depend on the old one? yes probably that is all
+;;; the weird boln stuff
+(require 'outline)
+
+;;;;; REGEXP and STRING CONSTANTS
+
+;;; Using the following constants makes regular expressions more readable in
+;;; Lisp code.
+
+(defconst rx-whitespace "\\s-*"
+ "Matches optional characters with whitespace syntax.")
+;;; Notice that this expression has parentheses.
+
+;;; FIX: As defined, it will match two newlines in a row, which is a
+;;; construction that would break TeX in the places where I use it. I would
+;;; like to improve the matching to avoid matching this case, to be consistent
+;;; with TeX, but I don't see that it will cause a problem under normal
+;;; circumstances.
+(defconst rx-whitespace-newlines "\\(\\s-\\|\n\\)*"
+ "Matches optional newlines or characters with whitespace syntax.")
+(defconst rx-normal-boln "^"
+ "Matches unhidden beginning of line.")
+(defconst rx-hidden-boln "[\^M]"
+ "Matches beginning of line when hidden in outline mode.")
+(defconst rx-eoln "$")
+(defconst rx-normal-whiteln (concat rx-normal-boln rx-whitespace rx-eoln)
+ "Matches empty line.")
+(defconst rx-dollar "\\$"
+ "Matches a dollar sign.")
+(defconst rx-backslash "\\\\"
+ "Matches a backslash.")
+(defconst rx-white-back (concat rx-whitespace rx-backslash)
+ "Matches optional whitespace plus backslash." )
+(defconst rx-or "\\|"
+ "Regexp string for logical OR." )
+;;; FIX: why do I need to avoid the \n? It's only working for top-level!
+;;; don't I mean innermost level?
+(defconst rx-brace-pair "{[^}\n]*}"
+ "Matches one balanced set of braces on a single line.")
+(defconst rx-tex-grop "{"
+ "Matches TeX group open character -- a left brace.
+Also (ab)used as a regular string for insertions.")
+(defconst rx-tex-grcl "}"
+ "Matches TeX group close character -- a right brace.
+Also (ab)used as a regular string for insertions.")
+(defconst stx-str-backslash "\\")
+
+;;;;; FONT LOCK / HILIT STUFF [FIX]
+
+;;; FIX: what do I mean 'loads'?
+;;; FIX: :require?
+(defvar stx-hilit nil
+ "Non-nil means highlight swifTeX buffers.
+Loads the library \"hilit-swiftex\".")
+
+;;; FIX: what do I mean 'loads'?
+;;; FIX: :require?
+;;; FIX: link to font-latex customization?
+(defvar stx-fontlock t
+ "Non-nil means font lock swifTeX buffers.
+Loads the library \"font-latex\" until I write something
+better.")
+
+;;; FIX what does load mean? :require?
+(defvar dtx-hilit t
+ "Non-nil means highlight docTeX buffers.
+Loads the library \"hilit-doctex\".")
+
+;;; FIX what does load mean?
+;;; FIX :require?
+;;; FIX :link to font-latex customization?
+(defvar dtx-fontlock nil
+ "Non-nil means font-lock docTeX buffers.
+Loads library \"font-latex\" for now until I write something
+better.")
+
+
+;;;;; SWIFTEX MODE
+
+;;; Much of what is defined below takes docTeX mode into account. Only the
+;;; code forms unique to docTeX mode appear in its section below.
+
+;;;;;; USER VARIABLES
+
+;;; FIX: use :set?
+;;; FIX: link?
+(defcustom stx-sectioning-offset 1
+ "Outline level offset for all LaTeX sectioning commands in a swifTeX buffer.
+See the documentation for the variable
+`stx-sectioning-commands'."
+ :tag "Sectioning Commands Outline Offset"
+ :type 'integer
+ :group 'swiftex)
+
+;;; FIX; :set?
+(defcustom stx-sectioning-commands '(
+ ("documentclass" . -2)
+ ;; leave off final
+ ;; closebrace, since the
+ ;; \> in the regexp needs
+ ;; to match the end of the
+ ;; strings here.
+ ("begin{document" . -2)
+ ("end{document" . -2)
+ ("endinput" . -2)
+ ("part" . -2)
+ ("frontmatter" . -1)
+ ("mainmatter" . -1)
+ ("backmatter" . -1)
+ ("chapter" . -1)
+ ("appendix" . -1)
+ ("section". 0)
+ ("subsection" . 1)
+ ("subsubsection" . 2)
+ ("paragraph" . 3)
+ ("subparagraph" . 4)
+ )
+ "An alist of LaTeX sectioning commands with level offsets for swifTeX mode.
+List elements have the form (NAME . NUMBER) where NAME is a
+string containing a LaTeX sectioning command with no
+backslash, and NUMBER is an integer which will be added to
+`stx-sectioning-offset' to get the actual outline level.
+
+The normal top level outline heading of `%*' is level 1.
+The default offset for \"\\section\" is 0, so its default
+level is 1. For documents with chapters, you might want to
+set `stx-sectioning-offset' to 2, so that \"\\chapter\" and
+\"%*\" are the same level.
+
+An \"endinput\" entry, if it exists, is treated specially in
+docTeX mode. See `stx-set-outlinevars'.
+
+Changes to `stx-sectioning-offset' and
+`stx-sectioning-commands' will take effect the next time
+`stx-set-vars' is called. This is normally called only by
+`swiftex-mode' and `doctex-mode'."
+ :tag "Sectioning Commands and Levels"
+ :type '(repeat (cons :format "%v"
+ (string :tag "Command")
+ (integer :tag "Level")))
+ :group 'swiftex)
+;;; FIX I don't understand :format, I copied this from
+;;; somewhere.
+
+;;; FIX: no nil
+;;; FIX: use :set?
+(defcustom stx-command-parseps '(
+ ;;; below ought to match first section of
+ ;;; `stx-command-parstarts' exactly:
+ "begin" "end"
+ "par"
+ "opening" "closing"
+ "\\[" "caption" "label" "usepackage"
+ "documentclass" "date" "author" "title"
+ "tableofcontents" "maketitle"
+ "listoffigures" "listoftables"
+ "bibliographystyle" "bibliography"
+ "include" "input" "includeonly"
+ "frontmatter" "mainmatter" "backmatter"
+ )
+ "A list of LaTeX commands which separate Emacs paragraphs.
+
+When these regexp strings occur after optional whitespace
+and a backslash, they separate Emacs paragraphs, and resist
+being filled.
+
+More specifically, `stx-set-vars' combines these strings
+with logical OR (`rx-or') and tacks them on to
+`paragraph-separate' with a logical OR.
+
+Sectioning commands included in `stx-sectioning-commands'
+don't need to be given here because they will get into
+`paragraph-separate' via `outline-regexp'.
+
+Do not make this list nil.
+
+Do not add strings to this variable without also adding them
+to `stx-command-parstarts', or otherwise ensuring they make
+it into `paragraph-start'."
+ :tag "Paragraph Separating Commands"
+ :type '(repeat regexp)
+ :group 'swiftex
+ :group 'doctex)
+(make-variable-buffer-local 'stx-command-parseps)
+
+;;; FIX: no nil
+;;; FIX: use :set?
+(defcustom stx-command-parstarts '(
+ ;;; below do not receive fill text:
+ "begin" "end"
+ "par"
+ "opening" "closing"
+ "\\[" "caption" "label" "usepackage"
+ "documentclass" "date" "author" "title"
+ "lastchange" "copystyle" "usepackage"
+ "tableofcontents" "maketitle"
+ "listoffigures" "listoftables"
+ "bibliographystyle" "bibliography"
+ "include" "input" "includeonly"
+ "frontmatter" "mainmatter" "backmatter"
+ ;;; below receive fill text:
+ "indent" "noindent"
+ "bibitem" "item"
+ "footnote"
+ )
+
+ "A list of LaTeX commands which start or separate Emacs paragraphs.
+
+When these regexps occur after a backslash at the beginning
+of a line, those that are not in `paragraph-separate' start
+Emacs paragraphs, and receive text on their line during
+fills.
+
+Sectioning commands included in `stx-sectioning-commands'
+don't need to be given here because they will get into
+`paragraph-separate' via `outline-regexp'.
+
+Do not make this list nil.
+
+See also `stx-command-parseps'."
+ :tag "Paragraph Starting or Separating Commands"
+ :type '(repeat regexp)
+ :group 'swiftex
+ :group 'doctex)
+(make-variable-buffer-local 'stx-command-parstarts)
+
+;;; FIX: need key-specification :type
+;;; FIX :set?
+(defcustom swiftex-dtx-prefix-key '"\C-c\C-d"
+ "Prefix key for certain docTeX mode commands available in swifTeX mode.
+A change in this variable takes effect the next time
+`swiftex-mode' is called."
+ :tag "Prefix for Certain docTeX Commands"
+ :type 'string
+ :group 'swiftex)
+
+;;;;;; FILE VARIABLES
+
+(defvar stx-local-command-parstarts nil
+ "Partial list of LaTeX commands that start or separate Emacs paragraphs.
+This variable exists so that it can be set as a file
+variable. After the line that sets it, include a line with
+`eval: stx-set-vars'
+
+When these regexp strings occur after optional whitespace
+and a backslash, those not in `paragraph-separate' start
+Emacs paragraphs, and receive text on their line during
+fills.
+
+More specifically, `stx-set-vars' combines these strings
+with logical OR (`rx-or'), precedes them by optional
+whitespace and a backslash, and tacks them on to
+`paragraph-separate' with a logical OR.
+
+Sectioning commands included in `stx-sectioning-commands'
+don't need to be given here because they will get into
+`paragraph-separate' via `outline-regexp'.
+
+See `stx-local-parstarts' for a way to add starters that are
+not LaTeX commands.
+
+See also `stx-local-parseps'.")
+(make-variable-buffer-local 'stx-local-command-parstarts)
+
+(defvar stx-local-command-parseps nil
+ "Partial list of LaTeX commands that separate Emacs paragraphs.
+This variable exists so that it can be set as a file
+variable. After the line that sets it, include a line with
+`eval: stx-set-vars'.
+
+When these regexp strings occur after optional whitespace
+and a backslash, they separate Emacs paragraphs, and resist
+being filled.
+
+More specifically, `stx-set-vars' combines these strings
+with logical OR (`rx-or'), precedes them by optional
+whitespace and a backslash, and tacks them on to
+`paragraph-separate' with a logical OR.
+
+Sectioning commands included in `stx-sectioning-commands'
+don't need to be given here because they will get into
+`paragraph-separate' via `outline-regexp'.
+
+Do not add strings to this list without also adding them to
+`stx-local-command-parstarts', or otherwise ensuring they
+make it into `paragraph-start'.
+
+See `stx-local-parseps' for a way to add separators that are
+not LaTeX commands.")
+(make-variable-buffer-local 'stx-local-command-parseps)
+
+(defvar stx-local-parstarts nil
+ "A part of the variable `paragraph-start' in swifTeX and docTeX modes.
+This variable exists so that it can be set as a file
+variable. After the line that sets it, include a line with
+`eval: stx-set-vars'.
+
+The regexp strings in this list that are not in
+`paragraph-separate' start Emacs paragraphs, and receive
+text on their line during a fill.
+
+More specifically, `stx-set-vars' combines these strings
+with logical OR (`rx-or') and tacks them on to
+`paragraph-start' with a logical OR.
+
+Sectioning commands included in `stx-sectioning-commands'
+don't need to be given here because they get into
+`paragraph-separate' via `outline-regexp'.
+
+See `stx-local-command-parstarts' for an easy way to add
+starters that are LaTeX commands.
+
+See also `stx-local-parseps'.")
+(make-variable-buffer-local 'stx-local-parstarts)
+
+(defvar stx-local-parseps nil
+ "A part of the variable `parargraph-separate' in swifTeX and docTeX modes.
+This variable exists so that it can be set as a file
+variable. After the line that sets it, include a line with
+`eval: stx-set-vars'.
+
+The regexp strings in this list separate Emacs paragraphs,
+and resist being filled.
+
+More specifically, `stx-set-vars' combines these strings
+with logical OR (`rx-or') and tacks them on to
+`paragraph-separate' with a logical OR.
+
+Sectioning commands included in `stx-sectioning-commands'
+don't need to be given here because they will get into
+`paragraph-separate' via `outline-regexp'.
+
+Do not add strings to this list without also adding them to
+`stx-local-parstarts', or otherwise ensuring they make it
+into `paragraph-start'.
+
+See `stx-local-command-parseps' for an easy way to add
+separators that are LaTeX commands.")
+(make-variable-buffer-local 'stx-local-parseps)
+;;;;;; HOOK VARIABLES
+;;; FIX see what define-derived will do as docstring for this
+;;; (defvar swiftex-mode-hook nil
+;;; "Hook run as the last thing after entering swifTeX mode.
+;;; When entering docTeX mode, the last thing done is to run this hook then
+;;; `doctex-mode-hook.")
+;;;;;; INTERNAL VARIABLES
+
+(defvar stx-comment-start "%"
+ "A regexp that matches the start of a comment.
+It is \"%\" in swifTeX mode and \"\\\\^\\\\^A\" in docTeX mode.")
+(make-variable-buffer-local 'stx-comment-start)
+
+(defvar stx-line-start ""
+ "A regexp for the beginning of all significant lines.
+It is the empty string in swifTeX mode and \"%*\" in docTeX mode.")
+(make-variable-buffer-local 'stx-line-start)
+
+;;;;;; INLINE FUNCTION-VARIABLES
+
+;;; Without these abbreviations, other code would be very hard to read.
+
+(defsubst stx-boln ()
+"Return regexp for the beginning of a line in swifTeX or docTeX modes.
+The regexp returned matches lines hidden in an outline, and
+depends on the value of `stx-line-start'."
+ (concat "\\(" rx-normal-boln rx-or rx-hidden-boln "\\)"
+ stx-line-start))
+
+(defsubst stx-bwb ()
+"Return a regexp boln + w-space + b-slash that is possibily hidden in an outline."
+ (concat (stx-boln) rx-whitespace rx-backslash))
+
+(defsubst stx-whiteln ()
+"Return a regexp for a blank line that is possibly hidden in an outline."
+ (concat (stx-boln) rx-whitespace rx-eoln))
+;;;;;; MODE INITIALIZATION FUNCTIONS
+
+(defun stx-set-outlinevars (sectioning-commands sectioning-offset doctex)
+ "Set `outline-regexp' and define `outline-function' for LaTeX buffers.
+
+Headings of the form `stx-comment-start' followed by at
+least one star (\"*\"), and elements of SECTIONING-COMMANDS
+are included. The variable SECTIONING-OFFSET controls the
+relative depths of these two kinds of headings. DOCTEX
+non-nil means the buffer is a docTeX buffer.
+
+In default use, the first two arguments will always be the
+variables of the same name with either `stx-' or `dtx-'
+prefixed, e.g., `dtx-sectioning-offset'.
+
+If an entry for \"endinput\" exists in SECTIONING-COMMANDS
+it is treated specially. In swifTeX mode (i.e., DOCTEX
+non-nil), it is treated just like the other sectioning
+commands. In docTeX mode, \"\\endinput\" will be an
+outline heading only if it begins in the first column of the
+buffer. This is because 1) there is no reason for it to
+occur as an executed macro behind a comment in the
+documentation text, and 2) when it occurs with preceding
+whitespace in a macrocode environment, doc.sty considers it
+to be part of a macro being defined, and does not obey it,
+so neither will docTeX."
+ (let (;; modifications to `sectioning-commands' below are local
+ (sectioning-commands (copy-sequence sectioning-commands))
+ ;; `endinput-entry' will be nil if \endinput is not there, i.e., not
+ ;; supposed to be an outline heading; or will be the cons cell if there
+ (endinput-entry (assoc "endinput" sectioning-commands)))
+ ;; STEP ONE -- set `outline-regexp'
+ (make-local-variable 'outline-regexp)
+ (setq outline-regexp
+ ;;`outline-regexp' is prefixed by "^" when it is used by the outline
+ ;;commands, and enclosed in regexp parentheses, so we don't need to
+ ;;use "^" or parentheses here.
+ (rx-catenate-or
+ nil
+ (concat stx-line-start stx-comment-start "[*]+")
+ (if (and doctex endinput-entry)
+ (progn
+ ;; Remove the endinput entry from `stx-sectioning-commands' so
+ ;; it doesn't get included below in the wrong way.
+ (delete endinput-entry sectioning-commands)
+ ;; include it in the right way here
+ (concat rx-backslash "endinput")))
+ (concat stx-line-start
+ rx-white-back
+ "\\("
+ ;; These are the actual sectioning commands.
+ (rx-catenate-or (mapcar 'car sectioning-commands))
+ "\\)"
+ "\\>")))
+ ;; STEP TWO -- define `stx-outline-level' or `dtx-outline-level'and
+ ;; `byte-compile' it. We want to make `(s|d)tx-outline-level' as fast as
+ ;; possible, so we avoid evaluating conditionals and variable references
+ ;; which are going to be the same throughout a buffer's life. The tradeoff
+ ;; is requiring the byte compiling code to be in memory.
+ (byte-compile
+ (eval
+ (`
+ (defun (, (if doctex
+ 'dtx-outline-level
+ 'stx-outline-level)) ()
+ (, (concat "Return the outline level for heading at point.
+
+For a sectioning command, return the value of
+`" (if doctex
+ "d"
+ "s") "tx-sectioning-offset' plus the number associated with the
+particular heading in `" (if doctex
+ "d"
+ "s") "tx-sectioning-commands'.
+
+For a normal outline heading `stx-comment-start' followed by
+at least one star (\"*\"), return the number of stars.
+
+Like the standard function `outline-level', this function
+must be called at the beginning of a header line."))
+ ;; First check if we're on a normal outline heading.
+ (if (looking-at (concat stx-line-start ; "" or "%*"
+ stx-comment-start ; "%" or "\\^\\^A"
+ "[*]+"))
+ ;; Return the number of stars. The formula is different in docTeX
+ ;; mode and swifTeX mode.
+ (, (if doctex
+ ;; length of match minus length of "%^^A"
+ '(- (- (match-end 0) (match-beginning 0)) 4)
+ ;; length of match minus length of "%"
+ '(1- (- (match-end 0) (match-beginning 0)))))
+ ;; Still don't know where we are.
+ ;; Check if we're on a sectioning command.
+ (let ((count 0)
+ (max (, (length sectioning-commands))))
+ (while (and (< count max)
+ (not (looking-at
+ (concat stx-line-start
+ rx-white-back
+ (car (elt '(, sectioning-commands)
+ count))
+ "\\>"))))
+ (setq count (1+ count)))
+ (if (equal count max)
+ ;; Still haven't figured where we are.
+ ;; If docTeX mode and \endinput is a heading, check for it.
+ (, (if (and doctex endinput-entry)
+ (` (if (looking-at (concat rx-backslash
+ "endinput"))
+ (, (cdr endinput-entry))
+ ;; We really don't know where we are. (In docTeX
+ ;; mode and looking for \endinput.)
+ (error
+ ;; FIX: s-or-d tx-outline-level
+ "`stx-outline-level' falling through! (a)")))
+ ;; We really don't know where we are. (In swifTeX mode,
+ ;; or docTeX mode and not looking for \endinput.)
+ ;; FIX: s-or-d tx-outline-level
+ '(error "`stx-outline-level' falling through! (b)")))
+ (+ (, sectioning-offset)
+ (cdr (elt '(, sectioning-commands) count))))))))))))
+
+(defun stx-set-parvars ()
+ "Set `paragraph-' variables for swifTeX or docTeX mode.
+
+Set `paragraph-start' to a string containing each of the
+following strings separated by logical OR (`rx-or'):
+
+ BOLN + whitespace + EOLN
+ BOLN + whitespace + `$$'
+ `$$' + whitespace + EOLN
+ `\\\\' + whitespace + EOLN
+ BOLN + `outline-regexp'
+ BOLN + significant text + single comment
+ BOLN + whitespace + double comment
+ `stx-local-parstarts'
+ BOLN + whitespace + `\\' + `command' + `\\>'
+ where `command' is an element of either
+ `stx-command-parstarts' or
+ `stx-local-command-parstarts'.
+
+Set `paragaph-separate' to the same string, with the
+substitution of `parseps' for `parstarts' in the obvious
+places.
+
+The variable `rx-whitespace' determines what whitespace is\;
+the variable `rx-eoln' determines EOLN\; the function
+`stx-boln' determines BOLN. Significant text is one or more
+non-newlines followed by an even number of backslashes
+\(including zero backslashes).
+
+The regexps are actually defined in a more efficient but
+logically equivalent way.
+
+The function `stx-merge-list' provides a convenient way to
+add items to list variables."
+ (let ((common
+ (rx-catenate-or nil
+ (stx-whiteln)
+ (concat (stx-boln) rx-whitespace rx-dollar rx-dollar)
+ (concat "\\("
+ rx-backslash rx-backslash rx-or
+ rx-dollar rx-dollar
+ "\\)"
+ rx-whitespace
+ rx-eoln)
+ (concat (stx-boln) outline-regexp)
+ (concat (stx-boln)
+ ".*[^\n\\]"
+ "\\(" rx-backslash rx-backslash "\\)*"
+ comment-start)
+ (concat (stx-boln)
+ rx-whitespace
+ stx-comment-start
+ "\\(" stx-comment-start "\\)+"))))
+ (setq paragraph-start
+ (rx-catenate-or nil
+ common
+ (concat (stx-boln)
+ rx-white-back
+ "\\("
+ (rx-catenate-or stx-command-parstarts)
+ (rx-catenate-or stx-local-command-parstarts)
+ "\\)"
+ "\\>"
+ (rx-catenate-or stx-local-parstarts))))
+ (setq paragraph-separate
+ (rx-catenate-or nil
+ common
+ (concat (stx-boln)
+ rx-white-back
+ "\\("
+ (rx-catenate-or stx-command-parseps)
+ (rx-catenate-or stx-local-command-parseps)
+ "\\)"
+ "\\>"
+ (rx-catenate-or stx-local-parseps))))))
+
+;;;;;; DEFINE MODE
+(define-derived-mode swiftex-mode latex-mode "swifTeX"
+ "Major mode for LaTeX documents derived from the standard LaTeX mode.
+
+The variables `paragraph-separate' and `paragraph-start' are
+carefully chosen to make filling and movement convenient.
+See `stx-set-parvars'.
+
+One consequence of their values is that single-commented
+paragraphs fill normally, and double-or-more commented lines
+resist filling (they separate Emacs paragraphs). Comments
+with non-whitespace before a \"%\" also resist filling.
+
+Outline headings are either a single \"%\" in the first
+column plus at least one star (\"*\"), or the standard LaTeX
+sectioning commands. See `stx-set-outlinevars'.
+
+The TAB key seems to behave as usual but inserts spaces only
+\(that is, no `\\t' characters). It is confusing when `\\t'
+characters occur inside verbatim environments (including
+macrocode environments) because the typeset appearance will
+not match the appearance of the source file, and
+code-indenting conventions will often get mangled.
+
+A number of commands facilitate movement and save typing.
+
+\\[stx-up-block] moves point past the next \"\\end{name}\".
+\\[stx-next-braces] moves point out of enclosing braces and just into the next set.
+\\[stx-begin-block] inserts \"\\begin{}\" and prompts for the argument.
+\\[stx-insert-block] inserts a \"\\begin{} \\end{}\" pair and prompts for the argument.
+\\[stx-close-block] creates an \"\\end{...}\" to match the last unclosed \"\\begin{...}\".
+\\[stx-close-block-from-inside] closes a LaTeX block after the user has typed the argument to \"\\begin\".
+\\[stx-emphasize] inserts \"\\emph{}\" and leaves point between braces.
+\\[stx-emphasize-word] surrounds word at point with \"\\emph{\" and \"}\".
+
+Certain docTeX mode commands are available with the prefix
+`swiftex-dtx-prefix-key':
+
+The following commands maintain the version information in
+the LaTeX buffer. They act on lines that define
+\\fileversion, \\filedate, or \\docdate, or the equivalent
+components of the \\ProvidesPackage or \\ProvidesClass
+declarations if the first are absent.
+
+\\[dtx-get-fileinfo] displays the buffer's version in the minibuffer.
+\\[dtx-update-minor-version] updates the minor version.
+\\[dtx-update-major-version] updates the major version.
+
+The last two also update the file date to the current date.
+
+\\[dtx-update-documentation-date] makes the documentation date current.
+\\[dtx-insert-change] inserts a LaTeX \\changes entry.
+\\[add-change-log-entry] adds a ChangeLog entry.
+
+Some convenient ways to customize behavior in individual
+files are provided by the `stx-local-' variables.
+
+\\{swiftex-mode-map}"
+ (make-local-variable 'adaptive-fill-regexp)
+ (setq adaptive-fill-regexp
+ ;; whitespace + optional stx-comment-start + whitespace
+ ;; Notice that a line with more than one "%" is a paragraph separator
+ ;; and therefore never part of a paragraph anyway.
+ (concat rx-whitespace
+ stx-comment-start "?"
+ rx-whitespace))
+ (make-local-variable 'paragraph-ignore-fill-prefix)
+ (setq paragraph-ignore-fill-prefix t)
+ (outline-minor-mode 1)
+ (make-local-variable 'outline-level)
+ (setq outline-level (function stx-outline-level))
+ (stx-set-vars)
+ (if stx-fontlock
+ (progn
+ (require 'font-latex)
+ (font-latex-setup))
+ (if stx-hilit
+ (require 'hilit-swiftex))))
+
+;;;;;; DEFINE KEYMAP
+(defvar swiftex-dtx-mode-map (make-sparse-keymap)
+ "Keymap for docTeX mode commands in swifTeX mode.")
+
+;; avoid message while byte-compiling
+(defvar swiftex-mode-map)
+(define-key swiftex-mode-map swiftex-dtx-prefix-key swiftex-dtx-mode-map)
+(define-key swiftex-dtx-mode-map "g" 'dtx-insert-change)
+(define-key swiftex-dtx-mode-map "l" 'add-change-log-entry)
+(define-key swiftex-dtx-mode-map "v" 'dtx-get-fileinfo)
+(define-key swiftex-dtx-mode-map "u" 'dtx-update-minor-version)
+(define-key swiftex-dtx-mode-map "U" 'dtx-update-major-version)
+(define-key swiftex-dtx-mode-map "D" 'dtx-update-documentation-date)
+(define-key swiftex-mode-map "\t" 'stx-tab)
+(define-key swiftex-mode-map "\C-c;" 'comment-region)
+(define-key swiftex-mode-map "\M-\t" 'stx-next-braces)
+(define-key swiftex-mode-map "\C-c\t" 'stx-next-braces)
+(define-key swiftex-mode-map "\C-c\C-]" 'stx-up-block)
+(define-key swiftex-mode-map "\C-]\C-]" 'up-list)
+(define-key swiftex-mode-map "\C-cl" 'tex-bibtex-file)
+(define-key swiftex-mode-map "\C-cp" 'stx-pdflatex-file)
+(define-key swiftex-mode-map "\C-cg" 'stx-pdfview-file)
+(define-key swiftex-mode-map "\"" 'stx-insert-quote)
+(define-key swiftex-mode-map "\C-cv" 'stx-verify-blocks)
+(define-key swiftex-mode-map "\C-c\M-u" 'stx-goto-first-unended-begin)
+(define-key swiftex-mode-map "\C-c\M-n" 'stx-goto-last-unbegun-end)
+(define-key swiftex-mode-map "\C-c\C-u" 'stx-goto-prev-unended-begin)
+(define-key swiftex-mode-map "\C-c\C-n" 'stx-goto-next-unbegun-end)
+(define-key swiftex-mode-map "\C-c\C-e" 'stx-close-block)
+(define-key swiftex-mode-map "\C-c\C-m" 'stx-emphasize-word)
+
+;;;;;; FUNCTIONS AND VARIABLES TAKEN FROM AUC TEX
+;;; The following are taken from AUC TeX.
+;;;
+;;; I have mirrored these variables with my own variables. This way, if a
+;;; user's .emacs sets things up for AUC TeX, this mode will do the right
+;;; thing. And a properly-named version exists, for someone who is looking for
+;;; things by completion. I have changed documentation strings conform to
+;;; proper convention.
+
+(defvar TeX-open-quote "``"
+ "String inserted by typing \\[stx-insert-quote] to open a quotation.")
+(defvar rx-tex-open-quote TeX-open-quote
+ "String inserted by typing \\[stx-insert-quote] to open a quotation.")
+(defvar TeX-close-quote "''"
+ "String inserted by typing \\[stx-insert-quote] to close a quotation.")
+(defvar rx-tex-close-quote TeX-close-quote
+ "String inserted by typing \\[stx-insert-quote] to close a quotation.")
+(defvar TeX-quote-after-quote nil
+ "See documentation for `stx-insert-quote'.")
+(defvar stx-quote-after-quote TeX-quote-after-quote
+ "See documentation for `stx-insert-quote'.")
+
+(defun stx-insert-quote (arg)
+ "Insert the appropriate quote marks for TeX.
+Inserts the value of `rx-tex-open-quote' (normally ``) or
+`rx-tex-close-quote' (normally '') depending on the
+context.
+
+`stx-quote-after-quote' non-nil means this insertion works
+only after \". A prefix argument ARG means always insert \"
+characters."
+ (interactive "*P")
+ (if arg
+ (self-insert-command (prefix-numeric-value arg))
+ (if stx-quote-after-quote
+ (insert (cond ((bobp)
+ ?\")
+ ((not (= (preceding-char) ?\"))
+ ?\")
+ ((save-excursion
+ (forward-char -1)
+ (bobp))
+ (delete-backward-char 1)
+ rx-tex-open-quote)
+ ((save-excursion
+ (forward-char -2) ;;; at -1 there is double quote
+ (looking-at "[ \t\n]\\|\\s("))
+ (delete-backward-char 1)
+ rx-tex-open-quote)
+ (t
+ (delete-backward-char 1)
+ rx-tex-close-quote)))
+ (insert (cond ((bobp)
+ rx-tex-open-quote)
+ ((= (preceding-char) (string-to-char stx-str-backslash))
+ ?\")
+ ((= (preceding-char) ?\")
+ ?\")
+ ((save-excursion
+ (forward-char (- (length rx-tex-open-quote)))
+ (looking-at (regexp-quote rx-tex-open-quote)))
+ (delete-backward-char (length rx-tex-open-quote))
+ ?\")
+ ((save-excursion
+ (forward-char (- (length rx-tex-close-quote)))
+ (looking-at (regexp-quote rx-tex-close-quote)))
+ (delete-backward-char (length rx-tex-close-quote))
+ ?\")
+ ((save-excursion
+ (forward-char -1)
+ (looking-at "[ \t\n]\\|\\s("))
+ rx-tex-open-quote)
+ (t
+ rx-tex-close-quote))))))
+
+;;;;;; INTERACTIVE FUNCTIONS
+
+;;; If you have tabs in a LaTeX buffer, you will be in for some surprises when
+;;; you use a verbatim environment. We define a version of `tab-to-tab-stop'
+;;; that only will insert spaces. I can't imagine that the savings of
+;;; file-size is at all significant using tabs instead of spaces, but you can
+;;; always debind this from tab if you want usual Emacs tabbing. I strongly
+;;; recommend you keep the new space-tabbing for `doctex-mode' because every
+;;; macrocode environment is a verbatim environment.
+
+;; This function's code is based on the standard `tab-to-tab-stop' in
+;; the standard "indent.el".
+(defun stx-tab ()
+ "Insert spaces (no tabs) to next defined tab-stop column.
+The variable `tab-stop-list' is a list of columns at which
+there are tab stops. Use \\[edit-tab-stops] to edit them
+interactively."
+ (interactive "*")
+ (if abbrev-mode (expand-abbrev))
+ (let ((tabs tab-stop-list))
+ (while (and tabs (>= (current-column) (car tabs)))
+ (setq tabs (cdr tabs)))
+ (if tabs
+ (insert (make-string (- (car tabs) (current-column)) ?\ ))
+ (insert ?\ ))))
+(defun stx-up-block ()
+ "Move point past the next \"\\end{name}\".
+Let * = point before calling this function,
+** = point afterward, and \\n = a new line:
+
+* [possible text here]
+ [more possible text]
+\\end{name}
+\\n
+**"
+ (interactive)
+ (goto-char (re-search-forward (concat rx-backslash "end" rx-brace-pair)))
+ (forward-line 1)
+ (newline))
+(defun stx-next-braces ()
+ "Move point out of enclosing braces and just into the next set.
+That is, call `up-list' and then go to position of next
+\"{\" plus one."
+ (interactive)
+ (up-list 1)
+ (goto-char (search-forward rx-tex-grop)))
+
+;;; Ugh. FIX. Horribly inefficient conditional on 'doctex-mode.
+(defun stx-next-beginorend ()
+ "Leave point at next \\begin or \\end in swifTeX or docTeX mode buffer.
+Signal error if not found."
+ (re-search-forward
+ (concat "\\(" rx-normal-boln rx-or rx-hidden-boln "\\)"
+ (if (equal major-mode 'doctex-mode) "%+" "")
+ rx-whitespace rx-backslash "\\(begin" rx-or "end\\)"
+ rx-whitespace rx-tex-grop)))
+
+;;; FIX where is point left? what does match-data have?
+;;; FIX: why is this a defsubst and not the above?
+;;; Ugh. FIX. Horribly inefficient conditional on 'doctex-mode.
+(defsubst stx-prev-beginorend ()
+ "Leave point at previous \\begin or \\end in swifTeX or docTeX mode buffer.
+Signal error if not found."
+ (re-search-backward
+ (concat "\\(" rx-normal-boln rx-or rx-hidden-boln "\\)"
+ (if (equal major-mode 'doctex-mode) "%+" "")
+ rx-whitespace rx-backslash "\\(begin" rx-or "end\\)"
+ rx-whitespace rx-tex-grop)))
+
+;;; Ugh. FIX. Horribly inefficient conditional on 'doctex-mode.
+(defun stx-next-is-end ()
+ "Return beginning if true, nil if false, or error if no prev."
+ (and (stx-next-beginorend)
+ ;; FIX can't i goto-char match-beginning or something?
+ (stx-prev-beginorend)
+ (let ((p (match-beginning 0)))
+ (if (looking-at
+ (concat "\\(" rx-normal-boln rx-or rx-hidden-boln "\\)"
+ (if (equal major-mode 'doctex-mode)
+ "%+" "")
+ rx-whitespace rx-backslash "end"
+ rx-whitespace rx-tex-grop))
+ p))))
+
+;;; Ugh. FIX. Horribly inefficient conditional on 'doctex-mode.
+(defun stx-prev-is-begin ()
+ "Return beginning if true, nil if false, or error if no prev."
+ (if (stx-prev-beginorend)
+ (let ((p (match-beginning 0)))
+ (if (looking-at
+ (concat "\\(" rx-normal-boln rx-or rx-hidden-boln "\\)"
+ (if (equal major-mode 'doctex-mode)
+ "%+" "")
+ rx-whitespace rx-backslash
+ "begin"
+ rx-whitespace rx-tex-grop))
+ p))))
+(defun stx-goto-next-unbegun-end ()
+ "Move point to the next unbegun \\end after point.
+Signal error if there isn't one.
+Leave mark at original point if there is."
+ (interactive)
+ (stx-unbegun-end-internal)
+ (message "Point moved to next unbegun \\end. Mark is at previous point."))
+(defun stx-goto-last-unbegun-end ()
+ "Move point to the last unbegun \\end in the buffer.
+Signal error if there isn't one.
+Leave mark at original point if there is."
+ (interactive)
+ (stx-unbegun-end-internal 'last)
+ (message "Point moved to first unbegun end. Mark is at previous point."))
+(defun stx-unbegun-end-internal (&optional last)
+ "Internal function to find an unbegun end.
+LAST non-nil means start at `(point-min)'."
+ (interactive)
+ (let (case-fold-search
+ (b 0)
+ (e 0)
+ result)
+ (save-excursion
+ (if last (goto-char (point-min)))
+ (condition-case nil
+ (setq result (stx-fue-recursor))
+ (error (if last
+ (error "There is no unbegun \\end")
+ (error "No unbegun \\end after point")))))
+ (if (car result)
+ (error "Something's wrong with stx-goto-first-unbegun end")
+ (push-mark)
+ (if (interactive-p)
+ (message "Point moved to first unbegun end. Mark is at previous point."))
+ (goto-char (cadr result)))))
+
+;; avoid message while byte-compiling
+(defvar b)
+(defvar e)
+(defun stx-fue-recursor ()
+ "Internal recursive function to find unbegun end."
+ (let ((next-is-end (stx-next-is-end)))
+ (if next-is-end
+ (setq e (1+ e))
+ (setq b (1+ b)))
+ (if (> e b)
+ (list nil next-is-end)
+ (forward-line)
+ (stx-fue-recursor))))
+(defun stx-goto-first-unended-begin ()
+ "Move point to the first unended \\begin in the buffer.
+Signal error if there isn't one.
+Leave mark at original point if there is."
+ (interactive)
+ (stx-unended-begin-internal 'first)
+ (message "Point moved to first unended \\begin. Mark is at previous point."))
+(defun stx-goto-prev-unended-begin (&optional silent)
+ "Move point to the first unended \\begin before point.
+Signal error if there isn't one.
+Leave mark at original point if there is.
+
+Optional argument SILENT non-nil means don't print a message."
+ (interactive)
+ (stx-unended-begin-internal)
+ (if (not silent)
+ (message "Point moved to previous unended \\begin. Mark is at previous point.")))
+(defun stx-unended-begin-internal (&optional first)
+ "Internal function to find unended begin.
+FIRST non-nil means start at \(point-max\)."
+ (let (case-fold-search
+ (b 0)
+ (e 0)
+ result)
+ (save-excursion
+ (if first (goto-char (point-max)))
+ (condition-case nil
+ (setq result (stx-fub-recursor))
+ (error (if first
+ (error "There is no unended \\begin")
+ (error "No unended \\begin before point")))))
+ (if (car result)
+ (error "Something's wrong with stx-goto-last-unended begin")
+ (push-mark)
+ (goto-char (cadr result)))))
+(defun stx-fub-recursor ()
+ "Internal recursive function to find unended begin."
+ (let ((prev-is-begin (stx-prev-is-begin)))
+ (if prev-is-begin
+ (setq b (1+ b))
+ (setq e (1+ e)))
+ (if (> b e)
+ (list nil prev-is-begin)
+ (stx-fub-recursor))))
+
+;; This is weird. Two errors mean everything's OK.
+(defun stx-verify-blocks ()
+ "Move point to a mismatched \\begin .. \\end block.
+Leave point alone if there are none. Leave mark at old
+point if we move point."
+ (interactive)
+ (condition-case nil
+ (stx-goto-first-unended-begin)
+ (error (condition-case nil
+ (stx-goto-last-unbegun-end)
+ (error (message "Your \\begin .. \\end blocks are OK."))))))
+(defun stx-close-block ()
+ "Create an \"\\end{...}\" to match the last unclosed \"\\begin{...}\".
+The \"\\begin{...}\" must follow `stx-bwb', which is
+duplicated in front of the \"\\end{...}\".
+
+Return indentation string."
+ (interactive "*")
+ (let ((bolp (bolp))
+ case-fold-search
+ text
+ indentation)
+ (save-excursion
+ (condition-case nil
+ (stx-goto-prev-unended-begin 'silent)
+ (error (error "Couldn't find unended \\begin above! (stx-close-block)")))
+ (setq indentation (buffer-substring
+ (save-excursion
+ (re-search-forward (concat (stx-boln) rx-whitespace)))
+ (point)))
+ (re-search-forward (concat rx-backslash "begin"
+ "\\(" rx-whitespace rx-brace-pair
+ "\\)"))
+ (setq text (buffer-substring (match-beginning 1) (match-end 1))))
+ (if (not bolp)
+ (let ((bol (save-excursion (beginning-of-line) (point))))
+ (if (save-excursion
+ (re-search-backward
+ (concat (stx-boln) rx-whitespace
+ rx-backslash "end"
+ rx-whitespace rx-brace-pair) bol t))
+ ;; if there is an \\end before point on the same line
+ (insert ?\n)
+ ;; if not
+ (beginning-of-line)
+ (setq bolp t))))
+ (insert indentation "\\end" text)
+ (if bolp
+ (insert ?\n)
+ (forward-char))
+ ;; return value
+ indentation))
+(defun stx-close-block-from-inside ()
+ "Close LaTeX block after typing the argument to \"\\begin\".
+Let * be point.
+Initial buffer contents:
+
+ \\begin{foo*}
+
+Final buffer contents:
+
+ \\begin{foo}
+ *
+ \\end{foo}"
+ (interactive "*")
+ (forward-line 1)
+ (let ((indent (stx-close-block)))
+ (forward-line -1)
+ (open-line 1)
+ (insert indent)))
+(defun stx-command (command &optional arg)
+ "Insert a one-argument LaTeX command \"\\COMMAND{}\".
+ARG non-nil means place ARG between braces following COMMAND
+and leave point (*) after both:
+
+\\COMMAND{ARG} *
+
+If ARG is nil, leave point between the braces:
+ \\COMMAND{*}"
+ (interactive "*")
+ (insert "\\" command "{")
+ (if arg
+ (insert arg "} ")
+ (insert "}")
+ (backward-char)))
+
+;; This code is based on `current-word' in the standard 19.28 simple.el.
+;;
+;; It seemed wisest to imitate its "strict" behavior.
+;;
+;; We explicitly add the original point to undo list, because we have to
+;; explicitly move point during the normal execution of the function to keep it
+;; on the same text on which it was called.
+;;
+;; FIX: consider `insert-before-markers'
+(defun stx-enclose-word (before after)
+ "Insert string BEFORE before word at point and string AFTER after it.
+Keep point over the same text as when the function is called."
+ (let* ((oldpoint (point))
+ (start oldpoint)
+ (end oldpoint))
+ ;; Since the following movement commands do not alter
+ ;; `buffer-undo-list', we add point manually. We could do this
+ ;; any time before the first command that modified it, which is
+ ;; the `insert' below.
+ (setq buffer-undo-list (cons oldpoint buffer-undo-list))
+ (skip-syntax-backward "w")
+ (setq start (point))
+ (goto-char oldpoint)
+ (skip-syntax-forward "w")
+ (setq end (point))
+ (if (and (eq start oldpoint)
+ (eq end oldpoint))
+ (error "Point is neither in nor adjacent to a word!")
+ ;; because the head of `buffer-undo-list' is non-nil, `insert'
+ ;; is going to add a boundary to it before adding its element.
+ (insert after)
+ ;; We remove the boundary now.
+ (setcdr buffer-undo-list (cdr (cdr buffer-undo-list)))
+ (goto-char start)
+ (insert before)
+ ;; We remove the boundary as before.
+ (setcdr buffer-undo-list (cdr (cdr buffer-undo-list)))
+ (goto-char (+ oldpoint (length before))))))
+(defun stx-emphasize-word ()
+ "Surround word at point with \"\\emph{\" and \"}\"."
+ (interactive "*")
+ (stx-enclose-word "\\emph{" "}"))
+(defun stx-emphasize ()
+ "Call `(stx-command \"emph\")'."
+ (interactive "*")
+ (stx-command "emph"))
+(defun stx-begin-block ()
+ "Call `(stx-command \"begin\")'."
+ (interactive "*")
+ (stx-command "begin"))
+(defalias 'stx-insert-block 'tex-latex-block)
+(defun stx-block-comment ()
+ "Call `(stx-insert-block \"comment\")'."
+ (interactive "*")
+ (stx-insert-block "comment"))
+(defun stx-block-quotation ()
+ "Call `(stx-insert-block \"quotation\")'."
+ (interactive "*")
+ (stx-insert-block "quotation"))
+;; avoid message while byte-compiling
+(eval-when-compile (require 'tex-mode))
+(defun stx-pdflatex-file ()
+ "Prompt to save all buffers and run PDFLaTeX on current buffer's file.
+This function is a wrapper for `tex-file'."
+ (interactive)
+ (let ((tex-command "pdflatex"))
+ (tex-file)))
+
+;; avoid message while byte-compiling
+(defvar tex-print-file)
+(defvar tex-last-buffer-texed)
+(defun stx-pdfview-file ()
+ "Preview with gv the last `.pdf' file made by running PDFLaTeX under Emacs.
+This means, made using \\[tex-region], \\[tex-buffer] or
+\\[tex-file]."
+ (interactive)
+ (let ((print-file-name-pdf (tex-append tex-print-file ".pdf"))
+ test-name)
+ (if (and (not (equal (current-buffer) tex-last-buffer-texed))
+ (buffer-file-name)
+ ;; Check that this buffer's printed file is up to date.
+ (file-newer-than-file-p
+ (setq test-name (tex-append (buffer-file-name) ".pdf"))
+ (buffer-file-name)))
+ (setq print-file-name-pdf test-name))
+ (if (not (file-exists-p print-file-name-pdf))
+ (error "No appropriate `.pdf' file could be found")
+ (if (tex-shell-running)
+ (tex-kill-job)
+ (tex-start-shell))
+ (tex-send-command "gv" print-file-name-pdf t))))
+
+
+;;;;; DOCTEX MODE
+
+;;; The code forms below are unique to docTeX mode, but rely on many of the
+;;; forms in the swifTeX mode section above.
+
+;;;;;; USER VARIABLES
+
+;;; FIX :link?
+(defcustom dtx-sectioning-offset 1
+ "Outline level offset for all LaTeX sectioning commands in a docTeX buffer.
+See the documentation for the variable
+`stx-sectioning-commands'."
+ :tag "Sectioning Commands Outline Offset"
+ :type 'integer
+ :group 'doctex)
+
+;;; FIX :link?
+(defcustom dtx-sectioning-commands '(
+ ("documentclass" . -2)
+ ;; leave off final
+ ;; closebrace, since the
+ ;; \> in the regexp needs
+ ;; to match the end of the
+ ;; strings here.
+ ("begin{document" . -2)
+ ("end{document" . -2)
+ ("endinput" . -2)
+ ("StopEventually" . -2)
+ ("Finale" . -2)
+ ("part" . -2)
+ ("appendix" . -1)
+ ("chapter" . -1)
+ ("section". 0)
+ ("subsection" . 1)
+ ("subsubsection" . 2)
+ ("paragraph" . 3)
+ ("subparagraph" . 4)
+ )
+ "Equivalent of `stx-sectioning-commands' for docTeX buffers.
+See documentation for that variable."
+ :tag "Sectioning Commands and Levels"
+ :type '(repeat (cons :format "%v"
+ (string :tag "Command")
+ (integer :tag "Level")))
+ :group 'doctex)
+
+;;; FIX prefix key type
+;;; FIX :set?
+(defcustom doctex-dtx-prefix-key '"\C-c\C-d"
+ "Prefix key for all commands unique to docTeX mode.
+A change in this variable takes effect the next time `doctex-mode' is
+called."
+ :tag "Prefix key for all docTeX Commands"
+ :type 'string
+ :group 'doctex)
+
+(defcustom rx-tex-def-cmd
+ (concat "\\("
+;;; FIX Frankenstein-specific stuff here; move to
+;;; FIX should have file-variable for new defining commands
+ (regexp-opt '("def" "long\\\\def"
+ "gdef" "global\\\\def"
+ "edef" "long\\\\edef"
+ "xdef" "global\\\\edef"
+ "ReserveCS" "ReserveCS\\*"
+ "InitCS" "InitCS\\*"
+ "newcommand" "newcommand\\*"
+ "renewcommand" "renewcommand\\*"
+ "defcommand" "defcommand\\*"
+ "requirecommand" "requirecommand\\*"
+ "CheckCommand" "CheckCommand\\*"
+ "CheckName" "CheckName\\*"
+ "NewUserInfo" "NewUserInfo\\*"
+ "CheckName" "CheckName\\*"
+ "RequireNewName" "RequireNewName\\*"
+ "DeclareRobustCommand"
+ "DeclareRobustCommand\\*"
+ "NewNameDef" "NewNameDef\\*"
+ "let" "global\\\\let"
+ "EElet" "global\\\\EElet"
+ "newlet" "global\\\\newlet"))
+ "\\)")
+ "Matches a (La)TeX defining command without its argument."
+ :tag "Defining Command Regexp"
+ :type 'regexp
+ :group 'doctex)
+(defcustom rx-dtx-version "\\(v?\\)\\([0-9.]*\\)\\([a-z]?\\)"
+ "Matches a LaTeX version string."
+ :tag "LaTeX Version Regexp"
+ :type 'regexp
+ :group 'doctex)
+(defcustom rx-dtx-date "[0-9]+/[0-9]+/[0-9]+"
+ "Matches a LaTeX date string."
+ :tag "LaTeX Date Regexp"
+ :type 'regexp
+ :group 'doctex)
+
+;;;;;; FILE VARIABLES
+(defvar dtx-bibstyle-mode nil
+ "Non-nil means assume the buffer contains a bibstyle source.
+
+FIX: this should be detected automatically. But for now, set this
+in the file variables. Right now this only has an effect on the functions
+which update the file version and date and documentation
+date.")
+
+;;;;;; HOOK VARIABLES
+;;; FIX see what define-derived-mode gives for its dox
+;;; (defvar doctex-mode-hook nil
+;;; "Hook run as the last thing after entering docTeX mode.
+;;; When entering docTeX mode, the last thing done is to run `swiftex-mode-hook'
+;;; then this hook.")
+
+;;;;;; INTERNAL VARIABLES
+
+(defvar dtx-file-version nil
+ "The version string of the file in the current buffer.")
+(make-variable-buffer-local 'dtx-file-version)
+
+(defvar dtx-prefix-version nil
+ "The leading part of the version string up until the major version.
+
+This is the optional \"v\" plus any following elements that
+will still leave two elements to the right, which are the
+major and minor versions.")
+(make-variable-buffer-local 'dtx-prefix-version)
+
+(defvar dtx-major-version nil
+ "The major version part of the version string.")
+(make-variable-buffer-local 'dtx-major-version)
+
+(defvar dtx-minor-version nil
+ "The minor version part of the version string.")
+(make-variable-buffer-local 'dtx-minor-version)
+
+;;;;;; INLINE FUNCTION-VARIABLES
+
+;;; Without these abbreviations, other code would be very hard to read.
+
+;;; The version control commands are going to be behind double %%'s, this is
+;;; just a fact of how bibstyle sources have to get generated. You can't have
+;;; the regular \TeX{} commands in the bibstyle.
+(defsubst dtx-bwcb ()
+ "Return a regexp boln + w-space + \"%%\" + w-space + b-slash.
+Do so even if hidden in an outline."
+ (concat (stx-boln) rx-whitespace "%%" rx-whitespace rx-backslash))
+(defsubst dtx-tex-defn (name)
+ "Return regexp string matching a line that defines NAME.
+The match begins at the beginning of the line, and goes
+through the \"{\" that begins the definition.
+
+The definitions searched for are expected to be in a doctex
+file, but not in the documentation, in a macrocode
+environment.
+
+The string returned will depend on the value of
+`dtx-bibstyle-mode'."
+ (concat (if dtx-bibstyle-mode (dtx-bwcb) (stx-bwb))
+ rx-tex-def-cmd
+ rx-tex-grop "?"
+ rx-backslash
+ name
+ rx-tex-grcl "?"
+ rx-whitespace
+ rx-tex-grop))
+
+;;;;;; DEFINE MODE
+;; avoid message while byte-compiling
+(defvar doctex-mode-syntax-table)
+(define-derived-mode doctex-mode swiftex-mode "docTeX"
+ "Major mode for LaTeX doc documents derived from swifTeX mode.
+
+DocTeX mode preserves the filling and outlining behavior of
+swifTeX mode behind the wall of of \"%\" characters in the
+first column of a LaTeX doc.sty buffer.
+
+You won't want to fill inside a \"macrocode\" environment.
+
+The TAB key seems to behave as usual but inserts spaces only
+\(that is, no `\\t' characters). It is confusing when `\\t'
+characters occur inside verbatim environments \(including
+macrocode environments) because the typeset appearance will
+not match the appearance of the source file, and
+code-indenting conventions will often get mangled.
+
+Outline headings all begin with a \"%\" in the first column.
+LaTeX sectioning commands are outline headings, and so is
+\"^^A\" followed by at least one star \(\"*\"). (The ltxdoc
+document class defines the \"^^A\" character as a LaTeX
+comment.) See `stx-set-outlinevars'.
+
+The following commands maintain the version information in
+the LaTeX buffer. They act on lines that define
+\\fileversion, \\filedate, or \\docdate, or the equivalent
+components of the \\ProvidesPackage or \\ProvidesClass
+declarations if the first are absent.
+
+\\[dtx-get-fileinfo] displays the buffer's version in the minibuffer.
+\\[dtx-update-minor-version] updates the minor version.
+\\[dtx-update-major-version] updates the major version.
+
+The last two also update the file date to the current date.
+
+\\[dtx-update-documentation-date] makes the documentation date current.
+\\[dtx-insert-change] inserts a LaTeX \\changes entry.
+\\[add-change-log-entry] adds a ChangeLog entry.
+
+A number of commands save typing. `insert' commands (on
+uppercase keys) begin and end the relevant environment and
+leave point in between\; `begin' commands \(on lowercase
+keys) just begin the environment. All prompt for the name
+of the thing in question.
+
+\\[dtx-interrupt-macrocode] interrupts a \"macrocode\" environment for more documentation.
+
+Some convenient ways to customize behavior in individual
+files are provided by the `stx-local-' variables.
+
+Some function and variable names begin with `stx-' and some
+with `dtx-'. The latter are unique to docTeX mode\; the
+former are in common with swifTeX mode. The difference is
+unimportant if you just want to use docTeX mode.
+
+\\{doctex-mode-map}"
+ ;; Change the syntax of % to punctuation. It's not a
+ ;; comment in docTeX mode, and leaving it as a comment
+ ;; char causes problems. I'm not sure what syntax class
+ ;; it should have, however.
+ (modify-syntax-entry ?% "." doctex-mode-syntax-table)
+ ;; Bug in Emacs: you have to declare this a buffer-local
+ ;; hook. FIX: version?
+ (make-local-hook 'write-contents-hooks)
+ (add-hook 'write-contents-hooks 'dtx-update-checksum nil t)
+ (setq stx-comment-start "\\^\\^A")
+ (setq stx-line-start "%*")
+ ;; FIX: merge?
+ ;; FIX: should have customizable dtx-extra-command-parstarts
+ (setq stx-command-parstarts
+ (append stx-command-parstarts '("DescribeMacro" "DescribeEnv")))
+ (setq stx-command-parseps
+ (append stx-command-parseps '("DescribeMacro" "DescribeEnv")))
+ (setq outline-level (function dtx-outline-level))
+ (stx-set-vars)
+ ;; FIX I think this is not so great, these variables aren't independent from
+ ;; stx-fontlock
+ (if dtx-fontlock
+ (progn
+ (require 'font-latex)
+ (font-latex-setup))
+ (if dtx-hilit
+ (require 'hilit-swiftex))))
+
+;;;;;; DEFINE KEYMAP
+
+(defvar doctex-dtx-mode-map (make-sparse-keymap)
+ "Keymap for all new commands in docTeX mode.")
+;; avoid message while byte-compiling
+(defvar doctex-mode-map)
+(define-key doctex-mode-map doctex-dtx-prefix-key doctex-dtx-mode-map)
+(define-key doctex-dtx-mode-map "g" 'dtx-insert-change)
+(define-key doctex-dtx-mode-map "l" 'add-change-log-entry)
+(define-key doctex-dtx-mode-map "e" 'dtx-begin-environment)
+(define-key doctex-dtx-mode-map "E" 'dtx-insert-environment)
+(define-key doctex-dtx-mode-map "f" 'dtx-begin-bibfunction)
+(define-key doctex-dtx-mode-map "F" 'dtx-insert-bibfunction)
+(define-key doctex-dtx-mode-map "m" 'dtx-begin-macro)
+(define-key doctex-dtx-mode-map "M" 'dtx-insert-macro)
+(define-key doctex-dtx-mode-map "i" 'dtx-interrupt-macrocode)
+(define-key doctex-dtx-mode-map "v" 'dtx-get-fileinfo)
+(define-key doctex-dtx-mode-map "s" 'dtx-update-checksum)
+(define-key doctex-dtx-mode-map "c" 'dtx-begin-macrocode)
+(define-key doctex-dtx-mode-map "C" 'dtx-insert-macrocode)
+(define-key doctex-dtx-mode-map "u" 'dtx-update-minor-version)
+(define-key doctex-dtx-mode-map "U" 'dtx-update-major-version)
+(define-key doctex-dtx-mode-map "d" 'dtx-update-documentation-date)
+
+;;;;;; FUNCTIONS TO SAVE TYPING
+
+(defun dtx-begin-macrocode ()
+ "Begin a \"macrocode\" environment."
+ (interactive "*")
+ (beginning-of-line)
+ (insert "% \\begin{macrocode}"))
+(defun dtx-insert-macro ()
+ "Insert a \"macro\" environment and matching \"macrocode\" environment."
+ (interactive "*")
+ (end-of-line)
+ (insert-string "
+% \\begin{macro}
+%
+% \\begin{macrocode}
+% \\end{macrocode}
+% \\end{macro}
+%")
+ (forward-line -5)
+ (end-of-line)
+ (insert rx-tex-grop (read-string "Macro: " stx-str-backslash) rx-tex-grcl)
+ (forward-line 1)
+ (end-of-line))
+(defun dtx-begin-macro ()
+ "Begin a \"macro\" environment."
+ (interactive "*")
+ (beginning-of-line)
+ (insert-string "% \\begin{macro}
+")
+ (forward-line -1)
+ (end-of-line)
+ (insert rx-tex-grop (read-string "Macro: " stx-str-backslash) rx-tex-grcl)
+ (forward-line 1)
+ (end-of-line))
+(defun dtx-insert-environment ()
+ "Insert an \"environment\" environment."
+ (interactive "*")
+ (end-of-line)
+ (insert-string "
+% \\begin{environment}
+%
+% \\begin{macrocode}
+% \\end{macrocode}
+% \\end{environment}
+%")
+ (forward-line -5)
+ (end-of-line)
+ (insert rx-tex-grop (read-string "Environment: ") rx-tex-grcl)
+ (forward-line 1)
+ (end-of-line))
+(defun dtx-begin-environment ()
+ "Begin an \"environment\" environment."
+ (interactive "*")
+ (beginning-of-line)
+ (insert-string "% \\begin{environment}
+")
+ (forward-line -1)
+ (end-of-line)
+ (insert rx-tex-grop (read-string "Environment: ") rx-tex-grcl)
+ (forward-line 1)
+ (end-of-line))
+(defun dtx-insert-bibfunction ()
+ "Insert a \"bibfunction\" environment."
+ (interactive "*")
+ (end-of-line)
+ (insert-string "
+% \\begin{bibfunction}
+%
+% \\begin{macrocode}
+% \\end{macrocode}
+% \\end{bibfunction}
+%")
+ (forward-line -5)
+ (end-of-line)
+ (insert rx-tex-grop (read-string "FUNCTION: ") rx-tex-grcl)
+ (forward-line 1)
+ (end-of-line))
+(defun dtx-begin-bibfunction ()
+ "Begin a \"bibfunction\" environment."
+ (interactive "*")
+ (beginning-of-line)
+ (insert-string "% \\begin{bibfunction}
+")
+ (forward-line -1)
+ (end-of-line)
+ (insert rx-tex-grop (read-string "FUNCTION: ") rx-tex-grcl)
+ (forward-line 1)
+ (end-of-line))
+(defun dtx-insert-change ()
+ "Insert a LaTeX change log entry with automatic date."
+ (interactive "*")
+ (if (null dtx-file-version)
+ (dtx-get-fileinfo))
+ (end-of-line)
+ (insert-string "
+% \\changes")
+ (insert rx-tex-grop dtx-file-version rx-tex-grcl)
+ (insert rx-tex-grop (dtx-current-date) rx-tex-grcl)
+ (insert rx-tex-grop (read-string "Change: ") rx-tex-grcl))
+(defun dtx-insert-macrocode ()
+ "Insert a \"macrocode\" environment."
+ (interactive "*")
+ (insert-string "% \\begin{macrocode}
+
+% \\end{macrocode}
+")
+ (forward-line -2))
+(defun dtx-interrupt-macrocode ()
+ "Interrupt a \"macrocode\" environment for more documentation."
+ (interactive "*")
+ (backward-char 1)
+ (end-of-line)
+ (insert-string "
+% \\end{macrocode}
+%
+% \\begin{macrocode}")
+ (forward-line -1)
+ (end-of-line))
+
+;;;;;; FUNCTIONS TO HANDLE VERSIONS, DATES, CHECKSUMS
+(defun dtx-get-fileinfo (&optional noecho)
+ "Set `dtx-' v.c. var.s according to lines in the buffer, and echo them.
+
+That is, set `dtx-file-version', `dtx-prefix-version',
+`dtx-major-version', and `dtx-minor-version', and echo them
+to the minibuffer.
+
+Optional NOECHO non-nil means don't echo information.
+
+To set them, look for a line that defines
+\"\\fileversion{<version>}\" (see `dtx-tex-defn').
+<version> is any number of integers separated by dots with
+an optional prefix \"v\" and an optional suffix of a
+lowercase letter. If no such line exists, then use the line
+with \"\\ProvidesPackage\" or \"\\ProvidesClass\".
+
+The major and minor version strings will be the last two
+elements of the <version>, counting the possible suffix as a
+separate element if it exists."
+ (interactive)
+ (let (case-fold-search
+ fileversion filedate docdate)
+ (save-excursion
+ (goto-char (point-min))
+ (if (or
+ ;; Look for definition of \fileversion.
+ (and (re-search-forward
+ (dtx-tex-defn "fileversion")
+ nil t)
+ ;; we search twice because we want to remain independent
+ ;; of how many \\(...\\) pairs are in `dtx-tex-defn'.
+ ;; FIX: we can not acceptably skip anything here -- what can we
+ ;; skip? What if we skip more?
+ (re-search-forward
+ (concat rx-whitespace rx-dtx-version
+ rx-whitespace rx-tex-grcl)
+ nil t))
+ ;; If the first search failed, point is still at point-min.
+ ;; Look for an optional argument to \ProvidesFoo.
+ (and (re-search-forward
+ (concat (stx-bwb) "Provides"
+ "\\(Package" rx-or "Class\\)"
+ ;; This used to be: rx-tex-grop "\\w+" rx-tex-grcl
+ ;; which is more restrictive than the rx-brace-pair I
+ ;; used elsewhere. I see no reason to use the more
+ ;; restrictive regexp.
+ ;; thanks to Peter Møller Neergaard for noticing this
+ rx-whitespace rx-brace-pair)
+ nil t)
+ ;; FIX: the only thing we can acceptably skip here is
+ ;; rx-whitespace-newlines -- what if we skip more?
+ (re-search-forward
+ (concat "\\["
+ rx-whitespace rx-dtx-date
+ rx-whitespace rx-dtx-version ".*\\]")
+ nil t)))
+ ;; We've found what we need.
+ (let* ((ver-match-data (match-data))
+ (the-list (dtx-massage-version
+ ;; NOTE: byte-compiling turns the arithmetic into constants
+ (buffer-substring (elt ver-match-data (* 2 2))
+ (elt ver-match-data (1+ (* 2 3))))))
+ (prefix (buffer-substring (elt ver-match-data (* 2 1))
+ (elt ver-match-data (1+ (* 2 1)))))
+ (n (length the-list))
+ (k 0))
+ (cond
+ ((= n 0)
+ (setq dtx-major-version ""
+ dtx-minor-version ""))
+ ((= n 1)
+ (setq dtx-major-version (elt the-list 0)
+ dtx-minor-version ""))
+ (t
+ (setq dtx-major-version (elt the-list (- n 2))
+ dtx-minor-version (elt the-list (- n 1)))))
+ (setq dtx-prefix-version prefix)
+ ;; now add onto the prefix whatever is right
+ (while (< k (- n 2))
+ (setq dtx-prefix-version
+ (concat dtx-prefix-version
+ (if (or (string-equal dtx-prefix-version "")
+ (string-equal dtx-prefix-version "v"))
+ "" ".")
+ (elt the-list k))
+ k (1+ k)))
+ (setq fileversion (dtx-set-version 'noecho)))
+ ;; We have not found what we need.
+ (error "Can't find file info! (dtx-get-fileinfo)"))
+ (if (null noecho)
+ (progn
+ (goto-char (point-min))
+ (if (and (re-search-forward (dtx-tex-defn "docdate") nil t)
+ (re-search-forward rx-dtx-date nil t))
+ (setq docdate (match-string 0))
+ (error
+ "Can't find documentation date! (dtx-get-fileinfo)"))
+ (goto-char (point-min))
+ (if (and (re-search-forward (dtx-tex-defn "filedate") nil t)
+ (re-search-forward rx-dtx-date nil t))
+ (setq filedate (match-string 0))
+ (if (and (re-search-forward
+ (concat (stx-bwb)
+ "Provides\\(Package" rx-or
+ "Class\\)"
+ rx-whitespace rx-brace-pair
+ rx-whitespace-newlines "\\[")
+ nil t)
+ (re-search-forward rx-dtx-date nil t))
+ (setq filedate (match-string 0))
+ (error "Can't find file date! (dtx-get-fileinfo)")))
+ (message "Version: %s Date: %s Docdate: %s"
+ fileversion filedate docdate))))))
+(defun dtx-update-documentation-date ()
+ "Update the \"\\docdate\" to the current date and update the checksum."
+ (interactive "*")
+ ;; FIX why update the checksum?
+;;; (dtx-update-checksum 'noecho)
+ (save-excursion
+ (goto-char (point-min))
+ (let (case-fold-search)
+ (if (and (re-search-forward (dtx-tex-defn "docdate") nil t)
+ (re-search-forward rx-dtx-date nil t))
+ (replace-match (dtx-current-date))
+ (error
+ "Can't find documentation date! (dtx-update-documentation-date)")))))
+(defun dtx-update-fileinfo ()
+ "Update the \fileversion and \filedate.
+
+First assemble `dtx-file-version' by calling
+`dtx-set-version'. Then find and update the version and
+date in the line that defines them (see `dtx-tex-defn')
+using the current values of `dtx-file-version' and
+`(dtx-current-date)', respectively. If no such defining
+line exists, use a \"\\ProvidesPackage\" or
+\"\\ProvidesClass\" line."
+ (dtx-set-version)
+ (let (case-fold-search)
+ (save-excursion
+ (goto-char (point-min))
+ (if (re-search-forward (dtx-tex-defn "fileversion") nil t)
+ (progn
+ ;; The argument can contain matching braces.
+ (backward-char)
+ (delete-region (point) (forward-list))
+ (insert rx-tex-grop dtx-file-version rx-tex-grcl))
+ ;; If first search failed, point is still point-min.
+ (if (and
+ (re-search-forward
+ (concat (stx-bwb) "Provides\\(Package" rx-or "Class\\)"
+ rx-whitespace rx-brace-pair
+ rx-whitespace-newlines "\\["
+ rx-whitespace rx-dtx-date rx-whitespace)
+ nil t)
+ (re-search-forward rx-dtx-version nil t))
+ (replace-match dtx-file-version)
+ (error "Can't find file version! (dtx-update-fileinfo)")))
+ ;; The date is only changed if a change above succeeds.
+ (goto-char (point-min))
+ (if (re-search-forward (dtx-tex-defn "filedate") nil t)
+ (progn
+ (backward-char)
+ (delete-region (point) (forward-list))
+ (insert rx-tex-grop (dtx-current-date) rx-tex-grcl))
+ (if (and (re-search-forward
+ (concat (stx-bwb)
+ "Provides\\(Package" rx-or
+ "Class\\)"
+ rx-whitespace rx-brace-pair
+ rx-whitespace-newlines "\\[")
+ nil t)
+ (re-search-forward rx-dtx-date nil t))
+ (replace-match (dtx-current-date))
+ (error "Can't find file date! (dtx-update-fileinfo)"))))))
+(defun dtx-update-minor-version ()
+ "Increment the minor version and update the checksum."
+ (interactive "*")
+ (if (null dtx-file-version)
+ (dtx-get-fileinfo))
+ (setq dtx-minor-version
+ (cond ((string-equal "" dtx-minor-version)
+ (read-string "Minor version: "))
+ ((string-match "[a-z]" dtx-minor-version)
+ (string (1+ (string-to-char dtx-minor-version))))
+ (t
+ (number-to-string (1+ (string-to-number dtx-minor-version))))))
+ ;; FIX: why bother to update the checksum?
+;;; (dtx-update-checksum 'noecho)
+ (dtx-update-fileinfo))
+
+;;; FIX: check behavior
+;;; 1.3b major 1.4
+;;; 1.5 major 2
+;;; 2 major 3
+(defun dtx-update-major-version ()
+ "Increment the major version and update the checksum."
+ (interactive "*")
+ (if (null dtx-file-version)
+ (dtx-get-fileinfo))
+ (setq dtx-minor-version ""
+ dtx-major-version (number-to-string
+ (1+ (string-to-number dtx-major-version))))
+ ;; FIX: why bother to update the checksum?
+;;; (dtx-update-checksum 'noecho)
+ (dtx-update-fileinfo))
+(defun dtx-set-version (&optional noecho)
+ "Assemble `dtx-file-version' from its constituent parts.
+
+NOECHO non-nil means don't echo the version to the
+minibuffer. Returns `dtx-file-version'."
+ (let (case-fold-search)
+ (setq dtx-file-version
+ (concat dtx-prefix-version
+ (if (or (string-equal dtx-prefix-version "")
+ (string-equal dtx-prefix-version "v"))
+ "" ".")
+ dtx-major-version
+ (if (not (string-equal dtx-minor-version ""))
+ (concat (if (or (string-equal dtx-major-version "")
+ (string-match "[a-z]" dtx-minor-version))
+ "" ".")
+ dtx-minor-version))))
+ (or noecho
+ (message "The version of this file is now <%s>"
+ dtx-file-version))
+ dtx-file-version))
+(defun dtx-massage-version (s)
+ "Massage a version string into a list of strings.
+Given a string S matching a series of unsigned integers
+separated by dots, return a list of those integers as
+strings.
+
+If a lowercase letter ends S, it will be tacked on to the
+returned list."
+ (let (case-fold-search
+ (k 0)
+ (n (length s))
+ element
+ number-list
+ kth-char-as-string)
+ (while (< k n)
+ (setq kth-char-as-string (string (elt s k)))
+ (cond
+ ((string-match "[0-9]" kth-char-as-string)
+ (setq element (concat element kth-char-as-string)))
+ ((string-match "\\." kth-char-as-string)
+ (setq number-list (append number-list (list element))
+ element nil))
+ ((string-match "[a-zA-Z]" kth-char-as-string)
+ (if (or (not (equal k (1- n)))
+ (string-match "[A-Z]" kth-char-as-string))
+ (error (concat "Bad letter \"%s\" in version string \"%s\"! "
+ "The last character is permitted to be a LOWERCASE letter. "
+ "(dtx-massage-version)") kth-char-as-string s)
+ (setq number-list (append number-list (list element))
+ element kth-char-as-string)))
+ (t
+ (error "Can't parse version string \"%s\"! (dtx-massage-version)" s)))
+ (setq k (1+ k)))
+ (setq number-list (append number-list (list element)))
+ (if (equal number-list (list nil))
+ (setq number-list nil))
+ number-list))
+
+;;; Thanks to Karl Eichwalder <ke@gnu.franken.de> for his improvement of this
+;;; function.
+(defun dtx-current-date ()
+ "Return the current date as a string in the form \"1991/01/23\"."
+ (format-time-string "%Y/%m/%d"))
+(defun dtx-report-checksum-error (function checksum)
+"Report a checksum error to the user.
+Use FUNCTION, which takes a string argument, to report the
+error CHECKSUM. Returns nil so it won't halt
+`write-contents-hooks'."
+ (cond
+ ((eq checksum 'checksum)
+ (funcall function "Can't find CheckSum declaration!"))
+ ((eq checksum 'macrocode)
+ (funcall function "Mismatched macrocode environments!"))
+ ((eq checksum 'finale)
+ (funcall function "Couldn't find Finale!"))
+ ((eq checksum 'stop)
+ (funcall function "Couldn't find StopEventually or AddToCheckSum!")))
+ nil)
+(defun dtx-update-checksum (&optional noecho)
+ "Update the argument of the \\CheckSum or \\AddToCheckSum command.
+If a error occurs while computing the checksum, signal an
+error in the interactive case or issue a warning message in
+the non-interactive case.
+
+NOECHO non-nil means don't echo the CheckSum to the minibuffer."
+ (interactive "*")
+ (let ((opoint (point))
+ (checksum (dtx-compute-checksum))
+ case-fold-search)
+ (if (stringp checksum)
+ ;; The checksum was successfully computed.
+ (save-excursion
+ (goto-char (point-min))
+ ;; \CheckSum and \AddToCheckSum should be behind at least one comment.
+ ;; If there is a \CheckSum in the file, there will not be a
+ ;; \AddToCheckSum and vice versa.
+ (if (or
+ ;; We find \CheckSum
+ ;; FIX: what if more than one comment?
+ (and (re-search-forward (concat (stx-boln) "%" rx-whitespace
+ rx-backslash "CheckSum{")
+ ;; Leave point at beginning if we don't find
+ ;; it.
+ nil t)
+ (progn
+ (backward-char)
+ (delete-region (point) (forward-list))
+ t))
+ ;; We find \AddToCheckSum.
+ (and (re-search-forward (concat (stx-boln) "%" rx-whitespace
+ rx-backslash "AddToCheckSum{")
+ nil 'move)
+ (progn
+ (backward-char)
+ (delete-region (point) (forward-list))
+ t))
+ ;; We query the user if we're interactive.
+ (and (if (interactive-p)
+ t
+ (dtx-report-checksum-error 'message 'checksum)
+ ;; don't proceed
+ nil)
+ (goto-char opoint)
+ (y-or-n-p
+ "I can't find a `\\CheckSum{}' declaration. Should I insert one at point? ")
+ (progn
+ (insert "\\CheckSum")
+ t)))
+ (progn
+ (insert rx-tex-grop checksum rx-tex-grcl)
+ (if (null noecho) (message "Checksum updated to %s." checksum))
+ ;; Return nil so that we can put this function in
+ ;; `write-contents-hooks'.
+ nil)))
+ ;; Checksum was not successfully computed.
+ (if (interactive-p)
+ (dtx-report-checksum-error 'error checksum)
+ (dtx-report-checksum-error 'message checksum)))))
+(defun dtx-compute-checksum ()
+"Return the `doctex-mode' checksum or an error code.
+The checksum is the number of backslashes in the macrocode
+environments between \\StopEventually and \\Finale if those
+declarations are found, and all macrocode environments if an
+\\AddToCheckSum declaration is found. The error codes are
+`macrocode' for unbalanced macrocode environments, `finale'
+for a missing \\Finale, and `stop' for a missing
+\\StopEventually. When a `macrocode' error occurs, the
+function leaves mark at point and skips to the unclosed
+\\begin.
+
+I think `'move' is a more efficient final argument to `re-search-*'
+than t; when it doesn't matter which, I've used `'move'."
+ (let* (checksum-error
+ (opoint (point))
+ ;; WARNING: see above notes on comment syntax.
+ (parse-sexp-ignore-comments nil)
+ (leave-me-here opoint)
+ case-fold-search
+ ;; The number of `%' characters must be exact, so we don't use `stx-boln'.
+ (begin-macrocode (concat "\\(" rx-normal-boln rx-or rx-hidden-boln "\\)% "
+ rx-backslash "begin{macrocode\*?}"))
+ (end-macrocode (concat "\\(" rx-normal-boln rx-or rx-hidden-boln "\\)% "
+ rx-backslash "end{macrocode\*?}"))
+ (stop-eventually (save-excursion
+ (goto-char (point-min))
+ ;; The argument to \StopEventually might contain
+ ;; some backslashes that we don't want to count, so
+ ;; we skip over it with `forward-list'.
+ ;; WARNING: see above notes on comment syntax.
+ (and
+ (re-search-forward (concat (stx-boln) "%"
+ rx-whitespace rx-backslash
+ "StopEventually")
+ nil 'move)
+ (forward-list))))
+ (addtochecksum (save-excursion
+ (goto-char (point-min))
+ (re-search-forward (concat (stx-boln) "%"
+ rx-whitespace rx-backslash
+ "AddToCheckSum{")
+ nil t))))
+ (unwind-protect
+ (if (or stop-eventually addtochecksum)
+ (save-excursion
+ ;; Goto `stop-eventually' if it's there, else beginning.
+ (goto-char (or stop-eventually (point-min)))
+ (let ((backslashes 0)
+ (codeblocks 0)
+ ;; We stop at either \Finale or the end.
+ (finale (if (not stop-eventually)
+ (point-max)
+ (save-excursion
+ ;; \Finale must be on a line by itself
+ (re-search-forward (concat (stx-boln) "%"
+ rx-whitespace rx-backslash
+ "Finale") nil 'move)))))
+ (if finale
+ (while (not (or checksum-error
+ (equal (point) finale)))
+ (let ((begin-code (re-search-forward begin-macrocode finale 'move))
+ (end-code (save-excursion
+ (re-search-forward end-macrocode finale 'move))))
+ (if begin-code
+ (if end-code
+ ;; we have a well-defined macrocode region
+ (progn
+ (setq codeblocks (1+ codeblocks))
+ (while (and (not (equal (point) end-code))
+ (search-forward "\\" end-code 'move))
+ (setq backslashes (1+ backslashes))))
+ ;; if `end-code' is nil but `begin-code' is non-nil we have a
+ ;; problem
+ (setq leave-me-here begin-code)
+ (setq checksum-error 'macrocode))
+ ;; if both `begin-code' and `end-code' are nil, the
+ ;; checksum is zero, but that's not an error.
+ )))
+ ;; if `finale' is nil we have a problem
+ (setq checksum-error 'finale))
+ ;; The count is too high because it counted the \ in each "\end{macrocode}".
+ ;; This is the checksum as a string.
+ (int-to-string (- backslashes codeblocks))))
+ ;; If `stop-eventually' and `addtochecksum' are nil we have a problem.
+ (setq checksum-error 'stop))
+ (if checksum-error
+ (progn
+ (push-mark opoint)
+ (goto-char leave-me-here)
+ checksum-error)
+ (goto-char leave-me-here)))))
+
+;;;;;; API FUNCTIONS
+
+;;; FIX: are set-outlinevars and set-parvars API?
+;;; if not, then should give abstract description of what
+;;; this func does.
+(defun stx-set-vars ()
+ "Call `stx-set-outlinevars' with appropriate args, then `stx-set-parvars'."
+ (interactive)
+ (if (equal major-mode 'doctex-mode)
+ (stx-set-outlinevars dtx-sectioning-commands dtx-sectioning-offset t)
+ (stx-set-outlinevars stx-sectioning-commands stx-sectioning-offset nil))
+ (stx-set-parvars))
+(defmacro stx-merge-list (old new &optional warn)
+ "Modify a list OLD to include all NEW's elements not in OLD.
+Compare elements with `equal'. New elements are added at the end of OLD. NEW
+and OLD can be both lists or both alists. NEW or OLD or both can be null.
+Duplicate elements in NEW will not be duplicated in OLD. Returns OLD. NEW is
+not altered.
+
+For alists, add NEW's keys to end of OLD if OLD does not have them.
+If OLD does have a matching key, change its value to NEW's value for
+that key. The key is the car of each element, the value is the cdr.
+
+Optional WARN non-nil means print a message whenever the value of one
+of OLD's keys is being replaced.
+
+In the case that OLD is nil, this macro evaluates OLD twice, so do not call
+`merge-list' with a computed argument that has a side effect that shouldn't be
+done twice. The only alternative I see is to work like `add-to-list' and
+require a constant symbol name as an argument, effectively requiring you to
+compute things once before you call the function. NEW and WARN are evaluated
+exactly once."
+ `(let ((n ,new)
+ (o ,old)
+ (w ,warn))
+ (unless o
+ ;; Move the car of `n' to `o'. Then we proceed as if we started in
+ ;; this state. This filters duplicates from `new' as advertised,
+ ;; whereas setting `old' to 'new' would not. If `old' is the *constant*
+ ;; nil then we get an error from `set', which is what we want.
+ (setq o (set ',old (list (pop n)))))
+ (when n
+ ;; Assume that if the car of `o' is a list, then `o' is an alist,
+ ;; otherwise it is a list. Same for `n'.
+ (let ((old-is-alist (listp (car o)))
+ n-car)
+ (when (not (eq old-is-alist (listp (car n))))
+ (error "Arguments to `merge-list' must be both lists or both alists"))
+ (if old-is-alist
+ ;; `o' and `n' are alists and non-null
+ (while (setq n-car (pop n))
+ (let ((o-cons (assoc (car n-car) o)))
+ (if (null o-cons)
+ (nconc o (list n-car))
+ (when w
+ (message "merge-list: changing value of key %s from %s to %s"
+ (car o-cons) (cdr o-cons) (cdr n-car)))
+ (setcdr o-cons (cdr n-car)))))
+ ;; `old' and `new' are regular lists and non-null
+ (while (setq n-car (pop n))
+ (unless (member n-car o)
+ (nconc o (list n-car)))))))
+ o))
+
+;;; FIX: emacs-19 only, right?
+;; This function can cause screwups if byte-compiled, and if calling it is part
+;; of a hook that gets called by `get-buffer-create', for example if it's part
+;; of the hook belonging to your `default-major-mode'.
+(defun rx-catenate-or (strlist &rest strings)
+ "Catenate strings with `rx-or' between them.
+
+Return catenation with `rx-or' of the elements of STRLIST
+and optional STRINGS which follow. Ignore STRINGS that are
+nil and elements of STRLIST that are nil. Return nil if
+passed no strings at all.
+
+Empty strings will get catenated, and should probably not be
+passed to this function.
+
+STRINGS and the elements of STRLIST are expected to be
+strings or nil, but can be other types. See the source for
+full details.
+
+CAUTION: if you are experiencing strange bugs with this
+function, see the warning in \"swiftex.el\"."
+ (if (not (listp strlist))
+ (error "First arg %S to `rx-catenate-or' must be a list!" strlist))
+ (let* ((strlist (mapconcat (function identity) (delq nil strlist) rx-or))
+ (strings (mapconcat (function identity) (delq nil strings) rx-or))
+ (islist (not (string-equal "" strlist)))
+ (arestrings (not (string-equal "" strings))))
+ (if (and arestrings islist)
+ (concat strlist rx-or strings)
+ (if arestrings
+ strings
+ (if islist
+ strlist)))))
+
+;;;; EMACS FILE VARIABLES
+;;;
+;;; Local Variables:
+;;; mode: checkdoc-minor
+;;; fill-column: 60
+;;; End:
+;;;
+;;; swiftex.el ends here
diff --git a/support/emacs-modes/texheader.tex b/support/emacs-modes/texheader.tex
new file mode 100644
index 0000000000..53ab3bd1ae
--- /dev/null
+++ b/support/emacs-modes/texheader.tex
@@ -0,0 +1,2 @@
+\documentstyle[a4,dk,epsf]{article}
+\begin{document}
diff --git a/support/emacs-modes/textrailer.tex b/support/emacs-modes/textrailer.tex
new file mode 100644
index 0000000000..6b47932f52
--- /dev/null
+++ b/support/emacs-modes/textrailer.tex
@@ -0,0 +1 @@
+\end{document}
diff --git a/support/emacs-modes/u8tex.el b/support/emacs-modes/u8tex.el
new file mode 100644
index 0000000000..878336c4d9
--- /dev/null
+++ b/support/emacs-modes/u8tex.el
@@ -0,0 +1,536 @@
+;;; quail/u8tex.el -- Quail package to input in -*- coding: utf-8 -*-
+
+;; Copyright (C) 2000 Sergei Pokrovsky
+;; Time-stamp: <2000-12-08 19:00:30 pok>, v. 1.2
+
+;; Keywords: mule, multilingual, unicode, input method, TeX
+
+;; Based on definitions stolen from "unicode-input.el" by
+;; Florian Weimer <fw@s.netic.de>.
+
+;; The latest version is to be found at CTAN/support/emacs-modes/u8tex.el;
+;; e.g. <ftp://ftp.dante.de/tex-archive/support/emacs-modes/u8tex.el>.
+
+;; This file is not a 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 2, 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, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+;;
+;; This file is intended for use with Markus Kuhn's Unicode fonts,
+;; see <http://www.cl.cam.ac.uk/~mgk25/unicode.html>, and the
+;; Otfried Cheong's extension of Mule-UCS, available at
+;; <http://www.cs.uu.nl/~otfried/Mule/>.
+
+;; The idea is to provide a routine way to input the many TeX
+;; characters (and some more) using the familiar TeX notation. Surely
+;; it is not convenient for typing a French or German text, for which
+;; there are special packages; but I prefer to use it for a mixed
+;; text, where some accented characters from various languages occur
+;; sporadically, and it is better to type a longer key sequence
+;; /"Arger for Ärger rather than suffer from unexpected äny" when
+;; typing "any" (as it is usual with the shorter `"Arger' manner, or
+;; with o'clock becoming oćlock etc).
+
+;; I've taken some liberties with the TeX notation:
+;; 1. Backslash is replaced with solidus in its escape function. The
+;; reason is obvious: TeX users heavily use backspace for many other
+;; purposes as well.
+;; 2. The prefix "text" is systematically dropped; just /euro rather
+;; than /texteuro, /perthousand rather than \textperthousand.
+;; 3. No internal spaces, e.g. /cC rather than {/c C} or /c{C}.
+;; 4. /! and /? are used instead of !` and ?` -- like in EuroTeX,
+;; just to reduce the number of escape characters.
+;; 5. /3/4 etc is used instead of \textthreequarters.
+;; 6. If HTML offers a ahorter Latin-1 name, it is preferred:
+;; /reg rather than \textregistered, /nbsp rather than \nobreakspace,
+;; /copy rather than \copyright etc. (Such abbreviations are marked
+;; with "HTML" in a comment field.)
+
+;; Installation:
+
+;; Save this file as quail/u8tex.el (the "quail" may be your
+;; emacs/20.*/leim/quail or a directory on your load-path), byte
+;; compile it and put a record like this:
+;;
+;; (register-input-method
+;; "u8tex" "utf-8" 'quail-use-package
+;; "τεχ" "Unicode input using (Euro)TeX names"
+;; "quail/u8tex")
+;;
+;; into emacs/20.*/leim/leim-list.el (probably there exists a more
+;; civilized way to extend leim-list?). Then (after reloading Mule)
+;; you can switch to u8tex in the usual way (`C-x C-m C-\ u8tex'; the
+;; first u... is sufficient for completion in my environment).
+
+;;; Changes in v. 1.2:
+;; 1. Documentation (reference to Otfried's package).
+;; 2. Some HTML abbreviations are adopted (/copy, /reg etc).
+;; 3. Errors corrected: /permil
+;; 4. More amssymb characters.
+
+;;; Code:
+
+(require 'quail)
+
+(quail-define-package
+ "u8tex" "utf-8" "τεχ" t
+ "Input Unicode characters using (Euro)TeX names.
+Use solidus (/) instead of backslash as Mule escape.
+
+ effect | prefix | examples
+ ------------+--------+-------------------
+ acute | /' | /'a → á /'{} → Ì
+ grave | /` | /`a → à /`{} → ̀
+ circumflex | /^ | /^a → â /^{} → ̂
+ diæresis | /\" | /\"a → ä /\"{} → ̈
+ dot above | /. | /.z → ż /.I → İ
+ macron | /= | /=a → Ä /=e → Ä“ /=H → Ħ
+ breve, háÄek| /u /v | /ua → ă /vc → Ä
+ cedilla | /c | /cc → ç /cs → ş
+ ogonek | /k | /ka → ą /kE → Ę
+
+// → /; /lq → ‘; /glqq → „; /S → §; /AE → Æ; /DH → Ã; x^2 → x²; /div → ÷ etc.
+
+" nil t nil nil nil nil nil nil nil nil t)
+
+(quail-define-rules
+
+ ("/`A" ?À) ("/`a" ?à)
+ ("/`E" ?È) ("/`e" ?è)
+ ("/`I" ?Ì) ("/`i" ?ì)
+ ("/`O" ?Ò) ("/`o" ?ò)
+ ("/`U" ?Ù) ("/`u" ?ù)
+
+ ("/'A" ?Ã) ("/'a" ?á)
+ ("/'C" ?Ć) ("/'c" ?ć)
+ ("/'E" ?É) ("/'e" ?é)
+ ("/'I" ?Ã) ("/'i" ?í)
+ ("/'N" ?Ń) ("/'n" ?ń)
+ ("/'L" ?Ĺ) ("/'l" ?ĺ)
+ ("/'O" ?Ó) ("/'o" ?ó)
+ ("/'R" ?Å”) ("/'r" ?Å•)
+ ("/'S" ?Åš) ("/'s" ?Å›)
+ ("/'U" ?Ú) ("/'u" ?ú)
+ ("/'Y" ?Ã) ("/'y" ?ý)
+ ("/'Z" ?Ź) ("/'z" ?ź)
+
+ ("/^A" ?Â) ("/^a" ?â)
+ ("/^C" ?Ĉ) ("/^c" ?ĉ)
+ ("/^E" ?Ê) ("/^e" ?ê)
+ ("/^G" ?Äœ) ("/^g" ?Ä)
+ ("/^H" ?Ĥ) ("/^h" ?ĥ)
+ ("/^I" ?Î) ("/^i" ?î)
+ ("/^J" ?Ĵ) ("/^j" ?ĵ)
+ ("/^O" ?Ô) ("/^o" ?ô)
+ ("/^S" ?Åœ) ("/^s" ?Å)
+ ("/^U" ?Û) ("/^u" ?û)
+ ("/^W" ?Ŵ) ("/^w" ?ŵ)
+ ("/^Y" ?Ŷ) ("/^y" ?ŷ)
+
+ ("/~A" ?Ã) ("/~a" ?ã)
+ ("/~I" ?Ĩ) ("/~i" ?ĩ)
+ ("/~N" ?Ñ) ("/~n" ?ñ)
+ ("/~I" ?Ĩ) ("/~i" ?ĩ)
+ ("/~O" ?Õ) ("/~o" ?õ)
+ ("/~U" ?Ũ) ("/~u" ?ũ)
+
+ ("/rU" ?Ů) ("/ru" ?ů) ; \r[ing] like en EuroTeX
+
+ ("/\"A" ?Ä) ("/\"a" ?ä)
+ ("/\"E" ?Ë) ("/\"e" ?ë)
+ ("/\"I" ?Ã) ("/\"i" ?ï)
+ ("/\"O" ?Ö) ("/\"o" ?ö)
+ ("/\"U" ?Ü) ("/\"u" ?ü)
+ ("/\"Y" ?Ÿ) ("/\"y" ?ÿ)
+
+ ("/cC" ?Ç) ("/cc" ?ç)
+ ("/cG" ?Ä¢) ("/cg" ?Ä£) ; actually it must be comma
+ ("/cN" ?Ņ) ("/cn" ?ņ)
+ ("/cS" ?Åž) ("/cs" ?ÅŸ)
+ ("/cT" ?Å¢) ("/ct" ?Å£) ; actually it must be comma
+
+ ("/=A" ?Ä€) ("/=a" ?Ä)
+ ("/=E" ?Ä’) ("/=e" ?Ä“)
+ ("/=I" ?Ī) ("/=i" ?ī)
+ ("/=O" ?ÅŒ) ("/=o" ?Å)
+ ("/=U" ?Ū) ("/=u" ?ū)
+ ("/=H" ?Ħ) ("/=h" ?ħ) ; abuse
+ ("/=T" ?Ŧ) ("/=t" ?ŧ) ; abuse
+
+ ("/uA" ?Ă) ("/ua" ?ă)
+ ("/uE" ?Ä”) ("/ue" ?Ä•)
+ ("/uG" ?Äž) ("/ug" ?ÄŸ)
+ ("/uI" ?Ĭ) ("/ui" ?ĭ)
+ ("/uO" ?ÅŽ) ("/uo" ?Å)
+ ("/uU" ?Ŭ) ("/uu" ?ŭ)
+
+ ("/vC" ?ÄŒ) ("/vc" ?Ä)
+ ("/vD" ?ÄŽ) ("/vd" ?Ä)
+ ("/vE" ?Äš) ("/ve" ?Ä›)
+ ("/vL" ?Ľ) ("/vl" ?ľ)
+ ("/vN" ?Ň) ("/vn" ?ň)
+ ("/vR" ?Ř) ("/vr" ?ř)
+ ("/vS" ?Å ) ("/vs" ?Å¡)
+ ("/vT" ?Ť) ("/vt" ?ť)
+ ("/vZ" ?Ž) ("/vz" ?ž)
+
+ ("/.A" ?Ȧ) ("/.a" ?ȧ)
+ ("/.C" ?ÄŠ) ("/.c" ?Ä‹)
+ ("/.E" ?Ä–) ("/.e" ?Ä—)
+ ("/.G" ?Ä ) ("/.g" ?Ä¡)
+ ("/.I" ?İ) ("/i" ?ı) ; also \imath
+ ("/.O" ?Ȯ) ("/.o" ?ȯ)
+ ("/.Z" ?Ż) ("/.z" ?ż)
+
+ ("/HO" ?Å) ("/Ho" ?Å‘)
+ ("/HU" ?Ű) ("/Hu" ?ű)
+
+ ("/kA" ?Ä„) ("/ka" ?Ä…)
+ ("/kE" ?Ę) ("/ke" ?ę)
+ ("/kI" ?Į) ("/ki" ?į)
+ ("/kU" ?Ų) ("/ku" ?ų)
+
+ ("/AA" ?Ã…) ("/aa" ?Ã¥)
+ ("/AE" ?Æ) ("/ae" ?æ)
+ ("/DH" ?Ã) ("/dh" ?ð)
+ ("/DJ" ?Ä) ("/dj" ?Ä‘)
+ ("/Y" ?IJ) ("/y" ?ij) ; Dutch ij
+ ("/L" ?Å) ("/l" ?Å‚)
+ ("/Lp" ?Ŀ) ("/lp" ?ŀ) ; Catalan l dot, as in paraŀlel
+ ("/NG" ?ÅŠ) ("/ng" ?Å‹)
+ ("/O" ?Ø) ("/o" ?ø)
+ ("/OE" ?Å’) ("/oe" ?Å“)
+ ("/longs" ?Å¿)
+ ("/ss" ?ß)
+ ("/st" ?ſt) ; or ?st
+ ("/TH" ?Þ) ("/th" ?þ)
+
+ ;; Lowercase Greek letters
+ ;; (the missing caps like \Alpha come first)
+
+ ("/Alpha" ?Α) ("/alpha" ?α)
+ ("/Beta" ?Β) ("/beta" ?β)
+ ("/gamma" ?γ) ("/Gamma" ?Γ)
+ ("/delta" ?δ) ("/Delta" ?Δ)
+ ("/Epsilon" ?Ε) ("/epsilon" ?ε)
+ ("/Zeta" ?Ζ) ("/zeta" ?ζ)
+ ("/Eta" ?Η) ("/eta" ?η)
+ ("/theta" ?θ) ("/vartheta" ?ϑ) ("/Theta" ?Θ)
+ ("/Iota" ?Ι) ("/iota" ?ι)
+ ("/Kappa" ?Κ) ("/kappa" ?κ)
+ ("/lambda" ?λ) ("/Lambda" ?Λ)
+ ("/Mu" ?Μ) ("/mu" ?μ)
+ ("/Nu" ?Î) ("/nu" ?ν)
+ ("/Omicron" ?Ο) ("/omicron" ?ο)
+ ("/xi" ?ξ) ("/Xi" ?Ξ)
+ ("/pi" ?π) ("/varpi" ?ϖ) ("/Pi" ?Π)
+ ("/Rho" ?Ρ) ("/rho" ?Ï) ("/varrho" ?ϱ)
+ ("/sigma" ?σ) ("/varsigma" ?ς) ("/Sigma" ?Σ)
+ ("/Tau" ?Τ) ("/tau" ?τ)
+ ("/upsilon" ?Ï…) ("/Upsilon" ?Î¥)
+ ("/phi" ?ϕ) ("/varphi" ?φ) ("/Phi" ?Φ)
+ ("/Chi" ?Χ) ("/chi" ?χ)
+ ("/psi" ?ψ) ("/Psi" ?Ψ)
+ ("/omega" ?ω) ("/Omega" ?Ω)
+
+ ;; Miscellaneous symbols
+
+ ("/aleph" ?ℵ) ("/beth" ?ℶ) ("/gimel" ?ℷ) ("/daleth" ?ℸ)
+ ("/hbar" ?â„)
+ ("/imath" ?ı)
+ ("/ell" ?â„“)
+ ("/wp" ?℘)
+ ("/Re" ?ℜ) ("/Im" ?ℑ)
+ ("/partial" ?∂)
+ ("/infty" ?∞)
+ ("/prime" ?′)
+ ("/emptyset" ?∅)
+ ("/nabla" ?∇)
+ ("/surd" ?√)
+ ("/top" ?⊤)
+ ("/bot" ?⊥)
+ ("/|" ?∥)
+ ("/angle" ?∠)
+ ("/triangle" ?â–³)
+ ("/backslash" ?\\)
+ ("//" ?/) ; special !!
+ ("/forall" ?∀) ("/exists" ?∃)
+ ("/neg" ?¬)
+ ("/flat" ?♭) ("/natural" ?♮) ("/sharp" ?♯)
+ ("/clubsuit" ?♣) ("/diamondsuit" ?♢)
+ ("/heartsuit" ?♡) ("/spadesuit" ?♠)
+ ("/mho" ?℧) ("/complement" ?âˆ) ("/lozenge" ?â—Š) ; amssymb
+ ("/square" ?â–¡) ("/blacksquare" ?â– ) ; amssymb
+ ("/barwedge" ?⊼) ("/veebar" ?⊻) ; amssymb
+
+ ;; “Large†operators
+
+ ("/sum" ?∑)
+ ("/prod" ?âˆ)
+ ("/coprod" ?âˆ)
+ ("/int" ?∫)
+ ("/oint" ?∮)
+ ("/bigcap" ?â‹‚)
+ ("/bigcup" ?⋃)
+ ("/bigvee" ?â‹)
+ ("/bigwedge" ?â‹€)
+
+ ;; Binary operations
+
+ ("/pm" ?±) ("/mp" ?∓)
+ ("/setminus" ?∖)
+ ("/cdot" ?⋅) ("/times" ?×)
+ ("/ast" ?∗) ("/star" ?⋆)
+ ("/diamond" ?â‹„)
+ ("/circ" ?∘)
+ ("/bullet" ?∙)
+ ("/div" ?÷)
+ ("/cap" ?∩) ("/cup" ?∪)
+ ("/uplus" ?⊎)
+ ("/sqcap" ?⊓) ("/sqcup" ?⊔)
+ ("/triangleleft" ?â—)
+ ("/triangleright" ?â–·)
+ ("/wr" ?≀)
+ ("/bigcirc" ?â—¯)
+ ("/bigtriangleup" ?â–³) ("/bigtriangledown" ?â–½)
+ ("/vee" ?∨) ("/wedge" ?∧)
+ ("/oplus" ?⊕) ("/ominus" ?⊖)
+ ("/otimes" ?⊗) ("/oslash" ?⊘)
+ ("/odot" ?⊙)
+ ("/dagger" ?†) ("/ddagger" ?‡)
+ ("/amalg" ?âˆ)
+
+ ;; Relations
+
+ ("/leq" ?≤)
+ ("/prec" ?≺) ("/preceq" ?≼)
+ ("/ll" ?≪)
+ ("/subset" ?⊂) ("/subseteq" ?⊆)
+ ("/sqsubseteq" ?⊑)
+ ("/in" ?∈)
+ ("/vdash" ?⊢)
+ ("/smile" ?⌣)
+ ("/frown" ?⌢)
+ ("/geq" ?≥)
+ ("/succ" ?≻) ("/succeq" ?≽)
+ ("/gg" ?≫)
+ ("/supset" ?⊃) ("/supseteq" ?⊇)
+ ("/sqsupseteq" ?⊒)
+ ("/ni" ?∋)
+ ("/dashv" ?⊣)
+ ("/mid" ?∣)
+ ("/parallel" ?∥)
+ ("/equiv" ?≡)
+ ("/sim" ?∼) ("/simeq" ?≃)
+ ("/asymp" ?â‰)
+ ("/approx" ?≈)
+ ("/cong" ?≅)
+ ("/bowtie" ?⋈)
+ ("/propto" ?âˆ)
+ ("/models" ?⊨)
+ ("/doteq" ?â‰)
+ ("/perp" ?⊥)
+
+ ;; Negated relations
+
+ ("/not<" ?≮)
+ ("/not/leq" ?≰)
+ ("/not/prec" ?⊀) ("/not/preceq" ?⋠)
+ ("/not/subset" ?⊄) ("/not/subseteq" ?⊈)
+ ("/not/sqsubseteq" ?â‹¢)
+ ("/not>" ?≯)
+ ("/not/geq" ?≱)
+ ("/not/succ" ?âŠ) ("/not/succeq" ?â‹¡)
+ ("/not/supset" ?⊅) ("/not/supseteq" ?⊉)
+ ("/not/sqsupseteq" ?â‹£)
+ ("/not=" ?≠)
+ ("/not/equiv" ?≢)
+ ("/not/sim" ?â‰) ("/not/simeq" ?≄)
+ ("/not/approx" ?≉)
+ ("/not/cong" ?≇)
+ ("/not/asymp" ?≭)
+
+ ;; Arrows
+
+ ("/leftarrow" ?â†) ("/Leftarrow" ?â‡)
+ ("/rightarrow" ?→) ("/Rightarrow" ?⇒)
+ ("/leftrightarrow" ?↔) ("/Leftrightarrow" ?⇔)
+ ("/mapsto" ?↦)
+ ("/hookleftarrow" ?↩)
+ ("/leftharpoonup" ?↼)
+ ("/leftharpoondown" ?↽)
+ ("/rightleftharpoons" ?⇌)
+ ("/hookrightarrow" ?↪)
+ ("/rightharpoonup" ?⇀)
+ ("/rightharpoondown" ?â‡)
+ ("/searrow" ?↘)
+ ("/swarrow" ?↙)
+ ("/nwarrow" ?↖)
+ ("/uparrow" ?↑) ("/Uparrow" ?⇑)
+ ("/downarrow" ?↓) ("/Downarrow" ?⇓)
+ ("/updownarrow" ?↕) ("/Updownarrow" ?⇕)
+ ("/nearrow" ?↗)
+
+ ;; Openings ;; Closings
+
+ ("/lfloor" ?⌊) ("/rfloor" ?⌋)
+ ("/langle" ?〈) ("/rangle" ?〉)
+ ("/lceil" ?⌈) ("/rceil" ?⌉)
+
+ ;; Alternate names
+
+ ("/ne" ?≠) ("/neq" ?≠)
+ ("/le" ?≤) ("/ge" ?≥)
+ ("/to" ?→)
+ ("/gets" ?â†)
+ ("/owns" ?∋)
+ ("/land" ?∧)
+ ("/lor" ?∨)
+ ("/lnot" ?¬)
+ ("/vert" ?∣)
+ ("/Vert" ?∥)
+
+ ;; Non-math symbols
+
+ ("/S" ?§) ("/P" ?¶)
+ ("/dag" ?†) ("/ddag" ?‡)
+ ("/brokenbar" ?¦)
+ ("/brvbar" ?¦) ; like in HTML
+ ("/reg" ?®) ; like in HTML, unlike TeX's /registered
+ ("/trade" ?â„¢) ; like in HTML
+ ("/frownie" ?☹)
+ ("/smiley" ?☺)
+ ("/blacksmiley" ?☻)
+
+ ;; Typographic symbols and ligatures
+
+ ("''" ?â€) ("``" ?“)
+ ("/lq" ?‘) ("/rq" ?’)
+ ("/flqq" ?«) ("/frqq" ?») ; French double quotes
+ ("/flq" ?‹) ("/frq" ?›) ; French double quotes
+ ("/glqq" ?„) ("/grqq" ?‟) ; German double quotes
+ ("/glq" ?‚) ("/grq" ?‛) ; German single quotes
+ ("/dots" ?…)
+ ("/-" ?â€) ; 2010 (HYPHEN)
+ ("/--" ?–) ; 2013 (EN DASH)
+ ("/---" ?—) ; 2014 (EM DASH)
+ ("/minus" ?−) ; 2212 (MINUS SIGN)
+ ("/nbsp" ? ) ; A0 (NO-BREAK SPACE), like in HTML
+; ("/thinspace" ? )
+; ("/," ? )
+ ("/ff" ?ff)
+ ("/fi" ?ï¬)
+ ("/fl" ?fl)
+ ("/ffi" ?ffi)
+ ("/ffl" ?ffl)
+ ("/!" ?¡) ("/?" ?¿); as in EuroTeX
+ ("/copy" ?©) ; like in HTML, unlike TeX's \copyright
+ ("/permil" ?‰) ; HTML (= PER MILLE SIGN) and wasysym
+ ("/perthousand" ?‰); \textperthousand
+ ("/micro" ?µ) ; different from GREEK SMALL LETTER /mu
+ ("/deg" ?°) ; like in HTML, unlike TeX's \textdegree
+ ("/1/4" ?¼) ; \textonequarter
+ ("/1/2" ?½) ; \textonehalf
+ ("/3/4" ?¾) ; \textthreequarters
+
+ ;; Combining characters
+
+ ("/'{}" ?Ì)
+ ("/`{}" ?Ì€)
+ ("/^{}" ?Ì‚)
+ ("/\"{}" ?̈)
+ ("/~{}" ?̃)
+ ("/={}" ?¯) ; or else COMBINING MACRON = ("/={}" ?̄) ?
+ ("/.{}" ?̇)
+ ("/u{}" ?̆)
+ ("/v{}" ?̌)
+ ("/H{}" ?Ì‹)
+ ("/t{}" ?Í¡)
+ ("/c{}" ?̧)
+ ("/d{}" ?Ì£)
+ ("/b{}" ?̱)
+
+ ;; Subscripts
+
+ ("_0" ?â‚€) ("_1" ?â‚) ("_2" ?â‚‚) ("_3" ?₃) ("_4" ?â‚„)
+ ("_5" ?₅) ("_6" ?₆) ("_7" ?₇) ("_8" ?₈) ("_9" ?₉)
+ ("_+" ?₊) ("_-" ?₋) ("_=" ?₌)
+ ("_(" ?â‚) ("_)" ?â‚Ž)
+
+
+ ;; Superscripts
+
+ ("^0" ?â°) ("^1" ?¹) ("^2" ?²) ("^3" ?³) ("^4" ?â´)
+ ("^5" ?âµ) ("^6" ?â¶) ("^7" ?â·) ("^8" ?â¸) ("^9" ?â¹)
+ ("^+" ?âº) ("^-" ?â») ("^=" ?â¼)
+ ("^(" ?â½) ("^)" ?â¾)
+ ("^a" ?ª) ("^n" ?â¿) ("^o" ?º)
+
+ ;; Currency signs
+
+ ("/cent" ?¢) ; after HTML and wasy
+ ("/pound" ?£) ; after HTML
+ ("/curren" ?¤) ; like in HTML, cf \textcurrency
+ ("/euro" ?€) ; \texteuro
+ ("/yen" ?Â¥) ; \textyen
+
+ ;; \mathbb
+
+ ("/bbC" ?â„‚) ("/bbH" ?â„) ("/bbN" ?â„•) ("/bbP" ?â„™)
+ ("/bbQ" ?â„š) ("/bbR" ?â„) ("/bbZ" ?ℤ)
+
+;; IPA (there is a dedicated MULE method!)
+
+ ("/turna" ?É)
+ ("/scripta" ?É‘)
+ ("/turnscripta" ?É’)
+ ("/turnv" ?ʌ)
+ ("/dezh" ?ʤ)
+ ("/schwa" ?É™) ("/inve" ?É™)
+ ("/schwahook" ?Éš)
+ ("/scriptg" ?É¡)
+ ("/turnh" ?É¥)
+ ("/openo" ?É”)
+ ("/scr" ?Ê€)
+ ("/invscr" ?Ê)
+ ("/tesh" ?ʧ)
+ ("/upsilon" ?ÊŠ)
+ ("/turnw" ?Ê)
+ ("/turny" ?ÊŽ)
+ ("/esh" ?ʃ)
+ ("/ezh" ?Ê’)
+ ("/long" ?Ë)
+ ("/stress" ?ˈ) ; primary stress
+ ("/secstress" ?ˌ) ; secondary stress
+
+; Ancient Cyrillic (after x2enc):
+
+ ("/FITA" ?Ѳ) ("/fita" ?ѳ)
+ ("/YAT" ?Ñ¢) ("/yat" ?Ñ£)
+ ("/BYUS" ?Ѫ) ("/byus" ?ѫ)
+ ("/LYUS" ?Ѧ) ("/lyus" ?ѧ)
+ ("/CYREPS" ?Є) ("/cyreps" ?є)
+ ("/IE" ?Ѥ) ("/ie" ?ѥ)
+ ("/`I" ?Ð) ("/`i" ?Ñ)
+ ("/OT" ?Ѿ) ("/ot" ?ѿ)
+ ("/UK" ?Ѹ) ("/uk" ?ѹ)
+ ("/IZH" ?Ѵ) ("/izh" ?ѵ)
+ ("/\"IZH" ?Ѷ) ("/\"izh" ?ѷ)
+
+)
+
+;;; u8tex.el ends here
diff --git a/support/emacs-modes/weave.ch b/support/emacs-modes/weave.ch
new file mode 100644
index 0000000000..3fd8f533c7
--- /dev/null
+++ b/support/emacs-modes/weave.ch
@@ -0,0 +1,626 @@
+% Change file for the WEAVE processor, for use on Berkeley UNIX systems.
+% This file was created by Howard Trickey and Pavel Curtis.
+
+% History:
+% 11/29/82 HWT Original version. This modifies weave to allow a new
+% control sequence:
+% @=...text...@> Put ...text... verbatim on a line
+% by itself in the Pascal output.
+% (argument must fit on one line)
+% This control sequence facilitates putting #include "gcons.h"
+% (for example) in files meant for the pc compiler.
+% Also, there is a command line option, -c, which means that
+% only the modules affected by the change file are to generate
+% TeX output. (All the limbo stuff still goes to the output
+% file, as does the index and table of contents.)
+%
+% 2/12/83 HWT Brought up for use with version 1.3. Uses Knuth's new
+% control sequences for verbatim Pascal (as above, without
+% the "on one line" part), and the force_line (@\) primitive.
+% Also, he added stuff to keep track of changed modules, and
+% output enough information that macros can choose only to
+% print changed modules. This isn't as efficient as my
+% implementation because I avoided outputting the text for
+% non-changed modules altogether, but this feature won't be
+% used too often (just for TeX and TeXware), so Knuth's
+% solution is accepted.
+% The change file changes that used
+% to implement these features have been removed.
+% There is a -x flag to cause WEAVE to omit cross referencing
+% of identifiers, and index and T.of.C. processing.
+% This, too, is unnecessary, for one could simply redefine some
+% WEB macros to avoid the printing, but there are only a couple
+% of easy changes, so they have been made.
+%
+% 2/18 HWT Increased stack size to 400 (not for TeX-related programs).
+%
+% 3/18 HWT Brought up for Version 1.5. Made it print newline at end of
+% run.
+%
+% 4/13 PC Merged with Pavel's version, including adding a call to
+% exit() at the end of the program, based upon the value of
+% `history'.
+% 4/16 PC Brought up to version 1.5 released with TeX 0.97 in April 1983
+% 6/29 HWT Brought up to version 1.7 released with TeX 0.99 in June 1983,
+% introducing a new change file format
+% 7/17 HWT Brought up to version 2.0 released with TeX 0.999 in July 1983
+% 7/29 HWT Brought up to version 2.1
+% 11/17 HWT Brought up to version 2.4 released with TeX 1.0. Made
+% changes to use C routines for I/O, for speedup.
+% 1/31 HWT Brought up to version 2.6
+% 12/28/85 PAM Brought up to version 2.8 (like 2.7, version number only)
+% 3/6/87 PAM Brought up to version 2.9 (like 2.8, version number only)
+% 8/10/89 don Brought up to version 3.1, with `otherwise' fixed too
+% 8/31/89 don Brought up to version 4, with all possible characters enabled
+% 10/16/89 don fixed bug when ".web" and ".ch" are explicitly stated
+
+% NOTE: The module numbers refer to the standard WEB manual (CS 980).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [0] WEAVE: print changes only
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+\pageno=\contentspagenumber \advance\pageno by 1
+@y
+\pageno=\contentspagenumber \advance\pageno by 1
+\let\maybe=\iffalse
+\def\title{WEAVE changes for Berkeley {\mc UNIX}}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1] Change banner message
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d banner=='This is WEAVE, Version 4'
+@y
+@d banner=='This is WEAVE, Version 4 for SunOS'
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [2] add input and output, remove other files, add ref to scan_args,
+% [2] and #include external definition for exit(), etc.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+program WEAVE(@!web_file,@!change_file,@!tex_file);
+label end_of_WEAVE; {go here to finish}
+const @<Constants in the outer block@>@/
+type @<Types in the outer block@>@/
+var @<Globals in the outer block@>@/
+@<Error handling procedures@>@/
+@y
+program WEAVE(@!input,@!output);
+label end_of_WEAVE; {go here to finish}
+const @<Constants in the outer block@>@/
+type @<Types in the outer block@>@/
+var @<Globals in the outer block@>@/
+@\
+@=#include "tangext.h"@>
+@\@/
+@<Error handling procedures@>@/
+@<|scan_args| procedure@>@/
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3] Show statistics
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d stat==@{ {change this to `$\\{stat}\equiv\null$'
+ when gathering usage statistics}
+@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$'
+ when gathering usage statistics}
+@y
+@d stat== {I'm gathering usage statistics}
+@d tats== {because I have to know how close \TeX\ comes to the limits}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [4] compiler options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead}
+@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging}
+@y
+@=(*$C-*)@> {no range check}
+@!debug @=(*$C+*)@>@+ gubed {but turn everything on when debugging}
+@\
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [7] Fix others:
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d othercases == others: {default for cases not listed explicitly}
+@y
+@d othercases == otherwise {SunOS Pascal default cases}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [8] Constants: Make stack_size=400 instead of 200
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@!stack_size=200; {number of simultaneous output levels}
+@y
+@!stack_size=400; {number of simultaneous output levels}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [17] enable maximum character set
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+for i:=1 to @'37 do xchr[i]:=' ';
+for i:=@'200 to @'377 do xchr[i]:=' ';
+@y
+for i:=1 to @'37 do xchr[i]:=chr(i);
+for i:=@'200 to @'377 do xchr[i]:=chr(i);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [20] terminal output: use standard i/o
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@y
+@d term_out==output
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@z
+
+@x
+@<Globals...@>=
+@!term_out:text_file; {the terminal as an output file}
+@y
+
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [21] init terminal
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ Different systems have different ways of specifying that the output on a
+certain file will appear on the user's terminal. Here is one way to do this
+on the \PASCAL\ system that was used in \.{TANGLE}'s initial development:
+@^system dependencies@>
+
+@<Set init...@>=
+rewrite(term_out,'TTY:'); {send |term_out| output to the terminal}
+@y
+@ Different systems have different ways of specifying that the output on a
+certain file will appear on the user's terminal.
+@^system dependencies@>
+
+@<Set init...@>=
+; {nothing need be done}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [22] flush terminal buffer
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d update_terminal == break(term_out) {empty the terminal output buffer}
+@y
+@d update_terminal == flush(term_out) {empty the terminal output buffer}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [24] open input files
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ The following code opens the input files. Since these files were listed
+in the program header, we assume that the \PASCAL\ runtime system has
+already checked that suitable file names have been given; therefore no
+additional error checking needs to be done. We will see below that
+\.{WEAVE} reads through the entire input twice.
+@^system dependencies@>
+
+@p procedure open_input; {prepare to read |web_file| and |change_file|}
+begin reset(web_file); reset(change_file);
+end;
+@y
+@ The following code opens the input files.
+This is called after |scan_args| has filled the file name variables
+appropriately.
+@^system dependencies@>
+
+@p procedure open_input; {prepare to read |web_file| and |change_file|}
+begin reset(web_file,web_name);
+ reset(change_file,change_name);
+end;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [26] opening tex file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ The following code opens |tex_file|.
+Since this file was listed in the program header, we assume that the
+\PASCAL\ runtime system has checked that a suitable external file name has
+been given.
+@^system dependencies@>
+
+@<Set init...@>=
+rewrite(tex_file);
+@y
+@ The following code opens |tex_file|.
+The |scan_args| procedure is used to set up |tex_name| as required.
+@^system dependencies@>
+
+@<Set init...@>=
+scan_args;
+rewrite(tex_file,tex_name);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [28] faster input_ln
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@p function input_ln(var f:text_file):boolean;
+ {inputs a line or returns |false|}
+var final_limit:0..buf_size; {|limit| without trailing blanks}
+begin limit:=0; final_limit:=0;
+if eof(f) then input_ln:=false
+else begin while not eoln(f) do
+ begin buffer[limit]:=xord[f^]; get(f);
+ incr(limit);
+ if buffer[limit-1]<>" " then final_limit:=limit;
+ if limit=buf_size then
+ begin while not eoln(f) do get(f);
+ decr(limit); {keep |buffer[buf_size]| empty}
+ if final_limit>limit then final_limit:=limit;
+ print_nl('! Input line too long'); loc:=0; error;
+@.Input line too long@>
+ end;
+ end;
+ read_ln(f); limit:=final_limit; input_ln:=true;
+ end;
+end;
+@y
+With Berkeley {\mc UNIX} we call an external C procedure, |line_read|.
+That routine fills |buffer| from 0 onwards with the |xord|'ed values
+of the next line, setting |limit| appropriately (ignoring trailing
+blanks).
+It will stop if |limit=buf_size|, and the following will cause an error
+message.
+Note: for bootstrapping purposes it is all right to use the original form
+of |input_ln|; it will just run slower.
+
+@p function input_ln(var f:text_file):boolean;
+ {inputs a line or returns |false|}
+begin limit:=0;
+if test_eof(f) then input_ln:=false
+else begin line_read(f);
+ if limit=buf_size then
+ begin
+ decr(limit); {keep |buffer[buf_size]| empty}
+ print_nl('! Input line too long'); loc:=0; error;
+@.Input line too long@>
+ end;
+ input_ln:=true;
+ end;
+end;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [50] don't enter xrefs if no_xref set
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d append_xref(#)==if xref_ptr=max_refs then overflow('cross reference')
+ else begin incr(xref_ptr); num(xref_ptr):=#;
+ end
+
+@p procedure new_xref(@!p:name_pointer);
+label exit;
+var q:xref_number; {pointer to previous cross reference}
+@!m,@!n: sixteen_bits; {new and previous cross-reference value}
+begin if (reserved(p)or(byte_start[p]+1=byte_start[p+ww]))and
+@y
+If the user has sent the |no_xref| flag (the -x option of the command line),
+then it is unnecessary to keep track of cross references for identifers.
+If one were careful, one could probably make more changes around module
+100 to avoid a lot of identifier looking up.
+
+@d append_xref(#)==if xref_ptr=max_refs then overflow('cross reference')
+ else begin incr(xref_ptr); num(xref_ptr):=#;
+ end
+
+@p procedure new_xref(@!p:name_pointer);
+label exit;
+var q:xref_number; {pointer to previous cross-reference}
+@!m,@!n: sixteen_bits; {new and previous cross-reference value}
+begin if no_xref then return;
+if (reserved(p)or(byte_start[p]+1=byte_start[p+ww]))and
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [122] faster flush_buffer
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+done: for k:=1 to j do write(tex_file,xchr[out_buf[k]]);
+@y
+done: linewrite(tex_file,j);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [239] omit index and module names if no_xref set
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@* Phase three processing.
+We are nearly finished! \.{WEAVE}'s only remaining task is to write out the
+index, after sorting the identifiers and index entries.
+
+@<Phase III: Output the cross-reference index@>=
+phase_three:=true; print_nl('Writing the index...');
+if change_exists then
+ begin finish_line; @<Tell about changed modules@>;
+ end;
+finish_line; out4("\")("i")("n")("x"); finish_line;
+@.\\inx@>
+@<Do the first pass of sorting@>;
+@<Sort and output the index@>;
+out4("\")("f")("i")("n"); finish_line;
+@.\\fin@>
+@<Output all the module names@>;
+out4("\")("c")("o")("n"); finish_line;
+@.\\con@>
+print('Done.');
+@y
+@* Phase three processing.
+We are nearly finished! \.{WEAVE}'s only remaining task is to write out the
+index, after sorting the identifiers and index entries.
+
+If the user has set the |no_xref| flag (the -x option on the command line),
+just finish off the page, omitting the index, module name list, and table of
+contents.
+
+@<Phase III: Output the cross-reference index@>=
+if no_xref then begin
+ finish_line;
+ out("\"); out5("v")("f")("i")("l")("l");
+ out4("\")("e")("n")("d");
+ finish_line;
+ end
+else begin
+phase_three:=true; print_nl('Writing the index...');
+finish_line;
+out("\"); out5("i")("n")("p")("u")("t"); out(" ");
+out5("I")("N")("D")("E")("X");
+finish_line;
+out("\"); out5("i")("n")("p")("u")("t"); out5(" ")("M")("O")("D")("U");
+out5("L")("E")("_")("N")("A"); out3("M")("E")("S");
+finish_line;
+rewrite(tex_file,'INDEX.tex');
+if change_exists then
+ begin @<Tell about changed modules@>;
+ end;
+finish_line; finish_line; out4("\")("i")("n")("x"); finish_line;
+@.\\inx@>
+@<Do the first pass of sorting@>;
+@<Sort and output the index@>;
+out4("\")("f")("i")("n"); finish_line;
+@.\\fin@>
+rewrite(tex_file,'MODULE_NAMES.tex');
+@<Output all the module names@>;
+out4("\")("c")("o")("n"); finish_line;
+@.\\con@>
+print('Done.');
+end;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [258] term_in == input, when debugging
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+any error stop will set |debug_cycle| to zero.
+@y
+any error stop will set |debug_cycle| to zero.
+
+@d term_in==input
+@z
+
+@x
+@!term_in:text_file; {the user's terminal as an input file}
+@y
+
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [259] Take out reset(term_in)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+reset(term_in,'TTY:','/I'); {open |term_in| as the terminal, don't do a |get|}
+@y
+
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [261] print newline at end of run and exit based upon value of history
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@p procedure Phase_I;
+@y
+@d UNIXexit==e@&x@&i@&t
+
+@p procedure Phase_I;
+@z
+
+@x
+end.
+@y
+new_line;
+if (history <> spotless) and (history <> harmless_message) then
+ UNIXexit(1)
+else
+ UNIXexit(0);
+end.
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [264] system dependent changes--the scan_args procedure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@* System-dependent changes.
+This module should be replaced, if necessary, by changes to the program
+that are necessary to make \.{WEAVE} work at a particular installation.
+It is usually best to design your change file so that all changes to
+previous modules preserve the module numbering; then everybody's version
+will be consistent with the printed program. More extensive changes,
+which introduce new modules, can be inserted here; then only the index
+itself will get a new module number.
+@^system dependencies@>
+@y
+@* System-dependent changes.
+The user calls \.{WEAVE} with arguments on the command line.
+These are either file names or flags (beginning with '-').
+The following globals are for communicating the user's desires to the rest
+of the program. The various |file_name| variables contain strings with
+the full names of those files, as UNIX knows them.
+
+The only flag that affects weave is |'-x'| whose status is kept in |no_xref|.
+
+@d max_file_name_length==60
+
+@<Globals...@>=
+@!web_name,@!change_name,@!tex_name:
+ array[1..max_file_name_length] of char;
+@!no_xref:boolean;
+
+@ The |scan_args| procedure looks at the command line arguments and sets
+the |file_name| variables accordingly.
+At least one file name must be present: the \.{WEB} file. It may have
+an extension, or it may omit it to get |'.web'| added.
+The \TeX\ output file name is formed by replacing the \.{WEB} file
+name extension by |'.tex'|.
+
+If there is another file name present among the arguments, it is the
+change file, again either with an extension or without one to get |'.ch'|
+An omitted change file argument means that |'/dev/null'| should be used,
+when no changes are desired.
+
+An argument beginning with a minus sign is a flag.
+Any letters following the minus sign may cause global flag variables to be
+set.
+Currently, an |x| means that the cross referencing information---the index,
+the module name list, and the table of contents---is to be suppressed.
+
+@<|scan_args|...@>=
+procedure scan_args;
+var dot_pos,i,a: integer; {indices}
+@!fname: array[1..max_file_name_length-5] of char; {temporary argument holder}
+@!found_web,@!found_change: boolean; {|true| when those file names have
+ been seen}
+begin
+found_web:=false;
+found_change:=false;
+no_xref:=false;
+for a:=1 to argc-1 do begin
+ argv(a,fname); {put argument number |a| into |fname|}
+ if fname[1]<>'-' then begin
+ if not found_web then
+ @<Get |web_name|, |pascal_name|, and
+ | pool_name| variables from |fname|@>
+ else if not found_change then
+ @<Get |change_name| from |fname|@>
+ else @<Print usage error message and quit@>;
+ end
+ else @<Handle flag argument in |fname|@>;
+ end;
+if not found_web then @<Print usage error message and quit@>;
+if not found_change then @<Set up null change file@>;
+end;
+
+@ Use all of |fname| for the |web_name| if there is a |'.'| in it,
+otherwise add |'.web'|.
+The other file names come from adding things after the dot.
+The |argv| procedure will not put more than |max_file_name_length-5|
+characters into |fname|, and this leaves enough room in the |file_name|
+variables to add the extensions.
+
+The end of a file name is marked with a |' '|, the convention assumed by
+the |reset| and |rewrite| procedures.
+
+@<Get |web_name|...@>=
+begin
+dot_pos:=-1;
+i:=1;
+while (fname[i]<>' ') and (i<=max_file_name_length-5) do begin
+ web_name[i]:=fname[i];
+ if fname[i]='.' then dot_pos:=i;
+ incr(i);
+ end;
+if dot_pos=-1 then begin
+ dot_pos:=i;
+ web_name[dot_pos]:='.';
+ web_name[dot_pos+1]:='w';
+ web_name[dot_pos+2]:='e';
+ web_name[dot_pos+3]:='b';
+ web_name[dot_pos+4]:=' ';
+ end
+else web_name[i]:=' ';
+for i:=1 to dot_pos do begin
+ tex_name[i]:=web_name[i];
+ end;
+tex_name[dot_pos+1]:='t';
+tex_name[dot_pos+2]:='e';
+tex_name[dot_pos+3]:='x';
+tex_name[dot_pos+4]:=' ';
+found_web:=true;
+end
+
+@
+
+@<Get |change_name|...@>=
+begin
+dot_pos:=-1;
+i:=1;
+while (fname[i]<>' ') and (i<=max_file_name_length-5)
+do begin
+ change_name[i]:=fname[i];
+ if fname[i]='.' then dot_pos:=i;
+ incr(i);
+ end;
+if dot_pos=-1 then begin
+ dot_pos:=i;
+ change_name[dot_pos]:='.';
+ change_name[dot_pos+1]:='c';
+ change_name[dot_pos+2]:='h';
+ change_name[dot_pos+3]:=' ';
+ end
+else change_name[i]:=' ';
+found_change:=true;
+end
+
+@
+
+@<Set up null...@>=
+begin
+ change_name[1]:='/';
+ change_name[2]:='d';
+ change_name[3]:='e';
+ change_name[4]:='v';
+ change_name[5]:='/';
+ change_name[6]:='n';
+ change_name[7]:='u';
+ change_name[8]:='l';
+ change_name[9]:='l';
+ change_name[10]:=' ';
+end
+
+@
+
+@<Handle flag...@>=
+begin
+i:=2;
+while (fname[i]<>' ') and (i<=max_file_name_length-5) do begin
+ if fname[i]='x' then no_xref:=true;
+ incr(i);
+ end;
+end
+
+@
+
+@<Print usage error message and quit@>=
+begin
+print_nl('! Usage: weave webfile[.web] [changefile[.ch]] [-x]');
+error;
+jump_out;
+end
+
+@z
diff --git a/support/emacs-modes/web-mode-manual.tex b/support/emacs-modes/web-mode-manual.tex
new file mode 100644
index 0000000000..5dc62abf22
--- /dev/null
+++ b/support/emacs-modes/web-mode-manual.tex
@@ -0,0 +1,1526 @@
+\magnification=\magstep1
+\raggedbottom
+% Produce verbatim listings of various sorts
+\def\uncatcodespecials{\def\do##1{\catcode`##1=12 } \dospecials}
+\font\TT=cmtt9
+\def\setupverbatim{%
+ \par \TT \spaceskip=0pt % Make sure we get fixed tt spacing
+ \obeylines\uncatcodespecials\obeyspaces\verbatimdefs
+}
+% This macro turns on verbatim mode until ?endverbatim is seen.
+\def\verbatim{\begingroup \setupverbatim
+ \parskip=0pt plus .05\baselineskip \parindent=0pt
+ \catcode`\ =13 \catcode`\^^M=13 \catcode`\?=0
+ \verbatimgobble}
+{\catcode`\^^M=13{\catcode`\ =13\gdef\verbatimdefs{\def^^M{\ \par}\let =\ }}
+ \gdef\verbatimgobble#1^^M{}}
+% This defines ?endverbatim to end the group which begins with \verbatim
+\let\endverbatim=\endgroup
+% Input a file in verbatim mode. Sometimes useful for including
+% real-life examples into a paper.
+\def\verbfile#1{\begingroup\setupverbatim
+ \parskip=0pt plus .05\baselineskip \parindent=0pt
+ \input#1 \endgroup
+}
+
+\def\BIND#1#2{\kern2pt\hbox{\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt{\tt ESC C-#1 C-#2}\kern2pt}}
+ \hrule}\vrule}} % used to have a \kern2pt between the last }'s
+\def\Bind#1#2{\kern2pt\hbox{\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt{\tt C-#1 C-#2}\kern2pt}}
+ \hrule}\vrule}}
+
+
+\def\Web{{\tt WEB}}
+\def\BS{\tt\char'134}
+\def\Command#1#2#3#4{$$\line{{\hskip\parindent\tt #1}\hfil
+ \ifnum #4>2
+ \BIND{#2}{#3}%
+ \else
+ \ifnum #4=1
+ \Bind{#2}{#3}%
+ \else
+ \fi
+ \fi
+ }
+ $$%
+ }
+\abovedisplayskip=\smallskipamount
+\belowdisplayskip=\smallskipamount
+\parskip=10pt plus2pt minus2pt
+\overfullrule=0sp
+\font\logofont=logo10
+\def\MF{{\logofont META}\-{\logofont FONT}}
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps for names like UNIX
+\def\Unix{{\mc UNIX}} \let\unix=\Unix
+\font\BF=cmbx10 scaled \magstep2
+\font\Bf=cmbx10 scaled \magstep1
+\font\SS=cmss10
+\font\Tt=cmtt10 scaled \magstep1
+\null\vskip3pc
+\centerline{\BF A User's Manual for}
+\medskip
+\centerline{\BF GNU Emacs' WEB-MODE}
+\bigskip
+\centerline{\Bf Mark Motl}
+\centerline{\bf Department of Computer Science}
+\centerline{\bf \TeX{}as A\&M University}
+\centerline{\tt motl@cs.tamu.edu}
+\bigskip
+This document is a companion to {\tt web-mode.el}, a collection of GNU
+Emacs Lisp functions designed to customize GNU Emacs so that it is
+sensitive to a \Web\ document. Appendix A is a complete list of the
+functions.
+
+You should receive two files: {\tt web-mode.el \rm and \tt
+limbo.material}. The first is the source {\tt web-mode.el}\null. The
+second is statements that commonly appear in the limbo portion of a
+\Web. This `limbo' code is borrowed from some of Knuth's \Web{}s.
+
+Throughout this document, I will use the symbology used by Emacs. For
+example, the {\tt find-file} command can be entered two different ways
+\Command{M-x find-file}{x}{f}{1}
+The first way of entering the command is to actually type the command as
+shown above. Press the {\tt META} key (on some terminals this may be the
+{\tt ESC} key); next press the {\tt x} key; finally, enter the
+characters {\tt find-file} followed by a carriage return. An alternate
+way of issuing this command is to use its associated keybinding as shown
+in the box to the right of the command above. In this keybinding {\tt
+C-} refers to the {\tt CTRL} key. Press and hold down the {\tt CTRL} key
+and then press the {\tt x} key followed by holding down the {\tt CTRL}
+key and then pressing the {\tt f} key. For all commands mentioned
+throughout this manual, both forms of invoking the command will be shown
+if they exist. Some commands, such as
+\Command{M-x what-line}{}{}{0}
+do not have a keybinding and hence must be entered by typing in the
+command name. All commands that are \Web{} extensions have been prefixed
+with ``{\tt web-}''.
+
+I strongly encourage all users of {\tt web-mode.el} to {\it
+byte-compile\/} it. The byte-compiled code runs considerably faster
+than interpreted code. To byte-compile {\tt web-mode.el}, start GNU
+Emacs. Issue the command
+\Command{M-x byte-compile-file}{}{}{0}
+The user will be prompted for the name of the file. Respond with {\tt
+web-mode.el}\null. This will create a new file named {\tt
+web-mode.elc}\null.
+
+\vfil\eject
+
+To get {\tt web-mode} automatically loaded, add the following
+lines of code to the file that configures your Emacs. This file is
+usually ``{\tt .emacs}'' on \Unix{} systems.
+\vskip\smallskipamount
+\verbatim
+(setq auto-mode-alist (cons '("\\.web\$" . web-mode) auto-mode-alist))
+(autoload 'web-mode "web-mode.elc" "Major mode for editing WEB-based documents" t)
+?endverbatim
+
+\noindent You can also enter {\tt web-mode} manually by loading the
+file that contains the {\tt web-mode} functions and then invoking the
+function {\tt web-mode}\null. The commands to do this are:
+$$\leftline{\hskip\parindent\tt M-x load-file\quad
+ {\it Respond with\/} {\tt web-mode.el} {\it or\/} {\tt web-mode.elc}\hfil}$$
+and
+\Command{M-x web-mode}{}{}{0}
+{\null\vfill
+ \centerline{{\bf NOTICE}}
+
+ The rest of this document will assume that either of the above means which
+ invoke {\tt web-mode} has been executed.
+
+ \null\vfill
+ \centerline{{\bf CAVEAT}}
+
+ Some of these functions may seem to be trivial and slow at first. We
+ believe they will pay big dividends for larger \Web{}s.
+}
+\vfill\eject
+\leftline{\Bf Getting Started}
+
+{\tt Web-mode} assists in creating and/or editing \Web{}s.
+\bigskip
+\leftline{\SS Creating a New \Web}
+
+If a \Web\ is being created, Emacs will need to be started with an empty
+file. For example, if the name of the new \Web\ is {\tt my.web}, you
+would probably enter the \Unix\ command
+\Command{\% emacs my.web}{}{}{0}
+The function {\tt web-mode} (see NOTICE on previous page) will prompt
+the user for the name of the file that contains the limbo portion of the
+\Web\null. To accept the default file ({\tt limbo.material}), the user
+need only press the return key. If, on the other hand, the user wishes
+to enter the name of another file, that can be done by answering with
+another file name. If the default is selected, the contents of the file
+{\tt limbo.material} are inserted and the user is asked to enter a title
+for the \Web\null.
+\bigskip
+\leftline{\SS Editing a \Web}
+
+If you wish to use {\tt web-mode} on an existing \Web, say {\tt
+primes.web}, you would begin by invoking Emacs with the \Unix\ command
+\Command{\% emacs primes.web}{}{}{0}
+When the function {\tt web-mode} is executed, it will perform some
+initialization of various data structures. A list of the module names
+is collected. If {\tt web-mode} detects that a module name has been used
+but never defined, a ``stub'' module is inserted at the {\bf end of the
+major section} in which it was first used. The form of the stub module
+is:
+
+{\vskip2pt\parskip0sp\tt\obeylines\def\SP{{\tt\char`\ }}
+ @\SP
+ @\char`\^ Stub@\char`>
+ @\char`< Name of undefined module@\char`>=
+ }
+%
+{\tt Web-mode} also reads in the {\tt CHange} file that accompanies the
+\Web\ currently being edited. If there is no {\tt CHange} file, one is
+created; however, this file is ``saved'' only if it is modified.
+%
+\vfill\eject
+%
+\leftline{\Bf Movement Within The \Tt{WEB}}
+\bigskip
+
+Several commands facilitate movement within the \Web\ document. The user
+can switch to the buffer containing the {\tt CHange} file by issuing the
+command
+\Command{M-x web-change-file}{c}{f}{3}
+Similarly, the user can switch to the buffer containing the \Web{} file
+at any time with the command
+\Command{M-x web-file}{w}{f}{3}
+If the \Web{} being edited is a {\tt CWEB}, the user can switch to any
+of the include files with the command
+\Command{M-x web-include-file}{i}{f}{3}
+This command takes a numeric argument. For example, giving the function
+an argument of 1 would cause the buffer containing the contents of the
+first include file command ({\tt @i}) encountered in the {\tt CWEB} to
+become the current buffer.
+
+The user can {\tt goto} any module or section at any time by issuing
+either
+\Command{M-x web-goto-module}{g}{m}{6}
+or
+\Command{M-x web-goto-section}{g}{s}{6}
+respectively. The user is then prompted for the module or section
+number. If a nonpositive number or a number greater than the number of
+modules or sections in the \Web\ is entered, an appropriate error
+message is displayed in the minibuffer. If a valid module or section
+number is entered, point moves to the beginning of that module or
+section in the \Web\null. The command can also be entered with a numeric
+argument which represents the destination module or section number. For
+example, if the user wants to {\tt goto} module 163, the command could
+be entered as
+$$\line{\hskip\parindent\tt C-u 163 M-x web-goto-module\hfil
+ {\kern2pt\hbox{\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt{\tt C-u 163 ESC C-g C-m}\kern2pt}}
+ \hrule}\vrule}}}%
+$$
+If the destination module has been changed, a message is printed in the
+minibuffer stating that the destination module has been changed.
+
+The user can also {\tt goto} the next or previous module by entering
+either
+\Command{M-x web-next-module}{n}{m}{3}
+or
+\Command{M-x web-previous-module}{p}{m}{6}
+respectively. If there is no next or previous module, an appropriate
+message is displayed in the minibuffer; otherwise, point moves to the
+beginning of the next or previous module, whichever is appropriate.
+
+The user can also {\tt goto} the next or previous major section in the
+\Web\ document by entering either
+\Command{M-x web-next-section}{n}{s}{3}
+or
+\Command{M-x web-previous-section}{p}{s}{6}
+respectively. If there is no next or previous section, an appropriate
+message is displayed in the minibuffer; otherwise, point moves to the
+beginning of the next or previous section, whichever is appropriate. It
+should be noted that these commands move point to the beginning of the
+next or previous section and not to the beginning of the current
+section.
+
+The user can determine the exact module number and major section point
+is positioned in at any time with the commands
+\Command{M-x web-what-module}{w}{m}{3}
+and
+\Command{M-x web-what-section}{w}{s}{3}
+respectively.
+
+If you are already an experienced \Web er, you might want to ask about
+the {\tt change} file. Please wait until you've read that section.
+%
+\vfill\eject
+%
+\leftline{\Bf Inserting A Module Name}
+\bigskip
+Whenever the {\tt \char`<} key is pressed in the buffer containing the
+\Web\ document, the function {\tt web-insert-module-name} is invoked. This
+function must determine whether this is the beginning of a module name
+or not. The function examines the preceding characters. If an odd
+number of {\tt @}'s precede the {\tt \char`<}, then it is the
+beginning of a module name and the function {\tt
+web-options-for-module-name-insertion} is automatically invoked;
+otherwise, the {\tt \char`<} is inserted and the user can continue
+typing.
+
+If the function determines that it is the beginning of a module name,
+the user is switched to another buffer with the following options:
+
+{\parskip=0sp\tt
+ \itemitem{A.} Abort
+ \itemitem{C.} Create New Module Name
+ \itemitem{L.} List All Modules Beginning with Letter
+ \itemitem{N.} Next Screen
+ \itemitem{P.} Previous Screen
+ \itemitem{S.} Select Existing Module Name\par }
+\noindent The user must then select one of the above options. A sample
+screen is shown in Figure~1. The \Web\ used for the figures is {\tt
+primes.web} contained in [1]\null.
+
+\verbatim
+Option Action
+------ -------------------------------------------
+ A Abort
+ C Create a New Module Name
+ L List all Module Names Beginning with Letter
+ N Next Screen
+ P Previous Screen
+ S Select Existing Module Name
+-------------------------------------------------------------------------------
+Number Name
+ 1 Fill table |p| with the first |m| prime numbers
+ 2 Give to |j_prime| the meaning: |j|~is a prime number
+ 3 If |p[n]| is a factor of~|j|, set |j_prime:=false|
+ 4 Increase |j| until it is the next prime number
+ 5 Initialize the data structures
+ 6 Other constants of the program
+ 7 Output a line of answers
+ 8 Output a page of answers
+ 9 Print table |p|
+ 10 Print the first |m| prime numbers
+ 11 Program to print the first thousand prime numbers
+ Displaying 11 Module Names of 14
+--**-Emacs: *Module Names* (Web)----All---------------------------------
+?endverbatim
+\medskip
+\centerline{{\bf Figure 1.}}
+
+{\parskip4pt plus2pt minus1pt
+
+\item{{\tt A.}} If this option is selected, the user is switched back
+to the buffer containing the \Web\ document and the two characters
+preceding point ({\tt @\char`<}) are deleted.
+
+The remaining options involve the list of module names. The
+module names are displayed below the menu choices. The module names
+are displayed in alphabetical order and are retrieved from the list
+that was created when {\tt web-mode} was invoked at the beginning of
+the editing session. The module names are displayed with a number to
+their left. The modules are numbered sequentially beginning with
+1\null.
+
+\item{{\tt C.}} If the option is chosen, the user is prompted for the
+name of the new module. Once entered, the user is switched back to the
+buffer containing the \Web\ document, the new module name is inserted,
+and the ending module delimiter (either {\tt @\char`>\ \rm or \tt
+@\char`> =}) is determined automatically and inserted. A check against
+the existing module names is conducted to ensure that the entered
+module name is indeed new. If the module name is new, a determination
+of whether a stub module needs to be appended is made and the new
+module name is added to the list of module names.
+
+\item{{\tt L.}} This causes all module names that begin with a
+particular letter to be displayed. The user is prompted for the letter.
+If no module names begin with the desired letter, an appropriate
+message is displayed in the minibuffer.
+
+\item{{\tt N.}} This causes the next screen of module names to be
+displayed. For example, if the screen is capable of displaying 21
+module names and currently module names 1 through 21 are displayed,
+choosing {\tt N} would cause module names 22 through 42 to be
+displayed.
+
+\item{{\tt P.}} This causes the previous screen of module names to be
+displayed. For example, if the screen is capable of displaying 21
+module names and currently module names 30 through 50 are displayed,
+choosing {\tt P} would cause module names 9 through 29 to be
+displayed.
+
+\item{{\tt S.}} This option asks the user to enter the number
+associated with the module name that he wishes to insert in the \Web\
+document. The ending module name delimiter (either {\tt @\char`>\ \rm
+or \tt @\char`> =}) is determined automatically and inserted.\par}
+
+\vfil
+{\it This might seem like a severe interruption of the coding
+process. However, getting the ``named modules'' spelled and spaced
+correctly is critical.}
+\vfil
+\eject
+%
+\leftline{\BF Viewing the Index, Module Names, and}
+\leftline{\BF Section Names}
+\bigskip
+{\tt Web-mode} allows a programmer to view the index as created by
+{\tt WEAVE}\null. A user can also display the list of module names
+that is maintained by {\tt web-mode}\null. It is also possible to
+view the names of the major sections of the \Web{} and the module
+number where each major section begins.
+\bigskip
+\leftline{\SS Viewing the Index}
+
+The user can view the contents of the index created by {\tt WEAVE} by
+issuing the command
+\Command{M-x web-view-index}{v}{i}{3}
+The user is first asked whether the \Web\ is a Pascal or C \Web\null.
+After the language has been determined, the function creates an
+asynchronous process which invokes the {\tt WEAVE} processor on the
+\Web\ in the current buffer. At Texas A\&M we have modified {\tt WEAVE}
+so that it writes the index to the file {\tt INDEX.tex} and the list of
+module names to the file {\tt MODULE\_NAMES.tex}\null. (The changes that
+must be made to {\tt WEAVE} to accomplish this are contained in Appendix
+C.)\ \ Once this process has completed, the contents of {\tt INDEX.tex}
+are inserted into another buffer. Some reformatting is done for a better
+presentation. The user can traverse the list of module numbers for a
+particular index entry by positioning the cursor anywhere on the line(s)
+where the index entry of interest is located and issuing the command
+\Command{M-x web-next-index}{n}{i}{3}
+or
+\Command{M-x web-previous-index}{p}{i}{6}
+These commands can be issued from the buffer where the index is
+displayed or they can be issued from the buffer that contains the \Web\
+document. If the commands are issued from the former, the user is
+switched back to the buffer that contains the \Web\ document, and point
+is positioned at the beginning of the module where the most recently
+selected index entry was next or previously referenced from point's
+current position.
+
+Once the user is back in the buffer that contains the \Web\ document,
+the list of modules associated with the most recently selected index
+entry can be traversed with the commands
+\Command{M-x web-next-index}{n}{i}{3}
+and
+\Command{M-x web-previous-index}{p}{i}{6}
+These commands work as expected and print an error message if the user
+attempts to run off of either end of the list. A portion of the index
+created for Knuth's {\tt primes.web} is shown in Figure~2\null.
+
+\midinsert
+\verbatim
+Bertrand, Joseph, postulate: 21.
+boolean: 15.
+c: 7.
+cc: 5, 7, 8, 10.
+Dijkstra, Edsger: 1, 15.
+Eratosthenes, sieve of: 24.
+false: 13, 26.
+integer: 4, 7, 12, 17, 24.
+j: 12.
+j\_prime: 13, 14, 15, 22, 26.
+k: 12.
+Knuth, Donald E.: 15.
+m: 2.
+mult: 24, 25, 26.
+n: 23.
+new\_line: 6*, 9, 10.
+new\_page: 6*, 9.
+ord: 17, 18, 19, 20, 21, 22, 23, 24, 25.
+ord\_max: 17, 19, 23, 24.
+output: 2, 6*.
+output format: 5, 9.
+p: 4.
+--**-Emacs: *INDEX for primes.web* (Web)----Top-----------------------------
+?endverbatim
+\medskip
+\centerline{{\bf Figure 2.}}
+\endinsert
+
+***{\bf Important}***\ \ It may be necessary for the {\tt web-view-index}
+source to be changed if the {\tt WEAVE} processor for Pascal \Web s is
+called something other than ``{\tt weave}'' or the {\tt WEAVE}
+processor for C \Web s is called something other than ``{\tt cweave}''
+on your computer system. The {\tt web-view-index} has calls to the Emacs'
+function {\tt call-process}\null. The first argument to this function
+is the name of the program that is to be run as a separate process. If
+the program names of the {\tt WEAVE} processors differ on your system,
+these lines will need to be changed accordingly in the function {\tt
+web-view-index}\null.
+
+\bigskip
+\leftline{\SS Viewing the Module Names}
+
+The user can also view the contents of the list of module names that
+is maintained by {\tt web-mode}\null. When the command
+\Command{M-x web-view-module-names-list}{v}{m}{3}
+is issued, the list is displayed in another buffer. Some reformatting
+is necessary. The user is free to peruse the list as much as he likes.
+The results of issuing this command on Knuth's {\tt primes.web} is shown
+in Figure~3\null.
+
+\midinsert
+\verbatim
+Fill table |p| with the first |m| prime numbers (11) (3)
+Give to |j_prime| the meaning: |j|~is a prime number (22) (14)
+If |p[n]| is a factor of~|j|, set |j_prime:=false| (26) (22)
+Increase |j| until it is the next prime number (14) (11)
+Initialize the data structures (16 18) (11)
+Other constants of the program (5 19) (2)
+Output a line of answers (10) (9)
+Output a page of answers (9) (8)
+Print table |p| (8) (3)
+Print the first |m| prime numbers (3) (2)
+Program to print the first thousand prime numbers (2) (1)
+Update variables that depend on~|j| (20) (14)
+Update variables that depend on~|ord| (21 25) (20)
+Variables of the program (4 7 12 15 17 23 24) (2)
+--**-Emacs: *Module Name (Defined In) (Used In)* (Web)--All------------------
+?endverbatim
+\medskip
+\centerline{{\bf Figure 3.}}
+\endinsert
+
+The commands
+\Command{M-x web-next-define}{n}{d}{3}
+\Command{M-x web-next-use}{n}{u}{3}
+\Command{M-x web-previous-define}{p}{d}{6}
+and
+\Command{M-x web-previous-use}{p}{u}{6}
+can be invoked from the buffer where the module names are displayed or
+they can be invoked from the buffer containing the \Web\ document. If
+they are invoked from the former, the user selects a module name by
+positioning the cursor anywhere on the line(s) where the module name of
+interest is located. Once a module name has been selected, the user is
+switched back to the buffer containing the \Web\ document at the module
+where the most recently selected module name was next/previously defined
+or used, whichever is appropriate, from point's current position.
+
+While in the \Web{} document, the ``Defined In'' and ``Used In'' lists
+can be traversed with the commands
+\Command{M-x web-next-define}{n}{d}{3}
+which positions point at the beginning of the module where the most
+recently selected module name was next defined,
+\Command{M-x web-previous-define}{p}{d}{6}
+which positions point at the beginning of the module where the most
+recently selected module name was previously defined,
+\Command{M-x web-next-use}{n}{u}{3}
+which positions point at the beginning of the module where the most
+recently selected module name was next used, and
+\Command{M-x web-previous-use}{p}{u}{6}
+which positions point at the beginning of the module where the most
+recently selected module name was previously used.
+
+It should be noted that these commands prevent the user from running
+off either end of either list.
+
+{\tt Web-mode} maintains a list of the form
+$$\vbox{\tabskip0sp\halign{\hfil#&(``module-name-$#$''\quad%
+ (Defined In Modules)\quad(Used In Modules))\hfil\cr
+ (&1\cr &2\cr &\omit$\ldots$\hfil\cr &n\cr )\cr
+ }}
+$$
+This list is collected automatically by {\tt web-mode} as well as
+maintained. If the user feels that this list is in error at any time
+during an editing session, the list can be recollected with the
+command
+\Command{M-x web-collect-module-names}{}{}{0}
+\vfil\eject
+\leftline{\SS Viewing the Major Section Names}
+
+The user can also view a list of the names of the major sections in
+the \Web\ document and the module number where each major section
+begins. The command
+\Command{M-x web-view-section-names-list}{v}{s}{3}
+collects the names of the major sections along with their module numbers
+and displays them in another buffer. The user is switched over to this
+buffer. The result of issuing this command on Knuth's {\tt primes.web}
+is shown in Figure~4\null.
+
+\midinsert
+\verbatim
+Module# Section Name
+ 1 Printing primes: An example of \WEB
+ 3 Plan of the program
+ 5 The output phase
+ 11 Generating the primes
+ 22 The inner loop
+ 27 Index
+--**-Emacs: *Section Names* (Web)----All------------------------------------
+?endverbatim
+\medskip
+\centerline{{\bf Figure 4.}}
+\endinsert
+
+\vfil\eject
+\leftline{\Bf Support for Change Files}
+\bigskip
+{\tt Web-mode} also provides support for {\tt change} files. The
+command
+\Command{M-x web-view-changed-modules-list}{v}{c}{3}
+can be invoked in either the buffer containing the \Web\ document or the
+buffer containing the {\tt change} file. It displays a list of modules
+that have been changed in a separate window.
+
+The command
+\Command{M-x web-edit-module}{e}{m}{3}
+will insert the contents of the module that point is positioned in when
+the command is invoked in the {\tt change} file in its proper position.
+The entire module's contents are copied twice---once between {\tt @x @y}
+and once between {\tt @y @z}. The user is positioned at the first line
+after the {\tt @y}\null. This command is only available in the buffer
+containing the \Web\ document.
+
+The command
+\Command{M-x web-what-change}{w}{c}{3}
+can only be invoked in the buffer containing the {\tt change} file. This
+function displays a descriptive message informing the user of what
+module in the \Web\ the change that point is positioned in corresponds
+to.
+
+Movement within the {\tt change} file is accomplished with the commands:
+\Command{M-x web-goto-change-corresponding-to-module}{g}{c}{6}
+If a numeric argument is not provided, the user is prompted. Point is
+positioned at the beginning of the change in the {\tt change} buffer
+that corresponds to the module number given as an argument.
+\Command{M-x web-next-change}{n}{c}{3}
+This command positions point at the beginning of the next change in the
+{\tt change} buffer.
+\Command{M-x web-previous-change}{p}{c}{6}
+This command positions point at the beginning of the previous change in
+the {\tt change} buffer.
+
+The command \Command{M-x web-count-changes}{c}{c}{3}
+will display the number of modules that have been changed.
+\vfil\eject
+
+\leftline{\Bf Miscellaneous Functions}
+\bigskip
+
+The function
+\Command{M-x web-count-modules}{c}{m}{3}
+displays in the minibuffer the total number of modules in the \Web\
+document that is currently being edited.
+
+The function
+\Command{M-x web-count-sections}{c}{s}{3}
+displays in the minibuffer the total number of sections in the \Web\
+document that is currently being edited.
+
+The command
+\Command{M-x web-delimiter-match-check}{d}{m}{3}
+looks at the entire
+\Web\ document module by module. It determines if the delimiters
+surrounding module names, namely, {\tt@\char`<} and {\tt@\char`>}, are
+matched. If the delimiters do not match properly, a descriptive message
+is printed in a temporary buffer.
+
+The function
+\Command{M-x web-determine-characteristics}{d}{c}{3}
+creates a table that shows the number of lines of commentary,
+definition/format macros, and code in each module in the \Web\ document.
+A message is displayed in the minibuffer indicating to the user which
+module the function is currently working on. Once completed, the user is
+switched to a buffer where the characteristics have been written. The
+user is free to peruse this buffer using regular Emacs commands.
+
+{\tt Web-mode} also makes it easier to enter index entries. When
+the function
+\Command{M-x web-insert-index-entry}{i}{i}{3}
+is issued, the user is prompted for two things:
+\null\vskip\baselineskip
+{\parskip=0sp
+ \item{1.} The type of font to be used (Roman, typewriter, or
+user-defined). This determines the opening delimiter to the index
+entry (either {\tt @\char`\^\rm , \tt @\char`.\rm , or \tt @\char`:}) and
+ \item{2.} The text of the index entry.
+}
+
+\noindent The complete index entry is then placed on a new line.
+
+\vfil\eject
+
+The command
+\Command{M-x web-rename-module}{r}{m}{3}
+allows the user to rename a module. Point should be positioned on the
+name that the user wishes to rename. The user is prompted for the new
+name. The user is then given the option of renaming a single
+occurrence, all occurrences, or is queried if each of the remaining
+occurrences should be renamed.
+
+There are several functions in {\tt web-mode} that are invoked
+automatically whenever a particular key is pressed. These functions
+include:
+\Command{M-x web-is-this-a-new-module-beginning}{}{}{0}
+which is invoked whenever the {\tt @} key is pressed. The function
+checks to see if the {\tt @} is at the beginning of a line. If it is,
+the next character is read. If this next character is either a space,
+newline, tab, or asterisk, then the {\tt @} in combination with the next
+character constitutes the beginning of a new module.
+
+Another useful function that is invoked automatically is
+\Command{M-x web-newline} {}{}{0}
+which is invoked whenever the newline character is pressed. This
+function positions point so that the next line has the same indentation
+as the current line that is being terminated.
+
+One keybinding that Emacs' users are familiar with has been rebound to
+another function. The keybinding {\tt C-x C-c} has been bound to
+the {\tt web-mode} function
+\Command{M-x web-mode-save-buffers-kill-emacs}{x}{c}{1}
+Before this function makes a call to Emacs' {\tt
+save-buffers-kill-emacs}, it completes the journal file that is
+maintained by {\tt web-mode}. This journal file keeps track of what file
+is being edited, who is editing it, when the editing began, when the
+editing stopped, and a count of the number of times each of {\tt
+web-mode}'s interactive functions were used.
+%
+\vfil\eject
+%
+\leftline{\Bf A Final Note}
+\bigskip
+Any suggestions for enhancements, problems with the existing
+functions, or criticisms can be submitted to
+\item{$\bullet$} the author ({\tt motl@cs.tamu.edu}) or
+\item{$\bullet$} Bart Childs ({\tt bart@cs.tamu.edu})\null.
+%
+\bigskip\null\vskip\baselineskip
+%
+\leftline{\Bf References}
+\bigskip
+{\parskip2pt plus1pt minus1pt
+\raggedright
+\item{1.} Donald E.~Knuth, ``Literate Programming,'' {\it The Computer
+Journal}, vol.~27, no.~2, May\ 1984, pp.~97--111.
+
+\item{2.} Bill Lewis, Dan LaLiberte, and the GNU Manual Group, {\it
+The GNU Emacs Lisp Reference Manual}, Emacs Version 18 for \Unix\ Users,
+Edition 1.01, Cambridge, MA: Free Software Foundation, Apr.~1990.
+
+\item{3.} Richard Stallman, {\it GNU Emacs Manual}, Fifth Edition,
+Version 18 for \Unix\ Users, Cambridge, MA: Free Software Foundation,
+Oct.~1986.
+
+%
+\bigskip\null\vskip\baselineskip
+%
+\leftline{\Bf Supplementary Sources}
+\bigskip\newcount\Itemno \Itemno=0
+\def\Item#1\Enditem{\global\advance \Itemno by 1 \item{\the\Itemno.} #1}
+
+\Item
+{Adrian Avenarius and Siegfried Oppermann,
+ ``FWEB: A Literate Programming System for Fortran8x,''
+ {\it SIGPLAN Notices,}
+ vol.~25, no.~1, Jan.~1990, pp.~52--58.
+}
+\Enditem
+
+\Item
+{Jon Bentley,
+ ``Programming Pearls: Literate Programming,''
+ {\it Communications of the ACM},
+ vol.~29, no.~5, May~1986, pp.~364--369.
+}
+\Enditem
+
+\Item
+{Jon Bentley and David Gries,
+ ``Programming Pearls: Abstract Data Types,''
+ {\it Communications of the ACM},
+ vol.~30, no.~4, Apr.~1987, pp.~284--290.
+}
+\Enditem
+
+\Item
+{Jon Bentley, Donald E.~Knuth, and Doug McIlroy,
+ ``Programming Pearls: A Literate Program,''
+ {\it Communications of the ACM},
+ vol.~29, no.~6, Jun.~1986, pp.~471--483.
+}
+\Enditem
+
+\Item
+{Marcus E.~Brown,
+ ``An Interactive Environment for Literate Programming,''
+ Ph.D.\ Dissertation, Dept.\ of Computer Science, Texas A\&M University,
+ College Station, TX, Aug.~1988.
+}
+\Enditem
+
+\Item
+{Marcus E.~Brown and Bart Childs,
+ ``An Interactive Environment for Literate Programming,''
+{\it Structured Programming}, vol.~11, no.~1, Jan.~1990, pp.~11--25.
+}
+\Enditem
+
+\Item
+{Peter J.~Denning,
+ ``Announcing Literate Programming,''
+ {\it Communications of the ACM},
+ vol.~30, no.~7, Jul.~1987, p.~593.
+}
+\Enditem
+
+\Item
+{Klaus Guntermann and Joachim Schrod,
+ ``\Web\ Adapted to C,''
+ {\it TUGboat},
+ vol.~7, no.~3, Oct.~1986, pp.~134--137.
+}
+\Enditem
+
+\Item
+{Eric Hamilton,
+ ``Literate Programming: Expanding Generalized Regular Expressions,''
+ {\it Communications of the ACM},
+ vol.~31, no.~12, Dec.~1988, pp.~1376--1385.
+}
+\Enditem
+
+\Item
+{David R.~Hanson,
+ ``Literate Programming: Printing Common Words,''
+ {\it Communications of the ACM},
+ vol.~30, no.~7, Jul.~1987, pp.~594--599.
+}
+\Enditem
+
+\Item
+{Michael A.~Jackson,
+ ``Literate Programming: Processing Transactions,''
+ {\it Communications of the ACM},
+ vol.~30, no.~12, Dec.~1987, pp.~1000--1010.
+}
+\Enditem
+
+\Item
+{Donald E.~Knuth,
+ {\it \MF: The Program},
+ vol.~D of {\it Computers \& Typesetting},
+ Reading, MA: Addison-Wesley Publishing Co.,
+ 1986.
+}
+\Enditem
+
+\Item
+{Donald E.~Knuth,
+ {\it \TeX: The Program},
+ vol.~B of {\it Computers \& Typesetting},
+ Reading, MA: Addison-Wesley Publishing Co.,
+ 1986.
+}
+\Enditem
+
+\Item
+{Donald E.~Knuth,
+ ``The \Web\ System of Structured Documentation,''
+ Stanford Computer Science Report STAN-CS-980,
+ Dept.\ of Computer Science,
+ Stanford University, Stanford, CA,
+ Sep.~1983.
+}
+\Enditem
+
+\Item
+{John A.~Krommes,
+ ``The \Web{} System of Structured Software Design and Documentation for
+ Fortran, Ratfor, and C,''
+ Technical Report, Princeton University, Princeton, NJ,
+ Nov.~1989. Available by anonymous {\tt ftp} from
+ {\tt ss01.pppl.gov} in directory {\tt/pub/fweb}.
+}
+\Enditem
+
+\Item
+{Silvio Levy,
+ ``\Web\ Adapted to C, Another Approach,''
+ {\it TUGboat},
+ vol.~8, no.~1,
+\hfil\break
+ Apr.~1987, pp.~12--13.
+}
+\Enditem
+
+\Item
+{Donald C.~Lindsay,
+ ``Literate Programming: A File Difference Program,''
+ {\it Communications of the ACM},
+ vol.~32, no.~6, Jun.~1989, pp.~740--752.
+}
+\Enditem
+
+\Item
+{Charles Lins,
+ ``A First Look at Literate Programming,''
+ {\it Structured Programming},
+ vol.~10, no.~1, 1989, pp.~60--62.
+}
+\Enditem
+
+\Item
+{Charles Lins,
+ ``An Introduction to Literate Programming,''
+ {\it Structured Programming},
+ vol.~10, no.~2, 1989, pp.~107--112.
+}
+\Enditem
+
+\Item
+{Norman Ramsey,
+ ``Literate Programming: Weaving a Language-Independent \Web,''
+ {\it Communications of the ACM},
+ vol.~32, no.~9, Sep.~1989, pp.~1051--1055.
+}
+\Enditem
+
+\Item
+{E.~W.~Sewell,
+ ``How to\/ {\tt MANGLE} Your Software: The\/ \Web\ System for
+ Modula-2,''
+\hfil\break
+ {\it TUGboat},
+ vol.~8, no.~2, Jul.~1987, pp.~118--122.
+}
+\Enditem
+
+\Item
+{E.~W.~Sewell,
+ {\it Weaving a Program: Literate Programming in WEB},
+ New York, NY: Van Nostrand Reinhold, 1989.
+}
+\Enditem
+
+\Item
+{Richard M.~Stallman,
+ ``EMACS: The Extensible, Customizable, Self-Doc\-u\-men\-ting Display
+ Editor,''
+ in {\it Interactive Programming Environments},
+ David R.~Barstow,
+\hfil\break
+ Howard E.~Shroke, and Erik Sandewall, Eds.,
+ New York, NY: McGraw-Hill Book Co., 1984, pp.~300--325.
+}
+\Enditem
+
+\Item
+{Harold~Thimbleby,
+ ``Experiences of `Literate Programming' using {\tt cweb} (a variant
+ of Knuth's \Web),''
+ {\it The Computer Journal},
+ vol.~29, no.~3, Jun.~1986, pp.~201--211.
+}
+\Enditem
+
+\Item
+{Sho-Huan Tung,
+ ``A Structured Method for Literate Programming,''
+ {\it Structured Programming},
+ vol.~10, no.~2, 1989, pp.~113--120.
+}
+\Enditem
+
+\Item
+{Christopher J.~Van Wyk,
+ ``Literate Programming: An Assessment,''
+ {\it Communications of the ACM},
+ vol.~33, no.~3, Mar.~1990, pp.~361 and 365.
+}
+\Enditem
+
+}% end reduced parskip for references.
+\vfil\eject
+%
+\centerline{\BF Glossary}
+\bigskip
+{\bf buffer} --- A buffer is the basic editing unit. In Emacs, a user can
+have many buffers, however, only one can be edited at any one time.
+
+{\bf change file} --- This file contains information that is used to
+override portions of the \Web{} file. Each ``change'' consists of
+repeating the lines from the \Web{} file that require modification and
+the new lines that are to replace the old ones. The {\tt TANGLE} and
+{\tt WEAVE} processors have the ability to scan both the \Web{} and
+change files so that the new lines replace the old lines at the
+appropriate places in the resulting high-level language and \TeX{} codes.
+
+{\bf major section} --- A major section is a ``starred'' module; that is,
+it is a module that begins with the symbols `{\tt@*}'.
+
+{\bf minibuffer} --- The bottom line of the screen when using Emacs.
+This area is used to display arguments to commands, commands that are
+typed in from the keyboard, and messages to the user. For commands that
+require arguments, the minibuffer area can be used for prompting as well.
+
+{\bf module} --- A module begins with the pair of symbols `{\tt@*}',
+`{\tt@\char`<}', `{\tt@\BS t}', `{\tt@\BS n}', or `{\tt@\char`\ }'. A
+module ends when the next module begins or the end of the file, whichever
+comes first.
+
+{\bf numeric argument} --- A number which is specified before a command
+to alter the effect of the command.
+
+{\bf section} --- A section is the same as a major section.
+
+{\bf web file} --- contains the source of the \Web\null. The file
+consists of the limbo portion and the individual units that comprise the
+\Web{} called modules. A module consists of a commentary, definition, and
+code parts, any two of which can be empty.
+
+\vfil\eject
+
+\centerline{\BF Appendix A}
+
+% SLIDES can be prepared using TeX without resorting to SliTeX.
+% SliTeX is an excellent way to do many things that will not show
+% in this macro package.
+%
+% To use this you should start off with:
+% \magnification=\magstep5 or 6. Try it and pick one.
+% Look at the other parameters in the slides.tex sample.
+% Now tex away!
+%
+% The following is taken from the first 120 lines of MANMAC.TeX.
+% A few lines have been deleted.
+% This is MANMAC.TEX in text format, as of Mar 31, 1986.
+% Macros for The TeXbook
+
+\catcode`@=11 % borrow the private macros of PLAIN (with care)
+
+\font\tentex=cmtex10
+
+\font\ninerm=cmr9
+\font\eightrm=cmr8
+\font\sixrm=cmr6
+
+\font\ninei=cmmi9
+\font\eighti=cmmi8
+\font\sixi=cmmi6
+\skewchar\ninei='177 \skewchar\eighti='177 \skewchar\sixi='177
+
+\font\ninesy=cmsy9
+\font\eightsy=cmsy8
+\font\sixsy=cmsy6
+\skewchar\ninesy='60 \skewchar\eightsy='60 \skewchar\sixsy='60
+
+\font\ninebf=cmbx9
+\font\eightbf=cmbx8
+\font\sixbf=cmbx6
+
+\font\ninett=cmtt9
+\font\eighttt=cmtt8
+
+\hyphenchar\tentt=-1 % inhibit hyphenation in typewriter type
+\hyphenchar\ninett=-1
+\hyphenchar\eighttt=-1
+
+\font\ninesl=cmsl9
+\font\eightsl=cmsl8
+
+\font\nineit=cmti9
+\font\eightit=cmti8
+
+\newfam\ssfam
+\font\tenss=lcmss8 scaled 1440
+\font\niness=lcmss8 scaled 1200
+\font\eightss=lcmss8
+
+\newskip\ttglue
+\def\X {\def\rm{\fam0\tenrm}% look at tenpoint in the TeXbook
+ \textfont0=\tenrm \scriptfont0=\sevenrm \scriptscriptfont0=\fiverm
+ \textfont1=\teni \scriptfont1=\seveni \scriptscriptfont1=\fivei
+ \textfont2=\tensy \scriptfont2=\sevensy \scriptscriptfont2=\fivesy
+ \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
+ \def\it{\fam\itfam\tenit}%
+ \textfont\itfam=\tenit
+ \def\sl{\fam\slfam\tensl}%
+ \textfont\slfam=\tensl
+ \def\bf{\fam\bffam\tenbf}%
+ \textfont\bffam=\tenbf \scriptfont\bffam=\sevenbf
+ \scriptscriptfont\bffam=\fivebf
+ \def\tt{\fam\ttfam\tentt\raggedright}%
+ \textfont\ttfam=\tentt
+ \tt \ttglue=.5em plus.25em minus.15em
+ \def\SS{\fam\ssfam\tenss}%
+ \textfont\ssfam=\tenss
+ \normalbaselineskip=12pt
+ \setbox\strutbox=\hbox{\vrule height8.5pt depth3.5pt width\z@}%
+ \normalbaselines \parskip=\normalbaselineskip \rm}
+
+\def\IX {\def\rm{\fam0\ninerm}% look at ninepoint in the TeXbook
+ \textfont0=\ninerm \scriptfont0=\sixrm \scriptscriptfont0=\fiverm
+ \textfont1=\ninei \scriptfont1=\sixi \scriptscriptfont1=\fivei
+ \textfont2=\ninesy \scriptfont2=\sixsy \scriptscriptfont2=\fivesy
+ \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
+ \def\it{\fam\itfam\nineit}%
+ \textfont\itfam=\nineit
+ \def\sl{\fam\slfam\ninesl}%
+ \textfont\slfam=\ninesl
+ \def\bf{\fam\bffam\ninebf}%
+ \textfont\bffam=\ninebf \scriptfont\bffam=\sixbf
+ \scriptscriptfont\bffam=\fivebf
+ \def\tt{\fam\ttfam\ninett\raggedright}%
+ \textfont\ttfam=\ninett
+ \tt \ttglue=.5em plus.25em minus.15em
+ \def\SS{\fam\ssfam\niness}%
+ \textfont\ssfam=\niness
+ \normalbaselineskip=11pt
+ \setbox\strutbox=\hbox{\vrule height8pt depth3pt width\z@}%
+ \normalbaselines \parskip=\normalbaselineskip \rm}
+
+\def\VIII {\def\rm{\fam0\eightrm}% look at eightpoint in the TeXbook
+ \textfont0=\eightrm \scriptfont0=\sixrm \scriptscriptfont0=\fiverm
+ \textfont1=\eighti \scriptfont1=\sixi \scriptscriptfont1=\fivei
+ \textfont2=\eightsy \scriptfont2=\sixsy \scriptscriptfont2=\fivesy
+ \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
+ \def\it{\fam\itfam\eightit}%
+ \textfont\itfam=\eightit
+ \def\sl{\fam\slfam\eightsl}%
+ \textfont\slfam=\eightsl
+ \def\bf{\fam\bffam\eightbf}%
+ \textfont\bffam=\eightbf \scriptfont\bffam=\sixbf
+ \scriptscriptfont\bffam=\fivebf
+ \def\tt{\fam\ttfam\eighttt\raggedright}%
+ \textfont\ttfam=\eighttt
+ \tt \ttglue=.5em plus.25em minus.15em
+ \def\SS{\fam\ssfam\eightss}%
+ \textfont\ssfam=\eightss
+ \normalbaselineskip=9pt
+ \setbox\strutbox=\hbox{\vrule height7pt depth2pt width\z@}%
+ \normalbaselines \parskip=\normalbaselineskip \rm}
+%
+% This is borrowed and extended from plain.tex
+%
+% 0 1 2 3 4 5
+\def\magstep#1{\ifcase#1 \@m\or 1200\or 1440\or 1728\or 2074\or 2488\or
+ 2986\or 3583\or 4300\or 5160 \fi\relax}
+% 6 7 8 9
+\catcode`@=12
+\message{}
+\message{I suggest you set eight point, VIII}
+\message{It also sets raggedright}
+\message{}
+
+{
+ \VIII
+ \newbox\AlphaCommands
+ \setbox\AlphaCommands=%
+ \vbox{\tabskip0sp\offinterlineskip
+ \def\tablerule{\noalign{\hrule}}
+ \halign{\vrule#&\strut\quad\tt#\hfil\quad
+ &\vrule#&\quad\hfil\tt#\hfil\quad
+ &\vrule#\cr
+ \multispan5\hfil Alphabetized Listing of {\tt web-mode} Commands\hfil\cr
+ \noalign{\vskip6truept}
+ \tablerule
+ &\bf Command&&\bf\hidewidth Key Binding\hidewidth&\cr
+ \tablerule
+ &web-change-file&&ESC C-c C-f&\cr\tablerule
+ &web-collect-module-names&&n/a${}^1$&\cr\tablerule
+ &web-count-changes&&ESC C-c C-c&\cr\tablerule
+ &web-count-modules&&ESC C-c C-m&\cr\tablerule
+ &web-count-sections&&ESC C-c C-s&\cr\tablerule
+ &web-delimiter-match-check&&ESC C-d C-m&\cr\tablerule
+ &web-determine-characteristics&&ESC C-d C-c&\cr\tablerule
+ &web-edit-module&&ESC C-e C-m&\cr\tablerule
+ &web-file&&ESC C-w C-f&\cr\tablerule
+ &web-goto-change-corresponding-to-module&&ESC C-g C-c&\cr\tablerule
+ &web-goto-module&&ESC C-g C-m&\cr\tablerule
+ &web-goto-section&&ESC C-g C-s&\cr\tablerule
+ &web-include-file&&ESC C-i C-f&\cr\tablerule
+ &web-insert-index-entry&&ESC C-i C-i&\cr\tablerule
+ &web-insert-module-name&&n/a${}^2$&\cr\tablerule
+ &web-is-this-a-new-module-beginning&&n/a${}^3$&\cr\tablerule
+ &web-mode&&n/a${}^1$&\cr\tablerule
+ &web-mode-save-buffers-kill-emacs&&C-x C-c&\cr\tablerule
+ &web-newline&&n/a${}^4$&\cr\tablerule
+ &web-next-change&&ESC C-n C-c&\cr\tablerule
+ &web-next-define&&ESC C-n C-d&\cr\tablerule
+ &web-next-index&&ESC C-n C-i&\cr\tablerule
+ &web-next-module&&ESC C-n C-m&\cr\tablerule
+ &web-next-section&&ESC C-n C-s&\cr\tablerule
+ &web-next-use&&ESC C-n C-u&\cr\tablerule
+ &web-previous-change&&ESC C-p C-c&\cr\tablerule
+ &web-previous-define&&ESC C-p C-d&\cr\tablerule
+ &web-previous-index&&ESC C-p C-i&\cr\tablerule
+ &web-previous-module&&ESC C-p C-m&\cr\tablerule
+ &web-previous-section&&ESC C-p C-s&\cr\tablerule
+ &web-previous-use&&ESC C-p C-u&\cr\tablerule
+ &web-rename-module&&ESC C-r C-m&\cr\tablerule
+ &web-view-changed-modules-list&&ESC C-v C-c&\cr\tablerule
+ &web-view-index&&ESC C-v C-i&\cr\tablerule
+ &web-view-module-names-list&&ESC C-v C-m&\cr\tablerule
+ &web-view-section-names-list&&ESC C-v C-s&\cr\tablerule
+ &web-what-change&&ESC C-w C-c&\cr\tablerule
+ &web-what-module&&ESC C-w C-m&\cr\tablerule
+ &web-what-section&&ESC C-w C-s&\cr\tablerule
+ \noalign{\vskip6truept}
+ \multispan5\rm${}^1$ No keybinding for this function.\hfil\cr
+ \multispan5\rm${}^2$ Invoked whenever {\tt\char`<} is pressed.\hfil\cr
+ \multispan5\rm${}^3$ Invoked whenever {\tt\char`@} is pressed.\hfil\cr
+ \multispan5\rm${}^4$
+ Invoked whenever the newline character is pressed.
+ Suggested by Donald Knuth.\hidewidth\hfil\cr
+ }
+ }
+
+ $$\box\AlphaCommands$$
+}
+
+With the exception of two functions
+\item{$\bullet$} {\tt web-file} and
+\item{$\bullet$} {\tt web-mode-save-buffers-kill-emacs}
+
+\noindent notice that all keybindings have a similar form that consists
+of three parts. Each command is prefaced with the escape key. The next
+part of the keybinding is the control key followed by the first letter
+of the second word of the function name. The second part of the
+keybinding is the control key followed by the first letter of the third
+word of the function name.
+
+{\VIII
+ \newbox\Files
+ \setbox\Files=\vbox{\hbox to 103truept{\hfil Movement Among\hfil}
+ \hbox to 103truept{\hfil Files\hfil}
+ }
+ \ht\Files=0sp \wd\Files=0sp
+
+ \newbox\Modules
+ \setbox\Modules=\vbox{\hbox to 103truept{\hfil Movement Among\hfil}
+ \hbox to 103truept{\hfil Modules\hfil}
+ }
+ \ht\Modules=0sp \wd\Modules=0sp
+
+ \newbox\Sections
+ \setbox\Sections=\vbox{\hbox to 103truept{\hfil Interactive Access to\hfil}
+ \hbox to 103truept{\hfil and\hfil}
+ \hbox to 103truept{\hfil Movement Among\hfil}
+ \hbox to 103truept{\hfil Sections\hfil}
+ }
+ \ht\Sections=0sp \wd\Sections=0sp
+
+ \newbox\Index
+ \setbox\Index=\vbox{\hbox to 103truept{\hfil Interactive Access to\hfil}
+ \hbox to 103truept{\hfil Index\hfil}
+ }
+
+ \ht\Index=0sp \wd\Index=0sp
+
+ \newbox\ModNames
+ \setbox\ModNames=\vbox{\hbox to 103truept{\hfil Interactive Access\hfil}
+ \hbox to 103truept{\hfil to Modules\hfil}
+ }
+
+ \ht\ModNames=0sp \wd\ModNames=0sp \dp\ModNames=0sp
+
+ \newbox\Change
+ \setbox\Change=\vbox{\hbox to 103truept{\hfil Change File\hfil}
+ \hbox to 103truept{\hfil Editing and Movement\hfil}
+ }
+ \ht\Change=0sp \wd\Change=0sp
+
+ \newbox\Structure
+ \setbox\Structure=\vbox{\hbox to 103truept{\hfil{\tt Web}\hfil}
+ \hbox to 103truept{\hfil Structure\hfil}
+ \hbox to 103truept{\hfil Information\hfil}
+ }
+ \ht\Structure=0sp \wd\Structure=0sp
+
+ \newbox\Misc
+ \setbox\Misc=\vbox{\hbox to 103truept{\hfil Miscellaneous\hfil}}
+ \ht\Misc=0sp \wd\Misc=0sp
+
+ \def\tablerule{\noalign{\hrule}}
+ \newbox\FuncCommands
+ \setbox\FuncCommands=%
+ \vbox{\offinterlineskip\tabskip0sp%
+ \halign{\vrule#%
+ &\quad\hbox to 103truept{\hfil#\hfil}\quad%
+ &\vrule#%
+ &\quad\hbox to 200truept{\tt#\hfil}\quad%
+ &\vrule#%
+ &\quad\tt\hfil#\hfil\quad%
+ &\vrule#\cr
+ \multispan7\hfil Alphabetized Listing of {\tt web-mode} Commands by
+ Functionality\hfil\cr
+ \noalign{\vskip6truept}
+ \tablerule
+ &\strut\bf\hfil Functionality\hfil
+ &&\bf Command&&\bf\hidewidth Key Binding\hidewidth&\cr
+ \tablerule
+ %
+ &\omit\quad\strut\box\Files&&web-change-file&&ESC C-c C-f&\cr
+ &&&\strut web-file&&ESC C-w C-f&\cr
+ &&&\strut web-include-file&&ESC C-i C-f&\cr\tablerule
+ %
+ &\omit\quad\strut\box\Modules&&web-goto-module&&ESC C-g C-m&\cr
+ &&&\strut web-next-module&&ESC C-n C-m&\cr
+ &&&\strut web-previous-module&&ESC C-p C-m&\cr\tablerule
+ %
+ &\omit\quad\strut\raise6truept\box\Sections%
+ &&web-goto-section&&ESC C-g C-s&\cr
+ &&&\strut web-next-section&&ESC C-n C-s&\cr
+ &&&\strut web-previous-section&&ESC C-p C-s&\cr
+ &&&\strut web-view-section-names-list&&ESC C-v C-s&\cr\tablerule
+ %
+ &\strut Inserting a Module&&web-insert-module-name%
+ &&n/a${}^{1\mathstrut}$&\cr
+ \tablerule
+ %
+ &\omit\quad\strut\box\Index&&web-next-index&&ESC C-n C-i&\cr
+ &&&\strut web-previous-index&&ESC C-p C-i&\cr
+ &&&\strut web-view-index&&ESC C-v C-i&\cr\tablerule
+ %
+ &&&\strut web-collect-module-names&&n/a${}^{2\mathstrut}$&\cr
+ &&&\strut web-next-define&&ESC C-n C-d&\cr
+ &\omit\quad\strut\raise6truept\box\ModNames&&web-next-use&&ESC C-n C-u&\cr
+ &&&\strut web-previous-define&&ESC C-p C-d&\cr
+ &&&\strut web-previous-use&&ESC C-p C-u&\cr
+ &&&\strut web-view-module-names-list&&ESC C-v C-m&\cr\tablerule
+ %
+ &&&\strut web-edit-module&&ESC C-e C-m&\cr
+ &\omit\quad\strut\raise6truept\box\Change%
+ &&web-goto-change-corresponding-to-module&&ESC C-g C-c&\cr
+ &&&\strut web-next-change&&ESC C-n C-c&\cr
+ &&&\strut web-previous-change&&ESC C-p C-c&\cr\tablerule
+ %
+ &&&\strut web-count-changes&&ESC C-c C-c&\cr
+ &&&\strut web-count-modules&&ESC C-c C-m&\cr
+ &&&\strut web-count-sections&&ESC C-c C-s&\cr
+ &\omit\quad\strut\raise6truept\box\Structure%
+ &&web-delimiter-match-check&&ESC C-d C-m&\cr
+ &&&\strut web-determine-characteristics&&ESC C-d C-c&\cr
+ &&&\strut web-view-changed-modules-list&&ESC C-v C-c&\cr
+ &&&\strut web-what-change&&ESC C-w C-c&\cr
+ &&&\strut web-what-module&&ESC C-w C-m&\cr
+ &&&\strut web-what-section&&ESC C-w C-s&\cr\tablerule
+ %
+ &&&\strut web-insert-index-entry&&ESC C-i C-i&\cr
+ &&&\strut web-is-this-a-new-module-beginning&&n/a${}^3$&\cr
+ &\omit\quad\strut\box\Misc&&web-mode&&n/a${}^2$&\cr
+ &&&\strut web-mode-save-buffers-kill-emacs&&C-x C-c&\cr
+ &&&\strut web-newline&&n/a${}^4$&\cr
+ &&&\strut web-rename-module&&ESC C-r C-m&\cr\tablerule
+ \noalign{\vskip6truept}
+ \multispan7\rm${}^1$ Invoked whenever {\tt\char`<} is pressed.\hfil\cr
+ \multispan7\rm${}^2$ No keybinding for this function.\hfil\cr
+ \multispan7\rm${}^3$ Invoked whenever {\tt\char`@} is pressed.\hfil\cr
+ \multispan7\rm${}^4$
+ Invoked whenever the newline character is pressed.
+ Suggested by Donald Knuth\hfil\cr
+ }
+ }
+ $$\box\FuncCommands$$
+}
+
+The non-interactive functions in {\tt web-mode} are:
+\medskip
+{\parindent0sp\parskip0sp\tt\obeylines
+ web-any-modules-undefined-initially
+ web-append-a-stub-module
+ web-binary-search-of-names
+ web-check-if-buffer-is-one-of-the-web-files
+ web-collect-list-of-changed-module-numbers
+ web-collect-location-of-modules
+ web-collect-module-names-in-buffer
+ web-collect-section-names
+ web-convert-list-to-string
+ web-count-the-matches
+ web-determine-characteristics-for-buffer
+ web-determine-module-name-ending
+ web-display-module-names
+ web-eliminate-control-sequences
+ web-eliminate-white-space
+ web-initialize-location-of-module-vector
+ web-initialize-module-names-list
+ web-insert-limbo-material
+ web-journal
+ web-next-or-previous-define-or-use
+ web-next-or-previous-index
+ web-options-for-module-name-insertion
+ web-reformat-the-index
+ web-update-the-location-of-module-vector
+ web-update-the-module-name-defined-in-used-in-list
+ web-write-module-names-to-a-file
+}
+\vfil\eject
+\centerline{\BF Appendix B}
+\bigskip
+The global variables used in {\tt web-mode} are:
+\medskip
+{\parindent0sp\parskip0sp\tt\obeylines
+web-buffer-name
+web-change-buffer-name
+web-default-directory
+web-defined-in-occurrence
+web-defined-in-used-in-location
+web-files
+web-index-buffer-name
+web-index-entry
+web-interactive-function-usage
+web-interactive-functions
+web-journal-on
+web-location-in-selected-index-entry-occurrences
+web-location-of-module
+web-max-number-of-modules
+web-mode-map
+web-module-begins
+web-module-changed-then-goto-change
+web-module-name
+web-module-name-defined-in-used-in
+web-module-names
+web-number-of-lines-in-window
+web-number-of-module-names
+web-number-of-modules-in-file
+web-selected-index-entry-occurrences
+web-selected-module-name
+web-used-in-occurrence
+}
+
+The documentation for the above can be viewed at any time by issuing
+the command
+$$\line{\hskip\parindent\tt M-x describe-variable\hfil
+ \kern2pt\hbox{\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt{\tt C-h v}\kern2pt}}
+ \hrule}\vrule}}
+$$
+At the prompt, the name of the variable of interest should be entered.
+
+\vfil\eject
+
+\centerline{\BF Appendix C}
+\bigskip
+In order to get {\tt WEAVE} to create a separate file containing the
+index and module names, the following changes were made to module 239:
+
+\verbatim
+@x
+@* Phase three processing.
+We are nearly finished! \.{WEAVE}'s only remaining task is to write out the
+index, after sorting the identifiers and index entries.
+
+@<Phase III: Output the cross-reference index@>=
+phase_three:=true; print_nl('Writing the index...');
+if change_exists then
+ begin finish_line; @<Tell about changed modules@>;
+ end;
+finish_line; out4("\")("i")("n")("x"); finish_line;
+@.\\inx@>
+@<Do the first pass of sorting@>;
+@<Sort and output the index@>;
+out4("\")("f")("i")("n"); finish_line;
+@.\\fin@>
+@<Output all the module names@>;
+out4("\")("c")("o")("n"); finish_line;
+@.\\con@>
+print('Done.');
+@y
+@* Phase three processing.
+We are nearly finished! \.{WEAVE}'s only remaining task is to write out the
+index, after sorting the identifiers and index entries.
+
+If the user has set the |no_xref| flag (the -x option on the command line),
+just finish off the page, omitting the index, module name list, and table of
+contents.
+
+@<Phase III: Output the cross-reference index@>=
+if no_xref then begin
+ finish_line;
+ out("\"); out5("v")("f")("i")("l")("l");
+ out4("\")("e")("n")("d");
+ finish_line;
+ end
+else begin
+phase_three:=true; print_nl('Writing the index...');
+finish_line;
+out("\"); out5("i")("n")("p")("u")("t"); out(" ");
+out5("I")("N")("D")("E")("X");
+finish_line;
+out("\"); out5("i")("n")("p")("u")("t"); out5(" ")("M")("O")("D")("U");
+out5("L")("E")("_")("N")("A"); out3("M")("E")("S");
+finish_line;
+rewrite(tex_file,'INDEX.tex');
+if change_exists then
+ begin @<Tell about changed modules@>;
+ end;
+finish_line; finish_line; out4("\")("i")("n")("x"); finish_line;
+@.\\inx@>
+@<Do the first pass of sorting@>;
+@<Sort and output the index@>;
+out4("\")("f")("i")("n"); finish_line;
+@.\\fin@>
+rewrite(tex_file,'MODULE_NAMES.tex');
+@<Output all the module names@>;
+out4("\")("c")("o")("n"); finish_line;
+@.\\con@>
+print('Done.');
+end;
+@z
+?endverbatim
+\vfil\eject
+
+Similarly, module 181 had to be changed in the {\tt WEAVE} for \Web s
+written in C\null. The changes are:
+
+\verbatim
+@x
+@ @c phase_three() {
+if (no_xref) {
+ finish_line();
+ out_str("\\vfill\\end");
+ finish_line();
+}
+else {
+ phase=3; printf("\nWriting the index...");
+ if (change_exists) {
+ finish_line(); @<Tell about changed modules@>;
+ }
+ finish_line(); out_str("\\inx"); finish_line();
+@.\\inx@>
+ @<Do the first pass of sorting@>;
+ @<Sort and output the index@>;
+ out_str("\\fin"); finish_line();
+@.\\fin@>
+ @<Output all the module names@>;
+ out_str("\\con"); finish_line();
+@.\\con@>
+}
+printf("Done.");
+check_complete(); /* was all of the change file used? */
+}
+@y
+@ @c phase_three() {
+if (no_xref) {
+ finish_line();
+ out_str("\\vfill\\end");
+ finish_line();
+}
+else {
+ phase=3; printf("\nWriting the index...");
+ finish_line();
+ out_str("\\input INDEX"); finish_line(); finish_line();
+ out_str("\\input MODULE_NAMES"); finish_line(); fclose(tex_file);
+ if ((tex_file=fopen("INDEX.tex","w"))==NULL)
+ fatal("! Cannot open ouput file ","INDEX.tex");
+ if (change_exists) { @<Tell about changed modules@>;
+ finish_line(); finish_line(); }
+ out_str("\\inx"); finish_line();
+@.\\inx@>
+ @<Do the first pass of sorting@>;
+ @<Sort and output the index@>;
+ out_str("\\fin"); finish_line(); fclose(tex_file);
+@.\\fin@>
+ if ((tex_file=fopen("MODULE_NAMES.tex","w"))==NULL)
+ fatal("! Cannot open ouput file ","MODULE_NAMES.tex");
+ @<Output all the module names@>;
+ out_str("\\con"); finish_line(); fclose(tex_file);
+@.\\con@>
+}
+printf("Done.");
+check_complete(); /* was all of the change file used? */
+}
+@z
+?endverbatim
+
+\bye
diff --git a/support/emacs-modes/web-mode.el b/support/emacs-modes/web-mode.el
new file mode 100644
index 0000000000..afe72d222c
--- /dev/null
+++ b/support/emacs-modes/web-mode.el
@@ -0,0 +1,5162 @@
+; Copyright (C) 1990 Mark B. Motl
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Publich License as published by
+; the Free Software Foundation.
+;
+; This program 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.
+;
+; To obtain a copy of the GNU General Public License, write to:
+; Free Software Foundation, Inc.
+; 675 Mass Ave.
+; Cambridge, MA 02139
+; USA
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; AUTHOR: Mark B. Motl <motl@cssun.tamu.edu>
+; Department of Computer Science
+; Texas A&M University
+; College Station, TX 77843-3112
+;
+; PURPOSE: The following functions are a set of GNU Emacs Lisp functions
+; to extend Emacs so that it is sensitive to the WEB style of
+; programming.
+;
+; DATE: The preliminary version of these functions was written in
+; Summer/Fall 1989.
+;
+; ADVISOR: Dr. S. Bart Childs <bart@cssun.tamu.edu>
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; <DISCLAIMER>
+; This program is still under development. The author accepts no
+; responsibility to anyone for the consequences of using it, for whether
+; it serves any particular purpose, or even works at all.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Any bugs or comments should be mailed to the author at the above address.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; REVISION HISTORY
+;
+; Late November 1989
+;
+; Made a significant change to the type of list maintained for the module
+; names. It now looks like
+;
+; (("Module Name 1" (Defined in Module #'s) (Used in Module #'s))
+; ("Module Name 2" (Defined in Module #'s) (Used in Module #'s))
+; ...
+; ("Module Name n" (Defined in Module #'s) (Used in Module #'s))
+; )
+;
+; As a consequence of this reorganization, the following functions had to
+; be modified: any-modules-undefined-initially, collect-module-names,
+; display-module-names, module-lookup, options-for-module-name-insertion,
+; and view-module-names.
+;
+; Two functions were deleted: print-module-names and replace-nth-element.
+;
+; The function "append-a-stub-module" was modified so that a stub module
+; is now added at the end of the section in which it is first used
+; instead of at the end of the buffer.
+;
+; Some new functions have been added:
+; 1) "collect-section-names" -- constructs a list of the major sections
+; and the module in which each section starts
+; 2) "view-section-names" -- prints the list of section names to another
+; buffer
+; 3) "switch-to-module" -- this function is useful when one is switched
+; to another buffer (e.g., running "view-section-names") and wants to
+; return to the buffer where the WEB document is. It prompts for a
+; module number to return to in the WEB; or, alternatively, one can
+; provide a prefix argument.
+; 4) "insert-new-module-name-in-list-of-module-names" -- this replaces
+; the old function "replace-nth-element".
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Early December 1989
+;
+; Added several functions so that traversal of the Defined In and Used In
+; lists in the list of module names could be accomplished. These are:
+;
+; first-use and first-define -- these can be executed from either the buffer
+; containing the WEB document or the buffer where the module names are
+; displayed. The only way to select a module is in the buffer containing
+; the list of module names (position the cursor on the line containing
+; the module name of interest). Once a module name has been selected,
+; first-use switches back to the buffer containing the WEB document at
+; the module where the selected module name was first used. If the
+; command is issued from the buffer containing the WEB document, point
+; is positioned at the beginning of the module where the most recently
+; selected module name was first used. The function first-define is analogous
+; to the operation of first-use except that it works on the Defined In
+; list instead of the Used In list.
+;
+; next-use, previous-use, next-define, and previous-define -- These functions
+; work as one would expect. These functions can only be used in the buffer
+; containing the WEB document.
+;
+; An internal support function, convert-list-to-string, was added so that
+; the lists Defined In and Used In (lists of integers) could be inserted
+; in the buffer where the module names are displayed.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Late December 1989
+;
+; Added some new functions to aid in communication with the index that
+; Weave creates. These are: eliminate-control-sequences, first-index-use,
+; next-index-use, previous-index-use, reformat-the-index, and view-index.
+; The second, third, fourth, and last of these are interactive; the remaining
+; ones are support functions. When the command view-index is invoked, it
+; first checks to see if the file INDEX.tex is present (we have modified the
+; output generated by Weave so that in addition to the TeX file, it also
+; creates two other files: INDEX.tex which contains the index and
+; MODULE_NAMES.tex which contains the list of section names). If not present,
+; it creates another process and Weaves the current buffer. The file
+; INDEX.tex is then read in and some reformatting is done so that it is more
+; readable. The user selects an index entry of interest by placing the
+; cursor anywhere on the line(s) where the index entry is located. An index
+; entry is selected then by issuing the command first-index-use. This command
+; can be issued from the buffer where the index is displayed or it can be
+; issued from the buffer containing the WEB document. If invoked from the
+; former, it switches back to the buffer containing the WEB document at the
+; beginning of the module where the selected index entry was first referenced.
+; If invoked from the latter, point is positioned at the beginning of the
+; module where the most recently selected index entry was first referenced.
+;
+; Once an index entry has been selected, the functions next-index-use and
+; previous-index-use can be used to traverse the list of references for the
+; most recently selected index entry.
+;
+; Also added functions count-sections (provides a count of the total number
+; of sections in the WEB), goto-section (which goes to the beginning of the
+; n-th section), and what-section (which informs the user of the section
+; that point is currently positioned in).
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; ACCOMMODATIONS FOR A CHANGE FILE
+;
+; In late December 1989, I added five new functions that deal with CHange
+; files. These are:
+;
+; 1) change-module --- Used in the buffer that contains the Web
+; document. The user positions point in the module that he wishes to
+; change and then invokes the function. It copies the entire module
+; contents from the Web buffer to the buffer containing the CHange file
+; twice---once between an @x @y and once between an @y @z. The text
+; is inserted in the proper position in the CHange file.
+;
+; 2) collect-list-of-changed-module-numbers --- collects and returns a list
+; of module numbers that have been changed in the CHange file.
+;
+; 3) escape-special-characters-in-regexp --- used when determining what
+; module in the Web a particular change corresponds to. Because the
+; text between the @x and @y may contain special characters Emacs uses
+; in regular expression searches, it is necessary to turn them into
+; ordinary characters.
+;
+; 4) view-list-of-changed-modules --- available in both the buffer
+; containing the Web document and the buffer containing the CHange file.
+; It displays a list of which modules in the Web have been changed in the
+; CHange file.
+;
+; 5) what-change --- available only in the buffer containing the CHange
+; file. Based on the position of point, it displays a descriptive message
+; in the minibufer indicating which module in the Web is being changed.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; January 3, 1990
+;
+; Changed the names of some functions:
+; FROM Name: TO Name:
+; module-count count-modules
+; section-count count-sections
+; show-index view-index
+; show-list-of-changed-modules view-list-of-changed-modules
+; show-module-names view-module-names
+; show-section-names view-section-names
+; statistics determine-statistics
+; what-module-does-this-change-correspond-to what-change
+;
+; Also added key-bindings which are accomplished at load time. I used the
+; convention: Each command takes the form
+; ESC (or META)
+; CTRL first-letter-of-function-name
+; CTRL first-letter-of-second-word-in-function-name
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; January 8, 1990
+;
+; Added two new functions change-file and web-file. When invoked they
+; set the current buffer to the CHange or Web file, respectively.
+; Eliminated the function switch-to-module.
+;
+; Changed some function names:
+; FROM TO
+; change-this-module edit-module
+; check-balance-of-module-delimiters delimiter-match-check
+; determine-statistics determine-characteristics
+; first-index-use first-index
+; next-index-use next-index
+; previous-index-use previous-index
+; view-list-of-changed-modules view-changed-modules-list
+; view-module-names view-module-names-list
+; view-section-names view-section-names-list
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; January 10, 1990
+;
+; Added four new functions:
+; 1) count-changes -- counts the number of changes in the CHange file.
+; 2) goto-change -- goes to the n-th change in the CHange file. The
+; changes are numbered sequentially beginning with 1.
+; 3) next-change -- positions point at the beginning of the next change.
+; 4) previous-change -- positions point at the beginning of the previous
+; change.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; January 13, 1990
+;
+; Added two new functions:
+; 1) initialize-module-names-list -- this function is invoked by web-mode
+; if two conditions prevail:
+; a) the file .mods exists for the WEB beging edited and
+; b) the file .mods is newer than the WEB
+; If both of these conditions are true, the information to initialize
+; the module-names list is read in from the file .mods. This saves
+; a considerable amount of time when the WEB is quite large, such as
+; initex.web. Thus, if the file initex.mods exists and it is newer
+; than initex.web, a lot of time can be saved in the initial startup.
+; 2) write-module-names-to-a-file -- this is also an internal support function.
+; Every time the module-names must be collected, this function is invoked
+; so that the new information can be written to the file .mods.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; January 16, 1990
+;
+; Completely changed the function collect-list-of-changed-module-numbers.
+; The method the function now uses closely resembles the method used by
+; Knuth in TANGLE and WEAVE. See modules 128 through 137 in TANGLE.WEB.
+; As a result of this change, I was able to delete the function escape-
+; special-characters-in-regexp.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; January 27, 1990
+;
+; Reworked the function collect-module-names so that it works considerably
+; faster.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; April 7, 1990
+;
+; Eliminated the functions first-index, first-define, and first-use. Made
+; the functions next-define, next-use, next-index, previous-define,
+; previous-use, and previous-index more logical. They work in either the
+; buffer displaying the index or module names or in the buffer containing
+; the Web document. If in one of the special buffers and one of these
+; commands is issued, the user is switched back to the Web document at the
+; next or previous occurrence based on point's position in the Web document
+; before the switch over to the special buffer.
+;
+; Added a global variable web-module-changed-then-goto-change. Its purpose
+; is to indicate where point is to be positioned when going to a module that
+; has been changed. If the variable's value is true, then point is positioned
+; in the CHange file at the change that corresponds to the module that the
+; user wants to go to. If the variables value is not true, then point is
+; positioned in the Web document with a message in the minibuffer that says
+; that the module has been changed.
+;
+; Renamed all functions and global variables so that web- precedes their name.
+; This was done in an effort to avoid any collisions when web-mode is used in
+; conjunction with other modes.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; July 30, 1990
+;
+; After looking at some journal files, I realized that when web-mode-save-
+; buffers-kill-emacs is invoked, the web-journal function doesn't write out
+; the proper count for web-mode-save-buffers-kill-emacs because the file
+; is written before the vector containing the counts gets updated.
+;
+; 1. Extend reformat or rewrite it to produce statistics.
+; These should include the usual things but for webs
+; it should also read a config file and produce things
+; like counts of @<*@>, @<sys*@>, and all other index
+; things, ...
+;
+; 2. The environment of Mark does not need this but a WEB
+; user does. Each library should have a corresponding
+; library whose elements are WEB sources for documenting
+; calls. For example: calling LEQT1F from IMSL should
+; be complemented by emacs including /usr/local/doc/imsl/leqt1f.web
+; and editing for the local use.
+;
+; 3. Major sections need a complementary command of the type
+; of @*subprogram-name@*. This string could be passed
+; to the index for scoping variables and comments that
+; may be entered into the index. Global vs local variables.
+;
+; 4. C prototypes and Pascal forward references: display of
+; these kinds of items could be handy for a programmer.
+; This is somewhat related to 2. above.
+;
+; 5. Integration with other tools such as Marcus' LPT or
+; Kevin Borden's work with X. Two particular items that
+; would yield the most benefit would be a tex previewer
+; and source level debugger. These may be possible now,
+; just not yet documented.
+;
+; 6. Also need to set up a default directory for Emacs to
+; search when @i's are encountered.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; GLOBAL variables and constants used in web-mode.
+;
+(defvar web-buffer-name "" "Name of Web document being edited.")
+
+(defvar web-change-buffer-name nil
+ "Name of the buffer containing the CHange file")
+
+(defvar web-default-directory nil
+ "The default-directory that the Web is located in.")
+
+(defvar web-defined-in-occurrence -1
+ "Used as a pointer into the (Defined In) list of the most recently selected
+module name.")
+
+(defvar web-defined-in-used-in-location -1
+ "Used as a pointer into the list of module names. Used to take the
+(web-defined-in-used-in-location)-th car of module-names.")
+
+(defvar web-files nil
+ "A list of the files used in the WEB. The general form of the list is:
+(\"CHange file name\" \"WEB file name\" \"include file 1\" \"include file 2\"
+... \"include file n\")")
+
+(defvar web-index-buffer-name ""
+ "Name of the buffer where the index is displayed.")
+
+(defvar web-index-entry ""
+ "The selected index entry.")
+
+(defvar web-interactive-function-usage nil
+ "A vector containing the number of times that the interactive functions
+were executed. The i-th element corresponds to the i-th car of
+web-interactive-functions")
+
+(defvar web-interactive-functions nil
+ "List of the interactive functions available in web-mode.")
+; initialize web-interactive-functions
+(setq web-interactive-functions
+ '("web-change-file"
+ "web-collect-module-names"
+ "web-count-changes"
+ "web-count-modules"
+ "web-count-sections"
+ "web-delimiter-match-check"
+ "web-determine-characteristics"
+ "web-edit-module"
+ "web-file"
+ "web-goto-change-corresponding-to-module"
+ "web-goto-module"
+ "web-goto-section"
+ "web-include-file"
+ "web-insert-index-entry"
+ "web-insert-module-name"
+ "web-is-this-a-new-module-beginning"
+ "web-mode"
+ "web-mode-save-buffers-kill-emacs"
+ "web-newline"
+ "web-next-change"
+ "web-next-define"
+ "web-next-index"
+ "web-next-module"
+ "web-next-section"
+ "web-next-use"
+ "web-previous-change"
+ "web-previous-define"
+ "web-previous-index"
+ "web-previous-module"
+ "web-previous-section"
+ "web-previous-use"
+ "web-rename-module"
+ "web-view-changed-modules-list"
+ "web-view-index"
+ "web-view-module-names-list"
+ "web-view-section-names-list"
+ "web-what-change"
+ "web-what-module"
+ "web-what-section"
+ ) ; end list
+) ; end setq
+
+(defvar web-location-in-selected-index-entry-occurrences -1
+ "Used as a pointer into the list selected-web-index-entry-occurrences.")
+
+(defvar web-location-of-module nil
+ "A vector of vectors. The i-th element contains information about the i-th
+module. Each element is a vector of 4 parts: the first part is an index into
+the list web-files indicative of which file the i-th module is located; the
+second part is the module number relative to the file that it is located in;
+the third part tells the major section that the i-th mdoule is located in;
+the fourth part indicates if the i-th module has been changed (0=no, 1=yes);
+and the fifth indicates the position of the CHange in the CHange file.")
+
+(defconst web-max-number-of-modules 2000
+ "The maximum number of modules in the WEB and its associated include
+files.")
+
+(defvar web-mode-map nil "Keymap used in Web Mode.")
+
+(defvar web-module-begins "^@\\( \\|\t\\|\n\\|\\*\\)"
+ "Regular expression used for determining the beginning of a module.")
+
+(defvar web-module-changed-then-goto-change nil
+ "Boolean variable. When going to a module and it is true, point is
+positioned in the CHange buffer at the CHange corresponding to the module
+number; otherwise, point is positioned at the module in the Web file.")
+
+(defvar web-module-name "\\(@@\\)*@<\\(@'\\|@\"\\|@@\\|[^@]\\)+@>"
+ "Regular expression used for isolating a valid module name.")
+
+(defvar web-module-name-defined-in-used-in nil
+ "A list of the Web's module names. The list takes the form
+ ((\"Module Name 1\" (Defined in Module #'s) (Used in Module #'s))
+ (\"Module Name 2\" (Defined in Module #'s) (Used in Module #'s))
+ ...
+ (\"Module Name n\" (Defined in Module #'s) (Used in Module #'s))
+ )")
+
+(defvar web-module-names nil "List of Web document's module names.")
+
+(defvar web-number-of-lines-in-window 0
+"Total number of lines in window where Emacs is used.")
+
+(defvar web-number-of-module-names 0
+ "Total number of module names in the Web.")
+
+(defvar web-number-of-modules-in-file nil
+ "A vector that contains number of modules in each of the WEB files. The
+elements are interpretted as follows: 0 - # of modules in the CHange file;
+1 - # of modules in the WEB file; 2 - # of modules in include file 1;
+3 - # of modules in include file 2; etc.")
+
+(defvar web-selected-index-entry-occurrences nil
+ "A list comprised of the module numbers where the most recently selected
+index entry was referenced.")
+
+(defvar web-selected-module-name ""
+ "Represents the name of the most recently selected module name.")
+
+(defvar web-used-in-occurrence -1
+ "Used as a pointer into the (Used In) list of the most recently selected
+module name.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Initialize the key-map used in web-mode. This is done at load-time.
+;
+(if web-mode-map
+; then the user has defined one
+ ()
+; else
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\e\C-c\C-f" 'web-change-file)
+ (define-key map "\e\C-c\C-c" 'web-count-changes)
+ (define-key map "\e\C-c\C-m" 'web-count-modules)
+ (define-key map "\e\C-c\C-s" 'web-count-sections)
+ (define-key map "\e\C-d\C-m" 'web-delimiter-match-check)
+ (define-key map "\e\C-d\C-c" 'web-determine-characteristics)
+ (define-key map "\e\C-e\C-m" 'web-edit-module)
+ (define-key map "\e\C-w\C-f" 'web-file)
+ (define-key map "\e\C-g\C-c" 'web-goto-change-corresponding-to-module)
+ (define-key map "\e\C-g\C-m" 'web-goto-module)
+ (define-key map "\e\C-g\C-s" 'web-goto-section)
+ (define-key map "\e\C-i\C-f" 'web-include-file)
+ (define-key map "\e\C-i\C-i" 'web-insert-index-entry)
+ (define-key map "<" 'web-insert-module-name)
+ (define-key map "@" 'web-is-this-a-new-module-beginning)
+ (define-key map "\015" 'web-newline)
+ (define-key map "\e\C-n\C-c" 'web-next-change)
+ (define-key map "\e\C-n\C-d" 'web-next-define)
+ (define-key map "\e\C-n\C-i" 'web-next-index)
+ (define-key map "\e\C-n\C-m" 'web-next-module)
+ (define-key map "\e\C-n\C-s" 'web-next-section)
+ (define-key map "\e\C-n\C-u" 'web-next-use)
+ (define-key map "\e\C-p\C-c" 'web-previous-change)
+ (define-key map "\e\C-p\C-d" 'web-previous-define)
+ (define-key map "\e\C-p\C-i" 'web-previous-index)
+ (define-key map "\e\C-p\C-m" 'web-previous-module)
+ (define-key map "\e\C-p\C-s" 'web-previous-section)
+ (define-key map "\e\C-p\C-u" 'web-previous-use)
+ (define-key map "\e\C-r\C-m" 'web-rename-module)
+ (define-key map "\e\C-v\C-c" 'web-view-changed-modules-list)
+ (define-key map "\e\C-v\C-i" 'web-view-index)
+ (define-key map "\e\C-v\C-m" 'web-view-module-names-list)
+ (define-key map "\e\C-v\C-s" 'web-view-section-names-list)
+ (define-key map "\e\C-w\C-c" 'web-what-change)
+ (define-key map "\e\C-w\C-m" 'web-what-module)
+ (define-key map "\e\C-w\C-s" 'web-what-section)
+ (setq web-mode-map map)
+ ) ; end let
+) ; end if
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Here are the functions that comprise web-mode.el
+;
+(defun web-any-modules-undefined-initially ()
+ "This function is invoked by \\[web-mode]. It checks to make sure that all
+modules are defined. If a module is undefined, a stub module is appended.
+ARGUMENTS : None
+GLOBAL Variables : web-module-name-defined-in-used-in and web-module-names
+LOCAL Variable : ctr and ptr
+RETURNS : Nothing
+USES : web-append-a-stub-module and web-goto-module"
+ (let ((ctr 0)
+ (ptr 0)
+ )
+ (while (nth ctr web-module-names)
+ (setq ptr (string-to-int (substring (nth ctr web-module-names)
+ (+ (string-match " " (nth ctr web-module-names)) 2))))
+ (if (null (car (car (cdr (nth ptr web-module-name-defined-in-used-in)))))
+ ; then
+ (progn
+ (ding)
+ (message "Appending a module for %s"
+ (substring (car (nth ptr web-module-name-defined-in-used-in)) 0
+ (length (car (nth ptr web-module-name-defined-in-used-in)))))
+ (sit-for 2)
+ (web-goto-module (car (car (cdr (cdr
+ (nth ptr web-module-name-defined-in-used-in))))))
+ (setq module-number-of-stub (web-append-a-stub-module (substring
+ (car (nth ptr web-module-name-defined-in-used-in)) 0
+ (length (car (nth ptr web-module-name-defined-in-used-in))))))
+ (setcdr (nth ptr web-module-name-defined-in-used-in)
+ (append (list (list module-number-of-stub))
+ (list (car (cdr (cdr
+ (nth ptr web-module-name-defined-in-used-in)))))))
+ ) ; end then
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ ) ; end let
+)
+
+(defun web-append-a-stub-module (module-name)
+ "This function is invoked when a new stub module needs to be inserted. It
+appends a module with no commentary, an index entry indicating that this module
+is a stub, and the named module MODULE-NAME with no code.
+ARGUMENT : module-name (required)
+GLOBAL Variables : None
+LOCAL Variables : module-number-of-stub
+RETURNS : module-number-of-stub
+USES : web-insert-index-entry, web-update-the-location-of-module-vector,
+ web-update-the-module-name-defined-in-used-in-list, and web-what-module"
+ (save-excursion
+ (let ((module-number-of-stub))
+ (if (re-search-forward "^@\\*" nil t)
+ ; then position point at the end of the current section
+ (forward-line -1)
+ ; else position point at the end of the buffer
+ ; (i.e., there is no next section)
+ (goto-char (point-max))
+ (newline)
+ ) ; end if
+ (newline)
+ (insert-string "@ ")
+ (web-update-the-location-of-module-vector ? )
+ (web-insert-index-entry "R" "Stub")
+ (insert-string (concat "@<" module-name "@>=\n"))
+ (setq module-number-of-stub (web-what-module))
+ (web-update-the-module-name-defined-in-used-in-list
+ module-number-of-stub)
+ module-number-of-stub
+ ) ; end let
+ ) ; end excursion
+)
+
+(defun web-binary-search-of-names (names num-elements-in-names search-key len)
+ "This is an internal support function that performs a binary search on the
+list NAMES with NUM-ELEMENTS-IN-NAMES elements to find SEARCH-KEY of length
+LEN.
+ARGUMENTS : names, num-elements-in-names, search-key, and len (all required)
+LOCAL Variables : bottom, found, location, mid, and top
+GLOBAL Variables : None
+RETURNS : location
+USES : Nothing"
+ (let ((bottom (1- num-elements-in-names))
+ found
+ (location -1)
+ (mid 0)
+ (top 0)
+ )
+ (while (and (not (null names))
+ (not found)
+ (<= top bottom)
+ )
+ (setq mid (/ (+ top bottom) 2))
+ (cond
+ ((string= (substring search-key 0 len)
+ (substring (nth mid names) 0
+ (min len (length (nth mid names)))))
+ ; then we have a match
+ (setq found t
+ location mid)
+ ) ; end case
+ ((string< (substring search-key 0 len)
+ (substring (nth mid names) 0
+ (min len (length (nth mid names)))))
+ (setq bottom (1- mid))
+ ) ; end case
+ (t
+ (setq top (1+ mid))
+ ) ; end case
+ ) ; end cond
+ ) ; end while
+ location ; return the location
+ ) ; end let
+)
+
+(defun web-change-file ()
+ "Makes the buffer that contains the CHange file the current buffer.
+ARGUMENTS : None
+LOCAL Variables : None
+GLOBAL Variable : web-change-buffer-name
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files and web-journal"
+ (interactive)
+ (web-journal "web-change-file")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (switch-to-buffer web-change-buffer-name)
+)
+
+(defun web-check-if-buffer-is-one-of-the-web-files ()
+ "This function checks if the current buffer is one of the files included
+in web-files. If the current buffer is not one of the files include in
+web-files, an error is signaled indicating that a user has attempted to use
+one of the functions in web-mode in a buffer that \\[web-mode] was not used
+on.
+ARGUMENTS : None
+GLOBAL Variables : web-default-directory and web-files
+LOCAL Variable : ctr
+RETURNS : pointer into the web-files list
+USES : Nothing"
+ (let ((ctr 0)
+ current-buffer-is-one-of-the-web-files
+ )
+ (while (and (not current-buffer-is-one-of-the-web-files)
+ (nth ctr web-files))
+ (if (string-equal
+ (expand-file-name (nth ctr web-files) web-default-directory)
+ (buffer-file-name))
+ ; then
+ (setq current-buffer-is-one-of-the-web-files t)
+ ; else
+ (setq ctr (1+ ctr))
+ ) ; end if
+ ) ; end while
+ (if (not current-buffer-is-one-of-the-web-files)
+ ; then
+ (if (not (or (string= (buffer-name (current-buffer))
+ (concat "STATISTICS for " web-buffer-name "*"))
+ (string= (buffer-name (current-buffer))
+ "*Module Names*")
+ (string= (buffer-name (current-buffer))
+ web-index-buffer-name)
+ (string= (buffer-name (current-buffer))
+ "*CHanged Modules*")
+ (string= (buffer-name (current-buffer))
+ "*Module Name (Defined In) (Used In)*")
+ (string= (buffer-name (current-buffer))
+ "*Section Names*")
+ (string= (buffer-name (current-buffer))
+ "web-mode.jou")
+ ) ; end or
+ ) ; end not
+ ; then
+ (error "Attempting to use a function in a non-Web buffer.")
+ ) ; end if
+ ; else
+ ctr ; return the location of the current-buffer in web-files
+ ) ; end if
+ ) ; end let
+)
+
+(defun web-collect-list-of-changed-module-numbers ()
+ "This is an internal support function used by \\[web-edit-module],
+\\[web-view-changed-modules-list], and \\[web-what-change]. It returns a list
+of the module numbers in the Web being edited that have been changed in the
+CHange file.
+ARGUMENTS : None
+GLOBAL Variables : web-change-buffer-name and web-buffer-name
+LOCAL Variables : change-begins-at, changed-module, discrepancies,
+ discrepancies-begin-at, line-in-change-file, and
+ line-no-in-web
+RETURNS : Nothing
+USES : web-what-module"
+ (let ((change-begins-at 0)
+ (changed-module 0)
+ (ctr 0)
+ (discrepancies 0)
+ (discrepancies-begin-at 0)
+ line-in-change-file
+ (line-no-in-web 1)
+ )
+ (message "Determining which modules have been CHanged...")
+ (save-excursion
+ (set-buffer web-change-buffer-name)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "^@\\(x\\|y\\|z\\)" nil t)
+ (if (or (char-equal (downcase (string-to-char (buffer-substring
+ (match-beginning 1) (match-end 1)))) ?y)
+ (char-equal (downcase (string-to-char (buffer-substring
+ (match-beginning 1) (match-end 1)))) ?z)
+ ) ; end condition
+ ; then
+ (error "CHange beginning on line %d in %s is missing an @x."
+ (count-lines (point-min) (point)) web-change-buffer-name)
+ ; else
+ (setq change-begins-at (count-lines (point-min) (point)))
+ (forward-line 1)
+ (if (eobp) (error "CHange file ended before @y."))
+ (setq line-in-change-file (buffer-substring (point)
+ (save-excursion (end-of-line) (point))))
+ (save-excursion ; find this line's position in the WEB file
+ (set-buffer web-buffer-name)
+ (save-excursion
+ (goto-line line-no-in-web)
+ (if (not (search-forward line-in-change-file nil t))
+ ; then couldn't find line from the change file
+ (error "WEB file ended during CHange.")
+ ; else did find the line from the change file
+ (setq line-no-in-web (count-lines (point-min) (point))
+ changed-module (web-what-module))
+ ) ; end if
+ ) ; end excursion
+ ) ; end excursion
+ (setq line-no-in-web (1+ line-no-in-web)
+ discrepancies 0)
+ (forward-line 1)
+ (if (eobp) (error "CHange file ended before @y."))
+ (while (not (looking-at "^@\\(x\\|y\\|z\\)"))
+ (if (not
+ (string-equal
+ (buffer-substring (point) (save-excursion (end-of-line)
+ (point)))
+ (save-excursion
+ (set-buffer web-buffer-name)
+ (save-excursion
+ (goto-line line-no-in-web)
+ (if (eobp) (error "WEB ended during CHange."))
+ (buffer-substring (point)
+ (save-excursion (end-of-line)
+ (point)))
+ ) ; end excursion
+ ) ; end excursion
+ ) ; end string-equal
+ ) ; end not
+ ; then
+ (progn
+ (if (zerop discrepancies)
+ ; then
+ (setq discrepancies-begin-at line-no-in-web)
+ ) ; end if
+ (setq discrepancies (1+ discrepancies))
+ ) ; end then
+ ) ; end if
+ (setq line-no-in-web (1+ line-no-in-web))
+ (forward-line 1)
+ (if (eobp) (error "CHange file ended during CHange."))
+ ) ; end while
+ (if (or (char-equal (downcase (string-to-char (buffer-substring
+ (match-beginning 1) (match-end 1)))) ?x)
+ (char-equal (downcase (string-to-char (buffer-substring
+ (match-beginning 1) (match-end 1)))) ?z)
+ ) ; end condition
+ ; then
+ (error "The @x located on line %d in %s has no matching @y."
+ change-begins-at web-change-buffer-name)
+ ; else scan forward to the next @
+ (if (not (zerop discrepancies))
+ ; then
+ (if (= discrepancies 1)
+ ; then
+ (error
+ "Hmm... %d line beginning at line %d in %s failed to match."
+ discrepancies discrepancies-begin-at web-buffer-name)
+ ; else
+ (error
+ "Hmm... %d lines beginning at line %d in %s failed to match."
+ discrepancies discrepancies-begin-at web-buffer-name)
+ ) ; end if
+ ) ; end if
+ (forward-line 1)
+ (if (eobp) (error "CHange file ended before @z."))
+ (while (not (looking-at "^@\\(x\\|y\\|z\\)"))
+ (forward-line 1)
+ (if (eobp) (error "CHange file ended before @z."))
+ ) ; end while
+ (if (or (char-equal (downcase (string-to-char (buffer-substring
+ (match-beginning 1) (match-end 1)))) ?x)
+ (char-equal (downcase (string-to-char (buffer-substring
+ (match-beginning 1) (match-end 1)))) ?y)
+ ) ; end condition
+ ; then
+ (error "The @x located on line %d in %s has no matching @z."
+ change-begins-at web-change-buffer-name)
+ ; else
+ (end-of-line)
+ ) ; end if
+ (aset (aref web-location-of-module changed-module) 3 1)
+ (if (zerop (aref (aref web-location-of-module changed-module) 4))
+ ; then
+ (save-excursion
+ (goto-line change-begins-at)
+ (forward-char 2)
+ (setq change-begins-at (point))
+ (goto-char (point-min))
+ (setq ctr 0)
+ (while (re-search-forward "^@x" change-begins-at t)
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (aset (aref web-location-of-module changed-module) 4 ctr)
+ ) ; end excursion
+ ) ; end if
+ ) ; end if
+ ) ; end while
+ ) ; end while
+ ) ; end excursion
+ ) ; end excursion
+ (message "Determining which modules have been CHanged...done")
+ ) ; end let
+)
+
+(defun web-collect-location-of-modules ()
+ "This function actually initializes the vector web-location-of-module. The
+vector consists of vectors. The i-th vector gives information about the i-th
+module in the Web. Each of these vectors has three elements: the first is a
+index into the list web-files which is indicative of the file that the i-th
+module is located; the secend the i-th module's position relative to the
+beginning of the file that it is located in; and the third element is
+indicative of the section that the i-th module is in.
+ARGUMENTS : NONE
+GLOBAL Variables : web-location-of-module, web-number-of-modules-in-file,
+ web-files, and web-mode-map
+LOCAL Variables : file-number, include-file-name, module-number, and
+ section-number
+RETURNS : Nothing
+USES : web-collect-location-of-modules and web-eliminate-white-space"
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "^@\\(i\\| \\|\n\\|\t\\|\\*\\)" nil t)
+ (if (char-equal ?i
+ (string-to-char (buffer-substring (match-beginning 1) (match-end 1))))
+ ; then
+ (progn
+ (setq include-file-name (buffer-substring (point)
+ (save-excursion (end-of-line) (point))))
+ (setq include-file-name (substring include-file-name 0
+ (string-match " " include-file-name 1)))
+ (setq web-files (append web-files (list
+ (web-eliminate-white-space include-file-name))))
+ (setq file-number (cons (1- (length web-files)) file-number))
+ (save-excursion
+ (find-file-noselect (expand-file-name
+ (nth (car file-number) web-files) web-default-directory))
+ (set-buffer (get-file-buffer (expand-file-name
+ (nth (car file-number) web-files) web-default-directory)))
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ (use-local-map web-mode-map)
+ (web-collect-location-of-modules)
+ ) ; end excursion
+ ) ; end then
+ ; else
+ (if (char-equal ?*
+ (string-to-char (buffer-substring (match-beginning 1) (match-end 1))))
+ ; then
+ (setq section-number (1+ section-number))
+ ) ; end if
+ (aset web-number-of-modules-in-file (car file-number)
+ (1+ (aref web-number-of-modules-in-file (car file-number))))
+ (aset web-location-of-module module-number
+ (vector (car file-number)
+ (aref web-number-of-modules-in-file (car file-number))
+ section-number
+ 0 ; has it changed
+ 0 ; if changed, the relative position in the CHange file
+ ) ; end vector
+ ) ; end aset
+ (setq module-number (1+ module-number))
+ ) ; end if
+ ) ; end while
+ (setq file-number (cdr file-number))
+ ) ; end excursion
+)
+
+(defun web-collect-module-names ()
+ "This function is invoked by \\[web-mode]. It collects the list
+module-name-defined-i9n-used-in list. This function can be invoked by the user
+if the list is in error (e.g., if a module name has been added but then the
+user deletes it--\\[web-mode] has no way of knowing when a module name or a
+module has been deleted
+ARGUMENTS : None
+GLOBAL Variables : web-module-name-defined-in-used-in, web-module-names,
+ web-number-of-module-names, web-default-directory,
+ and web-files
+LOCAL Variable : module-number
+RETURNS : Nothing
+USES : web-collect-module-names-in-buffer, web-journal, and
+ web-write-module-names-to-a-file"
+ (interactive)
+ (web-journal "web-collect-module-names")
+ (let ((module-number 1))
+ (setq web-module-name-defined-in-used-in ()
+ web-module-names ()
+ web-number-of-module-names 0)
+ (save-excursion
+ (set-buffer (get-file-buffer (expand-file-name (nth 1 web-files)
+ web-default-directory)))
+ (web-collect-module-names-in-buffer)
+ ) ; end excursion
+ (web-write-module-names-to-a-file)
+ ) ; end let
+)
+
+(defun web-collect-module-names-in-buffer ()
+ "This function is used to collect a list of all valid module names. The list
+takes the form
+ ((\"Module Name 1\" (Defined in Module #'s) (Used in Module #'s))
+ (\"Module Name 2\" (Defined in Module #'s) (Used in Module #'s))
+ ...
+ (\"Module Name n\" (Defined in Module #'s) (Used in Module #'s))
+ )
+First it must determine the beginning and ending points of where a module name
+begins and ends. Once it has the name isolated, it checks the last three
+characters. If the last three characters are an ellipsis the length of the
+module name is set to the number of characters between the starting and ending
+positions less 3; otherwise the length is set to the number of characters
+between the starting and ending positons of the module name. The list as
+mentioned above is not kept in alphabetical order. The module names themselves
+are maintained in a separate list in alphabetical order. Each module name has
+an integer appended to it which is used as a pointer into the list as mentioned
+above. This module name is then compared with the module names already in the
+list that contains only module names. If no match is found, the new module
+name is inserted into both lists. If a match is found, update either the
+Defined In or Used In list that accompanies the module name in the big list.
+ARGUMENTS : None
+GLOBAL Variables : web-module-name-defined-in-used-in, web-module-names,
+ web-number-of-module-names, web-default-directory,
+ and web-module-name
+LOCAL Variables : char-after-at-greater, include-file-name, len, location,
+ module-name, module-number, next-module-begins, and
+ number-of-modules
+RETURNS : web-module-names
+USES : web-binary-search-of-names, web-collect-module-names-in-buffer,
+ and web-eliminate-white-space"
+ (let (char-after-at-greater
+ (len 0)
+ include-file-name
+ (location -1)
+ module-name
+ (next-module-begins (point))
+ )
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "^@\\(i\\| \\|\n\\|\t\\|\\*\\)" nil t)
+ (if (char-equal ?i (string-to-char (buffer-substring
+ (match-beginning 1) (match-end 1))))
+ ; then
+ (save-excursion
+ (setq include-file-name (buffer-substring (point)
+ (save-excursion (end-of-line) (point))))
+ (setq include-file-name
+ (substring include-file-name 0
+ (string-match " " include-file-name 1)))
+ (set-buffer (get-file-buffer (expand-file-name
+ (web-eliminate-white-space include-file-name)
+ web-default-directory)))
+ (web-collect-module-names-in-buffer)
+ ) ; end excursion
+ ; else
+ (save-excursion
+ (if (re-search-forward "^@\\(i\\| \\|\n\\|\t\\|\\*\\)" nil t)
+ ; then
+ (setq next-module-begins (point))
+ ; else
+ (setq next-module-begins (point-max))
+ ) ; end if
+ ) ; end excursion
+ (message "Collecting module names in Module %d" module-number)
+ (while (re-search-forward web-module-name next-module-begins t)
+ (setq module-name (web-eliminate-white-space
+ (buffer-substring (match-beginning 2) (match-end 2))))
+ (setq len (length module-name))
+ (if (and (> len 3) (string-equal "..."
+ (substring module-name (- len 3) len)))
+ ; then
+ (setq len (- len 3))
+ ) ; end if
+ (if (looking-at "=")
+ ; then
+ (setq char-after-at-greater ?=)
+ ; else
+ (setq char-after-at-greater ? )
+ ) ; end if
+ (setq location
+ (web-binary-search-of-names web-module-names
+ web-number-of-module-names module-name len))
+ (if (= location -1)
+ ; then a new module name has been encountered
+ (progn
+ (setq web-module-names (sort (append web-module-names
+ (list (concat module-name
+ " " (int-to-string web-number-of-module-names))))
+ 'string<)
+ web-number-of-module-names
+ (1+ web-number-of-module-names))
+ (if (char-equal ?= char-after-at-greater)
+ ; then this new module was defined (i.e., @<...@>=)
+ (setq web-module-name-defined-in-used-in
+ (append web-module-name-defined-in-used-in
+ (list (list module-name (list module-number)
+ (list ())))))
+ ; else this new module was used before defined
+ (setq web-module-name-defined-in-used-in
+ (append web-module-name-defined-in-used-in
+ (list (list module-name (list ())
+ (list module-number)))))
+ ) ; end if
+ ) ; end then
+ ; else the module name is already in list
+ (setq location (string-to-int
+ (substring (nth location web-module-names)
+ (+ (string-match " " (nth location web-module-names)) 2))))
+ (if (char-equal ?= char-after-at-greater)
+ ; then an existing module name has been redefined
+ (if (null (car (car (cdr
+ (nth location web-module-name-defined-in-used-in)))))
+ ; then
+ (setcdr (nth location web-module-name-defined-in-used-in)
+ (append (list (list module-number))
+ (cdr (cdr (nth
+ location web-module-name-defined-in-used-in)))))
+ ; else
+ (setcdr (nth location web-module-name-defined-in-used-in)
+ (append (list (append
+ (car (cdr (nth
+ location web-module-name-defined-in-used-in)))
+ (list module-number)))
+ (cdr (cdr (nth
+ location web-module-name-defined-in-used-in)))))
+ ) ; end if
+ ; else an existing module has been used
+ (if (null (car (car (cdr (cdr
+ (nth location web-module-name-defined-in-used-in))))))
+ ; then
+ (setcdr (nth location web-module-name-defined-in-used-in)
+ (append (list (car (cdr
+ (nth location web-module-name-defined-in-used-in))))
+ (list (list module-number))))
+ ; else
+ (setcdr (nth location web-module-name-defined-in-used-in)
+ (append (list (car (cdr
+ (nth location web-module-name-defined-in-used-in))))
+ (list (append (car (cdr (cdr
+ (nth location web-module-name-defined-in-used-in))))
+ (list module-number)))))
+ ) ; end if
+ ) ; end if
+ ) ; end if
+ ) ; end while
+ (setq module-number (1+ module-number))
+ ) ; end if
+ ) ; end while
+ ) ; end excursion
+ ) ; end let
+)
+
+(defun web-collect-section-names ()
+ "This function collects a list of the major section names used in the Web.
+It also keeps track of the module number where each major section begins.
+ARGUMENTS: None
+GLOBAL Variables : None
+LOCAL Variables : ctr and section-names
+RETURNS : section-names
+USES : web-count-sections, web-eliminate-white-space, web-goto-section,
+ and web-what-module"
+ (let ((ctr 1)
+ (num-of-sections (web-count-sections))
+ section-names
+ )
+ (save-excursion
+ (while (<= ctr num-of-sections)
+ (web-goto-section ctr)
+ (re-search-forward "^@\\*\\(.*\\)\\.\\( \\|\n\\)" nil t)
+ (setq section-names (append section-names (list
+ (list (web-eliminate-white-space (buffer-substring
+ (match-beginning 1) (match-end 1)))
+ (web-what-module)))))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ ) ; end excursion
+ section-names ; return the list
+ ) ; end let
+)
+
+(defun web-convert-list-to-string (list-of-numbers)
+ "This is an internal support function that accepts a LIST-OF-NUMBERS and
+converts it into a string.
+ARGUMENT : list-of-numbers (required)
+GLOBAL Variables : None
+LOCAL Variables : ctr and list-as-string
+RETURNS : list-as-string
+USES : Nothing"
+ (let ((ctr 0)
+ list-as-string)
+ (while (not (null (nth ctr list-of-numbers)))
+ (setq list-as-string (concat list-as-string
+ (int-to-string (nth ctr list-of-numbers)) " "))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (if (> (length list-as-string) 1)
+ ; then eliminate the trailing space
+ (setq list-as-string
+ (substring list-as-string 0 (1- (length list-as-string))))
+ ) ; end if
+ list-as-string ; return the list of numbers as a string
+ ) ; end let
+)
+
+(defun web-count-changes ()
+ "Count the number of changes in the CHange file.
+ARGUMENTS : None
+GLOBAL Variable : web-location-of-module
+LOCAL Variables : count, index, and number-of-modules
+RETURNS : count
+USES : web-check-if-buffer-is-one-of-the-web-files, web-count-modules,
+ and web-journal"
+ (interactive)
+ (web-journal "web-count-changes")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((count 0)
+ (index 0)
+ (number-of-modules (web-count-modules))
+ )
+ (while (< index number-of-modules)
+ (if (not (zerop (aref (aref web-location-of-module index) 3)))
+ ; then
+ (setq count (1+ count))
+ ) ; end if
+ (setq index (1+ index))
+ ) ; end while
+ (message "%d modules have been CHanged." count)
+ count ; return the number of changes in the web
+ ) ; end let
+)
+
+(defun web-count-modules ()
+ "Count the number of modules in the Web file.
+ARGUMENTS : None
+GLOBAL Variables : web-number-of-modules-in-file and web-files
+LOCAL Variable : ctr and module-count
+RETURNS : module-count
+USES : web-check-if-buffer-is-one-of-the-web-files and web-journal"
+ (interactive)
+ (web-journal "web-count-modules")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((module-count 0)
+ (ctr 1)
+ )
+ (while (<= ctr (length web-files))
+ (setq module-count (+ module-count
+ (aref web-number-of-modules-in-file ctr))
+ ctr (1+ ctr))
+ ) ; end while
+ (message "The number of modules in %s is %d"
+ (upcase (nth 1 web-files)) module-count)
+ module-count ; return the number of modules in the web
+ ) ; end let
+)
+
+(defun web-count-sections ()
+ "Count the number of sections in the Web file.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variable : module-count
+RETURNS : the number of sections
+USES : web-check-if-buffer-is-one-of-the-web-files, web-count-modules, and
+ web-journal"
+ (interactive)
+ (web-journal "web-count-sections")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((module-count (web-count-modules)))
+ (message "The number of sections in %s is %d"
+ (upcase (nth 1 web-files))
+ (aref (aref web-location-of-module module-count) 2))
+ (aref (aref web-location-of-module module-count) 2) ; return # of sections
+ ) ; end let
+)
+
+(defun web-count-the-matches (search-string)
+ "This is an internal support function that counts the number of occurrences
+of SEARCH-STRING in the Web files.
+ARGUMENT : search-string (required)
+GLOBAL Variables : done, file-number, module-count, stopping-point, and
+ web-default-directory
+LOCAL Variable : file-no and include-file-name
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-count-the-matches, and
+ web-eliminate-white-space"
+ (save-excursion
+ (let ((file-no (web-check-if-buffer-is-one-of-the-web-files))
+ include-file-name
+ )
+ (goto-char (point-min))
+ (while (and (not done)
+ (re-search-forward search-string
+ (aref stopping-point file-no) t)
+ ) ; end condition
+ (if (char-equal ?i
+ (string-to-char (buffer-substring (match-beginning 1)
+ (match-end 1))))
+ ; then
+ (save-excursion
+ (setq include-file-name (buffer-substring (point)
+ (save-excursion (end-of-line) (point))))
+ (setq include-file-name (substring include-file-name 0
+ (string-match " " include-file-name 1)))
+ (set-buffer (get-file-buffer (expand-file-name
+ (web-eliminate-white-space include-file-name)
+ web-default-directory)))
+ (web-count-the-matches "^@\\(i\\| \\|\t\\|\n\\|\\*\\)")
+ ) ; end excursion
+ ; else
+ (setq module-count (1+ module-count))
+ ) ; end if
+ ) ; end while
+ (if (= file-no file-number)
+ ; then we are done
+ (setq done t)
+ ) ; end if
+ ) ; end let
+ ) ; end excursion
+)
+
+(defun web-delimiter-match-check ()
+ "This function checks if all module delimiters (namely, @<...@>) are matched.
+It records any missing delimiter pairs, whether they be opening or closing
+pairs that are missing. If any missing delimiters are discovered, a window
+pops up with the pertinent information. The user then needs to rectify the
+situation and re-invoke \\[web-mode].
+ARGUMENTS : None
+GLOBAL Variable : web-module-begins
+LOCAL Variables : balance, bound-for-search, closing-delimiters,
+ next-module-begins, opening-char, opening-delimiters,
+ and valid-delimiter
+RETURNS : balance (boolean indicating if module delimiters are balanced)
+USES : web-check-if-buffer-is-one-of-the-web-files and web-journal"
+ (interactive)
+ (web-journal "web-delimiter-match-check")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((balance t)
+ (bound-for-search 1)
+ closing-delimiters
+ (module-number 1)
+ (next-module-begins 0)
+ opening-char
+ opening-delimiters
+ valid-delimiter
+ )
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward web-module-begins nil t)
+ (message "Checking balance in Module %d" module-number)
+ (setq bound-for-searc (point))
+ (save-excursion
+ (if (not (re-search-forward web-module-begins nil t))
+ ; then
+ (setq next-module-begins (point-max))
+ ; else
+ (goto-char (match-beginning 0))
+ (setq next-module-begins (point))
+ ) ; end if
+ ) ; end excursion
+ (while (re-search-forward "\\(@@\\)*@\\(<\\|>\\)"
+ next-module-begins t)
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (if (char-equal (preceding-char) ?@)
+ ; then
+ (setq valid-delimiter nil)
+ ; else
+ (setq valid-delimiter t)
+ ) ; end if
+ ) ; end excursion
+ (if valid-delimiter
+ ; then
+ (progn
+ (cond
+ ((char-equal (preceding-char) ?<)
+ (setq opening-delimiters (cons
+ (count-lines (point-min) (point)) opening-delimiters))
+ ) ; end case
+ ((char-equal (preceding-char) ?>)
+ (save-excursion
+ (setq opening-char nil)
+ (while (and (null opening-char)
+ (re-search-backward
+ "\\(@@\\)*@\\(\\^\\|\\.\\|:\\|t\\|=\\|<\\)"
+ bound-for-search t))
+ (if (char-equal (preceding-char) ?@)
+ ; then keep searching backward
+ ()
+ ; else
+ (setq opening-char (string-to-char (buffer-substring
+ (match-beginning 2) (match-end 2))))
+ ) ; end if
+ ) ; end while
+ ) ; end excursion
+ (cond
+ ((null opening-char) ; then missing an opening delimiter
+ (setq closing-delimiters (append closing-delimiters
+ (list (count-lines (point-min) (point)))))
+ ) ; end case
+ ((char-equal opening-char ?<) ; valid module name
+ (setq opening-delimiters (cdr opening-delimiters))
+ ) ; end case
+ ) ; end cond
+ (setq bound-for-search (point))
+ ) ; end case
+ ) ; end cond
+ ) ; end then
+ ) ; end if
+ ) ; end while
+ (setq module-number (1+ module-number))
+ ) ; end while
+ ) ; end excursion
+ (if (and (null opening-delimiters) (null closing-delimiters))
+ ; then
+ (message "All module delimiters match")
+ ; else
+ (setq balance nil)
+ (with-output-to-temp-buffer "*Missing Delimiters*"
+ (princ
+ "After these errors are fixed, reissue the command M-x web-mode.")
+ (if (not (null opening-delimiters))
+ ; then
+ (if (nth 1 opening-delimiters)
+ ; then
+ (princ (format
+ "\nThe @<'s located on lines %s are missing an @>."
+ (sort opening-delimiters '<)))
+ ; else
+ (princ (format "\nThe @< located on line %d is missing an @>."
+ (car opening-delimiters)))
+ ) ; end if
+ ) ; end if
+ (if (not (null closing-delimiters))
+ ; then
+ (if (nth 1 closing-delimiters)
+ ; then
+ (princ (format
+ "\nThe @>'s located on lines %s are missing an @<."
+ closing-delimiters))
+ ; else
+ (princ (format "\nThe @> located on line %d is missing an @<."
+ (car closing-delimiters)))
+ ) ; end if
+ ) ; end if
+ ) ; end output to temp buffer
+ ) ; end if
+ balance ; return the boolean indicating if module delimiters balance
+ ) ; end let
+)
+
+(defun web-determine-characteristics ()
+ "This function is used to give the user an idea of how many lines of text
+exist in each module's commentary, definition/macro, and code parts.
+ARGUMENTS : None
+GLOBAL Variables : web-default-directory and web-files
+LOCAL Variables : code, code-begins, ctr, current-position, divider,
+ done, file-no, header, header1, header2, header3, header4,
+ line-in-table, lines-in-code, lines-in-commentary,
+ lines-in-macros, macros, macros-begin, max-module,
+ module-no, next-module-begins, number-of-columns,
+ space-to-left-of-table, spacer, spanner, stat-buffer-name,
+ title, and width-of-table
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-count-modules,
+ web-determine-characteristics-for-buffer, and web-journal"
+ (interactive)
+ (web-journal "web-determine-characteristics")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let* ((module-no 1)
+ (max-module (web-count-modules))
+ (number-of-columns 4)
+ (header1 "Module #")
+ (header2 "Commentary")
+ (header3 "Macros")
+ (header4 "Code")
+ (spanner "Number of Lines in")
+ (title (concat "STATISTICS FOR "
+ (upcase (buffer-name (current-buffer)))))
+ (spacer 2)
+ (width-of-table (+ (length header1) (length header2)
+ (length header3) (length header4) (* number-of-columns spacer 2)
+ (1+ number-of-columns)))
+ (space-to-left-of-table (/ (- (screen-width) width-of-table) 2))
+ (divider (concat
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header2) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header3) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header4) (* spacer 2)) ?_) "|\n"
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header2) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header3) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header4) (* spacer 2)) ? ) "|\n"))
+ (header (concat
+ (make-string (/ (- (screen-width) (length title)) 2) ? )
+ title "\n"
+ (make-string (1+ (/ (- (screen-width) width-of-table) 2)) ? )
+ (make-string (- width-of-table 2) ?_) "\n"
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2))? ) "|"
+ (make-string (+ (length header2) (length header3)
+ (length header4) (* 3 spacer 2) 2) ? ) "|\n"
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2)) ? ) "|"
+ (make-string (/ (- (+ (length header2) (length header3)
+ (length header4) (* 3 spacer 2) 2) (length spanner)) 2) ? )
+ spanner
+ (make-string (1- (- (- width-of-table (+ (length header1)
+ (* spacer 2) 2)) (+ (/ (- (+ (length header2) (length header3)
+ (length header4) (* 3 spacer 2) 2) (length spanner)) 2)
+ (length spanner)))) ? ) "|\n"
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2)) ? ) "|"
+ (make-string (1- (- width-of-table (+ (length header1)
+ (* spacer 2) 2))) ?_) "|\n"
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header2) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header3) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header4) (* spacer 2)) ? ) "|\n"
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string spacer ? ) header1
+ (make-string spacer ? ) "|"
+ (make-string spacer ? ) header2
+ (make-string spacer ? ) "|"
+ (make-string spacer ? ) header3
+ (make-string spacer ? ) "|"
+ (make-string spacer ? ) header4
+ (make-string spacer ? ) "|\n"
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header2) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header3) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header4) (* spacer 2)) ?_) "|\n"
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header2) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header3) (* spacer 2)) ? ) "|"
+ (make-string (+ (length header4) (* spacer 2)) ? ) "|\n"))
+ code
+ (code-begins)
+ (ctr 0)
+ (current-position 0)
+ done
+ file-no
+ line-in-table
+ (lines-in-code 0)
+ (lines-in-commentary 0)
+ (lines-in-macros 0)
+ macros
+ (macros-begin 0)
+ (next-module-begins 0)
+ (stat-buffer-name (concat "*STATISTICS for "
+ (buffer-name (current-buffer)) "*"))
+ )
+ (generate-new-buffer stat-buffer-name)
+ (save-excursion
+ (set-buffer stat-buffer-name)
+ (use-local-map web-mode-map)
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ (goto-char (point-min))
+ (kill-line (count-lines (point-min) (point-max)))
+ ) ; end excursion
+ (save-excursion
+ (set-buffer (get-file-buffer (expand-file-name (nth 1 web-files)
+ web-default-directory)))
+ (setq file-no (cons (web-check-if-buffer-is-one-of-the-web-files)
+ file-no))
+ (web-determine-characteristics-for-buffer)
+ ) ; end excursion
+ (switch-to-buffer stat-buffer-name)
+ (goto-char (point-min))
+ ) ; end let
+)
+
+(defun web-determine-characteristics-for-buffer ()
+ "This is an internal support function used by
+\\[web-determine-characteristics] to write the characteristics of each
+individual buffer to the buffer where they are being recorded.
+ARGUMENTS : None
+GLOBAL Variables : web-default-directory and web-files
+LOCAL Variables : code, code-begins, ctr, current-position, divider,
+ done, file-no, header, header1, header2, header3, header4,
+ include-file-name,
+ line-in-table, lines-in-code, lines-in-commentary,
+ lines-in-macros, macros, macros-begin, max-module,
+ module-no, next-module-begins, number-of-columns,
+ space-to-left-of-table, spacer, spanner, stat-buffer-name,
+ title, and width-of-table
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files and
+ web-eliminate-white-space"
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "^@\\(i\\| \\|\t\\|\n\\|\\*\\)" nil t)
+ (if (char-equal ?i
+ (string-to-char
+ (buffer-substring (match-beginning 1) (match-end 1))))
+ ; then switch to include file and collect its characteristics
+ (save-excursion
+ (setq include-file-name (buffer-substring (point)
+ (save-excursion (end-of-line) (point))))
+ (setq include-file-name (substring include-file-name 0
+ (string-match " " include-file-name 1)))
+ (set-buffer (get-file-buffer (expand-file-name
+ (web-eliminate-white-space include-file-name)
+ web-default-directory)))
+ (setq file-no (cons (web-check-if-buffer-is-one-of-the-web-files)
+ file-no))
+ (web-determine-characteristics-for-buffer)
+ ) ; end excursion
+ ; else continue collecting in the same buffer
+ (setq current-position (count-lines (point-min) (point)))
+ (save-excursion
+ (if (re-search-forward "^@\\(i\\| \\|\t\\|\n\\|\\*\\)" nil t)
+ ; then
+ (setq next-module-begins (point))
+ ; else
+ (setq next-module-begins (point-max))
+ ) ; end if
+ ) ; end excursion
+ (save-excursion
+ (setq macros nil)
+ (if (re-search-forward "@\\(d\\|f\\)" next-module-begins t)
+ ; then
+ (progn
+ (backward-char 2)
+ (setq done nil
+ ctr 0)
+ (while (null done)
+ (while (looking-at "@")
+ (backward-char 1)
+ (setq ctr (1+ ctr))
+ )
+ (forward-char (+ ctr 2))
+ (if (not (zerop (% ctr 2)))
+ ; then
+ (setq macros t
+ done t
+ macros-begin (count-lines (point-min) (point)))
+ ; else
+ (if (re-search-forward "@\\(d\\|f\\)" next-module-begins t)
+ ; then
+ (backward-char 2)
+ ; else
+ (setq done t)
+ ) ; end if
+ ) ; end if
+ ) ; end while
+ ) ; end then
+ ) ; end if
+ ) ; end excursion
+ (save-excursion
+ (setq code nil)
+ (if (re-search-forward "@\\(p\\|c\\|<\\)" next-module-begins t)
+ ; then
+ (progn
+ (backward-char 2)
+ (setq done nil
+ ctr 0)
+ (while (null done)
+ (while (looking-at "@")
+ (backward-char 1)
+ (setq ctr (1+ ctr))
+ )
+ (forward-char (+ ctr 2))
+ (if (not (zerop (% ctr 2)))
+ ; then
+ (setq code t
+ done t
+ code-begins (count-lines (point-min) (point)))
+ ; else
+ (if (re-search-forward "@\\(<\\|p\\|c\\)"
+ next-module-begins t)
+ ; then
+ (backward-char 2)
+ ; else
+ (setq done t)
+ ) ; end if
+ ) ; end if
+ ) ; end while
+ ) ; end then
+ ) ; end if
+ ) ; end excursion
+ (setq next-module-begins (count-lines
+ (point-min) next-module-begins))
+ (cond
+ ((and (null macros) (null code))
+ (setq lines-in-commentary
+ (- next-module-begins current-position))
+ (setq lines-in-macros 0)
+ (setq lines-in-code 0)
+ )
+ ((and (null macros) (not (null code)))
+ (setq lines-in-commentary (- code-begins current-position))
+ (setq lines-in-macros 0)
+ (setq lines-in-code (- next-module-begins code-begins))
+ )
+ ((and (not (null macros)) (null code))
+ (setq lines-in-commentary (- macros-begin current-position))
+ (setq lines-in-macros (- next-module-begins macros-begin))
+ (setq lines-in-code 0)
+ )
+ ((and (not (null macros)) (not (null code)))
+ (setq lines-in-commentary (- macros-begin current-position))
+ (setq lines-in-macros (- code-begins macros-begin))
+ (setq lines-in-code (- next-module-begins code-begins))
+ )
+ ) ; end cond
+ (setq line-in-table (concat
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string spacer ? )
+ (make-string (- (length header1)
+ (length (int-to-string module-no))) ? )
+ (int-to-string module-no)
+ (make-string spacer ? ) "|"
+ (make-string spacer ? )
+ (make-string (- (length header2)
+ (length (int-to-string lines-in-commentary))) ? )
+ (int-to-string lines-in-commentary)
+ (make-string spacer ? ) "|"
+ (make-string spacer ? )
+ (make-string (- (length header3)
+ (length (int-to-string lines-in-macros))) ? )
+ (int-to-string lines-in-macros)
+ (make-string spacer ? ) "|"
+ (make-string spacer ? )
+ (make-string (- (length header4)
+ (length (int-to-string lines-in-code))) ? )
+ (int-to-string lines-in-code)
+ (make-string spacer ? ) "|\n"
+ ) ; ends concat
+ ) ; ends setq
+ (message "Module %d" module-no)
+ (set-buffer stat-buffer-name)
+ (if (= module-no 1)
+ ; then
+ (progn
+ (goto-char (point-min))
+ (kill-line (count-lines (point-min) (point-max)))
+ (insert-string header)
+ ) ; end then
+ ) ; end if
+ (insert-string line-in-table)
+ (cond
+ ((= module-no max-module)
+ (setq divider (concat
+ (make-string space-to-left-of-table ? ) "|"
+ (make-string (+ (length header1) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header2) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header3) (* spacer 2)) ?_) "|"
+ (make-string (+ (length header4) (* spacer 2)) ?_) "|\n"
+ ) ; end concat
+ ) ; end setq
+ (insert-string divider)
+ ) ; end case
+ ((zerop (% module-no 3))
+ (insert-string divider)
+ ) ; end case
+ ) ; end cond
+ (setq module-no (1+ module-no))
+ (set-buffer (get-file-buffer (expand-file-name
+ (nth (car file-no) web-files) web-default-directory)))
+ ) ; end if
+ ) ; end while
+ (setq file-no (cdr file-no))
+ ) ; end excursion
+)
+
+(defun web-determine-module-name-ending ()
+ "This function determines if the appropriate ending to a module name is @> or
+@>=.
+ARGUMENTS : None
+GLOBAL Variable : web-module-begins
+LOCAL Variables : at-greater-than-equal, at-p, module-name-ending,
+ next-module-begins, and this-module-begins
+RETURNS : module-name-ending
+USES : Nothing"
+ (let (at-greater-than-equal
+ at-p
+ module-name-ending
+ (next-module-begins 0)
+ (this-module-begins 0)
+ )
+ (save-excursion
+ (re-search-backward web-module-begins nil t)
+ (setq this-module-begins (point))
+ ) ; end excursion
+ (save-excursion
+ (if (re-search-forward web-module-begins nil t)
+ ; then
+ (progn
+ (goto-char (match-beginning 0))
+ (setq next-module-begins (point))
+ ) ; end then
+ ; else
+ (setq next-module-begins (point-max))
+ ) ; end if
+ ) ; end excursion
+ (save-excursion
+ (goto-char this-module-begins)
+ (while (and (re-search-forward "\\(@@\\)*@\\(p\\|c\\|r\\|a\\|n\\)"
+ next-module-begins t)
+ (null at-p))
+ (if (not (char-equal ?@
+ (string-to-char (buffer-substring
+ (1- (match-beginning 0)) (match-beginning 0)))))
+ ; then it's valid
+ (setq at-p t)
+ ) ; end if
+ ) ; end while
+ (if at-p
+ ; then do nothing
+ ()
+ ; else check for a valid @>=
+ (while (and (re-search-forward "\\(@@\\)*@>="
+ next-module-begins t)
+ (null at-greater-than-equal))
+ (if (not (char-equal ?@
+ (string-to-char (buffer-substring
+ (1- (match-beginning 0)) (match-beginning 0)))))
+ ; then it's valid
+ (setq at-greater-than-equal t)
+ ) ; end if
+ ) ; end while
+ ) ; end if
+ ) ; end excursion
+ (if (and (null at-greater-than-equal)
+ (null at-p))
+ ; then
+ (setq module-name-ending "@>=")
+ ; else
+ (setq module-name-ending "@>")
+ ) ; end if
+ module-name-ending ; return the proper ending for the module name
+ ) ; end let
+)
+
+(defun web-display-module-names (top bottom &optional arg)
+ "This function is used to display a list of module names. This function is
+invoked by \\[web-options-for-module-name-insertion]. It displays the module
+name of the TOP-th car of web-module-names through the BOTTOM-th car of
+web-module-names. An optional argument ARG is used to choose between one of
+two messages displayed at the bottom of the window.
+ARGUMENTS : top (required), bottom (required), and arg (optional)
+GLOBAL Variables : web-module-names, web-number-of-lines-in-window, and
+ web-number-of-module-names
+LOCAL Variables : available-lines, ctr, module-name, phrase, and space-on-left
+RETURNS : Nothing
+USES : Nothing"
+ (let ((available-lines (- web-number-of-lines-in-window 11))
+ (ctr top)
+ module-name
+ phrase
+ (space-on-left
+ (/ (- 6 (length (int-to-string web-number-of-module-names))) 2))
+ )
+ (if (null arg)
+ ; then
+ (setq phrase (format "Displaying %d Module Names of %d"
+ (1+ (- bottom top)) web-number-of-module-names))
+ ; else
+ (setq phrase (format "Displaying %d of %d Matches"
+ (1+ (- bottom top)) arg))
+ )
+ (goto-char (point-min))
+ (forward-line 9)
+ (kill-line (count-lines (point) (point-max)))
+ (insert-string "Number Name\n")
+ (while (<= ctr bottom)
+ (setq module-name (substring (nth (1- ctr) web-module-names) 0
+ (string-match " " (nth (1- ctr) web-module-names))))
+ (if (> (length module-name) 71)
+ ; then
+ (setq module-name (concat (substring module-name 0 68) "..."))
+ )
+ (insert-string (concat (make-string (+ space-on-left
+ (- (length (int-to-string web-number-of-module-names))
+ (length (int-to-string ctr)))) ? ) (int-to-string ctr)
+ (make-string (- 8 (+ space-on-left
+ (length (int-to-string web-number-of-module-names)))) ? )
+ module-name "\n"))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (insert-string (make-string (- available-lines (1+ (- bottom top))) ?\012))
+ (insert-string (concat (make-string (/ (- 79 (length phrase)) 2) ? )
+ phrase))
+ ) ; end let
+)
+
+(defun web-edit-module ()
+ "This function can only be invoked from the buffer containing the Web
+document. Whatever module point is positioned in is the module that is to be
+changed. If the module to be changed already appears in the CHange file, the
+user is warned but is switched to the buffer containing the CHange file so that
+further changes can be made. If the module to be changed does not appear in
+the CHange file, the module to be changed from the Web buffer is copied
+verbatim at its proper position in the CHange file twice--once between @x and
+@y and once between @y and @z. Point is then positioned at the beginning of
+the line following @y so that changes can be made.
+ARGUMENTS : None
+GLOBAL Variables : web-change-buffer-name and web-buffer-name
+LOCAL Variables : comment-string, ctr, module-to-be-changed,
+ module-to-be-changed-begins-at,
+ and module-to-be-changed-ends-at
+RETURNS : Nothing
+USES : web-count-changes, web-count-modules,
+ web-goto-change-corresponding-to-module, web-goto-module, web-journal,
+ web-what-change, and web-what-module"
+ (interactive)
+ (web-journal "web-edit-module")
+ (if (not (string-equal web-buffer-name (buffer-name (current-buffer))))
+ ; then
+ (error "Not in the Web buffer that web-mode was used on most recently.")
+ ; else
+ (let* ((ctr 0)
+ done
+ (module-to-be-changed (web-what-module))
+ (module-to-be-changed-begins-at 0)
+ (module-to-be-changed-ends-at 0)
+ (comment-string (concat " Module "
+ (int-to-string module-to-be-changed) " "
+ (current-time-string) "\n"))
+ (total-number-of-modules (web-count-modules))
+ )
+ (if (= (aref (aref web-location-of-module module-to-be-changed) 3) 1)
+ ; then the module has already been changed
+ (progn
+ (web-goto-change-corresponding-to-module module-to-be-changed)
+ (message "Module %d has already been CHanged." module-to-be-changed)
+ ) ; end then
+ ; else
+ (if (zerop module-to-be-changed)
+ ; then the limbo portion of the Web is to be changed
+ (setq module-to-be-changed-begins-at 1)
+ ; else
+ (save-excursion
+ (web-goto-module module-to-be-changed)
+ (setq module-to-be-changed-begins-at (point))
+ ) ; end excursion
+ ) ; end if
+ (if (= module-to-be-changed (web-count-modules))
+ ; then the last module is being changed
+ (setq module-to-be-changed-ends-at (1- (point-max)))
+ ; else
+ (save-excursion
+ (web-goto-module (1+ module-to-be-changed))
+ (backward-char 1)
+ (while (looking-at "\n") (backward-char 1))
+ (setq module-to-be-changed-ends-at (1+ (point)))
+ ) ; end excursion
+ ) ; end if
+ (setq ctr (1+ module-to-be-changed))
+ (while (not done)
+ (cond
+ ((or (> ctr total-number-of-modules)
+ (= (aref (aref web-location-of-module ctr) 3) 1))
+ (setq done t)
+ ) ; end case
+ (t
+ (setq ctr (1+ ctr)
+ done nil)
+ ) ; end case
+ ) ; end cond
+ ) ; end while
+ (switch-to-buffer web-change-buffer-name)
+ (goto-char (point-min))
+ ; position point in the CHange file for the insertion of the
+ ; contents of the module that is to be changed. Update the
+ ; web-location-of-module vector.
+ (cond
+ ((zerop (web-count-changes))
+ (goto-char (point-max))
+ (aset (aref web-location-of-module module-to-be-changed) 3 1)
+ (aset (aref web-location-of-module module-to-be-changed) 4 1)
+ ) ; end case
+ ((= ctr (1+ total-number-of-modules))
+ ; then the new change goes at the bottom of the CHange file
+ (goto-char (point-max))
+ ; update the web-location-of-module vector
+ (aset (aref web-location-of-module module-to-be-changed) 3 1)
+ (save-excursion
+ (re-search-backward "^@z" nil t)
+ (aset (aref web-location-of-module module-to-be-changed) 4
+ (1+ (aref (aref web-location-of-module (web-what-change)) 4)))
+ ) ; end excursion
+ ) ; end case
+ (t
+ (re-search-forward "^@x" nil t ctr)
+ (goto-char (match-beginning 0))
+ (recenter 0)
+ (aset (aref web-location-of-module module-to-be-changed) 3 1)
+ (aset (aref web-location-of-module module-to-be-changed) 4
+ (aref (aref web-location-of-module ctr) 4))
+ (while (<= ctr total-number-of-modules)
+ (if (not (zerop (aref (aref web-location-of-module ctr) 3)))
+ ; then increment the relative position in the CHange file
+ (aset (aref web-location-of-module ctr) 4
+ (1+ (aref (aref web-location-of-module ctr) 4)))
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ ) ; end case
+ ) ; end cond
+ (if (re-search-backward "^@z" nil t)
+ ; then
+ (progn
+ (forward-line 1)
+ (if (not (looking-at "\n"))
+ ; then
+ (newline)
+ ; else
+ (forward-line)
+ ) ; end if
+ ) ; end then
+ ) ; end if
+ (insert "@x" comment-string)
+ (insert-buffer-substring web-buffer-name
+ module-to-be-changed-begins-at (1+ module-to-be-changed-ends-at))
+ (insert "@y" comment-string)
+ (insert-buffer-substring web-buffer-name
+ module-to-be-changed-begins-at (1+ module-to-be-changed-ends-at))
+ (insert "@z" comment-string "\n")
+ (re-search-backward "^@y" nil t)
+ (recenter 0)
+ (message "Module %d is ready to be changed." module-to-be-changed)
+ ) ; end if
+ ) ; end let
+ ) ; end if
+)
+
+(defun web-eliminate-control-sequences (search-string
+ &optional replacement-string)
+ "This is an internal support function used to eliminate delimited control
+sequences. The function searches for SEARCH-STRING replaces these delimited
+control sequences with their argument. An optional REPLACEMENT-STRING will be
+appended to the argument of the control sequence if present. This function is
+used when the index is being reformatted. For example, the index contains
+entries such as \[#] (where # represents a module number where the index entry
+was referenced) which are to be underlined in the final output. This function
+replaces the sequence with #.
+ARGUMENTS : search-string (required) and replacement-string (optional)
+GLOBAL Variables : None
+LOCAL Variables : None
+RETURNS : Nothing
+USES : Nothing"
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward search-string nil t)
+ (backward-char (length (buffer-substring (match-beginning 0)
+ (match-end 0))))
+ (insert-string (concat (buffer-substring (match-beginning 1)
+ (match-end 1)) replacement-string))
+ (delete-char (length (buffer-substring (match-beginning 0)
+ (match-end 0))))
+ ) ; end while
+ ) ; end excursion
+)
+
+(defun web-eliminate-white-space (string)
+ "This is an internal function used to eliminate all leading, trailing, and
+multiple inner occurrences of white space (tabs, carriage returns, and spaces)
+in STRING. The resulting string will always have a leading space, and hence,
+must be deleted before returning. If the last character in the input string is
+white space, a trailing space will also be present, and it, too, must be
+deleted before returning. This code adapted from Knuth (see Module 153 in
+tangle.web).
+ARGUMENT : string (required)
+GLOBAL Variables : None
+LOCAL Variables : d, k, loc, new-string
+RETURNS : new-string
+USES : Nothing"
+ (let (d
+ (k 1)
+ (loc 1)
+ (new-string " ")
+ )
+ (while (<= loc (length string))
+ (setq d (substring string (1- loc) loc)
+ loc (1+ loc)
+ k (1+ k))
+ (if (or (string-equal d " ")
+ (string-equal d "\n")
+ (string-equal d "\t"))
+ ; then
+ (progn
+ (setq d " ")
+ (if (string-equal (substring new-string (- k 2) (1- k)) " ")
+ ; then
+ (setq k (1- k))
+ ) ; end if
+ ) ; end then
+ ) ; end if
+ (setq new-string (concat (substring new-string 0 (1- k)) d))
+ ); end while
+ (if (string-equal (substring new-string (1- k) k) " ")
+ ; then
+ (setq new-string (substring new-string 0 (1- k)))
+ ) ; end if
+ (substring new-string 1 (length new-string)) ; return the new string
+ ) ; end let
+)
+
+(defun web-file ()
+ "Makes the buffer that contains the Web document the current buffer.
+ARGUMENTS : None
+LOCAL Variables : None
+GLOBAL Variables : web-buffer-name
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files and web-journal"
+ (interactive)
+ (web-journal "web-file")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (switch-to-buffer web-buffer-name)
+)
+
+(defun web-goto-change-corresponding-to-module (goto-change-number)
+ "This function positions point at the beginning of the change that
+corresponds to module GOTO-CHANGE-NUMBER. If no prefix argument is provided,
+the function prompts for one.
+ARGUMENT : goto-change-number (required)
+GLOBAL Variables : None
+LOCAL Variables : None
+RETURNS : Nothing
+USES : web-change-file, web-count-modules, and web-journal"
+ (interactive "NGoto change corresponding to module: ")
+ (web-journal "web-goto-change-corresponding-to-module")
+ (cond
+ ((or (< goto-change-number 0)
+ (> goto-change-number (web-count-modules)))
+ (error "There is no change that corresponds to %d." goto-change-number)
+ ) ; end case
+ ((zerop (aref (aref web-location-of-module goto-change-number) 3))
+ (error "Module %d has not been CHanged." goto-change-number)
+ ) ; end case
+ (t
+ (web-change-file)
+ (goto-char (point-min))
+ (re-search-forward "^@y" nil t
+ (aref (aref web-location-of-module goto-change-number) 4))
+ (goto-char (match-beginning 0))
+ (recenter 0)
+ (message "CHange for module %d" goto-change-number)
+ ) ; end case
+ ) ; end cond
+)
+
+(defun web-goto-module (goto-module-number)
+ "This function positions point at the beginning of the GOTO-MODULE-NUMBER
+module in the Web document. If no argument is provided, the user is prompted
+for one. The function will not permit a user to go to a module labelled 0 or
+less; nor will it permit a user to go to a module that exceeds the total number
+of modules.
+ARGUMENT : goto-module-number (required)
+GLOBAL Variables : web-location-of-module, web-files, web-default-directory,
+ web-module-begins, and web-module-changed-then-goto-change
+LOCAL Variable : tot-num-modules
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-count-modules,
+ and web-journal"
+ (interactive "NGoto module: ")
+ (web-journal "web-goto-module")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((tot-num-modules (web-count-modules)))
+ (cond
+ ((< goto-module-number 1)
+ (error "There is no module %d." goto-module-number)
+ ) ; end case
+ ((> goto-module-number tot-num-modules)
+ (error "Can't go to module %d. There are only %d modules."
+ goto-module-number tot-num-modules)
+ ) ; end case
+ (t
+ (if web-module-changed-then-goto-change
+ ; then
+ (progn
+ (web-change-file)
+ (goto-char (point-min))
+ (re-search-forward "^@y" nil t
+ (aref (aref web-location-of-module goto-module-number) 4))
+ (goto-char (match-beginning 0))
+ (recenter 0)
+ ) ; end then
+ ; else
+ (switch-to-buffer (get-file-buffer (expand-file-name
+ (nth (aref (aref web-location-of-module goto-module-number) 0)
+ web-files) web-default-directory)))
+ (goto-char (point-min))
+ (re-search-forward web-module-begins nil t
+ (aref (aref web-location-of-module goto-module-number) 1))
+ (goto-char (match-beginning 0))
+ (recenter 0)
+ ) ; end if
+ (message "Module %d in %s. %s" goto-module-number (nth 1 web-files)
+ (if (= (aref (aref web-location-of-module goto-module-number) 3) 1)
+ "This module has been CHanged." " "))
+ ) ; end case
+ ) ; end cond
+ ) ; end let
+)
+
+(defun web-goto-section (goto-section-number)
+ "This function positions point at the beginning of the GOTO-SECTION-NUMBER
+section in the Web document. If no argument is provided, the user is prompted
+for one. The function will not permit a user to go to a section labelled 0 or
+less; nor will it permit a user to go to a section that exceeds the total
+number of sections. If the current buffer is not the buffer containing the Web
+document, the buffer containing the Web document is made the current buffer.
+ARGUMENT : goto-section-number (required)
+GLOBAL Variables : web-location-of-module and web-files
+LOCAL Variable : ctr and tot-num-sections
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-count-sections,
+ web-goto-module, and web-journal"
+ (interactive "NGoto Section Number: ")
+ (web-journal "web-goto-section")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((tot-num-sections (web-count-sections))
+ (ctr 1)
+ )
+ (cond
+ ((< goto-section-number 1)
+ (error "There is no section %d." goto-section-number)
+ )
+ ((> goto-section-number tot-num-sections)
+ (error "Can't go to section %d. There are only %d sections."
+ goto-section-number tot-num-sections)
+ )
+ (t
+ (while (/= (aref (aref web-location-of-module ctr) 2)
+ goto-section-number)
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (web-goto-module ctr)
+ (message "Section %d in %s" goto-section-number
+ (upcase (nth 1 web-files)))
+ ) ; end case
+ ) ; end cond
+ ) ; end let
+)
+
+(defun web-include-file (include-file-number)
+ "This function switches to the buffer containing the contents of include file
+INCLUDE-FILE-NUMBER.
+ARGUMENTS include-file-number (required)
+GLOBAL Variables : web-default-directory and web-files
+LOCAL Variables : None
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files and web-journal"
+ (interactive "NInclude File to be switch to: ")
+ (web-journal "web-include-file")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (if (or (< include-file-number 1)
+ (> include-file-number (- (length web-files) 2)))
+ ; then
+ (error "There is no include file numbered %d" include-file-number)
+ ; else
+ (switch-to-buffer (get-file-buffer (expand-file-name
+ (nth (1+ include-file-number) web-files) web-default-directory)))
+ (goto-char (point-min))
+ ) ; end if
+)
+
+(defun web-initialize-location-of-module-vector ()
+ "This is an internal support function used to initialize the
+web-location-of-module vector.
+ARGUMENTS : NONE
+GLOBAL Variables : web-change-buffer-name, web-location-of-module,
+ web-number-of-modules-in-file, web-buffer-name
+ web-files, and web-max-number-of-modules
+LOCAL Variables : file-number, module-number, and section-number
+RETURNS : Nothing
+USES : web-collect-location-of-modules"
+ (let ((file-number '(1))
+ (module-number 1)
+ (section-number 0)
+ )
+ (setq web-location-of-module (make-vector (1+ web-max-number-of-modules)
+ (make-vector 5 0))
+ web-number-of-modules-in-file (make-vector 20 0)
+ web-files ()
+ ) ; end setq
+ (aset web-location-of-module 0 (vector 1 0 0 0 0))
+ (setq web-files (append web-files (list web-change-buffer-name)
+ (list web-buffer-name)))
+ (set-buffer (nth (car file-number) web-files))
+ (message "Collecting the vector web-location-of-module...")
+ (web-collect-location-of-modules)
+ (message "Collecting the vector web-location-of-module...done")
+ ) ; end let
+)
+
+(defun web-initialize-module-names-list ()
+ "This function is invoked by \\[web-mode] if 1) filename.mods exists and
+2) filename.mods is newer than filename.web. If these two conditions are
+true, then \\[web-mode] does not need to collect the web-module-names list from
+scratch. It can read this information from the file filename.mods.
+ARGUMENTS : None
+GLOBAL Variable : web-module-name-defined-in-used-in, web-module-names,
+ web-number-of-module-names, web-buffer-name,
+ and web-default-directory
+LOCAL Variables : defined-in-list, module-name, module-name-begins,
+ and used-in-list
+RETURNS : Nothing
+USES : web-eliminate-white-space"
+ (let (defined-in-list
+ module-name
+ (module-name-begins 0)
+ used-in-list
+ )
+ (find-file-noselect (expand-file-name
+ (concat (substring web-buffer-name 0
+ (string-match "\\." web-buffer-name)) ".mods") web-default-directory))
+ (set-buffer (concat (substring web-buffer-name 0
+ (string-match "\\." web-buffer-name)) ".mods"))
+ (goto-char (point-min))
+ (while (not (eobp))
+ (setq module-name-begins (point))
+ (forward-line 1)
+ (while (and (not (eobp))
+ (char-equal
+ (string-to-char (buffer-substring (point) (1+ (point))))
+ ? )
+ ) ; end condition
+ (forward-line 1)
+ ) ; end while
+ (save-excursion
+ (re-search-backward "(" nil t 2)
+ (setq module-name (web-eliminate-white-space
+ (buffer-substring module-name-begins (point))))
+ ) ; end excursion
+ (save-excursion
+ (setq defined-in-list ())
+ (re-search-backward "(" nil t 2)
+ (while (not (looking-at ")"))
+ (re-search-forward "[0-9]+" nil t)
+ (setq defined-in-list (append defined-in-list (list (string-to-int
+ (buffer-substring (match-beginning 0) (match-end 0))))))
+ ) ; end while
+ ) ; end excursion
+ (save-excursion
+ (setq used-in-list ())
+ (re-search-backward "(" nil t)
+ (while (not (looking-at ")"))
+ (re-search-forward "[0-9]+" nil t)
+ (setq used-in-list (append used-in-list (list (string-to-int
+ (buffer-substring (match-beginning 0) (match-end 0))))))
+ ) ; end while
+ ) ; end excursion
+ (setq web-module-name-defined-in-used-in
+ (append web-module-name-defined-in-used-in (list
+ (list module-name defined-in-list used-in-list))))
+ (setq web-module-names (append web-module-names (list
+ (concat module-name " " (int-to-string web-number-of-module-names)))))
+ (setq web-number-of-module-names (1+ web-number-of-module-names))
+ ) ; end while
+ ) ; end let
+)
+
+(defun web-insert-index-entry (&optional type-style phrase)
+ "This function inserts the necessary constructs so that an entry is placed in
+the index by Weave. Web supports three types of index entries. They differ in
+the type of type style used in the index itself. This function asks the user
+which TYPE-STYLE he prefers. Once a valid selection has been made, it asks for
+the PHRASE to be inserted in the index.
+ARGUMENTS : type-style and phrase (both required)
+GLOBAL Variables : None
+LOCAL Variables : first-part and prompt
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files and web-journal"
+ (interactive)
+ (web-journal "web-insert-index-entry")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let (first-part
+ (prompt "rm(R/r), tt(T/t), or User-Defined(U/u): ")
+ )
+ (if type-style
+ ; then an explicit argument has been provided
+ ()
+ ; else prompt for the type-style
+ (setq type-style (read-string (concat "Type Style: " prompt)))
+ (while (and (not (string-equal (upcase type-style) "R"))
+ (not (string-equal (upcase type-style) "U"))
+ (not (string-equal (upcase type-style) "T"))
+ )
+ (ding)
+ (setq type-style (read-string (concat "Try again. " prompt)))
+ ) ; end while
+ ) ; end if
+ (cond
+ ((string-equal (upcase type-style) "U")
+ (setq first-part "@:")
+ ) ; end case
+ ((string-equal (upcase type-style) "T")
+ (setq first-part "@.")
+ ) ; end case
+ (t ; default
+ (setq first-part "@^")
+ ) ; end case
+ ) ; end cond
+ (if (null phrase)
+ (setq phrase (read-string "Phrase to be placed in index: "))
+ )
+ (end-of-line)
+ (newline)
+ (insert first-part phrase "@>")
+ (newline)
+ ) ; end let
+)
+
+(defun web-insert-limbo-material ()
+ "This function is only invoked by \\[web-mode] when the edit buffer is empty,
+i.e., one is beginning a new Web document. The user is prompted for the title
+of the Web.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variables : limbo-file-name, line1, line2, line3, position-of-colon,
+ title, and width
+RETURNS : Nothing
+USES : Nothing"
+ (let (limbo-file-name
+ (line1 (concat "PROGRAM : " (buffer-name (current-buffer))))
+ (line2 (concat "CREATOR : " (user-full-name) " [" (user-login-name)
+ "@" (system-name) "]"))
+ (line3 (concat "CREATION DATE : " (current-time-string)))
+ (position-of-colon 0)
+ title
+ (width 0)
+ )
+ (cond
+ ((and (>= (length line1) (length line2))
+ (>= (length line1) (length line3)))
+ (setq width (length line1)
+ position-of-colon (+ (/ (- 77 width) 2) 9))
+ ) ; end case
+ ((and (>= (length line2) (length line1))
+ (>= (length line2) (length line3)))
+ (setq width (length line2)
+ position-of-colon (+ (/ (- 77 width) 2) 9))
+ ) ; end case
+ ((and (>= (length line3) (length line1))
+ (>= (length line3) (length line2)))
+ (setq width (length line3)
+ position-of-colon (+ (/ (- 77 width) 2) 15))
+ ) ; end case
+ (t
+ (error
+ "In web-insert-limbo-material. Shouldn't have reached this code.")
+ ) ; end case
+ ) ; end cond
+ ; insert a nice header
+ (insert (make-string 79 ?%) "\n"
+ ?% (make-string 77 ? ) ?% "\n"
+ ?% (make-string (- position-of-colon 9) ? ) line1
+ (make-string (- 77 (+ (length line1) (- position-of-colon 9))) ? )
+ "%\n"
+ ?% (make-string (- position-of-colon 9) ? ) line2
+ (make-string (- 77 (+ (length line2) (- position-of-colon 9))) ? )
+ "%\n"
+ ?% (make-string (- position-of-colon 15) ? ) line3
+ (make-string (- 77 (+ (length line3) (- position-of-colon 15))) ? )
+ "%\n"
+ ?% (make-string 77 ? ) "%\n"
+ (make-string 79 ?%) "\n")
+
+ (let ((insert-default-directory t))
+ (while (null (file-readable-p (setq limbo-file-name
+ (read-file-name "File containing limbo material "
+ (expand-file-name "limbo.material")
+ (expand-file-name "limbo.material")))))
+ (ding)
+ (message "%s does not exist or is non-readable" limbo-file-name)
+ (sit-for 2)
+ ) ; end while
+ ) ; end let
+ (insert-file-contents limbo-file-name)
+
+ (setq title (read-string "Title of Web: "))
+ (goto-char (point-min))
+ (if (re-search-forward "\\\\def\\\\title{{\\\\tt " nil t)
+ ; then
+ (insert-string title)
+ ) ; end if
+ (goto-char (point-max))
+ ) ; end let
+)
+
+(defun web-insert-module-name ()
+ "This function is invoked when the user presses <. This function must look
+at the preceding characters to determine if this represents the beginning of a
+module name or not. If the < is preceded by an odd number of @'s, then it
+represents the beginning of a module name; otherwise, it doesn't.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variable : ctr
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files,
+ web-options-for-module-name-insertion, web-journal, and web-what-module"
+ (interactive)
+ (web-journal "web-insert-module-name")
+ (let ((ctr 0)
+ (file-no (web-check-if-buffer-is-one-of-the-web-files))
+ )
+ (backward-char 1)
+ (while (and (not (bobp)) (looking-at "@"))
+ (backward-char 1)
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (forward-char (1+ ctr))
+ (insert-char ?< 1)
+ (cond
+ ((and (not (zerop (% ctr 2))) (>= (web-what-module) 1))
+ ; then the preceding @< marks the beginning of a module name
+ (web-options-for-module-name-insertion)
+ ) ; end case
+ ((and (not (zerop (% ctr 2))) (< (web-what-module) 1))
+ ; then we have a valid module beginning but are in the limbo portion
+ (delete-backward-char (1+ ctr))
+ (error "You can't insert a module name in the limbo portion")
+ ) ; end case
+ ) ; end cond
+ ) ; end let
+)
+
+(defun web-is-this-a-new-module-beginning ()
+ "This function is invoked whenever the user enters the character @. The
+function then reads the next character. If this next character is in the set
+{ (space),*,\\t(tab),\\n(newline)}, then it begins a new module and the vector
+web-location-of-module must be updated to reflect this addition. The @ must be
+at the beginning of a new line to be a valid module beginning.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variable : next-char
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-insert-module-name,
+ web-update-the-location-of-module-vector, and web-journal"
+ (interactive)
+ (web-journal "web-is-this-a-new-module-beginning")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (if (not (bolp))
+ ; then insert an @ -- it's not the beginning of a new module
+ (insert-char ?@ 1)
+ ; else get the next character
+ (let ((next-char (read-char)))
+ (if (not (or (char-equal next-char ? )
+ (char-equal next-char ?<)
+ (char-equal next-char ?*)
+ (char-equal next-char ?\t)
+ (char-equal next-char ?\015))) ; RET = ^M = \015 (octal)
+ ; then insert an @ and the last input char -- it's not the beginning
+ ; of a new module
+ (progn
+ (insert-char ?@ 1)
+ (insert-char next-char 1)
+ ) ; end then
+ ; else this does begin a new module, major section, or code section
+ (insert-char ?@ 1)
+ (if (char-equal next-char ?<)
+ ; then
+ (web-insert-module-name)
+ ; else
+ (if (char-equal next-char ?\015)
+ ; then
+ (insert-char ?\012 1)
+ ; else
+ (insert-char next-char 1)
+ ) ; end if
+ (web-update-the-location-of-module-vector next-char)
+ ) ; end if
+ ) ; end if
+ ) ; end let
+ ) ; end if
+)
+
+(defun web-journal (function-name)
+ "This function keeps track of the number of times FUNCTION-NAME has been
+invoked. Only the interactive functions in web-mode are kept track of.
+ARGUMENTS : function-name (required)
+GLOBAL Variables : web-interactive-function-usage, web-buffer-name, and
+ web-interactive-functions
+LOCAL Variables : ctr, start-time-in-seconds, stop-time,
+ stop-time-in-seconds, time-in-web-mode, and
+ time-in-web-mode-as-string
+RETURNS : Nothing
+USES : web-binary-search-of-names"
+ (let ((ctr 0)
+ (start-time-in-seconds 0)
+ stop-time
+ (stop-time-in-seconds 0)
+ (time-in-web-mode 0)
+ time-in-web-mode-as-string
+ )
+ (cond
+ ((string-equal function-name "web-mode")
+ ; web-mode is the first function invoked
+ ; thus, do initialization
+ (get-buffer-create "web-mode.jou")
+ (setq web-interactive-function-usage
+ (make-vector (length web-interactive-functions) 0)
+ start-time (current-time-string))
+ (save-excursion
+ (set-buffer "web-mode.jou")
+ (goto-char (point-min))
+ (kill-line (count-lines (point-min) (point-max)))
+ (insert (make-string 79 ?\045)
+ "\nUSER : " (user-full-name) " [" (user-login-name)
+ "@" (system-name) "]\nFILE : " web-buffer-name "\nSTART TIME : "
+ start-time "\n")
+ ) ; end excursion
+ ) ; end case
+ ((string-equal function-name "web-mode-save-buffers-kill-emacs")
+ ; this is the last function invoked by the user when he wants to quit
+ ; get the stop time, calculate the total time in web-mode, and
+ ; write the usage of the functions to the file web-mode.jou
+ (setq ctr (web-binary-search-of-names web-interactive-functions
+ (length web-interactive-functions)
+ function-name
+ (length function-name)))
+ (aset web-interactive-function-usage ctr
+ (1+ (aref web-interactive-function-usage ctr)))
+ (save-excursion
+ (set-buffer "web-mode.jou")
+ (setq stop-time (current-time-string))
+ (setq start-time-in-seconds (+
+ (* 3600 (string-to-int (substring start-time 11 13)))
+ (* 60 (string-to-int (substring start-time 14 16)))
+ (string-to-int (substring start-time 17 19))))
+ (setq stop-time-in-seconds (+
+ (* 3600 (string-to-int (substring stop-time 11 13)))
+ (* 60 (string-to-int (substring stop-time 14 16)))
+ (string-to-int (substring stop-time 17 19))))
+ (if (not (natnump (- stop-time-in-seconds start-time-in-seconds)))
+ ; then add the equivalent of a day to the stop time
+ (setq stop-time-in-seconds (+ stop-time-in-seconds 86400))
+ ) ; end if
+ (setq time-in-web-mode
+ (- stop-time-in-seconds start-time-in-seconds))
+ (if (< (/ time-in-web-mode 3600) 10)
+ ; then
+ (setq time-in-web-mode-as-string (concat "0"
+ (int-to-string (/ time-in-web-mode 3600)) ":"))
+ ; else
+ (setq time-in-web-mode-as-string (concat
+ (int-to-string (/ time-in-web-mode 3600)) ":"))
+ ) ; end if
+ (if (< (% (/ time-in-web-mode 60) 60) 10)
+ ; then
+ (setq time-in-web-mode-as-string
+ (concat time-in-web-mode-as-string "0"
+ (int-to-string (% (/ time-in-web-mode 60) 60)) ":"))
+ ; else
+ (setq time-in-web-mode-as-string
+ (concat time-in-web-mode-as-string
+ (int-to-string (% (/ time-in-web-mode 60) 60)) ":"))
+ ) ; end if
+ (if (< (% (% time-in-web-mode 3600) 60) 10)
+ ; then
+ (setq time-in-web-mode-as-string
+ (concat time-in-web-mode-as-string "0"
+ (int-to-string (% (% time-in-web-mode 3600) 60))))
+ ; else
+ (setq time-in-web-mode-as-string
+ (concat time-in-web-mode-as-string
+ (int-to-string (% (% time-in-web-mode 3600) 60))))
+ ) ; end if
+ (insert "FINISH TIME : " stop-time "\n"
+ "TOTAL TIME IN web-mode : " time-in-web-mode-as-string "\n"
+ (make-string 79 ?\055)
+ "\nINTERACTIVE FUNCTION USAGE\n")
+ (while (< ctr (length web-interactive-functions))
+ (if (not (zerop (aref web-interactive-function-usage ctr)))
+ (insert (make-string (- 4 (length (int-to-string
+ (aref web-interactive-function-usage ctr)))) ? )
+ (int-to-string (aref web-interactive-function-usage ctr))
+ " " (nth ctr web-interactive-functions) "\n")
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (write-region (point-min) (point-max) "web-mode.jou" t)
+ ) ; end excursion
+ ) ; end case
+ ) ; end cond
+ (setq ctr (web-binary-search-of-names web-interactive-functions
+ (length web-interactive-functions)
+ function-name
+ (length function-name)))
+ (if (>= ctr 0)
+ ; then the function-name was interactive
+ (aset web-interactive-function-usage ctr
+ (1+ (aref web-interactive-function-usage ctr)))
+ ; else the function was not found in the web-interactive-functions list
+ (error "Function %s wasn't found" function-name)
+ ) ; end if
+ ) ; end let
+)
+
+(defun web-mode ()
+ "This is the definition of the mode for manipulating Web documents. When
+invoked the function checks to see if the file that is being edited is new. If
+it is, limbo material is inserted. If the file is not new, the program checks
+for any undefined module names. If any modules are found to be undefined,
+stubs are appended.
+ARGUMENTS : None
+GLOBAL Variables : web-change-buffer-name, web-defined-in-used-in-location,
+ web-location-of-module, web-module-names,
+ web-number-of-lines-in-window, web-number-of-module-names,
+ web-selected-index-entry-occurrences, web-buffer-name,
+ web-default-directory, web-files, web-mode-map, and
+ web-module-changed-then-goto-change
+LOCAL Variables : None
+RETURNS : Nothing
+USES : web-any-modules-undefined-initially,
+ web-collect-list-of-changed-module-numbers, web-collect-module-names,
+ web-initialize-location-of-module-vector,
+ web-initialize-module-names-list, web-insert-limbo-material,
+ and web-journal"
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map web-mode-map)
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ (auto-fill-mode 1)
+ (setq web-change-buffer-name
+ (concat (substring (buffer-name (current-buffer))
+ 0 (string-match "\\." (buffer-name (current-buffer)))) ".ch")
+ web-defined-in-used-in-location -1
+ fill-column 70
+ web-location-of-module nil
+ web-module-names nil
+ web-number-of-lines-in-window (- (screen-height) 2)
+ web-number-of-module-names 0
+ web-selected-index-entry-occurrences nil
+ web-buffer-name (buffer-name (current-buffer))
+ web-default-directory default-directory
+ web-files nil
+ web-module-changed-then-goto-change nil
+ ) ; end setq
+ (web-journal "web-mode")
+ (if (= (length (buffer-substring (point-min) (point-max))) 0)
+ ; then
+ (web-insert-limbo-material)
+ ; else initialize the web-module-names list and
+ ; check to see if any modules are undefined
+ (save-excursion
+ (goto-char (point-min))
+ (while (search-forward "\f" nil t)
+ (replace-match "\n" t t)
+ ) ; end while
+ ) ; end excursion
+ (web-initialize-location-of-module-vector)
+ (if (and (file-readable-p
+ (expand-file-name (concat (substring web-buffer-name 0
+ (string-match "\\." web-buffer-name)) ".mods")))
+ (file-newer-than-file-p
+ (expand-file-name (concat (substring web-buffer-name 0
+ (string-match "\\." web-buffer-name)) ".mods"))
+ (expand-file-name web-buffer-name))
+ ) ; end condition
+ ; then
+ (progn
+ (message "Initializing the Module Names List...")
+ (web-initialize-module-names-list)
+ (message "Initializing the Module Names List...done")
+ (sit-for 1)
+ ) ; end then
+ ; else
+ (web-collect-module-names)
+ ) ; end if
+ (message "Checking to see if any modules are undefined...")
+ (web-any-modules-undefined-initially)
+ (message "Checking to see if any modules are undefined...done")
+ (find-file-noselect web-change-buffer-name)
+ (save-excursion
+ (set-buffer web-change-buffer-name)
+ (web-collect-list-of-changed-module-numbers)
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ (use-local-map web-mode-map)
+ ) ; end excursion
+ ) ; end if
+)
+
+(define-key (current-global-map) "\C-x\C-c" 'web-mode-save-buffers-kill-emacs)
+
+(defun web-mode-save-buffers-kill-emacs ()
+ "This function is used to replace Emacs' save-buffers-kill-emacs so that
+the journal file can be written.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variables : None
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-journal, and
+ web-write-module-names-to-a-file"
+ (interactive)
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (web-journal "web-mode-save-buffers-kill-emacs")
+ (web-write-module-names-to-a-file)
+ (save-buffers-kill-emacs)
+)
+
+(defun web-newline ()
+ "This function redefines the newline character so that the following line
+is indented like the previous one.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variable : ctr
+RETURNS : Nothing
+USES : web-journal"
+ (interactive)
+ (web-journal "web-newline")
+ (let ((ctr 0))
+ (save-excursion
+ (beginning-of-line)
+ (while (looking-at " ")
+ (setq ctr (1+ ctr))
+ (forward-char 1)
+ ) ; end while
+ ) ; end excursion
+ (newline)
+ (insert (make-string ctr ?\040))
+ ) ; end let
+)
+
+(defun web-next-change ()
+ "Advances point to the beginning of the next change.
+ARGUMENTS : None
+GLOBAL Variable : web-change-buffer-name
+LOCAL Variable : start-position
+RETURNS : Nothing
+USES : goto-change and web-journal"
+ (interactive)
+ (web-journal "web-next-change")
+ (if (not (string= web-change-buffer-name (buffer-name (current-buffer))))
+ ; then
+ (error "Not in the CHange buffer.")
+ ; else
+ (let ((start-position (point)))
+ (if (looking-at "^@x") (forward-char 2))
+ (if (re-search-forward "^@x" nil t)
+ ; then
+ (progn
+ (re-search-forward "^@y" nil t)
+ (goto-char (match-beginning 0))
+ (recenter 0)
+ ) ; end then
+ ; else there is no next change
+ (goto-char start-position)
+ (error "No next CHange.")
+ ) ; end if
+ ) ; end let
+ ) ; end if
+)
+
+(defun web-next-define ()
+ "This function is used to traverse the list of Defined In occurrences of the
+most recently selected module name in the forward direction. A module name is
+selected by issuing the command \\[web-view-module-names-list] and positioning
+the cursor on the line that contains the module name of interest.
+ARGUMENTS : None
+GLOBAL Variables : web-defined-in-occurrence, web-defined-in-used-in-location,
+ and web-module-name-defined-in-used-in
+LOCAL Variable : buffer-to-be-returned-to and current-module
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-goto-module,
+ web-next-or-previous-define-or-use, web-journal, and web-what-module"
+ (interactive)
+ (web-journal "web-next-define")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (cond
+ ((string= (buffer-name (current-buffer))
+ "*Module Name (Defined In) (Used In)*")
+ ; then the user needs to select an entry
+ (let ((buffer-to-be-returned-to
+ (web-next-or-previous-define-or-use "next" "defined-in")))
+ (if (>= web-defined-in-occurrence
+ (length (car (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ ; then there is no next define
+ (progn
+ (switch-to-buffer buffer-to-be-returned-to)
+ (error "No next define of %s" (car (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end then
+ ; else
+ (web-goto-module (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (message "Define %d of %d of %s" (1+ web-defined-in-occurrence)
+ (length (car (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end if
+ ) ; end let
+ ) ; end case
+ (t ; we are in a valid Web buffer
+ (if (= web-defined-in-used-in-location -1)
+ (error (concat "No selected module. "
+ "Execute M-x web-view-module-names-list to select."))
+ ; else
+ (let ((current-module (web-what-module)))
+ (setq web-defined-in-occurrence 0)
+ (while (and (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ (<= (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ current-module)
+ ) ; end and
+ (setq web-defined-in-occurrence (1+ web-defined-in-occurrence))
+ ) ; end while
+ (if (>= web-defined-in-occurrence
+ (length (car (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ ; then there is no next define
+ (error "No next define of %s" (car (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ; else
+ (web-goto-module (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (message "Define %d of %d of %s" (1+ web-defined-in-occurrence)
+ (length (car (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end if
+ ) ; end let
+ ) ; end if
+ ) ; end case
+ ) ; end cond
+)
+
+(defun web-next-index ()
+ "This function is used to traverse the list of occurrences of the most
+recently selected index entry in the forward direction. An index entry is
+selected by issuing the command \\[web-view-index] and positioning the cursor
+on the line that contains the index entry of interest.
+ARGUMENTS : None
+GLOBAL Variables : web-location-in-selected-index-entry-occurrences,
+ web-selected-index-entry-occurrences,
+ web-index-buffer-name, and web-index-entry
+LOCAL Variables : buffer-to-be-returned-to and current-module
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-goto-module,
+ web-journal, web-next-or-previous-index, and web-what-module"
+ (interactive)
+ (web-journal "web-next-index")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (cond
+ ((string-equal web-index-buffer-name (buffer-name (current-buffer)))
+ ; then we are in the index
+ (let ((buffer-to-be-returned-to (web-next-or-previous-index "next")))
+ (if (>= web-location-in-selected-index-entry-occurrences
+ (length web-selected-index-entry-occurrences))
+ ; then there is no next use
+ (progn
+ (switch-to-buffer buffer-to-be-returned-to)
+ (error "No next index reference for %s" web-index-entry)
+ ) ; end then
+ ; else
+ (web-goto-module (nth
+ web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences))
+ (message "Index Reference %d of %d for entry %s"
+ (1+ web-location-in-selected-index-entry-occurrences)
+ (length web-selected-index-entry-occurrences)
+ web-index-entry)
+ ) ; end if
+ ) ; end let
+ ) ; end case
+ (t ; else we are in a Web buffer
+ (if (null web-selected-index-entry-occurrences)
+ ; then
+ (error
+ "Issue the command M-x web-view-index to select an index entry.")
+ ; else
+ (let ((current-module (web-what-module)))
+ (setq web-location-in-selected-index-entry-occurrences 0)
+ (while (and (nth web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences)
+ (<= (nth web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences)
+ current-module)
+ ) ; end and
+ (setq web-location-in-selected-index-entry-occurrences
+ (1+ web-location-in-selected-index-entry-occurrences))
+ ) ; end while
+ (if (>= web-location-in-selected-index-entry-occurrences
+ (length web-selected-index-entry-occurrences))
+ ; then
+ (error "No next index reference for %s" web-index-entry)
+ ; else
+ (web-goto-module (nth
+ web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences))
+ (message "Index Reference %d of %d for entry %s"
+ (1+ web-location-in-selected-index-entry-occurrences)
+ (length web-selected-index-entry-occurrences)
+ web-index-entry)
+ ) ; end if
+ ) ; end let
+ ) ; end if
+ ) ; end case
+ ) ; end cond
+)
+
+(defun web-next-module ()
+ "This function moves point to the beginning of the next module. If point is
+currently in the last module of the Web, an appropriate message is sent to the
+minibuffer; otherwise, point is positioned at the first line of the next
+module.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variable : current-module
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files,
+ web-count-modules, web-goto-module, web-journal, and web-what-module"
+ (interactive)
+ (web-journal "web-next-module")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((current-module (web-what-module)))
+ (if (>= current-module (web-count-modules))
+ ; then
+ (error "No next module")
+ ; else
+ (web-goto-module (1+ current-module))
+ ) ; end if
+ ) ; end let
+)
+
+(defun web-next-or-previous-define-or-use (direction list)
+ "This is an internal support function that is called by both \\[web-next-use]
+and \\[web-next-define]. It determines the module name that the cursor is
+currently located at. After the name has been isolated, it is looked up in the
+list of module names so that the traversal of the module name's Defined In and
+Used In lists can be done.
+ARGUMENTS : direction and list (both required)
+GLOBAL Variables : web-defined-in-occurrence, web-defined-in-used-in-location,
+ web-module-names, web-number-of-module-names,
+ web-selected-module-name, and web-used-in-occurrence
+LOCAL Variables : beginning-of-module-name, ctr, current-module,
+ current-position, end-of-module-name, ptr, and
+ web-buffer-list
+RETURNS : buffer to be returned to on error
+USES : web-binary-search-of-names, web-eliminate-white-space,
+ and web-what-module"
+ (let ((beginning-of-module-name 0)
+ (ctr 1)
+ (current-module 0)
+ (current-position (point))
+ (end-of-module-name 0)
+ (ptr 0)
+ web-buffer-list
+ )
+ (if (eobp)
+ ; then
+ (error "No module name can be selected from point's current position.")
+ ) ; end if
+ (save-excursion
+ (setq current-position (point))
+ (beginning-of-line)
+ (while (char-equal
+ (string-to-char (buffer-substring (point) (1+ (point)))) ? )
+ (forward-line -1)
+ ) ; end while
+ (setq beginning-of-module-name (point))
+ (goto-char current-position)
+ (forward-line 1)
+ (while (and (not (eobp)) (char-equal
+ (string-to-char (buffer-substring (point) (1+ (point)))) ? ))
+ (forward-line 1)
+ ) ; end while
+ (backward-char 1)
+ (setq end-of-module-name (point))
+ (goto-char end-of-module-name)
+ (re-search-backward "(" beginning-of-module-name t 2)
+ (setq web-selected-module-name (web-eliminate-white-space
+ (buffer-substring beginning-of-module-name (1- (point)))))
+ ; Set the global variable search-last-string so that the user can
+ ; do a C-s C-s to go immediately to the selected module name.
+ (setq search-last-string web-selected-module-name)
+ (setq ptr (web-binary-search-of-names web-module-names
+ web-number-of-module-names
+ web-selected-module-name (length web-selected-module-name)))
+ (setq web-defined-in-used-in-location
+ (string-to-int (substring (nth ptr web-module-names)
+ (+ (string-match " " (nth ptr web-module-names)) 2))))
+ (setq web-buffer-list (mapcar (function buffer-name) (buffer-list)))
+ (setq ctr 1)
+ (while (char-equal (string-to-char
+ (substring (nth ctr web-buffer-list) 0 1)) ? )
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (save-excursion
+ (set-buffer (nth ctr web-buffer-list))
+ (setq current-module (web-what-module))
+ ) ; end excursion
+ (cond
+ ((and (string= direction "next")
+ (string= list "defined-in"))
+ (setq web-defined-in-occurrence 0)
+ (while (and (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ (<= (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ current-module)
+ ) ; end and
+ (setq web-defined-in-occurrence (1+ web-defined-in-occurrence))
+ ) ; end while
+ ) ; end case
+ ((and (string= direction "next")
+ (string= list "used-in"))
+ (setq web-used-in-occurrence 0)
+ (while (and (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (<= (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ current-module)
+ ) ; end and
+ (setq web-used-in-occurrence (1+ web-used-in-occurrence))
+ ) ; end while
+ ) ; end case
+ ((and (string= direction "previous")
+ (string= list "defined-in"))
+ (setq web-defined-in-occurrence (1- (length
+ (car (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))))
+ (while (and (>= web-defined-in-occurrence 0)
+ (>= (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ current-module)
+ ) ; end and
+ (setq web-defined-in-occurrence (1- web-defined-in-occurrence))
+ ) ; end while
+ ) ; end case
+ ((and (string= direction "previous")
+ (string= list "used-in"))
+ (setq web-used-in-occurrence (1- (length (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))))
+ (while (and (>= web-used-in-occurrence 0)
+ (>= (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ current-module)
+ ) ; end and
+ (setq web-used-in-occurrence (1- web-used-in-occurrence))
+ ) ; end while
+ ) ; end case
+ (t
+ (error "This case should not be reached.")
+ ) ; end case
+ ) ; end cond
+ ; return the name of the buffer to be returned to on error
+ (nth ctr web-buffer-list)
+ ) ; end excursion
+ ) ; end let
+)
+
+(defun web-next-or-previous-index (direction)
+ "This is an internal support function used by \\[web-next-index] and
+\\[web-previous-index]. This is common code and is only invoked when the
+user is viewing the index. This code determines the entry the user has
+selected and builds a list of the referenced module numbers for the selected
+index entry.
+ARGUMENT : direction (required)
+GLOBAL Variables : web-location-in-selected-index-entry-occurrences,
+ web-selected-index-entry-occurrences, and web-index-entry
+LOCAL Variables : ctr, current-module, end-of-web-index-entry, and
+ web-buffer-list
+RETURNS : the name of the buffer to return on an error
+USES : web-what-module"
+ (let ((ctr 1)
+ (current-module 0)
+ (end-of-web-index-entry 0)
+ web-buffer-list
+ )
+ (if (eobp)
+ ; then
+ (error "No index entry can be selected from this position.")
+ ) ; end if
+ (save-excursion
+ (beginning-of-line)
+ (while (looking-at " ") (forward-line -1))
+ (setq web-index-entry (buffer-substring (point)
+ (save-excursion (re-search-forward ": ") (- (point) 2))))
+ ; Set the global Emacs variable search-last-string to the index
+ ; entry selected by the user so that the user can use C-s C-s to
+ ; get to the entry much easier.
+ (setq search-last-string web-index-entry)
+ (save-excursion
+ (re-search-forward "\\.\n" nil t)
+ (setq end-of-web-index-entry (point))
+ ) ; end excursion
+ (while (re-search-forward
+ "\\([0-9]+\\)\\*?\\(, \\|,\n\\|\\.\n\\)"
+ end-of-web-index-entry t)
+ (setq web-selected-index-entry-occurrences (append
+ web-selected-index-entry-occurrences
+ (list (string-to-int
+ (buffer-substring (match-beginning 1) (match-end 1))))))
+ ) ; end while
+ ) ; end excursion
+ (setq web-buffer-list (mapcar (function buffer-name) (buffer-list)))
+ (setq ctr 1)
+ (while (char-equal (string-to-char
+ (substring (nth ctr web-buffer-list) 0 1)) ? )
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (save-excursion
+ (set-buffer (nth ctr web-buffer-list))
+ (setq current-module (web-what-module))
+ ) ; end excursion
+ (cond
+ ((string= direction "next")
+ (setq web-location-in-selected-index-entry-occurrences 0)
+ (while (and (nth web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences)
+ (<= (nth web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences)
+ current-module)
+ ) ; end and
+ (setq web-location-in-selected-index-entry-occurrences
+ (1+ web-location-in-selected-index-entry-occurrences))
+ ) ; end while
+ ) ; end case
+ ((string= direction "previous")
+ (setq web-location-in-selected-index-entry-occurrences
+ (1- (length web-selected-index-entry-occurrences)))
+ (while (and (>= web-location-in-selected-index-entry-occurrences 0)
+ (>= (nth web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences)
+ current-module)
+ ) ; end and
+ (setq web-location-in-selected-index-entry-occurrences
+ (1- web-location-in-selected-index-entry-occurrences))
+ ) ; end while
+ ) ; end case
+ (t
+ (error "This case should not be reached.")
+ ) ; end case
+ ) ; end cond
+ ; return the name of the buffer to return to on an error
+ (nth ctr web-buffer-list)
+ ) ; end let
+)
+
+(defun web-next-section ()
+ "This function moves point to the beginning of the next section. If point is
+currently in the last section of the Web, an appropriate message is sent to the
+minibuffer; otherwise, point is positioned at the first line of the next
+section.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variable : current-section
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files,
+ web-count-sections, web-goto-section, web-journal, and web-what-section"
+ (interactive)
+ (web-journal "web-next-section")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((current-section (web-what-section)))
+ (if (>= current-section (web-count-sections))
+ ; then
+ (error "No next section")
+ ; else
+ (web-goto-section (1+ current-section))
+ ) ; end if
+ ) ; end let
+)
+
+(defun web-next-use ()
+ "This function is used to traverse the list of Used In occurrences of the
+most recently selected module name in the forward direction. A module name is
+selected by issuing the command \\[web-view-module-names-list] and positioning
+the cursor on the line that contains the module name of interest.
+ARGUMENTS : None
+GLOBAL Variables : web-defined-in-used-in-location,
+ web-module-name-defined-in-used-in, and
+ web-used-in-occurrence
+LOCAL Variables : buffer-to-be-returned-to and current-module
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-goto-module,
+ web-next-or-previous-define-or-use, web-journal, and web-what-module"
+ (interactive)
+ (web-journal "web-next-use")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (cond
+ ((string= (buffer-name (current-buffer))
+ "*Module Name (Defined In) (Used In)*")
+ ; then the user needs to select an entry
+ (let ((buffer-to-be-returned-to
+ (web-next-or-previous-define-or-use "next" "used-in")))
+ (if (>= web-used-in-occurrence
+ (length (car (cdr (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))))
+ ; then there is no next use
+ (progn
+ (switch-to-buffer buffer-to-be-returned-to)
+ (error "No next use of %s"
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end then
+ ; else
+ (web-goto-module (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))))
+ (message "Use %d of %d of %s" (1+ web-used-in-occurrence)
+ (length (car (cdr (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end if
+ ) ; end let
+ ) ; end case
+ (t ; we are in a valid Web buffer
+ (if (= web-defined-in-used-in-location -1)
+ (error (concat "No selected module. "
+ "Execute M-x web-view-module-names-list to select."))
+ ; else
+ (let ((current-module (web-what-module)))
+ (setq web-used-in-occurrence 0)
+ (while (and (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (<= (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ current-module)
+ ) ; end and
+ (setq web-used-in-occurrence (1+ web-used-in-occurrence))
+ ) ; end while
+ (if (>= web-used-in-occurrence
+ (length (car (cdr (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))))
+ ; then there is no next define
+ (error "No next use of %s"
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ; else
+ (web-goto-module (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))))
+ (message "Use %d of %d of %s" (1+ web-used-in-occurrence)
+ (length (car (cdr (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end if
+ ) ; end let
+ ) ; end if
+ ) ; end case
+ ) ; end cond
+)
+
+(defun web-options-for-module-name-insertion ()
+ "This function is invoked by \\[web-insert-module-name] if the @< just
+encountered represents a valid module beginning. This function then presents
+the user with various options for choosing or creating a module name.
+ARGUMENTS : None
+GLOBAL Variables : web-module-names, web-number-of-lines-in-window, and
+ web-number-of-module-names
+LOCAL Variables : available-lines, char-after-at-greater, ctr, defined-in-list,
+ done, element-to-be-inserted, found, len, location, menu,
+ menu-choice, module-name, module-number, screen-bottom,
+ screen-top, search-letter, sub-menu, and used-in-list
+RETURNS : Nothing
+USES : web-append-a-stub-module, web-binary-search-of-names,
+ web-determine-module-name-ending, web-display-module-names,
+ web-eliminate-white-space, and web-what-module"
+ (let ((available-lines (- web-number-of-lines-in-window 11))
+ char-after-at-greater,
+ (ctr 0)
+ done
+ element-to-be-inserted
+ found
+ (len 0)
+ (location 0)
+ (menu (concat "Option Action\n------ " (make-string 43 ?-)
+ "\n A Abort\n"
+ " C Create a New Module Name\n"
+ " L List all Module Names Beginning with Letter\n"
+ " N Next Screen\n"
+ " P Previous Screen\n"
+ " S Select Existing Module Name\n"
+ (make-string 79 ?-) "\n"))
+ (menu-choice 0)
+ module-name
+ (module-number 0)
+ (screen-bottom 0)
+ (screen-top 0)
+ search-letter
+ used-in-list
+ )
+ (switch-to-buffer "*Module Names*")
+ (use-local-map web-mode-map)
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ (goto-char (point-min))
+ (kill-line (count-lines (point-min) (point-max)))
+ (insert-string menu)
+ (setq screen-top 1)
+ (if (>= web-number-of-module-names available-lines)
+ ; then
+ (setq screen-bottom available-lines)
+ ; else
+ (setq screen-bottom web-number-of-module-names)
+ ) ; end if
+ (web-display-module-names screen-top screen-bottom)
+ (setq menu-choice (read-string
+ "(A)bort, (C)reate, (L)ist, (N)ext, (P)revious, or (S)elect: "))
+ (while (not (string-match (upcase (substring menu-choice 0 1)) "ACLNPS"))
+ (ding)
+ (setq menu-choice (read-string
+ "(A)bort, (C)reate, (L)ist, (N)ext, (P)revious, or (S)elect: "))
+ ) ; end while
+ (setq done nil)
+ (while (not done)
+ (cond
+ ((char-equal (string-to-char (upcase (substring menu-choice 0 1))) ?A)
+ ; this is the Abort option
+ (switch-to-buffer (get-file-buffer (expand-file-name
+ (nth file-no web-files) web-default-directory)))
+ (delete-backward-char 2)
+ (setq done t)
+ ) ; end case
+ ((char-equal (string-to-char (upcase (substring menu-choice 0 1))) ?N)
+ ; show the Next screen of module names
+ (setq screen-bottom (+ screen-bottom available-lines))
+ (if (> screen-bottom web-number-of-module-names)
+ ; then
+ (setq screen-bottom web-number-of-module-names)
+ ) ; end if
+ (setq screen-top (1+ (- screen-bottom available-lines)))
+ (if (< screen-top 0)
+ ; then
+ (setq screen-top 1)
+ ) ; end if
+ (web-display-module-names screen-top screen-bottom)
+ (setq done nil)
+ ) ; end case
+ ((char-equal (string-to-char (upcase (substring menu-choice 0 1))) ?P)
+ ; show the Previous screen of module names
+ (setq screen-top (- screen-top available-lines))
+ (if (<= screen-top 0)
+ ; then
+ (setq screen-top 1)
+ ) ; end if
+ (setq screen-bottom (1- (+ screen-top available-lines)))
+ (if (>= screen-bottom web-number-of-module-names)
+ ; then
+ (setq screen-bottom web-number-of-module-names)
+ ) ; end if
+ (web-display-module-names screen-top screen-bottom)
+ (setq done nil)
+ ) ; end case
+ ((char-equal (string-to-char (upcase (substring menu-choice 0 1))) ?L)
+ ; list all module names beginning with a particular letter
+ (setq search-letter (read-string "Letter: ")
+ found nil
+ ctr 1)
+ (while (and (<= ctr web-number-of-module-names)
+ (<= (string-to-char
+ (substring (nth (1- ctr) web-module-names) 0 1))
+ (string-to-char search-letter)))
+ (if (and (null found) (string-equal
+ (substring (nth (1- ctr) web-module-names) 0 1)
+ (substring search-letter 0 1)))
+ ; then
+ (setq found t
+ screen-top ctr)
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (if (null found)
+ ; then
+ (progn
+ (ding)
+ (message "No module names begin with %s"
+ (substring search-letter 0 1))
+ (sit-for 3)
+ ) ; end then
+ ; else
+ (setq screen-bottom (min (1- ctr)
+ (1- (+ screen-top available-lines))))
+ (web-display-module-names screen-top screen-bottom
+ (- ctr screen-top))
+ ) ; end if
+ (setq done nil)
+ ) ; end case
+ ((char-equal (string-to-char (upcase (substring menu-choice 0 1))) ?S)
+ ; choose module name
+ (if (zerop web-number-of-module-names)
+ ; then this is an invalid choice
+ (progn
+ (ding)
+ (message
+ "Invalid since there are no module names to select from.")
+ (setq done nil)
+ ) ; end then
+ ; else select one of the existing names
+ (setq module-number (read-string
+ (format "Module Number [1..%d]: " web-number-of-module-names)))
+ (while (or (< (string-to-int module-number) 1)
+ (> (string-to-int module-number)
+ web-number-of-module-names))
+ (ding)
+ (setq module-number (read-string
+ (format "Module Number [1..%d]: " web-number-of-module-names)))
+ ) ; end while
+ (setq module-name (substring
+ (nth (1- (string-to-int module-number)) web-module-names)
+ 0 (string-match " "
+ (nth (1- (string-to-int module-number)) web-module-names))))
+ (switch-to-buffer (get-file-buffer (expand-file-name
+ (nth file-no web-files) web-default-directory)))
+ (insert-string module-name)
+ (insert-string (web-determine-module-name-ending))
+ (setq location (string-to-int (substring
+ (nth (1- (string-to-int module-number)) web-module-names)
+ (+ (string-match " " (nth (1- (string-to-int module-number))
+ web-module-names)) 2))))
+ (if (char-equal (preceding-char) ?=)
+ ; then an existing module name has been defined again
+ (progn
+ (setq new-module-number (web-what-module))
+ (web-update-the-module-name-defined-in-used-in-list
+ new-module-number)
+ (setq defined-in-list (sort (append (car (cdr (nth
+ location web-module-name-defined-in-used-in)))
+ (list new-module-number)) '<))
+ (setcdr (nth location web-module-name-defined-in-used-in)
+ (append (list defined-in-list)
+ (list (car (cdr (cdr
+ (nth location web-module-name-defined-in-used-in)))))))
+ ) ; end then
+ ; else update the used in list in the module names
+ (if (null (car (car (cdr (cdr
+ (nth location web-module-name-defined-in-used-in))))))
+ ; then
+ (setq used-in-list (list (web-what-module)))
+ ; else
+ (setq used-in-list (sort (append (car (cdr (cdr
+ (nth location web-module-name-defined-in-used-in))))
+ (list (web-what-module))) '<))
+ ) ; end if
+ (setcdr (nth location web-module-name-defined-in-used-in)
+ (append (list (car (cdr (nth location
+ web-module-name-defined-in-used-in))))
+ (list used-in-list)))
+ ) ; end if
+ (if (char-equal (preceding-char) ?=) (insert-char ?\012 1))
+ (setq done t)
+ ) ; end if
+ ) ; end case
+ ((char-equal (string-to-char (upcase (substring menu-choice 0 1))) ?C)
+ ; Create a new module name
+ (setq module-name (read-string "New Module Name: "))
+ (switch-to-buffer (get-file-buffer (expand-file-name
+ (nth file-no web-files) web-default-directory)))
+ (setq module-name (web-eliminate-white-space module-name))
+ (insert-string module-name)
+ (insert-string (web-determine-module-name-ending))
+ (if (char-equal (preceding-char) ?=)
+ ; then
+ (setq char-after-at-greater ?=)
+ ; else
+ (setq char-after-at-greater ? )
+ ) ; end if
+ (setq len (length module-name))
+ (if (and (> len 3) (string-equal "..."
+ (substring module-name (- len 3) len)))
+ ; then
+ (setq len (- len 3))
+ ) ; end if
+ (setq location (web-binary-search-of-names web-module-names
+ web-number-of-module-names module-name len))
+ (if (= location -1)
+ ; then it is indeed a new module name
+ (progn
+ (setq web-module-names (sort
+ (append web-module-names (list (concat
+ module-name " " (int-to-string web-number-of-module-names))))
+ 'string<))
+ (setq web-number-of-module-names (1+ web-number-of-module-names))
+ (setq new-module-number (web-what-module))
+ (if (char-equal ?= char-after-at-greater)
+ ; then this new module was defined (i.e., @<...@>=)
+ (progn
+ (web-update-the-module-name-defined-in-used-in-list
+ new-module-number)
+ (setq web-module-name-defined-in-used-in (append
+ web-module-name-defined-in-used-in (list (list module-name
+ (list new-module-number) (list ())))))
+ ) ; end then
+ ; else this new module was used before defined (insert a stub)
+ (ding)
+ (message "Appending a module for %s" module-name)
+ (sit-for 2)
+ (setq module-number-of-stub
+ (web-append-a-stub-module module-name))
+ (setq web-module-name-defined-in-used-in (append
+ web-module-name-defined-in-used-in (list (list module-name
+ (list module-number-of-stub) (list new-module-number)))))
+ ) ; end if
+ ) ; end then
+ ; else the user entered a supposedly new name that already exists
+ (setq location (string-to-int (substring
+ (nth location web-module-names)
+ (+ (string-match " " (nth location web-module-names)) 2))))
+ (if (char-equal (preceding-char) ?=)
+ ; then an existing module name has been defined again
+ (progn
+ (setq new-module-number (web-what-module))
+ (web-update-the-module-name-defined-in-used-in-list
+ new-module-number)
+ (setq defined-in-list (sort (append (car (cdr (nth
+ location web-module-name-defined-in-used-in)))
+ (list new-module-number)) '<))
+ (setcdr (nth location web-module-name-defined-in-used-in)
+ (append (list defined-in-list)
+ (list (car (cdr (cdr
+ (nth location web-module-name-defined-in-used-in)))))))
+ ) ; end then
+ ; else update the used in list in the module names
+ (if (null (car (car (cdr (cdr
+ (nth location web-module-name-defined-in-used-in))))))
+ ; then
+ (setq used-in-list (list (web-what-module)))
+ ; else
+ (setq used-in-list (sort (append (car (cdr (cdr
+ (nth location web-module-name-defined-in-used-in))))
+ (list (web-what-module))) '<))
+ ) ; end if
+ (setcdr (nth location web-module-name-defined-in-used-in)
+ (append (list (car (cdr (nth location
+ web-module-name-defined-in-used-in))))
+ (list used-in-list)))
+ ) ; end if
+ (if (char-equal (preceding-char) ?=) (insert-char ?\012 1))
+ ) ; end if
+ (setq done t)
+ ) ; end case
+ ) ; end cond
+ (if (not done)
+ ; then
+ (progn
+ (setq menu-choice (read-string
+ "(A)bort, (C)reate, (L)ist, (N)ext, (P)revious, or (S)elect: "))
+ (while (not
+ (string-match (upcase (substring menu-choice 0 1)) "ACLNPS"))
+ (ding)
+ (setq menu-choice (read-string
+ "(A)bort, (C)reate, (L)ist, (N)ext, (P)revious, or (S)elect: "))
+ ) ; end while
+ ) ; end then
+ ) ; end if
+ ) ; end while
+ ) ; end let
+)
+
+(defun web-previous-change ()
+ "Advances point to the beginning of the previous change.
+ARGUMENTS : None
+GLOBAL Variable : web-change-buffer-name
+LOCAL Variable : start-position
+RETURNS : Nothing
+USES : web-journal"
+ (interactive)
+ (web-journal "web-previous-change")
+ (if (not (string= web-change-buffer-name (buffer-name (current-buffer))))
+ ; then
+ (error "Not in the CHange buffer.")
+ ; else
+ (let ((start-position (point)))
+ (end-of-line)
+ (if (not (re-search-backward "^@x" nil t 2))
+ ; then
+ (progn
+ (goto-char start-position)
+ (error "No previous CHange.")
+ ) ; end then
+ ; else
+ (re-search-forward "^@y" nil t)
+ (goto-char (match-beginning 0))
+ (recenter 0)
+ ) ; end if
+ ) ; end let
+ ) ; end if
+)
+
+(defun web-previous-define ()
+ "This function can only be invoked in the buffer containing the Web document.
+It is used to traverse the list of Defined In occurrences of the most recently
+selected module name in the backward direction. A module name is selected by
+issuing the command \\[web-view-module-names-list] and positioning the cursor
+on the line that contains the module name of interest.
+ARGUMENTS : None
+GLOBAL Variables : web-defined-in-occurrence, web-defined-in-used-in-location,
+ and web-module-name-defined-in-used-in
+LOCAL Variable : buffer-to-be-returned-to and current-module
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-goto-module,
+ web-next-or-previous-define-or-use, web-journal, and web-what-module"
+ (interactive)
+ (web-journal "web-previous-define")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (cond
+ ((string= (buffer-name (current-buffer))
+ "*Module Name (Defined In) (Used In)*")
+ ; then the user needs to select an entry
+ (let ((buffer-to-be-returned-to
+ (web-next-or-previous-define-or-use "previous" "defined-in")))
+ (if (< web-defined-in-occurrence 0)
+ ; then there is no previous define
+ (progn
+ (switch-to-buffer buffer-to-be-returned-to)
+ (error "No previous define of %s" (car (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end then
+ ; else
+ (web-goto-module (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (message "Define %d of %d of %s" (1+ web-defined-in-occurrence)
+ (length (car (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end if
+ ) ; end let
+ ) ; end case
+ (t ; we are in a valid Web buffer
+ (if (= web-defined-in-used-in-location -1)
+ (error (concat "No selected module. "
+ "Execute M-x web-view-module-names-list to select."))
+ ; else
+ (let ((current-module (web-what-module)))
+ (setq web-defined-in-occurrence (1- (length
+ (car (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))))
+ (while (and (>= web-defined-in-occurrence 0)
+ (>= (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ current-module)
+ ) ; end and
+ (setq web-defined-in-occurrence (1- web-defined-in-occurrence))
+ ) ; end while
+ (if (< web-defined-in-occurrence 0)
+ ; then there is no next define
+ (error "No previous define of %s" (car (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ; else
+ (web-goto-module (nth web-defined-in-occurrence (car (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (message "Define %d of %d of %s" (1+ web-defined-in-occurrence)
+ (length (car (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end if
+ ) ; end let
+ ) ; end if
+ ) ; end case
+ ) ; end cond
+)
+
+(defun web-previous-index ()
+ "This function is used to traverse the list of occurrences of the most
+recently selected index entry in the backward direction. An index entry is
+selected by issuing the command \\[web-view-index] and positioning the cursor
+on the line that contains the index entry of interest.
+ARGUMENTS : None
+GLOBAL Variables : web-location-in-selected-index-entry-occurrences,
+ web-selected-index-entry-occurrences,
+ web-index-buffer-name, and web-index-entry
+LOCAL Variables : buffer-to-be-returned-to and current-module
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-goto-module,
+ web-journal, web-next-or-previous-index, and web-what-module"
+ (interactive)
+ (web-journal "web-previous-index")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (cond
+ ((string-equal web-index-buffer-name (buffer-name (current-buffer)))
+ ; then we are in the index
+ (let ((buffer-to-be-returned-to (web-next-or-previous-index "previous")))
+ (if (< web-location-in-selected-index-entry-occurrences 0)
+ ; then there is no previous use
+ (progn
+ (switch-to-buffer buffer-to-be-returned-to)
+ (error "No previous index reference for %s" web-index-entry)
+ ) ; end then
+ ; else
+ (web-goto-module (nth
+ web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences))
+ (message "Index Reference %d of %d for entry %s"
+ (1+ web-location-in-selected-index-entry-occurrences)
+ (length web-selected-index-entry-occurrences)
+ web-index-entry)
+ ) ; end if
+ ) ; end let
+ ) ; end case
+ (t ; else we are in a Web buffer
+ (if (null web-selected-index-entry-occurrences)
+ ; then
+ (error
+ "Issue the command M-x web-view-index to select an index entry.")
+ ; else
+ (let ((current-module (web-what-module)))
+ (setq web-location-in-selected-index-entry-occurrences
+ (1- (length web-selected-index-entry-occurrences)))
+ (while (and (>= web-location-in-selected-index-entry-occurrences 0)
+ (>= (nth web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences)
+ current-module)
+ ) ; end and
+ (setq web-location-in-selected-index-entry-occurrences
+ (1- web-location-in-selected-index-entry-occurrences))
+ ) ; end while
+ (if (< web-location-in-selected-index-entry-occurrences 0)
+ ; then
+ (error "No previous index reference for %s" web-index-entry)
+ ; else
+ (web-goto-module (nth
+ web-location-in-selected-index-entry-occurrences
+ web-selected-index-entry-occurrences))
+ (message "Index Reference %d of %d for entry %s"
+ (1+ web-location-in-selected-index-entry-occurrences)
+ (length web-selected-index-entry-occurrences)
+ web-index-entry)
+ ) ; end if
+ ) ; end let
+ ) ; end if
+ ) ; end case
+ ) ; end cond
+)
+
+(defun web-previous-module ()
+ "This function moves point to the beginning of the previous module. If point
+is currently in the limbo section of the Web or in module 1, an appropriate
+message is sent to the minibuffer; otherwise, point is positioned at the first
+line of the previous module.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variable : current-module
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files,
+ web-goto-module, web-journal, and web-what-module"
+ (interactive)
+ (web-journal "web-previous-module")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((current-module (web-what-module)))
+ (if (<= current-module 1)
+ ; then
+ (error "No previous module")
+ ; else
+ (web-goto-module (1- current-module))
+ ) ; end if
+ ) ; end let
+)
+
+(defun web-previous-section ()
+ "This function moves point to the beginning of the previous section. If
+point is currently in the limbo section of the Web or in the first section, an
+appropriate message is sent to the minibuffer; otherwise, point is positioned
+at the first line of the previous section.
+ARGUMENTS : None
+GLOBAL Variables : None
+LOCAL Variable : current-section
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files,
+ web-goto-section, web-journal, and web-what-section"
+ (interactive)
+ (web-journal "web-previous-section")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((current-section (web-what-section)))
+ (if (<= current-section 1)
+ ; then
+ (error "No previous section")
+ ; else
+ (web-goto-section (1- current-section))
+ ) ; end if
+ ) ; end let
+)
+
+(defun web-previous-use ()
+ "This function can only be invoked in the buffer containing the Web document.
+It is used to traverse the list of Used In occurrences of the most recently
+selected module name in the backward direction. A module name is selected by
+issuing the command \\[web-view-module-names-list] and positioning the cursor
+on the line that contains the module name of interest.
+ARGUMENTS : None
+GLOBAL Variables : web-defined-in-used-in-location,
+ web-module-name-defined-in-used-in, and
+ web-used-in-occurrence
+LOCAL Variables : buffer-to-be-returned-to and current-module
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-goto-module,
+ web-next-or-previous-define-or-use, web-journal, and web-what-module"
+ (interactive)
+ (web-journal "web-previous-use")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (cond
+ ((string= (buffer-name (current-buffer))
+ "*Module Name (Defined In) (Used In)*")
+ ; then the user needs to select an entry
+ (let ((buffer-to-be-returned-to
+ (web-next-or-previous-define-or-use "previous" "used-in")))
+ (if (< web-used-in-occurrence 0)
+ ; then there is no previous use
+ (progn
+ (switch-to-buffer buffer-to-be-returned-to)
+ (error "No previous use of %s"
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end then
+ ; else
+ (web-goto-module (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))))
+ (message "Use %d of %d of %s" (1+ web-used-in-occurrence)
+ (length (car (cdr (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end if
+ ) ; end let
+ ) ; end case
+ (t ; we are in a valid Web buffer
+ (if (= web-defined-in-used-in-location -1)
+ (error (concat "No selected module. "
+ "Execute M-x web-view-module-names-list to select."))
+ ; else
+ (let ((current-module (web-what-module)))
+ (setq web-used-in-occurrence (1- (length (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))))
+ (while (and (>= web-used-in-occurrence 0)
+ (>= (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ current-module)
+ ) ; end and
+ (setq web-used-in-occurrence (1- web-used-in-occurrence))
+ ) ; end while
+ (if (< web-used-in-occurrence 0)
+ ; then there is no next define
+ (error "No previous use of %s"
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ; else
+ (web-goto-module (nth web-used-in-occurrence (car (cdr (cdr (nth
+ web-defined-in-used-in-location
+ web-module-name-defined-in-used-in))))))
+ (message "Use %d of %d of %s" (1+ web-used-in-occurrence)
+ (length (car (cdr (cdr (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))))
+ (car (nth web-defined-in-used-in-location
+ web-module-name-defined-in-used-in)))
+ ) ; end if
+ ) ; end let
+ ) ; end if
+ ) ; end case
+ ) ; end cond
+)
+
+(defun web-reformat-the-index ()
+ "This is an internal support function used to reformat the raw index produced
+by Weave. Control sequences must be removed and some reformatting is necessary
+to clearly distinguish index entries (e.g., if an index entry occupies multiple
+lines, the second and succeeding lines are indented two spaces).
+ARGUMENTS : None
+GLOBAL Variables : web-default-directory, web-index-buffer-name, and
+ web-mode-map
+LOCAL Variables : ctr and line-to-be-inserted
+RETURNS : Nothing
+USES : web-eliminate-control-sequences and web-eliminate-white-space"
+ (let ((ctr 0)
+ line-to-be-inserted
+ )
+ (message "Reformatting the index...")
+ (switch-to-buffer web-index-buffer-name)
+ (use-local-map web-mode-map)
+ (goto-char (point-min))
+ (kill-line (count-lines (point-min) (point-max)))
+ (insert-file (expand-file-name "INDEX.tex" web-default-directory))
+ (save-excursion
+ (re-search-forward "\\\\W?inx" nil t)
+ (setq ctr (count-lines (point-min) (point)))
+ (goto-char (point-min))
+ (kill-line ctr)
+ ) ; end excursion
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward "\\\\W?fin" nil t)
+ (beginning-of-line)
+ (kill-line (count-lines (point) (point-max)))
+ ) ; end excursion
+ (goto-char (point-min))
+ ; indent index entries that occupy multiple lines
+ ; index entries look like \:entry, occurrence-1, occurrence-2, ...,
+ ; occurrence-n.
+ ;
+ ; WEAVE sometimes puts a %\n at the end of lines in the index. See
+ ; module 67 in the source for CWEAVE or module 122 in the source for
+ ; the Pascal WEAVE. Temporarily, make one long line out of these.
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "%\n" nil t)
+ (delete-char -2)
+ ) ; end while
+ ) ; end excursion
+ ; Eliminate \: and the , followoing the index entry.
+ (web-eliminate-control-sequences "\\\\:\\(.*\\)}," "}:")
+ (web-eliminate-control-sequences "\\\\:\\\\|\\(.\\)," ":")
+ ; FWEAVE sets built-in functions in the index as \:\@{function},
+ ; Two lines above changes this to \@{function}:
+ ; Now get rid of the \@{ and }
+ (web-eliminate-control-sequences "\\\\@{\\(.*\\)}:" ":")
+ ; Now entries to be set in roman type look like {...}: ... Now eliminate
+ ; the braces.
+ (web-eliminate-control-sequences "^{\\(.*\\)}:" ":")
+ ; Eliminate \\{ and } from \\{...} (used for italicizing index entries
+ ; of length greater than one
+ (web-eliminate-control-sequences "\\\\\\\\{\\(.*\\)}")
+ ; Eliminate \|{ and } from \|{...} (used for italicizing index entries
+ ; of length one
+ (web-eliminate-control-sequences "\\\\|{\\(.*\\)}")
+ ; Eliminate \&{ and } from \&{...} (used for boldfacing index entries
+ (web-eliminate-control-sequences "\\\\&{\\(.*\\)}")
+ ; Eliminate \9{, }, and {...} from \9{...}{...} (used for placing entry
+ ; in a special way. See p. 204 #11 in WEB User Manual.
+ (web-eliminate-control-sequences "\\\\9{\\(.*\\)}{.*}")
+ ; eliminate \.{ and } from \.{...} (used for placing index entries in a
+ ; typewriter font
+ (web-eliminate-control-sequences "\\\\\\.{\\(.*\\)}")
+ ; Eliminate \[ and ] from \[...] which is used to underline an index
+ ; occurrence entry. The only characters that can be inside the brackets
+ ; are digits and \* (the latter meaning that the module was changed).
+ (web-eliminate-control-sequences "\\\\\\[\\([0-9*\\]*\\)\\]")
+ (web-eliminate-control-sequences
+ "\\\\\\(\\\\\\|'\\|`\\|{\\|}\\|~\\| \\|_\\|&\\|#\\|\\$\\|%\\|\\^\\|\\*\\)"
+ )
+ ; FWEAVE places a control sequence \Windexspace before every group of
+ ; index entries beginning with a particular letter. Eliminate these lines.
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "\\\\Windexspace" nil t)
+ (beginning-of-line)
+ (kill-line 1)
+ ) ; end while
+ ) ; end excursion
+ (save-excursion (goto-char (point-min)) (replace-regexp "{\\\\AT}" "@"))
+ ; Some index entries occupy multiple lines. Indent the second and
+ ; succeeding lines.
+ (save-excursion
+ (while (re-search-forward ".+: \\(.+,\n\\)*.+\\.\n" nil t)
+ (if (/= (count-lines (point-min) (match-beginning 0))
+ (count-lines (point-min) (match-end 0)))
+ ; then
+ (progn
+ (setq line-to-be-inserted (web-eliminate-white-space
+ (buffer-substring
+ (match-beginning 0) (match-end 0))))
+ (delete-char (- 0 (length (buffer-substring (match-beginning 0)
+ (match-end 0)))))
+ (while (> (length line-to-be-inserted) 79)
+ (setq ctr 79)
+ (while (not (char-equal ?
+ (string-to-char
+ (substring line-to-be-inserted (1- ctr) ctr))))
+ (setq ctr (1- ctr))
+ ) ; end while
+ (insert-string (concat
+ (substring line-to-be-inserted 0 (1- ctr)) "\n"))
+ (setq line-to-be-inserted (concat " "
+ (substring line-to-be-inserted ctr)))
+ ) ; end while
+ (insert-string (concat line-to-be-inserted "\n"))
+ ) ; end then
+ ) ; end if
+ ) ; end while
+ ) ; end excursion
+ ) ; end let
+ (message "Reformatting the index...done")
+)
+
+(defun web-rename-module ()
+ "This function allows a user to rename a module. The user positions point
+within the module that is to be changed. The user can then change all, one,
+or some occurrences of this module name.
+ARGUMENTS : None
+GLOBAL Variables : web-module-name-defined-in-used-in, web-module-names, and
+ web-module-name
+LOCAL Variables : case, ctr, current-position, defined, data, done, len,
+ len-old-module-name, module-name, module-name-begins-at,
+ module-name-ends-at, module-number-of-replacement,
+ modules-where-name-is-to-be-replaced, new-define,
+ new-module-name, new-use, next-module-begins, old-define,
+ old-module-name, old-use,
+ position-in-web-module-name-defined-in-used-in-list,
+ position-in-module-names, replace-module-name, and
+ temp-list
+RETURNS : Nothing
+USES : web-append-a-stub-module, web-binary-search-of-names,
+ web-check-if-buffer-is-one-of-the-web-files, web-eliminate-white-space,
+ web-goto-module, web-view-module-names-list, web-journal and
+ web-what-module"
+ (interactive)
+ (web-journal "web-rename-module")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ ; isolate the module name that point is in
+ (let (case
+ (ctr 0)
+ (current-position (point))
+ defined
+ done
+ (len 0)
+ (len-old-module-name 0)
+ module-name
+ (module-name-begins-at 0)
+ (module-name-ends-at 0)
+ (module-number-of-replacement 0)
+ modules-where-name-is-to-be-replaced
+ new-define
+ new-module-name
+ new-use
+ (next-module-begins 0)
+ old-define
+ old-module-name
+ old-use
+ (position-in-web-module-name-defined-in-used-in-list 0)
+ (position-in-module-names 0)
+ replace-module-name
+ temp-list
+ )
+ (save-excursion
+ (cond
+ ((looking-at "<")
+ (forward-char 1)
+ ) ; end case
+ ((looking-at "@<")
+ (forward-char 2)
+ ) ; end case
+ ) ; end cond
+ ; find the beginning of the module name, if possible
+ (while (not done)
+ (if (not (re-search-backward "\\(@@\\)*\\(@<\\)" nil t))
+ ; then
+ (progn
+ (goto-char current-position)
+ (setq done nil)
+ (error "Point not positioned within a module name.")
+ ) ; end then
+ ; else
+ (goto-char (match-beginning 0))
+ (if (and (> (point) 1)
+ (char-equal (preceding-char) ?\@))
+ ; then point is not positioned at the beginning of a module name
+ (setq done nil)
+ ; else point is positioned at a valid module name beginning
+ (goto-char (match-beginning 2))
+ (setq done t)
+ ) ; end if
+ ) ; end if
+ ) ; end while
+ (setq module-name-begins-at (point)
+ done nil)
+ ; find the ending of the module name, if possible
+ (while (not done)
+ (if (not (re-search-forward "\\(@@\\)*\\(@>\\)" nil t))
+ ; then
+ (progn
+ (goto-char current-position)
+ (setq done nil)
+ (error "Point not positioned within a module name.")
+ ) ; end then
+ ; else
+ (goto-char (match-beginning 0))
+ (if (char-equal (preceding-char) ?\@)
+ ; then point is not positioned at the ending of a module name
+ (progn
+ (setq done nil)
+ (goto-char (match-end 2))
+ ) ; end then
+ ; else point is positioned at a valid module name ending
+ (goto-char (match-end 2))
+ (setq done t)
+ ) ; end if
+ ) ; end if
+ ) ; end while
+ (setq module-name-ends-at (point))
+ (if (< (point) current-position)
+ ; then
+ (error "Point not positioned within a module name.")
+ ) ; end if
+ (if (looking-at "=") (setq defined t))
+ (setq old-module-name (web-eliminate-white-space
+ (buffer-substring (+ module-name-begins-at 2)
+ (- module-name-ends-at 2))))
+ (setq len-old-module-name (length old-module-name))
+ (if (and (> len-old-module-name 3)
+ (string-equal "..."
+ (substring old-module-name
+ (- len-old-module-name 3) len-old-module-name)))
+ ; then
+ (setq len-old-module-name (- len-old-module-name 3))
+ ) ; end if
+ (setq position-in-module-names (web-binary-search-of-names
+ web-module-names
+ (length web-module-names) old-module-name len-old-module-name))
+ (setq position-in-web-module-name-defined-in-used-in-list
+ (string-to-int (substring
+ (nth position-in-module-names web-module-names)
+ (+ (string-match " "
+ (nth position-in-module-names web-module-names)) 2))))
+ (setq replace-module-name (web-eliminate-white-space
+ (read-string (format "Replacement Module Name: "))))
+ (if (> (web-binary-search-of-names web-module-names
+ (length web-module-names)
+ replace-module-name (length replace-module-name)) -1)
+ ; then the replace-module-name is already in list of web-module-names
+ (error "Replace module name has already been used.")
+ ) ; end if
+ ; ask the user if this is a global replacement, only one replacement,
+ ; or replace some
+ (setq case (read-string "Replace (a)ll, (o)ne, or (s)ome: "))
+ (while (not (string-match (downcase (substring case 0 1)) "aos"))
+ (ding)
+ (setq case (read-string "Replace (a)ll, (o)ne, or (s)ome: "))
+ ) ; end while
+ (cond
+ ((char-equal (string-to-char (downcase case)) ?a)
+ (while (nth ctr (car (cdr (nth
+ position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in))))
+ (setq modules-where-name-is-to-be-replaced (append
+ modules-where-name-is-to-be-replaced
+ (list (nth ctr (car (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (setq ctr 0)
+ (while (nth ctr (car (cdr (cdr (nth
+ position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))
+ (setq modules-where-name-is-to-be-replaced (append
+ modules-where-name-is-to-be-replaced
+ (list (nth ctr (car (cdr (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in))))))))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (setq modules-where-name-is-to-be-replaced (sort
+ modules-where-name-is-to-be-replaced '<))
+ (while (car modules-where-name-is-to-be-replaced)
+ (web-goto-module (car modules-where-name-is-to-be-replaced))
+ (forward-char 2) ; get past the module beginning
+ (save-excursion
+ (if (re-search-forward "^@\\(i\\| \\|\n\\|\t\\|\\*\\)" nil t)
+ ; then
+ (setq next-module-begins (point))
+ ; else
+ (setq next-module-begins (point-max))
+ ) ; end if
+ ) ; end excursion
+ (message "Replacing name in Module %d"
+ (car modules-where-name-is-to-be-replaced))
+ (while (re-search-forward web-module-name next-module-begins t)
+ (setq module-name (web-eliminate-white-space
+ (buffer-substring (match-beginning 2) (match-end 2))))
+ (setq len (length module-name))
+ (if (and (> len 3) (string-equal "..."
+ (substring module-name (- len 3) len)))
+ ; then
+ (setq len (- len 3))
+ ) ; end if
+ (if (string-equal (substring module-name 0
+ (min len len-old-module-name))
+ (substring old-module-name 0
+ (min len len-old-module-name)))
+ ; then do the replacement
+ (progn
+ (backward-char (+ (length (buffer-substring
+ (match-beginning 2) (match-end 2))) 2))
+ (delete-char (length (buffer-substring
+ (match-beginning 2) (match-end 2))))
+ (insert replace-module-name)
+ ) ; end then
+ ) ; end if
+ ) ; end while
+ (setq modules-where-name-is-to-be-replaced
+ (cdr modules-where-name-is-to-be-replaced))
+ ) ; end while
+ ; update the web-module-names and
+ ; web-module-name-defined-in-used-in lists
+ (setcar (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in) replace-module-name)
+ (setq ctr 0
+ temp-list nil)
+ (while (< ctr (length web-module-names))
+ (if (/= ctr position-in-module-names)
+ ; then
+ (setq temp-list (append temp-list
+ (list (nth ctr web-module-names))))
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (setq temp-list (append temp-list (list (concat
+ replace-module-name " "
+ (int-to-string
+ position-in-web-module-name-defined-in-used-in-list)))))
+ (setq web-module-names (sort temp-list 'string<))
+ (web-view-module-names-list)
+ ) ; end case
+ ((char-equal (string-to-char (downcase case)) ?o)
+ ; rename only one occurrence
+ (setq module-number-of-replacement (web-what-module)
+ temp-list nil
+ ctr 0)
+ (if defined
+ ; then
+ (progn
+ (if (= 1 (length (car (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))
+ ; then
+ (error (concat "Use the A option. "
+ "Attempt to rename module that was defined only once."))
+ ; else
+ (setq web-number-of-module-names
+ (1+ web-number-of-module-names))
+ (while (nth ctr (car (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in))))
+ (if (/= module-number-of-replacement
+ (nth ctr (car (cdr
+ (nth
+ position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))
+ ; then
+ (setq temp-list (append temp-list (list (nth ctr (car (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))))
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (setcdr (nth
+ position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)
+ (append (list temp-list)
+ (list (car (cdr (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))))
+ (setq web-module-name-defined-in-used-in (append
+ web-module-name-defined-in-used-in (list
+ (list replace-module-name
+ (list module-number-of-replacement) (list ())))))
+ (setq web-module-names (sort
+ (append web-module-names (list (concat
+ replace-module-name " "
+ (int-to-string (1- web-number-of-module-names)))))
+ 'string<))
+ ) ; end if
+ ) ; end then
+ ; else
+ (setq web-number-of-module-names (1+ web-number-of-module-names))
+ (while (nth ctr (car (cdr (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))
+ (if (/= module-number-of-replacement
+ (nth ctr (car (cdr (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in))))))
+ ; then
+ (setq temp-list (append temp-list (list (nth ctr (car (cdr (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in))))))))
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (setcdr (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)
+ (append (list (car (cdr (nth
+ position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in))))
+ (list temp-list)))
+ (setq web-module-name-defined-in-used-in (append
+ web-module-name-defined-in-used-in (list
+ (list replace-module-name
+ (list (web-append-a-stub-module replace-module-name))
+ (list ())))))
+ (setq web-module-names (sort (append web-module-names (list (concat
+ replace-module-name " "
+ (int-to-string (1- web-number-of-module-names)))))
+ 'string<))
+ ) ; end if
+ (goto-char (+ module-name-begins-at 2))
+ (delete-char (1- (- module-name-ends-at (point))))
+ (insert replace-module-name)
+ (web-view-module-names-list)
+ ) ; end case
+ ((char-equal (string-to-char (downcase case)) ?s)
+ (setq old-define nil
+ new-define nil
+ old-use nil
+ new-use nil
+ defined nil)
+ (while (nth ctr (car (cdr (nth
+ position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in))))
+ (setq modules-where-name-is-to-be-replaced (append
+ modules-where-name-is-to-be-replaced
+ (list (nth ctr (car (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (setq ctr 0)
+ (while (nth ctr (car (cdr (cdr (nth
+ position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))
+ (setq modules-where-name-is-to-be-replaced (append
+ modules-where-name-is-to-be-replaced
+ (list (nth ctr (car (cdr (cdr
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in))))))))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (setq modules-where-name-is-to-be-replaced (sort
+ modules-where-name-is-to-be-replaced '<))
+ (while (car modules-where-name-is-to-be-replaced)
+ (web-goto-module (car modules-where-name-is-to-be-replaced))
+ (forward-char 2) ; get past the module beginning
+ (save-excursion
+ (if (re-search-forward "^@\\(i\\| \\|\n\\|\t\\|\\*\\)" nil t)
+ ; then
+ (setq next-module-begins (point))
+ ; else
+ (setq next-module-begins (point-max))
+ ) ; end if
+ ) ; end excursion
+ (while (re-search-forward web-module-name next-module-begins t)
+ (setq module-name (web-eliminate-white-space
+ (buffer-substring (match-beginning 2) (match-end 2))))
+ (setq len (length module-name))
+ (if (and (> len 3) (string-equal "..."
+ (substring module-name (- len 3) len)))
+ ; then
+ (setq len (- len 3))
+ ) ; end if
+ (if (string-equal (substring module-name 0
+ (min len len-old-module-name))
+ (substring old-module-name 0
+ (min len len-old-module-name)))
+ ; then ask if it is to be replaced
+ (progn
+ (let ((data (match-data)))
+ (unwind-protect
+ (if (looking-at "=") (setq defined t))
+ (store-match-data data)
+ ) ; end protect
+ ) ; end let
+ (recenter 0)
+ (if (y-or-n-p (format
+ "Replace this %s occurrence in Module %d? "
+ (if defined "defined in" "used in")
+ (car modules-where-name-is-to-be-replaced)))
+ ; then
+ (progn
+ (if defined
+ ; then
+ (setq new-define (append new-define
+ (list (car modules-where-name-is-to-be-replaced))))
+ ; else
+ (setq new-use (append new-use
+ (list (car modules-where-name-is-to-be-replaced))))
+ ) ; end if
+ (backward-char (+ (length (buffer-substring
+ (match-beginning 2) (match-end 2))) 2))
+ (delete-char (length (buffer-substring
+ (match-beginning 2) (match-end 2))))
+ (insert replace-module-name)
+ ) ; end then
+ ; else
+ (if defined
+ ; then
+ (setq old-define (append old-define
+ (list (car modules-where-name-is-to-be-replaced))))
+ ; else
+ (setq old-use (append old-use
+ (list (car modules-where-name-is-to-be-replaced))))
+ ) ; end if
+ ) ; end if
+ ) ; end then
+ ) ; end if
+ ) ; end while
+ (setq modules-where-name-is-to-be-replaced
+ (cdr modules-where-name-is-to-be-replaced))
+ ) ; end while
+ (cond
+ ((and (null old-define) (null old-use))
+ ; similar to replace all -- the old name must be removed
+ (setcar (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in) replace-module-name)
+ (setq ctr 0
+ temp-list nil)
+ (while (< ctr (length web-module-names))
+ (if (/= ctr position-in-module-names)
+ ; then
+ (setq temp-list (append temp-list
+ (list (nth ctr web-module-names))))
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (setq temp-list (append temp-list (list (concat
+ replace-module-name " " (int-to-string
+ position-in-web-module-name-defined-in-used-in-list)))))
+ (setq web-module-names (sort temp-list 'string<))
+ (web-view-module-names-list)
+ ) ; end case
+ ((null old-define)
+ ; append a stub for the old
+ (setq web-number-of-module-names (1+ web-number-of-module-names))
+ (setcdr (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in) (append
+ (list (list (web-append-a-stub-module (car
+ (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)))))
+ (list old-use)))
+ (setq web-module-name-defined-in-used-in (append
+ web-module-name-defined-in-used-in
+ (list (list replace-module-name
+ new-define new-use))))
+ (setq web-module-names (sort
+ (append web-module-names (list (concat
+ replace-module-name " "
+ (int-to-string (1- web-number-of-module-names)))))
+ 'string<))
+ (web-view-module-names-list)
+ ) ; end case
+ ((and (null new-define) (null new-use))
+ ; do nothing -- no name has been replaced
+ ) ; end case
+ ((null new-define)
+ ; append a stub for the replace module name
+ (setq web-number-of-module-names (1+ web-number-of-module-names))
+ (setcdr (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)
+ (append (list old-define) (list old-use)))
+ (setq web-module-name-defined-in-used-in (append
+ web-module-name-defined-in-used-in
+ (list (list replace-module-name
+ (list (web-append-a-stub-module replace-module-name))
+ new-use))))
+ (setq web-module-names (sort
+ (append web-module-names (list (concat
+ replace-module-name " "
+ (int-to-string (1- web-number-of-module-names)))))
+ 'string<))
+ (web-view-module-names-list)
+ ) ; end case
+ (t
+ ; update both lists
+ (setq web-number-of-module-names (1+ web-number-of-module-names))
+ (setcdr (nth position-in-web-module-name-defined-in-used-in-list
+ web-module-name-defined-in-used-in)
+ (append (list old-define) (list old-use)))
+ (setq web-module-name-defined-in-used-in (append
+ web-module-name-defined-in-used-in
+ (list (list replace-module-name
+ new-define new-use))))
+ (setq web-module-names (sort
+ (append web-module-names (list (concat
+ replace-module-name " "
+ (int-to-string (1- web-number-of-module-names)))))
+ 'string<))
+ (web-view-module-names-list)
+ ) ; end case
+ ) ; end cond
+ ) ; end case
+ ) ; end cond
+ ) ; end excursion
+ ) ; end let
+)
+
+(defun web-update-the-location-of-module-vector (next-char)
+ "This function is invoked by \\[web-is-this-a-new-module-beginning] whenever
+a new module is started. The vector web-location-of-module must be updated to
+reflect the addition of the new module.
+ARGUMENTS : next-char (required)
+GLOBAL Variables : web-location-of-module, web-number-of-modules-in-file, and
+ web-max-number-of-modules
+LOCAL Variables : ctr, file-number, number-of-module-to-be-inserted,
+ relative-position, and section-number
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-count-modules,
+ and web-what-module"
+ (let ((ctr (web-count-modules))
+ (file-number (web-check-if-buffer-is-one-of-the-web-files))
+ (number-of-module-to-be-inserted (web-what-module))
+ (relative-position 0)
+ (section-number 0)
+ )
+ (if (>= ctr web-max-number-of-modules)
+ ; then
+ (error "Increase the constant web-max-number-of-modules.")
+ ; else
+ (message "Updating the web-location-of-module vector...")
+ (while (>= ctr number-of-module-to-be-inserted)
+ (if (= file-number (aref (aref web-location-of-module ctr) 0))
+ ; then increment its relative position in the file
+ (progn
+ (setq relative-position (aref (aref web-location-of-module ctr) 1))
+ (aset (aref web-location-of-module ctr) 1
+ (1+ (aref (aref web-location-of-module ctr) 1)))
+ ) ; end then
+ ) ; end if
+ (if (char-equal next-char ?*)
+ ; then increment the section number
+ (aset (aref web-location-of-module ctr) 2
+ (1+ (aref (aref web-location-of-module ctr) 2)))
+ ) ; end if
+ (aset web-location-of-module (1+ ctr)
+ (aref web-location-of-module ctr))
+ (setq ctr (1- ctr))
+ ) ; end while
+ (if (char-equal next-char ?*)
+ ; then
+ (setq section-number (1+ (aref
+ (aref web-location-of-module
+ (1- number-of-module-to-be-inserted)) 2)))
+ ; else
+ (setq section-number (aref
+ (aref web-location-of-module
+ (1- number-of-module-to-be-inserted)) 2))
+ ) ; end if
+ (aset web-location-of-module number-of-module-to-be-inserted
+ (vector file-number
+ (if (not (zerop relative-position))
+ ; then
+ relative-position
+ ; else
+ (1+ (aref web-number-of-modules-in-file file-number))
+ ) ; end if
+ section-number
+ 0
+ ) ; end vector
+ ) ; end aset
+ (aset web-number-of-modules-in-file file-number
+ (1+ (aref web-number-of-modules-in-file file-number)))
+ (message "Updating the web-location-of-module vector...done")
+ ) ; end if
+ ) ; end let
+)
+
+(defun web-update-the-module-name-defined-in-used-in-list (new-module-number)
+ "This function is invoked when NEW-MODULE-NUMBER is inserted. All module
+numbers in the list web-module-name-defined-in-used-in must be updated to
+reflect the insertion of this new module.
+ARGUMENTS : new-module-number
+GLOBAL Variable : web-module-name-defined-in-used-in
+LOCAL Variables : ctr, defined-in-list, i, and used-in-list
+RETURNS : Nothing
+USES : Nothing"
+ (let ((ctr 0)
+ defined-in-list
+ (i 0)
+ used-in-list
+ )
+ (while (nth ctr web-module-name-defined-in-used-in)
+ (setq defined-in-list ()
+ used-in-list ()
+ i 0
+ ) ; end setq
+ (while (nth i (car (cdr (nth ctr web-module-name-defined-in-used-in))))
+ (if (<= new-module-number
+ (nth i (car (cdr
+ (nth ctr web-module-name-defined-in-used-in)))))
+ ; then add 1 to the number and append to the list
+ (setq defined-in-list (append defined-in-list (list (1+
+ (nth i (car (cdr
+ (nth ctr web-module-name-defined-in-used-in))))))))
+ ; else
+ (setq defined-in-list (append defined-in-list (list
+ (nth i (car (cdr (nth ctr web-module-name-defined-in-used-in)))))))
+ ) ; end if
+ (setq i (1+ i))
+ ) ; end while
+ (setq i 0)
+ (while (nth i
+ (car (cdr (cdr (nth ctr web-module-name-defined-in-used-in)))))
+ (if (<= new-module-number
+ (nth i
+ (car (cdr (cdr (nth ctr web-module-name-defined-in-used-in))))))
+ ; then add 1 to the number and append to the list
+ (setq used-in-list (append used-in-list (list (1+
+ (nth i (car (cdr (cdr (nth ctr
+ web-module-name-defined-in-used-in)))))))))
+ ; else
+ (setq used-in-list (append used-in-list (list
+ (nth i (car (cdr (cdr (nth ctr
+ web-module-name-defined-in-used-in))))))))
+ ) ; end if
+ (setq i (1+ i))
+ ) ; end while
+ (setcdr (nth ctr web-module-name-defined-in-used-in)
+ (append (list defined-in-list) (list used-in-list)))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ ) ; end let
+)
+
+(defun web-view-changed-modules-list ()
+ "This function can be invoked from either the buffer containing the Web
+document or the buffer containing the associated CHange file. It displays in
+the minibuffer a list of the modules in the Web document that have been changed
+in the CHange file.
+ARGUMENTS : None
+GLOBAL Variable : web-location-of-module
+LOCAL Variables : changed-modules
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-convert-list-to-string,
+ web-count-modules and web-journal"
+ (interactive)
+ (web-journal "web-view-changed-modules-list")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let (changed-modules
+ (ctr 0)
+ (index 0)
+ line-to-be-inserted
+ (number-of-modules (web-count-modules))
+ )
+ (while (< ctr number-of-modules)
+ (if (not (zerop (aref (aref web-location-of-module ctr) 3)))
+ ; then
+ (setq changed-modules (append changed-modules
+ (list ctr)))
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (get-buffer-create "*CHanged Modules*")
+ (save-excursion
+ (set-buffer "*CHanged Modules*")
+ (goto-char (point-min))
+ (kill-line (count-lines (point-min) (point-max)))
+ (if (zerop (length changed-modules))
+ ; then
+ (setq line-to-be-inserted "No modules have been changed.")
+ ; else
+ (setq line-to-be-inserted
+ (concat
+ (if (= (length changed-modules) 1) "Module " "Modules ")
+ (web-convert-list-to-string changed-modules) " "
+ (if (= (length changed-modules) 1) "has " "have ")
+ "been changed."
+ ) ; end concat
+ ) ; end setq
+ ) ; end if
+ (if (> (length line-to-be-inserted) 79)
+ ; then
+ (progn
+ (while (> (length line-to-be-inserted) 79)
+ (setq index 79)
+ (while (not (char-equal ?
+ (string-to-char
+ (substring line-to-be-inserted (1- index) index))))
+ (setq index (1- index))
+ ) ; end while
+ (insert-string (concat
+ (substring line-to-be-inserted 0 (1- index)) "\n"))
+ (setq line-to-be-inserted
+ (substring line-to-be-inserted index))
+ ) ; end while
+ (insert-string (concat line-to-be-inserted "\n"))
+ ) ; end then
+ ; else
+ (insert-string (concat line-to-be-inserted "\n"))
+ ) ; end if
+ ) ; end excursion
+ (split-window-vertically
+ (save-excursion
+ (set-buffer "*CHanged Modules*")
+ (goto-char (point-min))
+ (- (screen-height) (max 3 (count-lines (point-min) (point-max))) 2)
+ ) ; end excursion
+ ) ; end split-window-vertically
+ (other-window 1)
+ (switch-to-buffer "*CHanged Modules*")
+ (use-local-map web-mode-map)
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ (other-window 1)
+ (message "Type C-x 1 to remove the bottom window")
+ ) ; end let
+)
+
+(defun web-view-index ()
+ "This function is used when the user wishes to see an index for the Web as
+produced by Weave. The Web document is Weaved if there have been changes or if
+no INDEX.tex file exists for the Web document. The index is then reformatted
+slightly to accommodate presentation by Emacs.
+ARGUMENTS : None
+GLOBAL Variable : web-change-buffer-name, web-selected-index-entry-occurrences,
+ web-buffer-name, and web-index-buffer-name
+LOCAL Variables : message-string, size-of-buffer, and web-type
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-reformat-the-index, and
+ web-journal"
+ (interactive)
+ (web-journal "web-view-index")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let (message-string
+ (size-of-buffer 0)
+ web-type
+ )
+ (setq web-selected-index-entry-occurrences nil)
+ (setq web-index-buffer-name
+ (concat "*INDEX for " (buffer-name (current-buffer)) "*"))
+ (get-buffer-create web-index-buffer-name)
+ (save-excursion
+ (set-buffer web-index-buffer-name)
+ (setq size-of-buffer (buffer-size))
+ (use-local-map web-mode-map)
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ ) ; end excursion
+ (if (and (not (buffer-modified-p
+ (get-file-buffer (expand-file-name web-change-buffer-name))))
+ (not (buffer-modified-p
+ (get-file-buffer (expand-file-name web-buffer-name))))
+ (not (zerop size-of-buffer))
+ )
+ ; then
+ (switch-to-buffer web-index-buffer-name)
+ ; else
+ (save-some-buffers)
+ (setq web-type (read-string
+ "Is this WEB, Pascal, C, or Fortran? (P, p, C, c, F, f) => "))
+ (while (and (not (char-equal (upcase (string-to-char web-type)) ?C))
+ (not (char-equal (upcase (string-to-char web-type)) ?P))
+ (not (char-equal (upcase (string-to-char web-type)) ?F)))
+ (ding)
+ (setq web-type (read-string
+ "Is this WEB, Pascal, C, or Fortran? (P, p, C, c, F, f) => "))
+ ) ; end while
+ (save-excursion ; determine if CHange file is empty
+ (set-buffer web-change-buffer-name)
+ (setq size-of-buffer (buffer-size))
+ ) ; end excursion
+ (if (not (zerop size-of-buffer))
+ ; then a CHange file exists
+ (cond
+ ((char-equal (upcase (string-to-char web-type)) ?C)
+ ; then CWEAVE the file
+ (setq message-string (concat "CWEAVEing "
+ web-buffer-name " and " web-change-buffer-name "..."))
+ (message "%s" message-string)
+ (call-process "/usr/local/lib/tex/web/cweave" nil
+ (get-buffer-create "WEAVE-Output") nil
+ web-buffer-name
+ web-change-buffer-name)
+ ) ; end case
+ ((char-equal (upcase (string-to-char web-type)) ?F)
+ ; then FWEAVE the file
+ (setq message-string (concat "FWEAVEing "
+ web-buffer-name " and " web-change-buffer-name "..."))
+ (message "%s" message-string)
+ (call-process "/usr/local/lib/tex/web/fweave" nil
+ (get-buffer-create "WEAVE-Output") nil
+ web-buffer-name
+ web-change-buffer-name)
+ ) ; end case
+ (t
+ ; else WEAVE the file (it's a Pascal Web)
+ (setq message-string (concat "WEAVEing "
+ web-buffer-name " and " web-change-buffer-name "..."))
+ (message "%s" message-string)
+ (call-process "/usr/local/lib/tex/web/weave" nil
+ (get-buffer-create "WEAVE-Output") nil
+ web-buffer-name
+ web-change-buffer-name)
+ ) ; end case
+ ) ; end cond
+ ; else no Change file exists
+ (cond
+ ((char-equal (upcase (string-to-char web-type)) ?C)
+ ; then CWEAVE the file
+ (setq message-string (concat
+ "CWEAVEing " (buffer-name (current-buffer)) "..."))
+ (message "%s" message-string)
+ (call-process "/usr/local/lib/tex/web/cweave" nil
+ (get-buffer-create "WEAVE-Output") nil
+ web-buffer-name)
+ ) ; end case
+ ((char-equal (upcase (string-to-char web-type)) ?F)
+ ; then FWEAVE the file
+ (setq message-string (concat
+ "FWEAVEing " (buffer-name (current-buffer)) "..."))
+ (message "%s" message-string)
+ (call-process "/usr/local/lib/tex/web/fweave" nil
+ (get-buffer-create "WEAVE-Output") nil
+ web-buffer-name)
+ ) ; end case
+ (t
+ ; else WEAVE the file (it's a Pascal Web)
+ (setq message-string
+ (concat "Pascal WEAVEing " (buffer-name (current-buffer)) "..."))
+ (message "%s" message-string)
+ (call-process "/usr/local/lib/tex/web/weave" nil
+ (get-buffer-create "WEAVE-Output") nil
+ web-buffer-name)
+ ) ; end case
+ ) ; end cond
+ ) ; end if
+ (message "%sdone" message-string)
+ (sit-for 1)
+ (web-reformat-the-index)
+ ) ; end if
+ ) ; end let
+)
+
+(defun web-view-module-names-list ()
+ "This function can be invoked by the user to display a list of the module
+names used in the Web. A list of the modules in which the module name is
+Defined In and Used In is also displayed.
+ARGUMENTS : None
+GLOBAL Variables : web-module-name-defined-in-used-in, web-module-names,
+ and web-mode-map
+LOCAL Variables : ctr, index, and ptr
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files,
+ web-convert-list-to-string, and web-journal"
+ (interactive)
+ (web-journal "web-view-module-names-list")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((ctr 0)
+ (index 0)
+ (ptr 0)
+ )
+ (switch-to-buffer "*Module Name (Defined In) (Used In)*")
+ (use-local-map web-mode-map)
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ (goto-char (point-min))
+ (kill-line (count-lines (point-min) (point-max)))
+ (while (nth ctr web-module-names)
+ (setq ptr (string-to-int (substring (nth ctr web-module-names)
+ (+ (string-match " " (nth ctr web-module-names)) 2))))
+ (setq line-to-be-inserted (concat
+ (car (nth ptr web-module-name-defined-in-used-in))
+ " ("
+ (web-convert-list-to-string
+ (car (cdr (nth ptr web-module-name-defined-in-used-in))))
+ ") ("
+ (web-convert-list-to-string
+ (car (cdr (cdr (nth ptr web-module-name-defined-in-used-in)))))
+ ")")
+ ) ; end setq
+ (if (> (length line-to-be-inserted) 79)
+ ; then
+ (progn
+ (while (> (length line-to-be-inserted) 79)
+ (setq index 79)
+ (while (not (char-equal ?
+ (string-to-char
+ (substring line-to-be-inserted (1- index) index))))
+ (setq index (1- index))
+ ) ; end while
+ (insert-string (concat
+ (substring line-to-be-inserted 0 (1- index)) "\n"))
+ (setq line-to-be-inserted (concat " "
+ (substring line-to-be-inserted index)))
+ ) ; end while
+ (insert-string (concat line-to-be-inserted "\n"))
+ ) ; end then
+ ; else
+ (insert-string (concat line-to-be-inserted "\n"))
+ ) ; end if
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (goto-char (point-min))
+ ) ; end let
+)
+
+(defun web-view-section-names-list ()
+ "This function prints a list of the major section names in the Web document.
+It also shows the module number where each major section begins. The list is
+displayed in another buffer, *Section Names*.
+ARGUMENTS : None
+GLOBAL Variable : web-mode-map
+LOCAL Variables : ctr, number-of-modules, section-name, section-names,
+ size-of-buffer, and space-on-left
+RETURNS : Nothing
+USES : web-check-if-buffer-is-one-of-the-web-files, web-collect-section-names,
+ web-count-modules and web-journal"
+ (interactive)
+ (web-journal "web-view-section-names-list")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (get-buffer-create "*Section Names*")
+ (save-excursion
+ (set-buffer "*Section Names*")
+ (setq size-of-buffer (buffer-size))
+ ) ; end excursion
+ (let* ((ctr 0)
+ (number-of-modules (web-count-modules))
+ section-name
+ (section-names (web-collect-section-names))
+ (space-on-left
+ (/ (- 7 (length (int-to-string number-of-modules))) 2))
+ )
+ (switch-to-buffer "*Section Names*")
+ (use-local-map web-mode-map)
+ (setq major-mode 'Web-mode
+ mode-name "Web")
+ (goto-char (point-min))
+ (kill-line (count-lines (point) (point-max)))
+ (insert-string "Module# Section Name\n")
+ (while (nth ctr section-names)
+ (setq section-name (car (nth ctr section-names)))
+ (if (> (length section-name) 71)
+ ; then
+ (setq section-name (concat (substring section-name 0 68) "..."))
+ ) ; end if
+ (insert-string (concat (make-string (+ space-on-left
+ (- (length (int-to-string number-of-modules))
+ (length (int-to-string (car (cdr (nth ctr section-names))))))) ? )
+ (int-to-string (car (cdr (nth ctr section-names))))
+ (make-string (- 9 (+ space-on-left
+ (length (int-to-string number-of-modules)))) ? )
+ section-name "\n"))
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (goto-char (point-min))
+ ) ; end let
+)
+
+(defun web-what-change ()
+ "This function can only be invoked in the buffer containing the CHange file
+associated with the Web document that \\[web-mode] was used on most recently.
+Based on point's position in the CHange file buffer, this function displays a
+descriptive message indicating what module is being changed.
+ARGUMENTS : None
+GLOBAL Variables : web-change-buffer-name, web-location-of-module,
+ and web-buffer-name
+LOCAL Variables : bound-for-search, index, module-number,
+ next-change-begins-at, number-of-changes,
+ and number-of-preceding-@x
+RETURNS : module-number
+USES : web-journal"
+ (interactive)
+ (web-journal "web-what-change")
+ (if (not (string= (buffer-name (current-buffer)) web-change-buffer-name))
+ ; then
+ (error "Not in CHange buffer associated with %s" web-buffer-name)
+ ; else
+ (if (zerop (buffer-size))
+ ; then
+ (error "CHange buffer is empty")
+ ; else
+ (let ((bound-for-search 0)
+ (module-number 0)
+ (next-change-begins-at 0)
+ (number-of-preceding-@x 0)
+ )
+ (save-excursion
+ (end-of-line)
+ (setq bound-for-search (point))
+ (if (not (re-search-backward "^@x" nil t))
+ ; then
+ (error "Point not positioned between an @x @z")
+ ) ; end if
+ (forward-char (length
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (save-excursion
+ (if (re-search-forward "^@x" nil t)
+ ; then
+ (setq next-change-begins-at (- (point)
+ (length (buffer-substring (match-beginning 0) (match-end 0)))))
+ ; else
+ (setq next-change-begins-at (point-max))
+ ) ; end if
+ ) ; end excursion
+ (if (not (re-search-forward "^@z" next-change-begins-at t))
+ ; then
+ (error "This CHange has no matching @z")
+ ) ; end if
+ (if (> bound-for-search (save-excursion (end-of-line) (point)))
+ ; then
+ (error "Point not positioned between an @x @z")
+ ; else
+ (goto-char (point-min))
+ (while (re-search-forward "^@x" bound-for-search t)
+ (setq number-of-preceding-@x (1+ number-of-preceding-@x))
+ ) ; end while
+ ) ; end if
+ ) ; end excursion
+ (while (< (aref (aref web-location-of-module module-number) 4)
+ number-of-preceding-@x)
+ (setq module-number (1+ module-number))
+ ) ; end while
+ (if (> (aref (aref web-location-of-module module-number) 4)
+ number-of-preceding-@x)
+ ; then search back to the previous change
+ (progn
+ (setq module-number (1- module-number))
+ (while (/= (aref (aref web-location-of-module module-number) 3) 1)
+ (setq module-number (1- module-number))
+ ) ; end while
+ ) ; end then
+ ) ; end if
+ (message "CHange corresponds to Module %d" module-number)
+ module-number ; return the module number of the CHange
+ ) ; end let
+ ) ; end if
+ ) ; end if
+)
+
+(defun web-what-module ()
+ "This function tells the user what module point is currently positioned in.
+ARGUMENTS : None
+GLOBAL Variables : web-default-directory, web-files, and web-module-begins
+LOCAL Variables : ctr, done, file-number, module-count, and stopping-point
+RETURNS : the module # that point is currently positioned in
+USES : web-check-if-buffer-is-one-of-the-web-files, web-count-the-matches and
+ web-journal"
+ (interactive)
+ (web-journal "web-what-module")
+ (save-excursion
+ (let ((ctr 1)
+ done
+ (file-number (web-check-if-buffer-is-one-of-the-web-files))
+ (module-count 0)
+ (stopping-point (make-vector (length web-files) 0))
+ )
+ (while (nth ctr web-files)
+ (save-excursion
+ (set-buffer (get-file-buffer (expand-file-name (nth ctr web-files)
+ web-default-directory)))
+ (goto-char (point-max))
+ (aset stopping-point ctr (point))
+ ) ; end escursion
+ (setq ctr (1+ ctr))
+ ) ; end while
+ (aset stopping-point file-number
+ (save-excursion (beginning-of-line) (point)))
+ (save-excursion
+ (set-buffer (get-file-buffer (expand-file-name (nth 1 web-files)
+ web-default-directory)))
+ (web-count-the-matches "^@\\(i\\| \\|\t\\|\n\\|\\*\\)")
+ ) ; end excursion
+ (beginning-of-line)
+ (if (looking-at web-module-begins)
+ ; then
+ (setq module-count (1+ module-count))
+ ) ; end if
+ (message "Module %d" module-count)
+ module-count ; return the module #
+ ) ; end let
+ ) ; end excursion
+)
+
+(defun web-what-section ()
+ "This function tells the user what section the cursor is currently positioned
+in.
+ARGUMENTS : None
+GLOBAL Variables : web-location-of-module and web-files
+LOCAL Variables : current-module
+RETURNS : the section number that point is positioned in
+USES : web-check-if-buffer-is-one-of-the-web-files, web-journal,
+ and web-what-module"
+ (interactive)
+ (web-journal "web-what-section")
+ (web-check-if-buffer-is-one-of-the-web-files)
+ (let ((current-module (web-what-module)))
+ (message "Section %d in %s"
+ (aref (aref web-location-of-module current-module) 2)
+ (upcase (nth 1 web-files)))
+ ; return the section #
+ (aref (aref web-location-of-module current-module) 2)
+ ) ; end let
+)
+
+(defun web-write-module-names-to-a-file ()
+ "This is an internal support function that writes the module names,
+defined-in lists, and Used In lists to a file. This is done so that initial
+startup can be speeded up.
+ARGUMENTS : None
+GLOBAL Variable : web-buffer-name
+LOCAL Variables : None
+RETURNS : Nothing
+USES : web-view-module-names-list"
+ (save-excursion
+ (web-view-module-names-list)
+ (write-region 1 (point-max) (concat (substring web-buffer-name 0
+ (string-match "\\." web-buffer-name)) ".mods") nil 1)
+ ) ; end excursion
+)