diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/emacs-modes |
Initial commit
Diffstat (limited to 'support/emacs-modes')
-rw-r--r-- | support/emacs-modes/00readme.txt | 45 | ||||
-rw-r--r-- | support/emacs-modes/aux-renum.el | 299 | ||||
-rw-r--r-- | support/emacs-modes/bibtex-mode.el | 1566 | ||||
-rw-r--r-- | support/emacs-modes/cweave.ch | 77 | ||||
-rw-r--r-- | support/emacs-modes/fweave.ch | 88 | ||||
-rw-r--r-- | support/emacs-modes/inspec2bibtex.el | 836 | ||||
-rw-r--r-- | support/emacs-modes/limbo.material | 38 | ||||
-rw-r--r-- | support/emacs-modes/meta-mode.el | 1099 | ||||
-rw-r--r-- | support/emacs-modes/minor-map.el | 126 | ||||
-rw-r--r-- | support/emacs-modes/outline-m.el | 184 | ||||
-rw-r--r-- | support/emacs-modes/swiftex/hilit-swiftex.el | 314 | ||||
-rw-r--r-- | support/emacs-modes/swiftex/swiftex-doc.txt | 548 | ||||
-rw-r--r-- | support/emacs-modes/swiftex/swiftex.el | 2170 | ||||
-rw-r--r-- | support/emacs-modes/texheader.tex | 2 | ||||
-rw-r--r-- | support/emacs-modes/textrailer.tex | 1 | ||||
-rw-r--r-- | support/emacs-modes/u8tex.el | 536 | ||||
-rw-r--r-- | support/emacs-modes/weave.ch | 626 | ||||
-rw-r--r-- | support/emacs-modes/web-mode-manual.tex | 1526 | ||||
-rw-r--r-- | support/emacs-modes/web-mode.el | 5162 |
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 +) |