+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL FAQ
-
+
+
+
@@ -32,15 +37,13 @@
})();
-
+
-
-
-
+
+
FAQ: Questions and Answers
@@ -447,10 +450,8 @@ or get more memory+swap.
diff --git a/cmucl-www/www/benchmarks/index.html b/cmucl-www/www/benchmarks/index.html
index 6932204d80b3bf6ec005546b0f40393a2c5aab25..7db191e8abfdfdbc625299c7810eb4e4f676c337 100644
--- a/cmucl-www/www/benchmarks/index.html
+++ b/cmucl-www/www/benchmarks/index.html
@@ -3,7 +3,7 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL performance benchmarks
@@ -14,6 +14,8 @@
+
@@ -58,7 +60,8 @@
hashtable exercising
-
READ-LINE exercising
+
+ READ-LINE exercising
mathematical functions: factorial, fibonnaci, ackermann's number
@@ -243,7 +246,7 @@
diff --git a/cmucl-www/www/credits.html b/cmucl-www/www/credits.html
index 27ce346bd9f986d242caeb318c725f670bbee440..e1230c76c9e730993b8754af3167ec6fe4ab55ea 100644
--- a/cmucl-www/www/credits.html
+++ b/cmucl-www/www/credits.html
@@ -3,16 +3,19 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL credits
-
+
+
@@ -32,15 +35,13 @@
})();
-
+
-
-
-
+
+
Credits: project history & who's who
@@ -235,10 +236,8 @@
diff --git a/cmucl-www/www/doc/index.html b/cmucl-www/www/doc/index.html
index 36a37ec09619310af47c942334ae255cffc5adf6..5d87418a46b7a9efd6d381079aa2ea0c51eff2e2 100644
--- a/cmucl-www/www/doc/index.html
+++ b/cmucl-www/www/doc/index.html
@@ -3,7 +3,7 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
@@ -16,6 +16,9 @@
+
@@ -366,7 +369,7 @@
diff --git a/cmucl-www/www/download.html b/cmucl-www/www/download.html
index a0b3bd1129fcf6880770838c0d1ee37fabc9c693..1933be02b794d726b8d6ca85abf9284f1432276c 100644
--- a/cmucl-www/www/download.html
+++ b/cmucl-www/www/download.html
@@ -3,16 +3,19 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL downloads
-
+
+
@@ -42,15 +45,13 @@
})();
-
+
-
-
-
+
+
Download: how to get CMUCL
@@ -96,8 +97,8 @@
A mirror of the downloads directory, located in Germany with good
- bandwidth across Europe and the USA. Only has snapshots
- up to 2018-10.
+ bandwidth across Europe and the USA. Only has snapshots up to
+ 2018-10.
-Last modified: Sun Mar 15 10:03:09 PDT 2020
+
+Last modified: Wed Apr 1 22:09:42 PDT 2020
diff --git a/cmucl-www/www/hemlock/index.html b/cmucl-www/www/hemlock/index.html
index 2e11d09962ad22aa3eebb9bba225407525636125..c7b6ae381fc534396401a0ddc41f53ef9d98ddf6 100644
--- a/cmucl-www/www/hemlock/index.html
+++ b/cmucl-www/www/hemlock/index.html
@@ -3,7 +3,7 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
The Hemlock editor
@@ -14,6 +14,9 @@
+
@@ -33,15 +36,13 @@
})();
-
+
-
-
-
+
+
Hemlock: an extensible Emacs-like editor
@@ -102,10 +103,8 @@
diff --git a/cmucl-www/www/index.html b/cmucl-www/www/index.html
index 6afc92f5178e151c4d5d055e51525f9e1f30b308..41b4e8fff7b1a9b1c56ae0e4e0a3f54963802ed1 100644
--- a/cmucl-www/www/index.html
+++ b/cmucl-www/www/index.html
@@ -3,13 +3,14 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL Home Page
-
+
@@ -20,7 +21,8 @@
content="CMUCL, Common Lisp, CLOS">
+ "CMUCL is a high-performance, free Common Lisp implementation that runs on most major Unix platforms. It mostly conforms to the ANSI Common Lisp standard.">
+
-
+
-
-
-
+
+
Home: a high-performance, free Common Lisp
@@ -172,9 +172,10 @@
common-lisp.net announced
- that Gitlab would replace the
- current Trac system. The
- pages from Trac are slowing being migrated to CMUCL's gitlab page.
+ that Gitlab would replace
+ the current Trac system.
+ The pages from Trac are slowing being migrated to CMUCL's gitlab
+ page.
CMUCL 20e released
@@ -210,10 +211,8 @@
diff --git a/cmucl-www/www/install.html b/cmucl-www/www/install.html
index 1e9b4ffcc62adb7e04bb969ba3cbef5a64ad9459..ffbced449dae5e301d9989fcc4124dfc4b623463 100644
--- a/cmucl-www/www/install.html
+++ b/cmucl-www/www/install.html
@@ -3,16 +3,20 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
Installing CMUCL
-
+
+
@@ -32,15 +36,13 @@
})();
-
+
-
-
-
+
+
Install: installing CMUCL
@@ -54,10 +56,8 @@
diff --git a/cmucl-www/www/news/index.html b/cmucl-www/www/news/index.html
index 16a9d454f88115f35bbb88cb0bb1542f33f8ae6c..96e9ae4988e5e8ca67e7076056d5a6048ce482a6 100644
--- a/cmucl-www/www/news/index.html
+++ b/cmucl-www/www/news/index.html
@@ -3,16 +3,20 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL News
-
+
+
@@ -32,15 +36,13 @@
})();
-
+
-
-
-
+
+
News
@@ -549,10 +551,8 @@ the short-hand syntax above, you can also use
diff --git a/cmucl-www/www/platforms.html b/cmucl-www/www/platforms.html
index 5672c762f26854a4619362a120357fb05cd4996a..2c2bbf429f9e17f0cb94e9efeacbfa77559d8fea 100644
--- a/cmucl-www/www/platforms.html
+++ b/cmucl-www/www/platforms.html
@@ -3,16 +3,20 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL: Supported platforms
-
+
+
@@ -32,15 +36,13 @@
})();
-
+
-
-
-
+
+
Platforms: what does it run on?
@@ -238,10 +240,8 @@
diff --git a/cmucl-www/www/ports.html b/cmucl-www/www/ports.html
index 24598cfaff6bde84e401b3758e3d12bd3cca0d68..d6e6c90a0ba2a85eeda38f67187994ef04bcd9f2 100644
--- a/cmucl-www/www/ports.html
+++ b/cmucl-www/www/ports.html
@@ -3,7 +3,7 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL ports
@@ -14,6 +14,9 @@
+
@@ -289,7 +292,7 @@ Pictures is a CLOS-based interface to CLIO.
diff --git a/cmucl-www/www/projects.html b/cmucl-www/www/projects.html
index 605cbe526c7300cb867d0719bffc420e2753e9ef..f6c40476674d34ce4ab23ead2ba21e6af8fb41c7 100644
--- a/cmucl-www/www/projects.html
+++ b/cmucl-www/www/projects.html
@@ -3,16 +3,19 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL projects
-
+
+
@@ -32,15 +35,13 @@
})();
-
+
-
-
-
+
+
Projects: improvements to CMUCL
@@ -118,10 +119,8 @@
diff --git a/cmucl-www/www/support.html b/cmucl-www/www/support.html
index a4759959bbe8a40580ac35ba47623de1e2e49419..63bd8254743aa1048ed54d61d3e506d2dc07ce95 100644
--- a/cmucl-www/www/support.html
+++ b/cmucl-www/www/support.html
@@ -3,16 +3,20 @@
+ content="HTML Tidy for HTML5 for Linux version 5.7.28">
CMUCL support
-
+
+
@@ -32,15 +36,13 @@
})();
-
+
-
-
-
+
+
Support: mailing list & help for CMUCL users
@@ -163,9 +165,9 @@ on
diff --git a/docs/hem/cim/aux-sys.mss b/docs/hem/cim/aux-sys.mss
new file mode 100644
index 0000000000000000000000000000000000000000..945aa7a3358237cbce850305522cb7d773ed410d
--- /dev/null
+++ b/docs/hem/cim/aux-sys.mss
@@ -0,0 +1,694 @@
+@comment{-*- Dictionary: /usr/lisp/scribe/hem/hem; Mode: spell; Package: Hemlock; Log: /usr/lisp/scribe/hem/hem-docs.log -*-}
+@chapter (Auxiliary Systems)
+This chapter describes utilities that some implementations of @hemlock may
+leave unprovided or unsupported.
+
+
+@section[Key-events]
+@index(I/O)
+@index[keyboard input]
+@index[input, keyboard]
+@index[mouse input]
+@index[input, mouse]
+@label[key-events]
+
+These routines are defined in the @f["EXTENSIONS"] package since other projects
+have often used @hemlock's input translations for interfacing to CLX.
+
+
+@subsection[Introduction]
+
+The canonical representation of editor input is a key-event structure. Users
+can bind commands to keys (see section @ref[key-bindings]), which are non-zero
+length sequences of key-events. A key-event consists of an identifying token
+known as a @i[keysym] and a field of bits representing modifiers. Users define
+keysyms, integers between 0 and 65535 inclusively, by supplying names that
+reflect the legends on their keyboard's keys. Users define modifier names
+similarly, but the system chooses the bit and mask for recognizing the
+modifier. You can use keysym and modifier names to textually specify
+key-events and Hemlock keys in a @f[#k] syntax. The following are some
+examples:
+@begin[programexample]
+ #k"C-u"
+ #k"Control-u"
+ #k"c-m-z"
+ #k"control-x meta-d"
+ #k"a"
+ #k"A"
+ #k"Linefeed"
+@end[programexample]
+This is convenient for use within code and in init files containing
+@f[bind-key] calls.
+
+The @f[#k] syntax is delimited by double quotes, but the system parses the
+contents rather than reading it as a Common Lisp string. Within the double
+quotes, spaces separate multiple key-events. A single key-event optionally
+starts with modifier names terminated by hyphens. Modifier names are
+alphabetic sequences of characters which the system uses case-insensitively.
+Following modifiers is a keysym name, which is case-insensitive if it consists
+of multiple characters, but if the name consists of only a single character,
+then it is case-sensitive.
+
+You can escape special characters @dash hyphen, double quote, open angle
+bracket, close angle bracket, and space @dash with a backslash, and you can
+specify a backslash by using two contiguously. You can use angle brackets to
+enclose a keysym name with many special characters in it. Between angle
+brackets appearing in a keysym name position, there are only two special
+characters, the closing angle bracket and backslash.
+
+
+
+@subsection[Interface]
+
+All of the following routines and variables are exported from the "EXTENSIONS"
+("EXT") package.
+
+
+@defun[fun {define-keysym}, args {@i[keysym] @i[preferred-name] @rest @i[other-names]}]
+This function establishes a mapping from @i[preferred-name] to @i[keysym] for
+purposes of @f[#k] syntax. @i[Other-names] also map to @i[keysym], but the
+system uses @i[preferred-name] when printing key-events. The names are
+case-insensitive simple-strings; however, if the string contains a single
+character, then it is used case-sensitively. Redefining a keysym or re-using
+names has undefined effects.
+
+You can use this to define unused keysyms, but primarily this defines keysyms
+defined in the @i[X Window System Protocol, MIT X Consortium Standard, X
+Version 11, Release 4]. @f[translate-key-event] uses this knowledge to
+determine what keysyms are modifier keysyms and what keysym stand for
+alphabetic key-events.
+@enddefun
+
+
+@defun[fun {define-mouse-keysym}, args {@i[button] @i[keysym] @i[name] @i[shifted-bit] @i[event-key]}]
+This function defines @i[keysym] named @i[name] for key-events representing the
+X @i[button] cross the X @i[event-key] (@kwd[button-press] or
+@kwd[button-release]). @i[Shifted-bit] is a defined modifier name that
+@f[translate-mouse-key-event] sets in the key-event it returns whenever the X
+shift bit is set in an incoming event.
+
+Note, by default, there are distinct keysyms for each button distinguishing
+whether the user pressed or released the button.
+
+@i[Keysym] should be an one unspecified in @i[X Window System Protocol, MIT X
+Consortium Standard, X Version 11, Release 4].
+@enddefun
+
+
+@defun[fun {name-keysym}, args {@i[name]}]
+This function returns the keysym named @i[name]. If @i[name] is unknown, this
+returns @nil.
+@enddefun
+
+@defun[fun {keysym-names}, args {@i[keysym]}]
+This function returns the list of all names for @i[keysym]. If @i[keysym] is
+undefined, this returns @nil.
+@enddefun
+
+@defun[fun {keysym-preferred-name}, args {@i[keysym]}]
+This returns the preferred name for @i[keysym], how it is typically printed.
+If @i[keysym] is undefined, this returns @nil.
+@enddefun
+
+@defun[fun {define-key-event-modifier}, args {@i[long-name] @i[short-name]}]
+This establishes @i[long-name] and @i[short-name] as modifier names for
+purposes of specifying key-events in @f[#k] syntax. The names are
+case-insensitive simple-strings. If either name is already defined, this
+signals an error.
+
+The system defines the following default modifiers (first the long name,
+then the short name):
+@begin[Itemize]
+@f["Hyper"], @f["H"]
+
+@f["Super"], @f["S"]
+
+@f["Meta"], @f["M"]
+
+@f["Control"], @f["C"]
+
+@f["Shift"], @f["Shift"]
+
+@f["Lock"], @f["Lock"]
+@end[Itemize]
+@enddefun
+
+
+@defvar[var {all-modifier-names}]
+This variable holds all the defined modifier names.
+@enddefvar
+
+
+@defun[fun {define-clx-modifier}, args {@i[clx-mask] @i[modifier-name]}]
+This function establishes a mapping from @i[clx-mask] to a defined key-event
+@i[modifier-name]. @f[translate-key-event] and @f[translate-mouse-key-event]
+can only return key-events with bits defined by this routine.
+
+The system defines the following default mappings between CLX modifiers and
+key-event modifiers:
+@begin[Itemize]
+@f[(xlib:make-state-mask :mod-1) --> "Meta"]
+
+@f[(xlib:make-state-mask :control) --> "Control"]
+
+@f[(xlib:make-state-mask :lock) --> "Lock"]
+
+@f[(xlib:make-state-mask :shift) --> "Shift"]
+@end[Itemize]
+@enddefun
+
+
+@defun[fun {make-key-event-bits}, args {@rest @i[modifier-names]}]
+This function returns bits suitable for @f[make-key-event] from the supplied
+@i[modifier-names]. If any name is undefined, this signals an error.
+@enddefun
+
+@defun[fun {key-event-modifier-mask}, args {@i[modifier-name]}]
+This function returns a mask for @i[modifier-name]. This mask is suitable for
+use with @f[key-event-bits]. If @i[modifier-name] is undefined, this signals
+an error.
+@enddefun
+
+@defun[fun {key-event-bits-modifiers}, args {@i[bits]}]
+This returns a list of key-event modifier names, one for each modifier
+set in @i[bits].
+@enddefun
+
+
+@defun[fun {translate-key-event}, args {@i[display] @i[scan-code] @i[bits]}]
+This function translates the X @i[scan-code] and X @i[bits] to a key-event.
+First this maps @i[scan-code] to an X keysym using @f[xlib:keycode->keysym]
+looking at @i[bits] and supplying index as @f[1] if the X shift bit is on,
+@f[0] otherwise.
+
+If the resulting keysym is undefined, and it is not a modifier keysym,
+then this signals an error. If the keysym is a modifier key, then this
+returns @nil.
+
+If these conditions are satisfied
+@begin[Itemize]
+The keysym is defined.
+
+The X shift bit is off.
+
+The X lock bit is on.
+
+The X keysym represents a lowercase letter.
+@end[Itemize]
+then this maps the @i[scan-code] again supplying index as @f[1] this time,
+treating the X lock bit as a caps-lock bit. If this results in an undefined
+keysym, this signals an error. Otherwise, this makes a key-event with the
+keysym and bits formed by mapping the X bits to key-event bits.
+
+Otherwise, this makes a key-event with the keysym and bits formed by
+mapping the X bits to key-event bits.
+@enddefun
+
+
+@defun[fun {translate-mouse-key-event}, args {@i[scan-code] @i[bits] @i[event-key]}]
+This function translates the X button code, @i[scan-code], and modifier bits,
+@i[bits], for the X @i[event-key] into a key-event. See
+@f[define-mouse-keysym].
+@enddefun
+
+@defun[fun {make-key-event}, args {@i[object] @i[bits]}]
+This function returns a key-event described by @i[object] with @i[bits].
+@i[Object] is one of keysym, string, or key-event. When @i[object] is a
+key-event, this uses @f[key-event-keysym]. You can form @i[bits] with
+@f[make-key-event-bits] or @f[key-event-modifier-mask].
+@enddefun
+
+@defun[fun {key-event-p}, args {@i[object]}]
+This function returns whether @i[object] is a key-event.
+@enddefun
+
+@defun[fun {key-event-bits}, args {@i[key-event]}]
+This function returns the bits field of a @i[key-event].
+@enddefun
+
+@defun[fun {key-event-keysym}, args {@i[key-event]}]
+This function returns the keysym field of a @i[key-event].
+@enddefun
+
+@defun[fun {char-key-event}, args {@i[character]}]
+This function returns the key-event associated with @i[character]. You can
+associate a key-event with a character by @f[setf]'ing this form.
+@enddefun
+
+@defun[fun {key-event-char}, args {@i[key-event]}]
+This function returns the character associated with @i[key-event]. You can
+associate a character with a key-event by @f[setf]'ing this form. The system
+defaultly translates key-events in some implementation dependent way for text
+insertion; for example, under an ASCII system, the key-event @f[#k"C-h"], as
+well as @f[#k"backspace"] would map to the Common Lisp character that causes a
+backspace.
+@enddefun
+
+@defun[fun {key-event-bit-p}, args {@i[key-event] @i[bit-name]}]
+This function returns whether @i[key-event] has the bit set named by
+@i[bit-name]. This signals an error if @i[bit-name] is undefined.
+@enddefun
+
+@defmac[fun {do-alpha-key-events}, args
+{(@i[var] @i[kind] @optional @i[result]) @mstar<@i[form]>}]
+ This macro evaluates each @i[form] with @i[var] bound to a key-event
+representing an alphabetic character. @i[Kind] is one of @kwd[lower],
+@kwd[upper], or @kwd[both], and this binds @i[var] to each key-event in order
+as specified in @i[X Window System Protocol, MIT X Consortium Standard, X
+Version 11, Release 4]. When @kwd[both] is specified, this processes lowercase
+letters first.
+@enddefmac
+
+@defun[fun {print-pretty-key}, args {@i[key] @optional @i[stream] @i[long-names-p]}]
+This prints @i[key], a key-event or vector of key-events, in a user-expected
+fashion to @i[stream]. @i[Long-names-p] indicates whether modifiers should
+print with their long or short name. @i[Stream] defaults to
+@var[standard-output].
+@enddefun
+
+@defun[fun {print-pretty-key-event}, args {@i[key-event] @optional @i[stream] @i[long-names-p]}]
+This prints @i[key-event] to @i[stream] in a user-expected fashion.
+@i[Long-names-p] indicates whether modifier names should appear using the long
+name or short name. @i[Stream] defaults to @var[standard-output].
+@enddefun
+
+
+
+@section (CLX Interface)
+
+@subsection (Graphics Window Hooks)
+This section describes a few hooks used by Hemlock's internals to handle
+graphics windows that manifest Hemlock windows. Some heavy users of Hemlock as
+a tool have needed these in the past, but typically functions that replace the
+default values of these hooks must be written in the "@f[HEMLOCK-INTERNALS]"
+package. All of these symbols are internal to this package.
+
+If you need this level of control for your application, consult the current
+implementation for code fragments that will be useful in correctly writing your
+own window hook functions.
+
+@defvar[var {create-window-hook}]
+This holds a function that @Hemlock calls when @f[make-window] executes under
+CLX. @Hemlock passes the CLX display and the following arguments from
+@f[make-window]: starting mark, ask-user, x, y, width, height, and modelinep.
+The function returns a CLX window or nil indicating one could not be made.
+@enddefvar
+
+@defvar[var {delete-window-hook}]
+This holds a function that @hemlock calls when @f[delete-window] executes under
+CLX. @hemlock passes the CLX window and the @hemlock window to this function.
+@enddefvar
+
+@defvar[var {random-typeout-hook}]
+This holds a function that @hemlock calls when random typeout occurs under CLX.
+@hemlock passes it a @hemlock device, a pre-existing CLX window or @nil, and
+the number of pixels needed to display the number of lines requested in the
+@f[with-pop-up-display] form. It should return a window, and if a new window
+is created, then a CLX gcontext must be the second value.
+@enddefvar
+
+@defvar[var {create-initial-windows-hook}]
+This holds a function that @hemlock calls when it initializes the screen
+manager and makes the first windows, typically windows for the @hid[Main] and
+@hid[Echo Area] buffers. @hemlock passes the function a @hemlock device.
+@enddefvar
+
+
+@subsection (Entering and Leaving Windows)
+
+@defhvar[var "Enter Window Hook"]
+When the mouse enters an editor window, @hemlock invokes the functions in this
+hook. These functions take a @Hemlock window as an argument.
+@enddefhvar
+
+@defhvar[var "Exit Window Hook"]
+When the mouse exits an editor window, @hemlock invokes the functions in this
+hook. These functions take a @Hemlock window as an argument.
+@enddefhvar
+
+
+@subsection (How to Lose Up-Events)
+Often the only useful activity user's design for the mouse is to click on
+something. @Hemlock sees a character representing the down event, but what do
+you do with the up event character that you know must follow? Having the
+command eat it would be tasteless, and would inhibit later customizations that
+make use of it, possibly adding on to the down click command's functionality.
+Bind the corresponding up character to the command described here.
+
+@defcom[com "Do Nothing"]
+This does nothing as many times as you tell it.
+@enddefcom
+
+
+@section (Slave Lisps)
+@index (Slave lisp interface functions)
+Some implementations of @hemlock feature the ability to manage multiple slave
+Lisps, each connected to one editor Lisp. The routines discussed here spawn
+slaves, send evaluation and compilation requests, return the current server,
+etc. This is very powerful because without it you can lose your editing state
+when code you are developing causes a fatal error in Lisp.
+
+The routines described in this section are best suited for creating editor
+commands that interact with slave Lisps, but in the past users implemented
+several independent Lisps as nodes communicating via these functions. There is
+a better level on which to write such code that avoids the extra effort these
+routines take for the editor's sake. See the @i[CMU Common Lisp User's Manual]
+for the @f[remote] and @f[wire] packages.
+
+
+@subsection (The Current Slave)
+There is a slave-information structure that these return which is suitable for
+passing to the routines described in the following subsections.
+
+@defun[fun {create-slave}, args {@optional @i[name]}]
+This creates a slave that tries to connect to the editor. When the slave
+connects to the editor, this returns a slave-information structure, and the
+interactive buffer is the buffer named @i[name]. This generates a name if
+@i[name] is @nil. In case the slave never connects, this will eventually
+timeout and signal an editor-error.
+@enddefun
+
+@defun[fun {get-current-eval-server}, args {@optional @i[errorp]}]
+@defhvar1[var {Current Eval Server}]
+This returns the server-information for the @hid[Current Eval Server] after
+making sure it is valid. Of course, a slave Lisp can die at anytime. If this
+variable is @nil, and @i[errorp] is non-@nil, then this signals an
+editor-error; otherwise, it tries to make a new slave. If there is no current
+eval server, then this tries to make a new slave, prompting the user based on a
+few variables (see the @i[Hemlock User's Manual]).
+@enddefun
+
+@defun[fun {get-current-compile-server}]
+@defhvar1[var {Current Compile Server}]
+This returns the server-information for the @hid[Current Compile Server] after
+making sure it is valid. This may return nil. Since multiple slaves may
+exist, it is convenient to use one for developing code and one for compiling
+files. The compilation commands that use slave Lisps prefer to use the current
+compile server but will fall back on the current eval server when necessary.
+Typically, users only have separate compile servers when the slave Lisp can
+live on a separate workstation to save cycles on the editor machine, and the
+@hemlock commands only use this for compiling files.
+@enddefun
+
+
+@subsection (Asynchronous Operation Queuing)
+The routines in this section queue requests with an eval server. Requests are
+always satisfied in order, but these do not wait for notification that the
+operation actually happened. Because of this, the user can continue editing
+while his evaluation or compilation occurs. Note, these usually execute in the
+slave immediately, but if the interactive buffer connected to the slave is
+waiting for a form to return a value, the operation requested must wait until
+the slave is free again.
+
+@defun[fun {string-eval}, args {@i[string]}, keys {[server][package][context]}]
+@defun1[fun {region-eval}, args {@i[region]}, keys {[server][package][context]}]
+@defun1[fun {region-compile}, args {@i[region]}, keys {[server][package]}]
+@f[string-eval] queues the evaluation of the form read from @i[string] on eval
+server @i[server]. @i[Server] defaults to the result of
+@f[get-current-server], and @i[string] is a simple-string. The evaluation
+occurs with @var[package] bound in the slave to the package named by
+@i[package], which defaults to @hid[Current Package] or the empty string; the
+empty string indicates that the slave should evaluate the form in its current
+package. The slave reads the form in @i[string] within this context as well.
+@i[Context] is a string to use when reporting start and end notifications in
+the @hid[Echo Area] buffer; it defaults to the concatenation of @f["evaluation
+of "] and @i[string].
+
+@f[region-eval] is the same as @f[string-eval], but @i[context] defaults
+differently. If the user leaves this unsupplied, then it becomes a string
+involving part of the first line of region.
+
+@f[region-compile] is the same as the above. @i[Server] defaults the same; it
+does not default to @f[get-current-compile-server] since this compiles the
+region into the slave Lisp's environment, to affect what you are currently
+working on.
+@enddefun
+
+@defun[fun {file-compile}, args {@i[file]},
+ keys {[output-file][error-file][load][server]},
+ morekeys {[package]}]
+@defhvar1[var {Remote Compile File}, val {nil}]
+This compiles @i[file] in a slave Lisp. When @i[output-file] is @true (the
+default), this uses a temporary output file that is publicly writable in case
+the client is on another machine, which allows for file systems that do not
+permit remote write access. This renames the temporary file to the appropriate
+binary name or deletes it after compilation. Setting @hid[Remote Compile File]
+to @nil, inhibits this. If @i[output-file] is non-@nil and not @true, then it
+is the name of the binary file to write. The compilation occurs with
+@var[package] bound in the slave to the package named by @i[package], which
+defaults to @hid[Current Package] or the empty string; the empty string
+indicates that the slave should evaluate the form in its current package.
+@i[Error-file] is the file in which to record compiler output, and a @nil value
+inhibits this file's creation. @i[Load] indicates whether to load the
+resulting binary file, defaults to @nil. @i[Server] defaults to
+@f[get-current-compile-server], but if this returns nil, then @i[server]
+defaults to @f[get-current-server].
+@enddefun
+
+@subsection (Synchronous Operation Queuing)
+The routines in this section queue requests with an eval server and wait for
+confirmation that the evaluation actually occurred. Because of this, the user
+cannot continue editing while the slave executes the request. Note, these
+usually execute in the slave immediately, but if the interactive buffer
+connected to the slave is waiting for a form to return a value, the operation
+requested must wait until the slave is free again.
+
+@defun[fun {eval-form-in-server},
+ args {@i[server-info] @i[string] @optional @i[package]}]
+ This function queues the evaluation of a form in the server associated with
+@i[server-info] and waits for the results. The server @f[read]'s the form from
+@i[string] with @var[package] bound to the package named by @i[package]. This
+returns the results from the slave Lisp in a list of string values. You can
+@f[read] from the strings or simply display them depending on the @f[print]'ing
+of the evaluation results.
+
+@i[Package] defaults to @hid[Current Package]. If this is @nil, the server
+uses the value of @var[package] in the server.
+
+While the slave executes the form, it binds @var[terminal-io] to a stream that
+signals errors when read from and dumps output to a bit-bucket. This prevents
+the editor and slave from dead locking by waiting for each other to reply.
+@enddefun
+
+@defun[fun {eval-form-in-server-1},
+ args {@i[server-info] @i[string] @optional @i[package]}]
+ This function calls @f[eval-form-in-server] and @f[read]'s the result in the
+first string it returns. This result must be @f[read]'able in the editor's
+Lisp.
+@enddefun
+
+
+@section (Spelling)
+@index (Spelling checking)
+@hemlock supports spelling checking and correcting commands based on the ITS
+Ispell dictionary. These commands use the following routines which include
+adding and deleting entries, reading the Ispell dictionary in a compiled binary
+format, reading user dictionary files in a text format, and checking and
+correcting possible spellings.
+
+@defun[fun {maybe-read-spell-dictionary}, package {spell}]
+This reads the default binary Ispell dictionary. Users must call this before
+the following routines will work.
+@enddefun
+
+@defun[fun {spell-read-dictionary}, package {spell}, args {@i[filename]}]
+This adds entries to the dictionary from the lines in the file @i[filename].
+Dictionary files contain line oriented records like the following:
+@begin[programexample]
+entry1/flag1/flag2
+entry2
+entry3/flag1
+@end[programexample]
+The flags are the Ispell flags indicating which endings are appropriate for the
+given entry root, but these are unnecessary for user dictionary files. You can
+consult Ispell documentation if you want to know more about them.
+@enddefun
+
+@defun[fun {spell-add-entry}, package {spell},
+ args {@i[line] @optional @i[word-end]}]
+This takes a line from a dictionary file, and adds the entry described by
+@i[line] to the dictionary. @i[Word-end] defaults to the position of the first
+slash character or the length of the line. @i[Line] is destructively modified.
+@enddefun
+
+@defun[fun {spell-remove-entry}, package {spell}, args {@i[entry]}]
+This removes entry, a simple-string, from the dictionary, so it will be an
+unknown word. This destructively modifies @i[entry]. If it is a root word,
+then all words derived with @i[entry] and its flags will also be deleted. If
+@i[entry] is a word derived from some root word, then the root and any words
+derived from it remain known words.
+@enddefun
+
+@defun[fun {correct-spelling}, package {spell}, args {@i[word]}]
+This checks the spelling of @i[word] and outputs the results. If this finds
+@i[word] is correctly spelled due to some appropriate suffix on a root, it
+generates output indicating this. If this finds @i[word] as a root entry, it
+simply outputs that it found @i[word]. If this cannot find @i[word] at all,
+then it outputs possibly correct close spellings. This writes to
+@var[standard-output], and it calls @f[maybe-read-spell-dictionary] before
+attempting any lookups.
+@enddefun
+
+@defun[fun {spell-try-word}, package {spell}, args {@i[word] @i[word-len]}]
+@defcon1[var {max-entry-length}, val {31}]
+This returns an index into the dictionary if it finds @i[word] or an
+appropriate root. @i[Word-len] must be inclusively in the range 2 through
+@f[max-entry-length], and it is the length of @i[word]. @i[Word] must be
+uppercase. This returns a second value indicating whether it found @i[word]
+due to a suffix flag, @nil if @i[word] is a root entry.
+@enddefun
+
+@defun[fun {spell-root-word}, package {spell}, args {@i[index]}]
+This returns a copy of the root word at dictionary entry @i[index]. This index
+is the same as returned by @f[spell-try-word].
+@enddefun
+
+@defun[fun {spell-collect-close-words}, package {spell}, args {@i[word]}]
+This returns a list of words correctly spelled that are @i[close] to @i[word].
+@i[Word] must be uppercase, and its length must be inclusively in the range 2
+through @f[max-entry-length]. Close words are determined by the Ispell rules:
+@begin[enumerate]
+Two adjacent letters can be transposed to form a correct spelling.
+
+One letter can be changed to form a correct spelling.
+
+One letter can be added to form a correct spelling.
+
+One letter can be removed to form a correct spelling.
+@end[enumerate]
+@enddefun
+
+@defun[fun {spell-root-flags}, package {spell}, args {@i[index]}]
+This returns a list of suffix flags as capital letters that apply to the
+dictionary root entry at @i[index]. This index is the same as returned by
+@f[spell-try-word].
+@enddefun
+
+
+@section (File Utilities)
+Some implementations of @hemlock provide extensive directory editing commands,
+@hid[Dired], including a single wildcard feature. An asterisk denotes a
+wildcard.
+
+@defun[fun {copy-file}, package {dired},
+ args {@i[spec1] @i[spec2]}, keys {[update][clobber][directory]}]
+ This function copies @i[spec1] to @i[spec2]. It accepts a single wildcard in
+the filename portion of the specification, and it accepts directories. This
+copies files maintaining the source's write date.
+
+If @i[spec1] and @i[spec2] are both directories, this recursively copies the
+files and subdirectory structure of @i[spec1]; if @i[spec2] is in the
+subdirectory structure of @i[spec1], the recursion will not descend into it.
+Use @f["/spec1/*"] to copy only the files from @i[spec1] to directory
+@i[spec2].
+
+If @i[spec2] is a directory, and @i[spec1] is a file, then this copies
+@i[spec1] into @i[spec2] with the same @f[pathname-name].
+
+When @kwd[update] is non-@nil, then the copying process only copies files if the
+source is newer than the destination.
+
+When @kwd[update] and @kwd[clobber] are @nil, and the destination exists, the
+copying process stops and asks the user whether the destination should be
+overwritten.
+
+When the user supplies @kwd[directory], it is a list of pathnames, directories
+excluded, and @i[spec1] is a pattern containing one wildcard. This then copies
+each of the pathnames whose @f[pathname-name] matches the pattern. @i[Spec2]
+is either a directory or a pathname whose @f[pathname-name] contains a
+wildcard.
+@enddefun
+
+@defun[fun {rename-file}, package {dired},
+ args {@i[spec1] @i[spec2]}, keys {[clobber][directory]}]
+ This function renames @i[spec1] to @i[spec2]. It accepts a single wildcard in
+the filename portion of the specification, and @i[spec2] may be a directory
+with the destination specification resulting in the merging of @i[spec2] with
+@i[spec1]. If @kwd[clobber] is @nil, and @i[spec2] exists, then this asks the
+user to confirm the renaming. When renaming a directory, end the specification
+without the trailing slash.
+
+When the user supplies @kwd[directory], it is a list of pathnames, directories
+excluded, and @i[spec1] is a pattern containing one wildcard. This then copies
+each of the pathnames whose @f[pathname-name] matches the pattern. @i[Spec2]
+is either a directory or a pathname whose @f[pathname-name] contains a
+wildcard.
+@enddefun
+
+@defun[fun {delete-file}, package {dired},
+ args {@i[spec]}, keys {[recursive][clobber]}]
+ This function deletes @i[spec]. It accepts a single wildcard in the filename
+portion of the specification, and it asks for confirmation on each file if
+@kwd[clobber] is @nil. If @kwd[recursive] is non-@nil, then @i[spec] may be a
+directory to recursively delete the entirety of the directory and its
+subdirectory structure. An empty directory may be specified without
+@kwd[recursive] being non-@nil. Specify directories with the trailing
+slash.
+@enddefun
+
+@defun[fun {find-file}, package {dired},
+ args {@i[name] @optional @i[directory] @i[find-all]}]
+ This function finds the file with @f[file-namestring] @i[name], recursively
+looking in @i[directory]. If @i[find-all] is non-@nil (defaults to @nil), then
+this continues searching even after finding a first occurrence of file.
+@i[Name] may contain a single wildcard, which causes @i[find-all] to default to
+@true instead of @nil.
+@enddefun
+
+@defun[fun {make-directory}, package {dired}, args {@i[name]}]
+This function creates the directory with @i[name]. If it already exists, this
+signals an error.
+@enddefun
+
+@defun[fun {pathnames-from-pattern}, package {dired},
+ args {@i[pattern] @i[files]}]
+This function returns a list of pathnames from the list @i[files] whose
+@f[file-namestring]'s match @i[pattern]. @i[Pattern] must be a non-empty
+string and contain only one asterisk. @i[Files] contains no directories.
+@enddefun
+
+@defvar[var {update-default}, package {dired}]
+@defvar1[var {clobber-default}, package {dired}]
+@defvar1[var {recursive-default}, package {dired}]
+These are the default values for the keyword arguments above with corresponding
+names. These default to @nil, @true, and @nil respectively.
+@enddefvar
+
+@defvar[var {report-function}, package {dired}]
+@defvar1[var {error-function}, package {dired}]
+@defvar1[var {yesp-function}, package {dired}]
+These are the function the above routines call to report progress, signal
+errors, and prompt for @i[yes] or @i[no]. These all take format strings and
+arguments.
+@enddefvar
+
+
+@defun[fun {merge-relative-pathnames}, args {@i[pathname] @i[default-directory]}]
+This function merges @i[pathname] with @i[default-directory]. If @i[pathname]
+is not absolute, this assumes it is relative to @i[default-directory]. The
+result is always a directory pathname.
+@enddefun
+
+@defun[fun {directoryp}, args {@i[pathname]}]
+This function returns whether @i[pathname] names a directory: it has no name
+and no type fields.
+@enddefun
+
+
+@section (Beeping)
+
+@defun[fun {hemlock-beep}]
+@Hemlock binds @f[system:*beep-function*] to this function to beep the device.
+It is different for different devices.
+@enddefvar
+
+@defhvar[var "Bell Style", val {:border-flash}]
+@defhvar1[var "Beep Border Width", val {20}]
+@hid[Bell Style] determines what @var[hemlock-beep] does in @hemlock under CLX.
+Acceptable values are @kwd[border-flash], @kwd[feep],
+@kwd[border-flash-and-feep], @kwd[flash], @kwd[flash-and-feep], and @nil (do
+nothing).
+
+@hid[Beep Border Width] is the width in pixels of the border flashed by border
+flash beep styles.
+@enddefhvar
diff --git a/docs/hem/cim/cim.mss b/docs/hem/cim/cim.mss
new file mode 100644
index 0000000000000000000000000000000000000000..03ae31f51712e36eacc62587993e49cf2919661e
--- /dev/null
+++ b/docs/hem/cim/cim.mss
@@ -0,0 +1,4039 @@
+@make[Manual] @comment{-*- Dictionary: /afs/cs/project/clisp/docs/hem/hem; Mode: spell; Package: Hemlock; Log: /usr/lisp/scribe/hem/hem-docs.log -*-}
+@Device[postscript]
+@style(FontFamily = TimesRoman)
+@Style(Spacing = 1.2 lines)
+@Style(StringMax = 5000)
+@style(Hyphenation = On)
+@style(Date="March 1952")
+@use(database "/afs/cs/project/clisp/docs/database/")
+@Style [DoubleSided]
+@Libraryfile[ArpaCredit]
+@Libraryfile[Hem]
+@Libraryfile[Spice]
+@Libraryfile[Uttir]
+
+@String(ReportTitle "Hemlock Command Implementor's Manual")
+
+@comment<
+@begin[TitlePage]
+@begin[TitleBox]
+>
+@blankspace(1.3inches)
+@heading[Hemlock Command Implementor's Manual]
+
+@center[
+@b
+@b
+
+@b<@value[date]>
+
+@b
+]
+@comment<@end[TitleBox]>
+@blankspace(2lines)
+@begin[Center]
+School of Computer Science
+Carnegie Mellon University
+Pittsburgh, PA 15213
+@end[Center]
+
+@blankspace(2lines)
+@begin[Center]
+This is a revised version of Technical Report CMU-CS-87-159.
+@end[Center]
+@heading[Abstract]
+@begin(Text, indent 0)
+This document describes how to write commands for the @Hemlock text editor, as
+of version M3.2. @Hemlock is a customizable, extensible text editor whose
+initial command set closely resembles that of ITS/TOPS-20 @Emacs. @Hemlock is
+written in the CMU Common Lisp and has been ported to other implementations.
+@end(Text)
+
+@blankspace(0.5in)
+@begin[ResearchCredit]
+@arpacredit[Contract=Basic87-90]
+@end[ResearchCredit]
+@comment<@end[TitlePage]>
+
+
+@commandstring(dash = "@Y[M]")
+
+
+@Tabclear
+
+@chapter(Introduction)
+
+ @hemlock is a text editor which follows in the tradition of editors
+such as EMACS and the Lisp Machine editor ZWEI. In its basic form,
+@hemlock has almost the same command set as EMACS, and similar
+features such as multiple buffers and windows, extended commands,
+and built in documentation.
+
+Both user extensions and the original commands are written in Lisp,
+therefore a command implementor will have a working knowledge of this
+language. Users not familiar with Lisp need not despair however. Many
+users of Multics EMACS, another text editor written in Lisp, came to learn
+Lisp simply for the purpose of writing their own editor extensions, and
+found, to their surprise, that it was really pretty easy to write simple
+commands.
+
+This document describes the Common Lisp functions, macros and data structures
+that are used to implement new commands. The basic editor consists of a set of
+Lisp utility functions for manipulating buffers and the other data structures
+of the editor as well as handling the display. All user level commands are
+written in terms of these functions. To find out how to define commands see
+chapter @ref[commands].
+
+@chapter(Representation of Text)
+@index (Lines)
+@section(Lines)
+In @hemlock all text is in some @i[line]. Text is broken into lines wherever
+it contains a newline character; newline characters are never stored, but are
+assumed to exist between every pair of lines. The implicit newline character
+is treated as a single character by the text primitives.
+
+@defun[fun {linep}, args {@i[line]}]
+This function returns @true if @i[line] is a @f[line] object, otherwise @nil.
+@enddefun
+
+@defun[fun {line-string}, args {@i[line]}]
+Given a @i(line), this function returns as a simple string the characters in
+the line. This is @f[setf]'able to set the @f[line-string] to any string that
+does not contain newline characters. It is an error to destructively modify
+the result of @f[line-string] or to destructively modify any string after the
+@f[line-string] of some line has been set to that string.
+@enddefun
+
+@defun[fun {line-previous}, args {@i[line]}]
+@defun1[fun {line-next}, args {@i[line]}]
+Given a @i(line), @f[line-previous] returns the previous line or @nil if there
+is no previous line. Similarly, @f[line-next] returns the line following
+@i[line] or @nil.
+@enddefun
+
+@defun[fun {line-buffer}, args {@i[line]}]
+This function returns the buffer which contains this @i(line). Since a
+line may not be associated with any buffer, in which case @f[line-buffer]
+returns @nil.
+@enddefun
+
+@defun[fun {line-length}, args {@i[line]}]
+This function returns the number of characters in the @i(line). This excludes
+the newline character at the end.
+@enddefun
+
+@defun[fun {line-character}, args {@i[line] @i[index]}]
+This function returns the character at position @i[index] within @i[line]. It
+is an error for @i[index] to be greater than the length of the line or less
+than zero. If @i[index] is equal to the length of the line, this returns a
+@f[#\newline] character.
+@enddefun
+
+@defun[fun {line-plist}, args {@i[line]}]
+This function returns the property-list for @i[line]. @f[setf], @f[getf],
+@f[putf] and @f[remf] can be used to change properties. This is typically used
+in conjunction with @f[line-signature] to cache information about the line's
+contents.
+@enddefun
+
+@defun[fun {line-signature}, args {@i[line]}]
+This function returns an object that serves as a signature for a @i[line]'s
+contents. It is guaranteed that any modification of text on the line will
+result in the signature changing so that it is not @f[eql] to any previous
+value. The signature may change even when the text remains unmodified, but
+this does not happen often.
+@enddefun
+
+
+@section(Marks)
+@label[marks]
+@index (Marks)
+A mark indicates a specific position within the text represented by a line and
+a character position within that line. Although a mark is sometimes loosely
+referred to as pointing to some character, it in fact points between
+characters. If the @f[charpos] is zero, the previous character is the newline
+character separating the previous line from the mark's @f[line]. If the
+charpos is equal to the number of characters in the line, the next character is
+the newline character separating the current line from the next. If the mark's
+line has no previous line, a mark with @f[charpos] of zero has no previous
+character; if the mark's line has no next line, a mark with @f[charpos] equal
+to the length of the line has no next character.
+
+This section discusses the very basic operations involving marks, but a lot of
+@hemlock programming is built on altering some text at a mark. For more
+extended uses of marks see chapter @ref[doing-stuff].
+
+
+@subsection(Kinds of Marks)
+@index (Permanent marks)
+@index (Temporary marks)
+A mark may have one of two lifetimes: @i[temporary] or @i[permanent].
+Permanent marks remain valid after arbitrary operations on the text; temporary
+marks do not. Temporary marks are used because less bookkeeping overhead is
+involved in their creation and use. If a temporary mark is used after the text
+it points to has been modified results will be unpredictable. Permanent marks
+continue to point between the same two characters regardless of insertions and
+deletions made before or after them.
+
+There are two different kinds of permanent marks which differ only in their
+behavior when text is inserted @i(at the position of the mark); text is
+inserted to the left of a @i[left-inserting] mark and to the right of
+@i[right-inserting] mark.
+
+
+@subsection(Mark Functions)
+@defun[fun {markp}, args {@i[mark]}]
+This function returns @true if @i[mark] is a @f[mark] object, otherwise @nil.
+@enddefun
+
+@defun[fun {mark-line}, args {@i[mark]}]
+This function returns the line to which @i(mark) points.
+@enddefun
+
+@defun[fun {mark-charpos}, args {@i[mark]}]
+This function returns the character position of the character after @i(mark).
+If @i[mark]'s line has no next line, this returns the length of the line as
+usual; however, there is actually is no character after the mark.
+@enddefun
+
+@defun[fun {mark-kind}, args {@i[mark]}]
+This function returns one of @kwd[right-inserting], @kwd[left-inserting] or
+@kwd[temporary] depending on the mark's kind. A corresponding @f[setf] form
+changes the mark's kind.
+@enddefun
+
+@defun[fun {previous-character}, args {@i[mark]}]
+@defun1[fun {next-character}, args {@i[mark]}]
+This function returns the character immediately before (after) the position of
+the @i[mark], or @nil if there is no previous (next) character. These
+characters may be set with @f[setf] when they exist; the @f[setf] methods for
+these forms signal errors when there is no previous or next character.
+@enddefun
+
+
+@subsection(Making Marks)
+@defun[fun {mark}, args {@i[line] @i[charpos] @optional @i[kind]}]
+This function returns a mark object that points to the @i(charpos)'th character
+of the @i(line). @i(Kind) is the kind of mark to create, one of
+@kwd[temporary], @kwd[left-inserting], or @kwd[right-inserting]. The default
+is @kwd[temporary].
+@enddefun
+
+@defun[fun {copy-mark}, args {@i[mark] @optional @i[kind]}]
+This function returns a new mark pointing to the same position and of the same
+kind, or of kind @i[kind] if it is supplied.
+@enddefun
+
+@defun[fun {delete-mark}, args {@i[mark]}]
+This function deletes @i(mark). Delete any permanent marks when you are
+finished using it.
+@enddefun
+
+@Defmac[Fun {with-mark}, Args
+ {(@Mstar<(@i[mark] @i[pos] @mopt[@i(kind)])>) @Mstar<@i[form]>}]
+ This macro binds to each variable @i[mark] a mark of kind @i[kind], which
+defaults to @kwd[temporary], pointing to the same position as the mark @i[pos].
+On exit from the scope the mark is deleted. The value of the last @i[form] is
+the value returned.
+@enddefmac
+
+
+@subsection(Moving Marks)
+@index(Moving marks)
+These functions destructively modify marks to point to new positions. Other
+sections of this document describe mark moving routines specific to higher
+level text forms than characters and lines, such as words, sentences,
+paragraphs, Lisp forms, etc.
+
+@defun[fun {move-to-position}, args {@i[mark] @i[charpos] @optional @i[line]}]
+This function changes the @i(mark) to point to the given character position on
+the line @i(line). @i(Line) defaults to @i[mark]'s line.
+@enddefun
+
+@defun[fun {move-mark}, args {@i[mark] @i[new-position]}]
+This function moves @i[mark] to the same position as the mark @i[new-position]
+and returns it.
+@enddefun
+
+@defun[fun {line-start}, args {@i[mark] @optional @i[line]}]
+@defun1[fun {line-end}, args {@i[mark] @optional @i[line]}]
+This function changes @i[mark] to point to the beginning or the end of @i(line)
+and returns it. @i[Line] defaults to @i[mark]'s line.
+@enddefun
+
+@defun[fun {buffer-start}, args {@i[mark] @optional @i[buffer]}]
+@defun1[fun {buffer-end}, args {@i[mark] @optional @i[buffer]}]
+These functions change @i[mark] to point to the beginning or end of @i[buffer],
+which defaults to the buffer @i[mark] currently points into. If @i[buffer] is
+unsupplied, then it is an error for @i[mark] to be disassociated from any
+buffer.
+@enddefun
+
+@defun[fun {mark-before}, args {@i[mark]}]
+@defun1[fun {mark-after}, args {@i[mark]}]
+These functions change @i[mark] to point one character before or after the
+current position. If there is no character before/after the current position,
+then they return @nil and leave @i[mark] unmodified.
+@enddefun
+
+@defun[fun {character-offset}, args {@i[mark] @i[n]}]
+This function changes @i[mark] to point @i[n] characters after (@i[n] before if
+@i[n] is negative) the current position. If there are less than @i[n]
+characters after (before) the @i[mark], then this returns @nil and @i[mark] is
+unmodified.
+@enddefun
+
+@defun[fun {line-offset}, args {@i[mark] @i[n] @optional @i[charpos]}]
+This function changes @i[mark] to point @i[n] lines after (@i[n] before if
+@i[n] is negative) the current position. The character position of the
+resulting mark is
+@lisp
+(min (line-length @i(resulting-line)) (mark-charpos @i(mark)))
+@endlisp
+if @i[charpos] is unspecified, or
+@lisp
+(min (line-length @i(resulting-line)) @i(charpos))
+@endlisp
+if it is. As with @t(character-offset), if there are not @i[n] lines then
+@nil is returned and @i[mark] is not modified.
+@enddefun
+
+
+@section(Regions)
+@index (Regions)
+A region is simply a pair of marks: a starting mark and an ending mark.
+The text in a region consists of the characters following the starting
+mark and preceding the ending mark (keep in mind that a mark points between
+characters on a line, not at them).
+
+By modifying the starting or ending mark in a region it is possible to
+produce regions with a start and end which are out of order or even in
+different buffers. The use of such regions is undefined and may
+result in arbitrarily bad behavior.
+
+
+@subsection(Region Functions)
+@defun[fun {region}, args {@i[start] @i[end]}]
+This function returns a region constructed from the marks @i[start] and
+@i[end]. It is an error for the marks to point to non-contiguous lines or for
+@i(start) to come after @i(end).
+@enddefun
+
+@defun[fun {regionp}, args {@i[region]}]
+This function returns @true if @i[region] is a @f[region] object, otherwise
+@nil.
+@enddefun
+
+@defun[fun {make-empty-region}]
+This function returns a region with start and end marks pointing to the start
+of one empty line. The start mark is a @kwd[right-inserting] mark, and the end
+is a @kwd[left-inserting] mark.
+@enddefun
+
+@defun[fun {copy-region}, args {@i[region]}]
+This function returns a region containing a copy of the text in the specified
+@i[region]. The resulting region is completely disjoint from @i[region] with
+respect to data references @dash marks, lines, text, etc.
+@enddefun
+
+@defun[fun {region-to-string}, args {@i[region]}]
+@defun1[fun {string-to-region}, args {@i[string]}]
+These functions coerce regions to Lisp strings and vice versa. Within the
+string, lines are delimited by newline characters.
+@enddefun
+
+@defun[fun {line-to-region}, args {@i[line]}]
+This function returns a region containing all the characters on @i[line]. The
+first mark is @kwd[right-inserting] and the last is @kwd[left-inserting].
+@enddefun
+
+@defun[fun {region-start}, args {@i[region]}]
+@defun1[fun {region-end}, args {@i[region]}]
+This function returns the start or end mark of @i(region).
+@enddefun
+
+@defun[fun {region-bounds}, args {@i[region]}]
+This function returns as multiple-values the starting and ending marks of
+@i[region].
+@enddefun
+
+@defun[fun {set-region-bounds}, args {@i[region] @i[start] @i[end]}]
+This function sets the start and end of region to @i[start] and @i[end]. It is
+an error for @i[start] to be after or in a different buffer from @i[end].
+@enddefun
+
+@index(Counting lines and characters)
+@defun[fun {count-lines}, args {@i[region]}]
+This function returns the number of lines in the @i(region), first and last
+lines inclusive. A newline is associated with the line it follows, thus a
+region containing some number of non-newline characters followed by one newline
+is one line, but if a newline were added at the beginning, it would be two
+lines.
+@enddefun
+
+@defun[fun {count-characters}, args {@i[region]}]
+This function returns the number of characters in a given @i(region). This
+counts line breaks as one character.
+@enddefun
+
+@defun[fun {check-region-query-size}, args {@i[region]}]
+@defhvar1[var {Region Query Size}, val {30}]
+@f[check-region-query-size] counts the lines in @i[region], and if their number
+exceeds the @hid[Region Query Size] threshold, it prompts the user for
+confirmation. This should be used in commands that perform destructive
+operations and are not undoable. If the user responds negatively, then this
+signals an editor-error, aborting whatever command was in progress.
+@enddefun
+
+
+
+@chapter(Buffers)
+@index (Buffers)
+@label[buffers]
+A buffer is an environment within @hemlock consisting of:
+@begin(enumerate)
+A name.
+
+A piece of text.
+
+A current focus of attention, the point.
+
+An associated file (optional).
+
+A write protect flag.
+
+Some variables (page @pageref[variables]).
+
+Some key bindings (page @pageref[key-bindings]).
+
+Some collection of modes (page @pageref[modes]).
+
+Some windows in which it is displayed (page @pageref[windows]).
+
+A list of modeline fields (optional).
+@end(enumerate)
+
+
+@section (The Current Buffer)
+@index (Current buffer)
+@defun[fun {current-buffer}]
+@defhvar1[var {Set Buffer Hook}]
+@defhvar1[var {After Set Buffer Hook}]
+@f[current-buffer] returns the current buffer object. Usually this is the
+buffer that @funref[current-window] is displaying. This value may be changed
+with @f[setf], and the @f[setf] method invokes @hid[Set Buffer Hook] before the
+change occurs with the new value. After the change occurs, the method invokes
+@hid[After Set Buffer Hook] with the old value.
+@enddefun
+
+@defun[fun {current-point}]
+This function returns the @f[buffer-point] of the current buffer.
+This is such a common idiom in commands that it is defined despite
+its trivial implementation.
+@enddefun
+
+@defun[fun {current-mark}]
+@defun1[fun {pop-buffer-mark}]
+@defun1[fun {push-buffer-mark}, args {@i[mark] @optional @i[activate-region]}]
+@index(Buffer mark stack)
+@index(Mark stack)
+@label(mark-stack)
+@f[current-mark] returns the top of the current buffer's mark stack. There
+always is at least one mark at the beginning of the buffer's region, and all
+marks returned are right-inserting.
+
+@f[pop-buffer-mark] pops the current buffer's mark stack, returning the mark.
+If the stack becomes empty, this pushes a new mark on the stack pointing to the
+buffer's start. This always deactivates the current region (see section
+@ref[active-regions]).
+
+@f[push-buffer-mark] pushes @i[mark] into the current buffer's mark stack,
+ensuring that the mark is right-inserting. If @i[mark] does not point into the
+current buffer, this signals an error. Optionally, the current region is made
+active, but this never deactivates the current region (see section
+@ref[active-regions]). @i[Mark] is returned.
+@enddefun
+
+@defvar[var {buffer-list}]
+This variable holds a list of all the buffer objects made with @f[make-buffer].
+@enddefvar
+
+@defvar[var {buffer-names}]
+This variable holds a @f[string-table] (page @pageref(string-tables)) of all the
+names of the buffers in @var[buffer-list]. The values of the entries are the
+corresponding buffer objects.
+@enddefvar
+
+@defvar[var {buffer-history}]
+This is a list of buffer objects ordered from those most recently selected to
+those selected farthest in the past. When someone makes a buffer, an element
+of @hid[Make Buffer Hook] adds this buffer to the end of this list. When
+someone deletes a buffer, an element of @hid[Delete Buffer Hook] removes the
+buffer from this list. Each buffer occurs in this list exactly once, but it
+never contains the @var[echo-area-buffer].
+@enddefvar
+
+@defun[fun {change-to-buffer}, args {@i[buffer]}]
+This switches to @i[buffer] in the @f[current-window] maintaining
+@f[buffer-history].
+@enddefun
+
+@defun[fun {previous-buffer}]
+This returns the first buffer from @var[buffer-history] that is not the
+@f[current-buffer]. If none can be found, then this returns @nil.
+@enddefun
+
+
+@section(Buffer Functions)
+@defun[fun {make-buffer}, args {@i[name]}, keys {[modes][modeline-fields][delete-hook]}]
+@defhvar1[var {Make Buffer Hook}]
+@defhvar1[var {Default Modeline Fields}]
+@f[make-buffer] creates and returns a buffer with the given @i(name). If a
+buffer named @i[name] already exists, @nil is returned. @i[Modes] is a list of
+modes which should be in effect in the buffer, major mode first, followed by
+any minor modes. If this is omitted then the buffer is created with the list
+of modes contained in @hvarref[Default Modes]. @i[Modeline-fields] is a list
+of modeline-field objects (see section @ref[modelines]) which may be @nil.
+@f[delete-hook] is a list of delete hooks specific to this buffer, and
+@f[delete-buffer] invokes these along with @hid[Delete Buffer Hook].
+
+Buffers created with @f[make-buffer] are entered into the list
+@var[buffer-list], and their names are inserted into the
+string-table @var[buffer-names]. When a buffer is created the hook
+@hid[Make Buffer Hook] is invoked with the new buffer.
+@enddefun
+
+@defun[fun {bufferp}, args {@i[buffer]}]
+Returns @true if @i[buffer] is a @f[buffer] object, otherwise @nil.
+@enddefun
+
+@defun[fun {buffer-name}, args {@i[buffer]}]
+@defhvar1[var {Buffer Name Hook}]
+@f[buffer-name] returns the name, which is a string, of the given @i(buffer).
+The corresponding @f[setf] method invokes @hid[Buffer Name Hook] with
+@i[buffer] and the new name and then sets the buffer's name. When the user
+supplies a name for which a buffer already exists, the @f[setf] method signals
+an error.
+@enddefun
+
+@defun[fun {buffer-region}, args {@i[buffer]}]
+Returns the @i[buffer]'s region. This can be set with @f[setf]. Note, this
+returns the region that contains all the text in a buffer, not the
+@funref[current-region].
+@enddefun
+
+@defun[fun {buffer-pathname}, args {@i[buffer]}]
+@defhvar1[var {Buffer Pathname Hook}]
+@f[buffer-pathname] returns the pathname of the file associated with
+the given @i(buffer), or nil if it has no associated file. This is
+the truename of the file as of the most recent time it was read or
+written. There is a @f[setf] form to change the pathname. When the
+pathname is changed the hook @hid[Buffer Pathname Hook] is invoked
+with the buffer and new value.
+@enddefun
+
+@defun[fun {buffer-write-date}, args {@i[buffer]}]
+Returns the write date for the file associated with the buffer in universal
+time format. When this the @f[buffer-pathname] is set, use @f[setf] to set
+this to the corresponding write date, or to @nil if the date is unknown or
+there is no file.
+@enddefun
+
+@defun[fun {buffer-point}, args {@i[buffer]}]
+Returns the mark which is the current location within @i[buffer]. To
+move the point, use @f[move-mark] or @funref[move-to-position] rather
+than setting @f[buffer-point] with @f[setf].
+@enddefun
+
+@defun[fun {buffer-mark}, args {@i[buffer]}]
+@index(Buffer mark stack)
+@index(Mark stack)
+This function returns the top of @i[buffer]'s mark stack. There always
+is at least one mark at the beginning of @i[buffer]'s region, and all marks
+returned are right-inserting.
+@enddefun
+
+@defun[fun {buffer-start-mark}, args {@i[buffer]}]
+@defun1[fun {buffer-end-mark}, args {@i[buffer]}]
+These functions return the start and end marks of @i[buffer]'s region:
+@Begin[ProgramExample]
+(buffer-start-mark buffer) <==>
+ (region-start (buffer-region buffer))
+and
+(buffer-end-mark buffer) <==>
+ (region-end (buffer-region buffer))
+@End[ProgramExample]
+@enddefun
+
+@defun[fun {buffer-writable}, args {@i[buffer]}]
+@defhvar1[var "Buffer Writable Hook"]
+This function returns @true if you can modify the @i(buffer), @nil if you
+cannot. If a buffer is not writable, then any attempt to alter text in the
+buffer results in an error. There is a @f[setf] method to change this value.
+
+The @f[setf] method invokes the functions in @hid[Buffer Writable Hook] on the
+buffer and new value before storing the new value.
+@enddefun
+
+@defun[fun {buffer-modified}, args {@i[buffer]}]
+@defhvar1[var "Buffer Modified Hook"]
+@f[buffer-modified] returns @true if the @i[buffer] has been modified, @nil if
+it hasn't. This attribute is set whenever a text-altering operation is
+performed on a buffer. There is a @f[setf] method to change this value.
+
+The @f[setf] method invokes the functions in @hid[Buffer Modified Hook] with
+the buffer whenever the value of the modified flag changes.
+@enddefun
+
+@defmac[fun {with-writable-buffer}, args {(@i[buffer]) @rest @i[forms]}]
+This macro executes @i[forms] with @i[buffer]'s writable status set. After
+@i[forms] execute, this resets the @i[buffer]'s writable and modified status.
+@enddefmac
+
+@defun[fun {buffer-signature}, args {@i[buffer]}]
+This function returns an arbitrary number which reflects the buffer's current
+@i[signature]. The result is @f[eql] to a previous result if and only if the
+buffer has not been modified between the calls.
+@enddefun
+
+@defun[fun {buffer-variables}, args {@i[buffer]}]
+This function returns a string-table (page @pageref[string-tables]) containing
+the names of the buffer's local variables. See chapter @ref[variables].
+@enddefun
+
+@defun[fun {buffer-modes}, args {@i[buffer]}]
+This function returns the list of the names of the modes active in @i[buffer].
+The major mode is first, followed by any minor modes. See chapter @ref[modes].
+@enddefun
+
+@defun[fun {buffer-windows}, args {@i[buffer]}]
+This function returns the list of all the windows in which the buffer may be
+displayed. This list may include windows which are not currently visible. See
+page @pageref[windows] for a discussion of windows.
+@enddefun
+
+@defun[fun {buffer-delete-hook}, args {@i[buffer]}]
+This function returns the list of buffer specific functions @f[delete-buffer]
+invokes when deleting a buffer. This is @f[setf]'able.
+@enddefun
+
+@defun[fun {delete-buffer}, args {@i[buffer]}]
+@defhvar1[var {Delete Buffer Hook}]
+@f[delete-buffer] removes @i[buffer] from @varref[buffer-list] and its name
+from @varref[buffer-names]. Before @i[buffer] is deleted, this invokes the
+functions on @i[buffer] returned by @f[buffer-delete-hook] and those found in
+@hid[Delete Buffer Hook]. If @i[buffer] is the @f[current-buffer], or if it is
+displayed in any windows, then this function signals an error.
+@enddefun
+
+@defun[fun {delete-buffer-if-possible}, args {@i[buffer]}]
+This uses @f[delete-buffer] to delete @i[buffer] if at all possible. If
+@i[buffer] is the @f[current-buffer], then this sets the @f[current-buffer] to
+the first distinct buffer in @f[buffer-history]. If @i[buffer] is displayed in
+any windows, then this makes each window display the same distinct buffer.
+@enddefun
+
+
+@section(Modelines)
+@index(Modelines)
+@label(modelines)
+
+A Buffer may specify a modeline, a line of text which is displayed across the
+bottom of a window to indicate status information. Modelines are described as
+a list of @f[modeline-field] objects which have individual update functions and
+are optionally fixed-width. These have an @f[eql] name for convenience in
+referencing and updating, but the name must be unique for all created
+modeline-field objects. When creating a modeline-field with a specified width,
+the result of the update function is either truncated or padded on the right to
+meet the constraint. All modeline-field functions must return simple strings
+with standard characters, and these take a buffer and a window as arguments.
+Modeline-field objects are typically shared amongst, or aliased by, different
+buffers' modeline fields lists. These lists are unique allowing fields to
+behave the same wherever they occur, but different buffers may display these
+fields in different arrangements.
+
+Whenever one of the following changes occurs, all of a buffer's modeline fields
+are updated:
+@Begin[Itemize]
+A buffer's major mode is set.
+
+One of a buffer's minor modes is turned on or off.
+
+A buffer is renamed.
+
+A buffer's pathname changes.
+
+A buffer's modified status changes.
+
+A window's buffer is changed.
+@End[Itemize]
+
+The policy is that whenever one of these changes occurs, it is guaranteed that
+the modeline will be updated before the next trip through redisplay.
+Furthermore, since the system cannot know what modeline-field objects the
+user has added whose update functions rely on these values, or how he has
+changed @hid[Default Modeline Fields], we must update all the fields. When any
+but the last occurs, the modeline-field update function is invoked once for
+each window into the buffer. When a window's buffer changes, each
+modeline-field update function is invoked once; other windows' modeline
+fields should not be affected due to a given window's buffer changing.
+
+The user should note that modelines can be updated at any time, so update
+functions should be careful to avoid needless delays (for example, waiting for
+a local area network to determine information).
+
+@defun[fun {make-modeline-field}, keys {[name][width][function]}]
+@defun1[fun {modeline-field-p}, args @i(modeline-field)]
+@defun1[fun {modeline-field-name}, args @i(modeline-field)]
+@f[make-modeline-field] returns a modeline-field object with @i[name],
+@i[width], and @i[function]. @i[Width] defaults to @nil meaning that the field
+is variable width; otherwise, the programmer must supply this as a positive
+integer. @i[Function] must take a buffer and window as arguments and return a
+@f[simple-string] containing only standard characters. If @i[name] already
+names a modeline-field object, then this signals an error.
+
+@f[modeline-field-name] returns the name field of a modeline-field object. If
+this is set with @f[setf], and the new name already names a modeline-field,
+then the @f[setf] method signals an error.
+
+@f[modeline-field-p] returns @true or @nil, depending on whether its argument
+is a @f[modeline-field] object.
+@enddefun
+
+@defun[fun {modeline-field}, args {@i[name]}]
+This returns the modeline-field object named @i[name]. If none exists, this
+returns nil.
+@enddefun
+
+@defun[fun {modeline-field-function}, args {@i[modeline-field]}]
+Returns the function called when updating the @i[modeline-field]. When this is
+set with @f[setf], the @f[setf] method updates @i[modeline-field] for all
+windows on all buffers that contain the given field, so the next trip through
+redisplay will reflect the change. All modeline-field functions must return
+simple strings with standard characters, and they take a buffer and a window
+as arguments.
+@enddefun
+
+@defun[fun {modeline-field-width}, args {@i[modeline-field]}]
+Returns the width to which @i[modeline-field] is constrained, or @nil
+indicating that it is variable width. When this is set with @f[setf], the
+@f[setf] method updates all modeline-fields for all windows on all buffers that
+contain the given field, so the next trip through redisplay will reflect the
+change. All the fields for any such modeline display must be updated, which is
+not the case when setting a modeline-field's function.
+@enddefun
+
+@defun[fun {buffer-modeline-fields}, args {@i[buffer]}]
+Returns a copy of the list of @i[buffer]'s modeline-field objects. This list
+can be destructively modified without affecting display of @i[buffer]'s
+modeline, but modifying any particular field's components (for example, width
+or function) causes the changes to be reflected the next trip through redisplay
+in every modeline display that uses the modified modeline-field. When this is
+set with @f[setf], @f[update-modeline-fields] is called for each window into
+@i[buffer].
+@enddefun
+
+@defun[fun {buffer-modeline-field-p}, args {@i[buffer] @i[field]}]
+If @i[field], a modeline-field or the name of one, is in buffer's list of
+modeline-field objects, it is returned; otherwise, this returns nil.
+@enddefun
+
+@defun[fun {update-modeline-fields}, args {@i[buffer] @i[window]}]
+This invokes each modeline-field object's function from @i[buffer]'s list,
+passing @i[buffer] and @i[window]. The results are collected regarding each
+modeline-field object's width as appropriate, and the window is marked so
+the next trip through redisplay will reflect the changes. If window does not
+display modelines, then no computation occurs.
+@enddefun
+
+@defun[fun {update-modeline-field}, args {@i[buffer] @i[window] @i[field-or-name}]
+This invokes the modeline-field object's function for @i[field-or-name], which
+is a modeline-field object or the name of one for @i[buffer]. This passes
+@i[buffer] and @i[window] to the update function. The result is applied to the
+@i[window]'s modeline display using the modeline-field object's width, and the
+window is marked so the next trip through redisplay will reflect the changes.
+If the window does not display modelines, then no computation occurs. If
+@i[field-or-name] is not found in @i[buffer]'s list of modeline-field objects,
+then this signals an error. See @f[buffer-modeline-field-p] above.
+@enddefun
+
+
+
+@chapter(Altering and Searching Text)
+@label[doing-stuff]
+
+@section(Altering Text)
+@index(Altering text)
+@index(Inserting)
+@index(Deleting)
+A note on marks and text alteration: @kwd[temporary] marks are invalid
+after any change has been made to the text the mark points to; it is an
+error to use a temporary mark after such a change has been made. If
+text is deleted which has permanent marks pointing into it then they
+are left pointing to the position where the text was.
+
+@defun[fun {insert-character}, args {@i[mark] @i[character]}]
+@defun1[fun {insert-string}, args {@i[mark] @i[string]}]
+@defun1[fun {insert-region}, args {@i[mark] @i[region]}]
+Inserts @i[character], @i[string] or @i[region] at @i[mark].
+@f[insert-character] signals an error if @i[character] is not
+@f[string-char-p]. If @i[string] or @i[region] is empty, and @i[mark] is in
+some buffer, then @hemlock leaves @f[buffer-modified] of @i[mark]'s buffer
+unaffected.
+@enddefun
+
+@defun[fun {ninsert-region}, args {@i[mark] @i[region]}]
+Like @f[insert-region], inserts the @i[region] at the @i[mark]'s position,
+destroying the source region. This must be used with caution, since if anyone
+else can refer to the source region bad things will happen. In particular, one
+should make sure the region is not linked into any existing buffer. If
+@i[region] is empty, and @i[mark] is in some buffer, then @hemlock leaves
+@f[buffer-modified] of @i[mark]'s buffer unaffected.
+@enddefun
+
+@defun[fun {delete-characters}, args {@i[mark] @i[n]}]
+This deletes @i[n] characters after the @i[mark] (or -@i[n] before if @i[n] is
+negative). If @i[n] characters after (or -@i[n] before) the @i[mark] do not
+exist, then this returns @nil; otherwise, it returns @true. If @i[n] is zero,
+and @i[mark] is in some buffer, then @hemlock leaves @f[buffer-modified] of
+@i[mark]'s buffer unaffected.
+@enddefun
+
+@defun[fun {delete-region}, args {@i[region]}]
+This deletes @i[region]. This is faster than @f[delete-and-save-region]
+(below) because no lines are copied. If @i[region] is empty and contained in
+some buffer's @f[buffer-region], then @hemlock leaves @f[buffer-modified] of
+the buffer unaffected.
+@enddefun
+
+@defun[fun {delete-and-save-region}, args {@i[region]}]
+This deletes @i[region] and returns a region containing the original
+@i[region]'s text. If @i[region] is empty and contained in some buffer's
+@f[buffer-region], then @hemlock leaves @f[buffer-modified] of the buffer
+unaffected. In this case, this returns a distinct empty region.
+@enddefun
+
+@defun[fun {filter-region}, args {@i[function] @i[region]}]
+Destructively modifies @i[region] by replacing the text
+of each line with the result of the application of @i[function] to a
+string containing that text. @i[Function] must obey the following
+restrictions:
+@begin[enumerate]
+The argument may not be destructively modified.
+
+The return value may not contain newline characters.
+
+The return value may not be destructively modified after it is
+returned from @i[function].
+@end[enumerate]
+The strings are passed in order, and are always simple strings.
+
+Using this function, a region could be uppercased by doing:
+@lisp
+(filter-region #'string-upcase region)
+@endlisp
+@enddefun
+
+
+@section(Text Predicates)
+@defun[fun {start-line-p}, args {@i[mark]}]
+Returns @true if the @i(mark) points before the first character in a line,
+@nil otherwise.
+@enddefun
+
+@defun[fun {end-line-p}, args {@i[mark]}]
+Returns @true if the @i(mark) points after the last character in a line and
+before the newline, @nil otherwise.
+@enddefun
+
+@defun[fun {empty-line-p}, args {@i[mark]}]
+Return @true of the line which @i[mark] points to contains no characters.
+@enddefun
+
+@defun[fun {blank-line-p}, args {@i[line]}]
+Returns @true if @i[line] contains only characters with a
+@hid[Whitespace] attribute of 1. See chapter @ref[character-attributes] for
+discussion of character attributes.
+@enddefun
+
+@defun[fun {blank-before-p}, args {@i[mark]}]
+@defun1[fun {blank-after-p}, args {@i[mark]}]
+These functions test if all the characters preceding or following
+@i[mark] on the line it is on have a @hid[Whitespace] attribute of @f[1].
+@enddefun
+
+@defun[fun {same-line-p}, args {@i[mark1] @i[mark2]}]
+Returns @true if @i(mark1) and @i(mark2) point to the same line, or @nil
+otherwise; That is,
+@example[(same-line-p a b) <==> (eq (mark-line a) (mark-line b))]
+@enddefun
+
+@defun[fun {mark<}, funlabel {mark-LSS}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark<=}, funlabel {mark-LEQ}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark=}, funlabel {mark-EQL}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark/=}, funlabel {mark-NEQ}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark>=}, funlabel {mark-GEQ}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark>}, funlabel {mark-GTR}, args {@i[mark1] @i[mark2]}]
+These predicates test the relative ordering of two marks in a piece of
+text, that is a mark is @f[mark>] another if it points to a position
+after it. If the marks point into different, non-connected pieces of
+text, such as different buffers, then it is an error to test their
+ordering; for such marks @f[mark=] is always false and @f[mark/=] is
+always true.
+@enddefun
+
+@defun[fun {line<}, funlabel {line-LSS}, args {@i[line1] @i[line2]}]
+@defun1[fun {line<=}, funlabel {line-LEQ}, args {@i[line1] @i[line2]}]
+@defun1[fun {line>=}, funlabel {line-GEQ}, args {@i[line1] @i[line2]}]
+@defun1[fun {line>}, funlabel {line-GTR}, args {@i[line1] @i[line2]}]
+These predicates test the ordering of @i[line1] and @i[line2]. If the
+lines are in unconnected pieces of text it is an error to test their
+ordering.
+@enddefun
+
+@defun[fun {lines-related}, args {@i[line1] @i[line2]}]
+This function returns @true if @i[line1] and @i[line2] are in the same
+piece of text, or @nil otherwise.
+@enddefun
+
+@defun[fun {first-line-p}, args {@i[mark]}]
+@defun1[fun {last-line-p}, args {@i[mark]}]
+@f[first-line-p] returns @true if there is no line before the line
+@i[mark] is on, and @nil otherwise. @i[Last-line-p] similarly tests
+tests whether there is no line after @i[mark].
+@enddefun
+
+
+@section(Kill Ring)
+@index(Kill ring)
+@label(kill-ring)
+
+@defvar[var {kill-ring}]
+This is a ring (see section @ref[rings]) of regions deleted from buffers.
+Some commands save affected regions on the kill ring before performing
+modifications. You should consider making the command undoable (see section
+@ref[undo]), but this is a simple way of achieving a less satisfactory means
+for the user to recover.
+@enddefvar
+
+@defun[fun {kill-region}, args {@i[region] @i[current-type]}]
+This kills @i[region] saving it in @var[kill-ring]. @i[Current-type] is either
+@kwd[kill-forward] or @kwd[kill-backward]. When the @funref[last-command-type]
+is one of these, this adds @i[region] to the beginning or end, respectively, of
+the top of @var[kill-ring]. The result of calling this is undoable using the
+command @hid[Undo] (see the @i[Hemlock User's Manual]). This sets
+@f[last-command-type] to @i[current-type], and it interacts with
+@f[kill-characters].
+@enddefun
+
+@defun[fun {kill-characters}, args {@i[mark] @i[count]}]
+@defhvar1[var {Character Deletion Threshold}, val {5}]
+@f[kill-characters] kills @i[count] characters after @i[mark] if @i[count] is
+positive, otherwise before @i[mark] if @i[count] is negative. When @i[count]
+is greater than or equal to @hid[Character Deletion Threshold], the killed
+characters are saved on @var[kill-ring]. This may be called multiple times
+contiguously (that is, without @funref[last-command-type] being set) to
+accumulate an effective count for purposes of comparison with the threshold.
+
+This sets @f[last-command-type], and it interacts with @f[kill-region]. When
+this adds a new region to @var[kill-ring], it sets @f[last-command-type] to
+@kwd[kill-forward] (if @i[count] is positive) or @kwd[kill-backward] (if
+@i[count] is negative). When @f[last-command-type] is @kwd[kill-forward] or
+@kwd[kill-backward], this adds the killed characters to the beginning (if
+@i[count] is negative) or the end (if @i[count] is positive) of the top of
+@var[kill-ring], and it sets @f[last-command-type] as if it added a new region
+to @var[kill-ring]. When the kill ring is unaffected, this sets
+@f[last-command-type] to @kwd[char-kill-forward] or @kwd[char-kill-backward]
+depending on whether @i[count] is positive or negative, respectively.
+
+This returns mark if it deletes characters. If there are not @i[count]
+characters in the appropriate direction, this returns nil.
+@enddefun
+
+
+@section(Active Regions)
+@index(Active regions)
+@label(active-regions)
+
+Every buffer has a mark stack (page @pageref[mark-stack]) and a mark known as
+the point where most text altering nominally occurs. Between the top of the
+mark stack, the @f[current-mark], and the @f[current-buffer]'s point, the
+@f[current-point], is what is known as the @f[current-region]. Certain
+commands signal errors when the user tries to operate on the @f[current-region]
+without its having been activated. If the user turns off this feature, then
+the @f[current-region] is effectively always active.
+
+When writing a command that marks a region of text, the programmer should make
+sure to activate the region. This typically occurs naturally from the
+primitives that you use to mark regions, but sometimes you must explicitly
+activate the region. These commands should be written this way, so they do not
+require the user to separately mark an area and then activate it. Commands
+that modify regions do not have to worry about deactivating the region since
+modifying a buffer automatically deactivates the region. Commands that insert
+text often activate the region ephemerally; that is, the region is active for
+the immediately following command, allowing the user wants to delete the region
+inserted, fill it, or whatever.
+
+Once a marking command makes the region active, it remains active until:
+@begin[itemize]
+a command uses the region,
+
+a command modifies the buffer,
+
+a command changes the current window or buffer,
+
+a command signals an editor-error,
+
+or the user types @binding[C-g].
+@end[itemize]
+
+@defhvar[var "Active Regions Enabled", val {t}]
+When this variable is non-@nil, some primitives signal an editor-error if
+the region is not active. This may be set to @nil for more traditional @emacs
+region semantics.
+@enddefhvar
+
+@defvar[var {ephemerally-active-command-types}]
+This is a list of command types (see section @ref[command-types]), and its
+initial value is the list of @kwd[ephemerally-active] and @kwd[unkill]. When
+the previous command's type is one of these, the @f[current-region] is active
+for the currently executing command only, regardless of whether it does
+something to deactivate the region. However, the current command may activate
+the region for future commands. @kwd[ephemerally-active] is a default command
+type that may be used to ephemerally activate the region, and @kwd[unkill] is
+the type used by two commands, @hid[Un-kill] and @hid[Rotate Kill Ring] (what
+users typically think of as @binding[C-y] and @binding[M-y]).
+@enddefvar
+
+@defun[fun {activate-region}]
+This makes the @f[current-region] active.
+@enddefun
+
+@defun[fun {deactivate-region}]
+After invoking this the @f[current-region] is no longer active.
+@enddefun
+
+@defun[fun {region-active-p}]
+Returns whether the @f[current-region] is active, including ephemerally. This
+ignores @hid[Active Regions Enabled].
+@enddefun
+
+@defun[fun {check-region-active}]
+This signals an editor-error when active regions are enabled, and the
+@f[current-region] is not active.
+@enddefun
+
+@defun[fun {current-region},
+ args {@optional @i[error-if-not-active] @i[deactivate-region]}]
+This returns a region formed with @f[current-mark] and @f[current-point],
+optionally signaling an editor-error if the current region is not active.
+@i[Error-if-not-active] defaults to @true. Each call returns a distinct region
+object. Depending on @i[deactivate-region] (defaults to @true), fetching the
+current region deactivates it. @hemlock primitives are free to modify text
+regardless of whether the region is active, so a command that checks for this
+can deactivate the region whenever it is convenient.
+@enddefun
+
+
+@section(Searching and Replacing)
+@index(Searching)
+@index(Replacing)
+
+Before using any of these functions to do a character search, look at character
+attributes (page @pageref[character-attributes]). They provide a facility
+similar to the syntax table in real EMACS. Syntax tables are a powerful,
+general, and efficient mechanism for assigning meanings to characters in
+various modes.
+
+@defcon[var {search-char-code-limit}]
+An exclusive upper limit for the char-code of characters given to the searching
+functions. The result of searches for characters with a char-code greater than
+or equal to this limit is ill-defined, but it is @i[not] an error to do such
+searches.
+@enddefcon
+
+@defun[fun {new-search-pattern},
+args {@i[kind] @i[direction] @i[pattern] @optional @i[result-search-pattern]}]
+
+Returns a @i[search-pattern] object which can be given to the @f[find-pattern]
+and @f[replace-pattern] functions. A search-pattern is a specification of a
+particular sort of search to do. @i[direction] is either @kwd[forward] or
+@kwd[backward], indicating the direction to search in. @i[kind] specifies the
+kind of search pattern to make, and @i[pattern] is a thing which specifies what
+to search for.
+
+The interpretation of @i[pattern] depends on the @i[kind] of pattern being
+made. Currently defined kinds of search pattern are:
+@begin(description)
+@kwd[string-insensitive]@\Does a case-insensitive string search,
+@i[pattern] being the string to search for.
+
+@kwd[string-sensitive]@\Does a case-sensitive string search for
+@i[pattern].
+
+@kwd[character]@\Finds an occurrence of the character @i[pattern].
+This is case sensitive.
+
+@kwd[not-character]@\Find a character which is not the character
+@i[pattern].
+
+@kwd[test]@\Finds a character which satisfies the function @i[pattern].
+This function may not be applied an any particular fashion, so it
+should depend only on what its argument is, and should have no
+side-effects.
+
+@kwd[test-not]@\Similar to as @kwd[test], except it finds a character that
+fails the test.
+
+@kwd[any]@\Finds a character that is in the string @i[pattern].
+
+@kwd[not-any]@\Finds a character that is not in the string @i[pattern].
+@end(description)
+
+@i[result-search-pattern], if supplied, is a search-pattern to
+destructively modify to produce the new pattern. Where reasonable
+this should be supplied, since some kinds of search patterns may
+involve large data structures.
+@enddefun
+
+@defun[fun {search-pattern-p}, args {@i[search-pattern]}]
+Returns @true if @i[search-pattern] is a @f[search-pattern] object, otherwise
+@nil.
+@enddefun
+
+@defun[fun {get-search-pattern}, args {@i[string] @i[direction]}]
+@defvar1[var {last-search-pattern}]
+@defvar1[var {last-search-string}]
+@f[get-search-pattern] interfaces to a default search string and pattern that
+search and replacing commands can use. These commands then share a default
+when prompting for what to search or replace, and save on consing a search
+pattern each time they execute. This uses @hid[Default Search Kind] (see the
+@i[Hemlock User's Manual]) when updating the pattern object. This returns the
+pattern, so you probably don't need to refer to @var[last-search-pattern], but
+@var[last-search-string] is useful when prompting.
+@enddefun
+
+@defun[fun {find-pattern}, args {@i[mark] @i[search-pattern]}]
+Find the next match of @i[search-pattern] starting at @i[mark]. If a
+match is found then @i[mark] is altered to point before the matched text
+and the number of characters matched is returned. If no match is
+found then @nil is returned and @i[mark] is not modified.
+@enddefun
+
+@defun[fun {replace-pattern}, args
+ {@i[mark] @i[search-pattern] @i[replacement] @optional @i[n]}]
+Replace @i[n] matches of @i[search-pattern] with the string
+@i[replacement] starting at @i[mark]. If @i[n] is @nil (the default)
+then replace all matches. A mark pointing before the last replacement
+done is returned.
+@enddefun
+
+
+
+@Chapter(The Current Environment)
+@label(current-environment)
+@index(Current environment)
+
+@section(Different Scopes)
+ In @hemlock the values of @i[variables] (page @pageref[variables]),
+@i[key-bindings] (page @pageref(key-bindings)) and
+@i[character-attributes] (page @pageref[character-attributes]) may
+depend on the @funref(current-buffer) and the modes
+active in it. There are three possible scopes for
+@hemlock values:
+@begin(description)
+@i[buffer local]@\The value is present only if the buffer it is local
+to is the @f[current-buffer].
+
+@i[mode local]@\The value is present only when the mode it is local to
+is active in the @f[current-buffer].
+
+@i[global]@\The value is always present unless shadowed by a buffer or
+mode local value.
+@end(description)
+
+
+@section(Shadowing)
+ It is possible for there to be a conflict between different values
+for the same thing in different scopes. For example, there be might a
+global binding for a given variable and also a local binding in the
+current buffer. Whenever there is a conflict shadowing occurs,
+permitting only one of the values to be visible in the current
+environment.
+
+ The process of resolving such a conflict can be described as a
+search down a list of places where the value might be defined, returning
+the first value found. The order for the search is as follows:
+@begin(enumerate)
+Local values in the current buffer.
+
+Mode local values in the minor modes of the current buffer, in order
+from the highest precedence mode to the lowest precedence mode. The
+order of minor modes with equal precedences is undefined.
+
+Mode local values in the current buffer's major mode.
+
+Global values.
+@end(enumerate)
+
+
+
+@chapter(Hemlock Variables)
+@index (Hemlock variables)
+@label(variables)
+@hemlock implements a system of variables separate from normal Lisp variables
+for the following reasons:
+@begin(enumerate)
+@hemlock has different scoping rules which are useful in an editor. @hemlock
+variables can be local to a @i(buffer) (page @pageref[buffers]) or a @i(mode)
+(page @pageref[modes]).
+
+@hemlock variables have @i(hooks) (page @pageref[hooks]), lists of functions
+called when someone sets the variable. See @f[variable-value] for the
+arguments @hemlock passes to these hook functions.
+
+There is a database of variable names and documentation which makes it easier
+to find out what variables exist and what their values mean.
+@end(enumerate)
+
+
+@section(Variable Names)
+To the user, a variable name is a case insensitive string. This
+string is referred to as the @i[string name] of the variable. A
+string name is conventionally composed of words separated by spaces.
+
+In Lisp code a variable name is a symbol. The name of this symbol is
+created by replacing any spaces in the string name with hyphens. This
+symbol name is always interned in the @hemlock package and referring
+to a symbol with the same name in the wrong package is an error.
+
+@defvar[var {global-variable-names}]
+This variable holds a string-table of the names of all the global @hemlock
+variables. The value of each entry is the symbol name of the variable.
+@enddefvar
+
+@defun[fun {current-variable-tables}]
+This function returns a list of variable tables currently established,
+globally, in the @f[current-buffer], and by the modes of the
+@f[current-buffer]. This list is suitable for use with
+@f[prompt-for-variable].
+@enddefun
+
+
+@section(Variable Functions)
+In the following descriptions @i[name] is the symbol name of the variable.
+
+@defun[fun {defhvar}, args {@i[string-name] @i[documentation]},
+ keys {[mode][buffer][hooks][value]}]
+ This function defines a @hemlock variable. Functions that take a variable
+name signal an error when the variable is undefined.
+@begin(description)
+@i[string-name]@\The string name of the variable to define.
+
+@i[documentation]@\The documentation string for the variable.
+
+@multiple{
+@kwd[mode],
+@kwd[buffer]}@\
+ If @i[buffer] is supplied, the variable is local to that buffer. If @i[mode]
+is supplied, it is local to that mode. If neither is supplied, it is global.
+
+@kwd[value]@\
+ This is the initial value for the variable, which defaults to @nil.
+
+@kwd[hooks]@\
+ This is the initial list of functions to call when someone sets the variable's
+value. These functions execute before @hemlock establishes the new value. See
+@f[variable-value] for the arguments passed to the hook functions.
+@end(description)
+If a variable with the same name already exists in the same place, then
+@f[defhvar] sets its hooks and value from @i[hooks] and @i[value] if the user
+supplies these keywords.
+@enddefun
+
+@defun[fun {variable-value}, args {@i[name] @optional @i[kind] @i[where]}]
+This function returns the value of a @hemlock variable in some place.
+The following values for @i[kind] are defined:
+@begin[description]
+@kwd[current]@\
+ Return the value present in the current environment, taking into consideration
+any mode or buffer local variables. This is the default.
+
+@kwd[global]@\
+ Return the global value.
+
+@kwd[mode]@\
+ Return the value in the mode named @i[where].
+
+@kwd[buffer]@\
+ Return the value in the buffer @i[where].
+@end[description]
+When set with @f[setf], @hemlock sets the value of the specified variable and
+invokes the functions in its hook list with @i[name], @i[kind], @i[where], and
+the new value.
+@enddefun
+
+@defun[fun {variable-documentation}, args
+ {@i[name] @optional @i[kind] @i[where]}]
+@defun1[fun {variable-hooks}, args
+ {@i[name] @optional @i[kind] @i[where]}]
+@defun1[fun {variable-name}, args
+ {@i[name] @optional @i[kind] @i[where]}]
+These function return the documentation, hooks and string name of a
+@hemlock variable. The @i[kind] and @i[where] arguments are the same
+as for @f[variable-value]. The documentation and hook list may be set
+using @f[setf].
+@enddefun
+
+@defun[fun {string-to-variable}, args {@i[string]}]
+This function converts a string into the corresponding variable symbol
+name. @i[String] need not be the name of an actual @hemlock variable.
+@enddefun
+
+@defmac[fun {value}, args {@i[name]}]
+@defmac1[fun {setv}, args {@i[name] @i[new-value]}]
+These macros get and set the current value of the @hemlock variable
+@i[name]. @i[Name] is not evaluated. There is a @f[setf] form for
+@f[value].
+@enddefmac
+
+@Defmac[Fun {hlet}, Args {(@Mstar<(@i[var] @i[value])>) @Mstar<@i[form]>}]
+This macro is very similar to @f[let] in effect; within its scope each
+of the @hemlock variables @i[var] have the respective @i[value]s, but
+after the scope is exited by any means the binding is removed. This
+does not cause any hooks to be invoked. The value of the last
+@i[form] is returned.
+@enddefmac
+
+@defun[fun {hemlock-bound-p}, args {@i[name] @optional @i[kind] @i[where]}]
+Returns @true if @i[name] is defined as a @hemlock variable in the
+place specified by @i[kind] and @i[where], or @nil otherwise.
+@enddefun
+
+@defun[fun {delete-variable}, args {@i(name) @optional @i[kind] @i[where]}]
+@defhvar1[var {Delete Variable Hook}]
+@f[delete-variable] makes the @hemlock variable @i[name] no longer
+defined in the specified place. @i[Kind] and @i[where] have the same
+meanings as they do for @f[variable-value], except that @kwd[current]
+is not available, and the default for @i[kind] is @kwd[global]
+
+An error will be signaled if no such variable exists. The hook,
+@hid[Delete Variable Hook] is invoked with the same arguments before the
+variable is deleted.
+@enddefun
+
+
+@section(Hooks)
+@index(Hooks)
+@label[hooks]
+@hemlock actions such as setting variables, changing buffers, changing windows,
+turning modes on and off, etc., often have hooks associated with them. A hook
+is a list of functions called before the system performs the action. The
+manual describes the object specific hooks with the rest of the operations
+defined on these objects.
+
+Often hooks are stored in @hemlock variables, @hid[Delete Buffer Hook] and
+@hid[Set Window Hook] for example. This leads to a minor point of confusion
+because these variables have hooks that the system executes when someone
+changes their values. These hook functions @hemlock invokes when someone sets
+a variable are an example of a hook stored in an object instead of a @hemlock
+variable. These are all hooks for editor activity, but @hemlock keeps them in
+different kinds of locations. This is why some of the routines in this section
+have a special interpretation of the hook @i[place] argument.
+
+@defmac[fun {add-hook}, args {@i[place] @i[hook-fun]}]
+@defmac1[fun {remove-hook}, args {@i[place] @i[hook-fun]}]
+These macros add or remove a hook function in some @i[place]. If @i[hook-fun]
+already exists in @i[place], this call has no effect. If @i[place] is a
+symbol, then it is a @hemlock variable; otherwise, it is a generalized variable
+or storage location. Here are two examples:
+@Begin[ProgramExample]
+(add-hook delete-buffer-hook 'remove-buffer-from-menu)
+
+(add-hook (variable-hooks 'check-mail-interval)
+ 'reschedule-mail-check)
+@End[ProgramExample]
+@enddefmac
+
+@defmac[fun {invoke-hook}, args {@i[place] @rest @i[args]}]
+This macro calls all the functions in @i[place]. If @i[place] is a symbol,
+then it is a @hemlock variable; otherwise, it is a generalized variable.
+@enddefun
+
+
+
+@chapter(Commands)
+@index (Commands)
+@label[commands]
+
+
+@section(Introduction)
+The way that the user tells @hemlock to do something is by invoking a
+@i(command). Commands have three attributes:
+@begin(description)
+@i[name]@\A command's name provides a way to refer to it. Command
+names are usually capitalized words separated by spaces, such as
+@hid[Forward Word].
+
+@i[documentation]@\The documentation for a command is used by
+on-line help facilities.
+
+@i[function]@\A command is implemented by a Lisp function, which is callable
+from Lisp.
+@end(description)
+
+@defvar[var {command-names}]
+Holds a string-table (page @pageref[string-tables]) associating
+command names to command objects. Whenever a new command is defined
+it is entered in this table.
+@enddefvar
+
+
+@subsection(Defining Commands)
+
+@defmac[fun {defcommand}, args
+{@^@mgroup<@i[command-name] @MOR (@i[command-name] @i[function-name])> @i[lambda-list]
+@\@i[command-doc] @i[function-doc] @mstar<@i[form]>}]
+
+Defines a command named @i[name]. @f[defcommand] creates a function to
+implement the command from the @i[lambda-list] and @i[form]'s supplied. The
+@i[lambda-list] must specify one required argument, see section
+@ref[invoking-commands-as-functions], which by convention is typically named
+@f[p]. If the caller does not specify @i[function-name], @f[defcommand]
+creates the command name by replacing all spaces with hyphens and appending
+"@f[-command]". @i[Function-doc] becomes the documentation for the function
+and should primarily describe issues involved in calling the command as a
+function, such as what any additional arguments are. @i[Command-doc] becomes
+the command documentation for the command. @enddefmac
+
+@defun[fun {make-command}, args
+ {@i[name] @i[documentation] @i[function]}]
+Defines a new command named @i[name], with command documentation
+@I[documentation] and function @i[function]. The command in entered
+in the string-table @varref[command-names], with the command object as
+its value. Normally command implementors will use the @f[defcommand]
+macro, but this permits access to the command definition mechanism at
+a lower level, which is occasionally useful.
+@enddefun
+
+@defun[fun {commandp}, args {@i[command]}]
+Returns @true if @i[command] is a @f[command] object, otherwise @nil.
+@enddefun
+
+@defun[fun {command-documentation}, args {@i[command]}]
+@defun1[fun {command-function}, args {@i[command]}]
+@defun1[fun {command-name}, args {@i[command]}]
+Returns the documentation, function, or name for @i[command]. These
+may be set with @f[setf].
+@enddefun
+
+
+@subsection(Command Documentation)
+@i[Command documentation] is a description of what the command does
+when it is invoked as an extended command or from a key. Command
+documentation may be either a string or a function. If the
+documentation is a string then the first line should briefly summarize
+the command, with remaining lines filling the details. Example:
+@lisp
+(defcommand "Forward Character" (p)
+ "Move the point forward one character.
+ With prefix argument move that many characters, with negative
+ argument go backwards."
+ "Move the point of the current buffer forward p characters."
+ . . .)
+@endlisp
+
+Command documentation may also be a function of one argument. The
+function is called with either @kwd[short] or @kwd[full], indicating
+that the function should return a short documentation string or do
+something to document the command fully.
+
+
+@section(The Command Interpreter)
+@index[Interpreter, command]
+@index[Invocation, command]
+@index[Command interpreter]
+
+The @i[command interpreter] is a function which reads key-events (see section
+@ref[key-events-intro]) from the keyboard and dispatches to different commands
+on the basis of what the user types. When the command interpreter executes a
+command, we say it @i[invokes] the command. The command interpreter also
+provides facilities for communication between commands contiguously running
+commands, such as a last command type register. It also takes care of
+resetting communication mechanisms, clearing the echo area, displaying partial
+keys typed slowly by the user, etc.
+
+@defvar[var {invoke-hook}]
+This variable contains a function the command interpreter calls when it wants
+to invoke a command. The function receives the command and the prefix argument
+as arguments. The initial value is a function which simply funcalls the
+@f[command-function] of the command with the supplied prefix argument. This is
+useful for implementing keyboard macros and similar things.
+@enddefhvar
+
+@defhvar[var "Command Abort Hook"]
+The command interpreter invokes the function in this variable whenever someone
+aborts a command (for example, if someone called @f[editor-error]).
+@enddefhvar
+
+When @hemlock initially starts the command interpreter is in control, but
+commands may read from the keyboard themselves and assign whatever
+interpretation they will to the key-events read. Commands may call the command
+interpreter recursively using the function @funref[recursive-edit].
+
+
+@subsection(Editor Input)
+@label[key-events-intro]
+@index[key-events]
+
+The canonical representation of editor input is a key-event structure. Users
+can bind commands to keys (see section @ref[key-bindings]), which are non-zero
+length sequences of key-events. A key-event consists of an identifying token
+known as a @i[keysym] and a field of bits representing modifiers. Users define
+keysyms, integers between 0 and 65535 inclusively, by supplying names that
+reflect the legends on their keyboard's keys. Users define modifier names
+similarly, but the system chooses the bit and mask for recognizing the
+modifier. You can use keysym and modifier names to textually specify
+key-events and Hemlock keys in a @f[#k] syntax. The following are some
+examples:
+@begin[programexample]
+ #k"C-u"
+ #k"Control-u"
+ #k"c-m-z"
+ #k"control-x meta-d"
+ #k"a"
+ #k"A"
+ #k"Linefeed"
+@end[programexample]
+This is convenient for use within code and in init files containing
+@f[bind-key] calls.
+
+The @f[#k] syntax is delimited by double quotes, but the system parses the
+contents rather than reading it as a Common Lisp string. Within the double
+quotes, spaces separate multiple key-events. A single key-event optionally
+starts with modifier names terminated by hyphens. Modifier names are
+alphabetic sequences of characters which the system uses case-insensitively.
+Following modifiers is a keysym name, which is case-insensitive if it consists
+of multiple characters, but if the name consists of only a single character,
+then it is case-sensitive.
+
+You can escape special characters @dash hyphen, double quote, open angle
+bracket, close angle bracket, and space @dash with a backslash, and you can
+specify a backslash by using two contiguously. You can use angle brackets to
+enclose a keysym name with many special characters in it. Between angle
+brackets appearing in a keysym name position, there are only two special
+characters, the closing angle bracket and backslash.
+
+For more information on key-events see section @ref[key-events].
+
+
+
+@subsection(Binding Commands to Keys)
+@label[Key-Bindings]
+@Index[Key Bindings]
+
+The command interpreter determines which command to invoke on the basis of
+@i[key bindings]. A key binding is an association between a command and a
+sequence of key-events (see section @ref[key-events-intro]. A sequence of
+key-events is called a @i[key] and is represented by a single key-event or a
+sequence (list or vector) of key-events.
+
+Since key bindings may be local to a mode or buffer, the current environment
+(page @pageref[current-environment]) determines the set of key bindings in
+effect at any given time. When the command interpreter tries to find the
+binding for a key, it first checks if there is a local binding in the
+@w[@funref[current-buffer]], then if there is a binding in each of the minor
+modes and the major mode for the current buffer @w[(page @pageref[modes])], and
+finally checks to see if there is a global binding. If no binding is found,
+then the command interpreter beeps or flashes the screen to indicate this.
+
+@defun[fun {bind-key}, args
+ {@i(name) @i(key) @optional @i[kind] @i[where]}]
+ This function associates command @i[name] and @i[key] in some environment.
+@i[Key] is either a key-event or a sequence of key-events. There are three
+possible values of @i[kind]:
+@begin(description)
+@kwd[global]@\
+ The default, make a global key binding.
+
+@kwd[mode]@\
+ Make a mode specific key binding in the mode whose name is @i[where].
+
+@kwd[buffer]@\
+ Make a binding which is local to buffer @i[where].
+@end(description)
+
+This processes @i[key] for key translations before establishing the binding.
+See section @ref[key-trans].
+
+If the key is some prefix of a key binding which already exists in the
+specified place, then the new one will override the old one, effectively
+deleting it.
+
+@f[ext:do-alpha-key-events] is useful for setting up bindings in certain new
+modes.
+@enddefun
+
+@defun[fun {command-bindings}, args {@i[command]}]
+This function returns a list of the places where @i[command] is bound. A place
+is specified as a list of the key (always a vector), the kind of binding, and
+where (either the mode or buffer to which the binding is local, or @nil if it
+is a global).
+@enddefun
+
+@defun[fun {delete-key-binding}, args {@i[key] @optional @i[kind] @i[where]}]
+This function removes the binding of @i[key] in some place. @i[Key] is either
+a key-event or a sequence of key-events. @i[kind] is the kind of binding to
+delete, one of @kwd[global] (the default), @kwd[mode] or @kwd[buffer]. If
+@i[kind] is @kwd[mode], @i[where] is the mode name, and if @i[kind] is
+@kwd[buffer], then @i[where] is the buffer.
+
+This function signals an error if @i[key] is unbound.
+
+This processes @i[key] for key translations before deleting the binding. See
+section @ref[key-trans].
+@enddefun
+
+@defun[fun {get-command}, args {@i[key] @optional @i[kind] @i[where]}]
+This function returns the command bound to @i[key], returning @nil if it is
+unbound. @i[Key] is either a key-event or a sequence of key-events. If
+@i[key] is an initial subsequence of some keys, then this returns the keyword
+@kwd[prefix]. There are four cases of @i[kind]:
+@begin(description)
+@kwd[current]@\
+ Return the current binding of @i[key] using the current buffer's search list.
+If there are any transparent key bindings for @i[key], then they are returned
+in a list as a second value.
+
+@kwd[global]@\
+ Return the global binding of @i[key]. This is the default.
+
+@kwd[mode]@\
+ Return the binding of @i[key] in the mode named @i[where].
+
+@kwd[buffer]@\
+ Return the binding of @i[key] local to the buffer @i[where].
+@end(description)
+
+This processes @i[key] for key translations before looking for any binding.
+See section @ref[key-trans].
+@enddefun
+
+@defun[fun {map-bindings}, Args {@i[function] @i[kind] @optional @i[where]}]
+This function maps over the key bindings in some place. For each binding, this
+passes @i[function] the key and the command bound to it. @i[Kind] and
+@i[where] are the same as in @f[bind-key]. The key is not guaranteed to remain
+valid after a given iteration.
+@enddefmac
+
+
+@subsection[Key Translation]
+@index[bit-prefix keys]
+@index[key translation]
+@index[translating keys]
+@label[key-trans]
+Key translation is a process that the command interpreter applies to keys
+before doing anything else. There are two kinds of key translations:
+substitution and bit-prefix. In either case, the command interpreter
+translates a key when a specified key-event sequence appears in a key.
+
+In a substitution translation, the system replaces the matched subsequence with
+another key-event sequence. Key translation is not recursively applied to the
+substituted key-events.
+
+In a bit-prefix translation, the system removes the matched subsequence and
+effectively sets the specified bits in the next key-event in the key.
+
+While translating a key, if the system encounters an incomplete final
+subsequence of key-events, it aborts the translation process. This happens
+when those last key-events form a prefix of some translation. It also happens
+when they translate to a bit-prefix, but there is no following key-event to
+which the system can apply the indicated modifier. If there is a binding for
+this partially untranslated key, then the command interpreter will invoke that
+command; otherwise, it will wait for the user to type more key-events.
+
+@defun[fun {key-translation}, args {@i[key]}]
+This form is @f[setf]'able and allows users to register key translations that
+the command interpreter will use as users type key-events.
+
+This function returns the key translation for @i[key], returning @nil if there
+is none. @i[Key] is either a key-event or a sequence of key-events. If
+@i[key] is a prefix of a translation, then this returns @kwd[prefix].
+
+A key translation is either a key or modifier specification. The bits
+translations have a list form: @w<@f[(:bits {]@i[bit-name]@f[}*)]>.
+
+Whenever @i[key] appears as a subsequence of a key argument to the binding
+manipulation functions, that portion will be replaced with the translation.
+@enddefun
+
+
+
+@subsection[Transparent Key Bindings]
+@label[transparent-key-bindings]
+@index[Transparent key bindings]
+
+Key bindings local to a mode may be @i[transparent]. A transparent key
+binding does not shadow less local key bindings, but rather indicates that
+the bound command should be invoked before the first normal key binding.
+Transparent key bindings are primarily useful for implementing minor modes
+such as auto fill and word abbreviation. There may be several transparent
+key bindings for a given key, in which case all of the commands bound are
+invoked in the order they were found. If there no normal key binding for a
+key typed, then the command interpreter acts as though the key is unbound
+even if there are transparent key bindings.
+
+The @kwd[transparent-p] argument to @funref[defmode] determines whether the
+key bindings in a mode are transparent or not.
+
+
+@subsection (Interactive)
+@index (Keyboard macro vs. interactive)
+@index (Interactive vs. keyboard macro)
+@Hemlock supports keyboard macros. A user may enter a mode where the editor
+records his actions, and when the user exits this mode, the command @hid[Last
+Keyboard Macro] plays back the actions. Some commands behave differently when
+invoked as part of the definition of a keyboard macro. For example, when used
+in a keyboard macro, a command that @f[message]'s useless user confirmation
+will slow down the repeated invocations of @hid[Last Keyboard Macro] because
+the command will pause on each execution to make sure the user sees the
+message. This can be eliminated with the use of @f[interactive]. As another
+example, some commands conditionally signal an editor-error versus simply
+beeping the device depending on whether it executes on behalf of the user or a
+keyboard macro.
+
+@defun[fun {interactive}]
+This returns @true when the user invoked the command directly.
+@enddefun
+
+
+@section(Command Types)
+@index(Command types)
+@label(command-types)
+In many editors the behavior of a command depends on the kind of command
+invoked before it. @hemlock provides a mechanism to support this known as
+@i(command type).
+
+@defun[fun {last-command-type}]
+This returns the command type of the last command invoked. If this is set with
+@f[setf], the supplied value becomes the value of @f[last-command-type] until
+the next command completes. If the previous command did not set
+@f[last-command-type], then its value is @nil. Normally a command type is a
+keyword. The command type is not cleared after a command is invoked due to a
+transparent key binding.
+@enddefun
+
+
+@section(Command Arguments)
+@label[invoking-commands-as-functions]
+There are three ways in which a command may be invoked: It may be bound to a
+key which has been typed, it may be invoked as an extended command, or it may
+be called as a Lisp function. Ideally commands should be written in such a way
+that they will behave sensibly no matter which way they are invoked. The
+functions which implement commands must obey certain conventions about argument
+passing if the command is to function properly.
+
+
+@subsection(The Prefix Argument)
+@index(Prefix arguments)
+Whenever a command is invoked it is passed as its first argument what
+is known as the @i[prefix argument]. The prefix argument is always
+either an integer or @nil. When a command uses this value it is
+usually as a repeat count, or some conceptually similar function.
+
+@defun[fun {prefix-argument}]
+This function returns the current value of the prefix argument. When
+set with @f[setf], the new value becomes the prefix argument for the
+next command.
+@enddefun
+
+If the prefix argument is not set by the previous command then the
+prefix argument for a command is @nil. The prefix argument is not cleared
+after a command is invoked due to a transparent key binding.
+
+
+@subsection(Lisp Arguments)
+It is often desirable to call commands from Lisp code, in which case
+arguments which would otherwise be prompted for are passed as optional
+arguments following the prefix argument. A command should prompt for
+any arguments not supplied.
+
+
+@section(Recursive Edits)
+@index(Recursive edits)
+@defmac[fun {use-buffer}, args {@i[buffer] @mstar<@i[form]>}]
+The effect of this is similar to setting the current-buffer to @i[buffer]
+during the evaluation of @i[forms]. There are restrictions placed on what the
+code can expect about its environment. In particular, the value of any global
+binding of a @hemlock variable which is also a mode local variable of some mode
+is ill-defined; if the variable has a global binding it will be bound, but the
+value may not be the global value. It is also impossible to nest
+@f[use-buffer]'s in different buffers. The reason for using @f[use-buffer] is
+that it may be significantly faster than changing @f[current-buffer] to
+@i[buffer] and back.
+@enddefmac
+
+@defun[fun {recursive-edit}, args {@optional @i[handle-abort]}]
+@defhvar1[var {Enter Recursive Edit Hook}]
+@index[aborting]
+@f[recursive-edit] invokes the command interpreter. The command interpreter
+will read from the keyboard and invoke commands until it is terminated with
+either @f[exit-recursive-edit] or @f[abort-recursive-edit].
+
+Normally, an editor-error or @bf[C-g] aborts the command in progress and
+returns control to the top-level command loop. If @f[recursive-edit] is used
+with @i[handle-abort] true, then @f[editor-error] or @bf[C-g] will only abort
+back to the recursive command loop.
+
+Before the command interpreter is entered the hook
+@hid[Enter Recursive Edit Hook] is invoked.
+@enddefun
+
+@defun[fun {in-recursive-edit}]
+This returns whether the calling point is dynamically within a recursive edit
+context.
+@enddefun
+
+@defun[fun {exit-recursive-edit}, args {@optional @i[values-list]}]
+@defhvar1[var {Exit Recursive Edit Hook}]
+@f[exit-recursive-edit] exits a recursive edit returning as multiple values
+each element of @i[values-list], which defaults to @nil. This invokes
+@hid[Exit Recursive Edit Hook] after exiting the command interpreter. If no
+recursive edit is in progress, then this signals an error.
+@enddefun
+
+@defun[fun {abort-recursive-edit}, args {@rest @i[args]}]
+@defhvar1[var {Abort Recursive Edit Hook}]
+@f[abort-recursive-edit] terminates a recursive edit by applying
+@funref[editor-error] to @i[args] after exiting the command interpreter. This
+invokes @hid[Abort Recursive Edit Hook] with @i[args] before aborting the
+recursive edit . If no recursive edit is in progress, then this signals an
+error.
+@enddefun
+
+
+
+@Chapter(Modes)
+@label[modes]
+@index (Modes)
+A mode is a collection of @hemlock values which may be present in the current
+environment @w<(page @pageref(current-environment))> depending on the editing
+task at hand. Examples of typical modes are @hid[Lisp], for editing Lisp code,
+and @hid[Echo Area], for prompting in the echo area.
+
+
+@section(Mode Hooks)
+ When a mode is added to or removed from a buffer, its @i[mode hook]
+is invoked. The hook functions take two arguments, the buffer
+involved and @true if the mode is being added or @nil if it is being
+removed.
+
+Mode hooks are typically used to make a mode do something additional to
+what it usually does. One might, for example, make a text mode hook
+that turned on auto-fill mode when you entered.
+
+
+@section(Major and Minor Modes)
+There are two kinds of modes, @i[major] modes and @i[minor] modes. A buffer
+always has exactly one major mode, but it may have any number of minor modes.
+Major modes may have mode character attributes while minor modes may not.
+
+A major mode is usually used to change the environment in some major way, such
+as to install special commands for editing some language. Minor modes
+generally change some small attribute of the environment, such as whether lines
+are automatically broken when they get too long. A minor mode should work
+regardless of what major mode and minor modes are in effect.
+
+@defhvar[var {Default Modes}, val {("Fundamental" "Save")}]
+This variable contains a list of mode names which are instantiated in a
+buffer when no other information is available.
+@enddefhvar
+
+@defvar[var {mode-names}]
+Holds a string-table of the names of all the modes.
+@enddefvar
+
+@defcom[com "Illegal"]
+This is a useful command to bind in modes that wish to shadow global bindings
+by making them effectively illegal. Also, although less likely, minor modes
+may shadow major mode bindings with this. This command calls @f[editor-error].
+@enddefcom
+
+
+@section(Mode Functions)
+
+@defun[fun {defmode}, args {@i[name]},
+ keys {[setup-function][cleanup-function][major-p]},
+ morekeys {[precedence][transparent-p][documentation]}]
+This function defines a new mode named @i[name], and enters it in
+@varref[mode-names]. If @i[major-p] is supplied and is not @nil
+then the mode is a major mode; otherwise it is a minor mode.
+
+@i[Setup-function] and @i[cleanup-function] are functions which are
+invoked with the buffer affected, after the mode is turned on, and
+before it is turned off, respectively. These functions typically are
+used to make buffer-local key or variable bindings and to remove them
+when the mode is turned off.
+
+@i[Precedence] is only meaningful for a minor mode. The precedence of a
+minor mode determines the order in which it in a buffer's list of modes.
+When searching for values in the current environment, minor modes are
+searched in order, so the precedence of a minor mode determines which value
+is found when there are several definitions.
+
+@i[Transparent-p] determines whether key bindings local to the defined mode
+are transparent. Transparent key bindings are invoked in addition to the
+first normal key binding found rather than shadowing less local key bindings.
+
+@i[Documentation] is some introductory text about the mode. Commands such as
+@hid[Describe Mode] use this.
+@enddefun
+
+@defun[fun {mode-documentation}, args {@i[name]}]
+This function returns the documentation for the mode named @i[name].
+@enddefun
+
+@defun[fun {buffer-major-mode}, args {@i[buffer]}]
+@defhvar1[var {Buffer Major Mode Hook}]
+@f[buffer-major-mode] returns the name of @i[buffer]'s major mode.
+The major mode may be changed with @f[setf]; then
+ @hid[Buffer Major Mode Hook] is invoked with
+@i[buffer] and the new mode.
+@enddefun
+
+@defun[fun {buffer-minor-mode}, args {@i[buffer] @i[name]}]
+@defhvar1[var {Buffer Minor Mode Hook}]
+@f[buffer-minor-mode] returns @true if the minor mode @i[name] is active
+in @i[buffer], @nil otherwise. A minor mode may be turned on or off
+by using @f[setf]; then @hid[Buffer Minor Mode Hook] is
+invoked with @i[buffer], @i[name] and the new value.
+@enddefun
+
+@defun[fun {mode-variables}, args {@i[name]}]
+Returns the string-table of mode local variables.
+@enddefun
+
+@defun[fun {mode-major-p}, args {@i[name]}]
+Returns @true if @i[name] is the name of a major mode, or @nil if
+it is the name of a minor mode. It is an error for @i[name] not to be
+the name of a mode.
+@enddefun
+
+
+
+@chapter(Character Attributes)
+@label(character-attributes)
+@index(Character attributes)
+@index(Syntax tables)
+
+@section(Introduction)
+Character attributes provide a global database of information about characters.
+This facility is similar to, but more general than, the @i[syntax tables] of
+other editors such as @f[EMACS]. For example, you should use character
+attributes for commands that need information regarding whether a character is
+@i[whitespace] or not. Use character attributes for these reasons:
+@begin(enumerate)
+If this information is all in one place, then it is easy the change the
+behavior of the editor by changing the syntax table, much easier than it would
+be if character constants were wired into commands.
+
+This centralization of information avoids needless duplication of effort.
+
+The syntax table primitives are probably faster than anything that can be
+written above the primitive level.
+@end(enumerate)
+
+Note that an essential part of the character attribute scheme is that
+@i[character attributes are global and are there for the user to change.]
+Information about characters which is internal to some set of commands (and
+which the user should not know about) should not be maintained as a character
+attribute. For such uses various character searching abilities are provided by
+the function @funref[find-pattern].
+
+@defcon[var {syntax-char-code-limit}]
+The exclusive upper bound on character codes which are significant in
+the character attribute functions. Font and bits are always ignored.
+@enddefcon
+
+
+@section(Character Attribute Names)
+
+As for @hemlock variables, character attributes have a user visible
+string name, but are referred to in Lisp code as a symbol. The string
+name, which is typically composed of capitalized words separated by
+spaces, is translated into a keyword by replacing all spaces with
+hyphens and interning this string in the keyword package. The
+attribute named @hid[Ada Syntax] would thus become @kwd[ada-syntax].
+
+@defvar[var {character-attribute-names}]
+Whenever a character attribute is defined, its name is entered in
+this string table (page @pageref[string-tables]), with the
+corresponding keyword as the value.
+@enddefvar
+
+
+@section(Character Attribute Functions)
+
+@defun[fun {defattribute}, args
+ {@i[name] @i[documentation] @optional @i[type] @i[initial-value]}]
+ This function defines a new character attribute with @i[name], a
+simple-string. Character attribute operations take attribute arguments as a
+keyword whose name is @i[name] uppercased with spaces replaced by hyphens.
+
+@i[Documentation] describes the uses of the character attribute.
+
+@i[Type], which defaults to @w<@f[(mod 2)]>, specifies what type the values of
+the character attribute are. Values of a character attribute may be of any
+type which may be specified to @f[make-array]. @i[Initial-value] (default
+@f[0]) is the value which all characters will initially have for this
+attribute.
+@enddefun
+
+@defun[fun {character-attribute-name}, args {@i[attribute]}]
+@defun1[fun {character-attribute-documentation}, args {@i[attribute]}]
+These functions return the name or documentation for @i[attribute].
+@enddefun
+
+@defun[fun {character-attribute}, args {@i[attribute] @i[character]}]
+@defhvar1[var {Character Attribute Hook}]
+@f[character-attribute] returns the value of @i[attribute] for @i[character].
+This signals an error if @i[attribute] is undefined.
+
+@f[setf] will set a character's attributes. This @f[setf] method invokes the
+functions in @hid[Character Attribute Hook] on the attribute and character
+before it makes the change.
+
+If @i[character] is @nil, then the value of the attribute for the beginning or
+end of the buffer can be accessed or set. The buffer beginning and end thus
+become a sort of fictitious character, which simplifies the use of character
+attributes in many cases.
+@enddefun
+
+@defun[fun {character-attribute-p}, args {@i[symbol]}]
+This function returns @true if @i[symbol] is the name of a character attribute,
+@nil otherwise.
+@enddefun
+
+@defun[fun {shadow-attribute}, args
+{@i[attribute] @i[character] @i[value] @i[mode]}]
+@defhvar1[var {Shadow Attribute Hook}]
+This function establishes @i[value] as the value of @i[character]'s
+@i[attribute] attribute when in the mode @i[mode]. @i[Mode] must be the name
+of a major mode. @hid[Shadow Attribute Hook] is invoked with the same
+arguments when this function is called. If the value for an attribute is set
+while the value is shadowed, then only the shadowed value is affected, not the
+global one.
+@enddefun
+
+@defun[fun {unshadow-attribute}, args {@i[attribute] @i[character] @i[mode]}]
+@defhvar1[var {Unshadow Attribute Hook}]
+Make the value of @i[attribute] for @i[character] no longer be shadowed in
+@i[mode]. @hid[Unshadow Attribute Hook] is invoked with the same arguments
+when this function is called.
+@enddefun
+
+@defun[fun {find-attribute},
+ args {@i[mark] @i[attribute] @optional @i[test]}]
+@defun1[fun {reverse-find-attribute},
+ args {@i[mark] @i[attribute] @optional @i[test]}]
+ These functions find the next (or previous) character with some value for the
+character attribute @i[attribute] starting at @i[mark]. They pass @i[Test] one
+argument, the value of @i[attribute] for the character tested. If the test
+succeeds, then these routines modify @i[mark] to point before (after for
+@f[reverse-find-attribute]) the character which satisfied the test. If no
+characters satisfy the test, then these return @nil, and @i[mark] remains
+unmodified. @i[Test] defaults to @f[not zerop]. There is no guarantee that
+the test is applied in any particular fashion, so it should have no side
+effects and depend only on its argument.
+@enddefun
+
+
+@section(Character Attribute Hooks)
+
+It is often useful to use the character attribute mechanism as an abstract
+interface to other information about characters which in fact is stored
+elsewhere. For example, some implementation of @hemlock might decide to define
+a @hid[Print Representation] attribute which controls how a character is
+displayed on the screen.
+
+To make this easy to do, each attribute has a list of hook functions
+which are invoked with the attribute, character and new value whenever
+the current value changes for any reason.
+
+@defun[fun {character-attribute-hooks}, args {@i[attribute]}]
+Return the current hook list for @i[attribute]. This may be set with
+@f[setf]. The @f[add-hook] and @macref[remove-hook] macros should
+be used to manipulate these lists.
+@enddefun
+
+
+@section (System Defined Character Attributes)
+@label(sys-def-chars)
+These are predefined in @hemlock:
+@begin[description]
+@hid[Whitespace]@\
+A value of @f[1] indicates the character is whitespace.
+
+@hid[Word Delimiter]@\
+A value of @f[1] indicates the character separates words (see section
+@ref[text-functions]).
+
+@hid[Digit]@\
+A value of @f[1] indicates the character is a base ten digit. This may be
+shadowed in modes or buffers to mean something else.
+
+@hid[Space]@\
+This is like @hid[Whitespace], but it should not include @binding[Newline].
+@hemlock uses this primarily for handling indentation on a line.
+
+@hid[Sentence Terminator]@\
+A value of @f[1] indicates these characters terminate sentences (see section
+@ref[text-functions]).
+
+@hid[Sentence Closing Char]@\
+A value of @f[1] indicates these delimiting characters, such as @binding["]
+or @binding[)], may follow a @hid[Sentence Terminator] (see section
+@ref[text-functions]).
+
+@hid[Paragraph Delimiter]@\
+A value of @f[1] indicates these characters delimit paragraphs when they begin
+a line (see section @ref[text-functions]).
+
+@hid[Page Delimiter]@\
+A value of @f[1] indicates this character separates logical pages (see section
+@ref[logical-pages]) when it begins a line.
+
+@hid[Scribe Syntax]@\
+This uses the following symbol values:
+@begin[multiple]
+@begin[description]
+@nil@\These characters have no interesting properties.
+
+@kwd[escape]@\This is @binding[@@] for the Scribe formatting language.
+
+@kwd[open-paren]@\These characters begin delimited text.
+
+@kwd[close-paren]@\These characters end delimited text.
+
+@kwd[space]@\These characters can terminate the name of a formatting command.
+
+@kwd[newline]@\These characters can terminate the name of a formatting command.
+@end[description]
+@end[multiple]
+
+
+@hid[Lisp Syntax]@\
+This uses symbol values from the following:
+@begin[multiple]
+@begin[description]
+@nil@\These characters have no interesting properties.
+
+@kwd[space]@\These characters act like whitespace and should not include
+@binding[Newline].
+
+@kwd[newline]@\This is the @binding[Newline] character.
+
+@kwd[open-paren]@\This is @binding[(] character.
+
+@kwd[close-paren]@\This is @binding[)] character.
+
+@kwd[prefix]@\This is a character that is a part of any form it precedes @dash
+for example, the single quote, @binding['].
+
+@kwd[string-quote]@\This is the character that quotes a string literal,
+@binding["].@comment["]
+
+@kwd[char-quote]@\This is the character that escapes a single character,
+@binding[\].
+
+@kwd[comment]@\This is the character that makes a comment with the rest of the
+line, @binding[;].
+
+@kwd[constituent]@\These characters are constitute symbol names.
+@end[description]
+@end[multiple]
+
+@end[description]
+
+
+
+@chapter (Controlling the Display)
+@section (Windows)
+@tag[windows]
+@index(Windows)
+@index(modelines)
+
+A window is a mechanism for displaying part of a buffer on some physical
+device. A window is a way to view a buffer but is not synonymous with one; a
+buffer may be viewed in any number of windows. A window may have a
+@i[modeline] which is a line of text displayed across the bottom of a window to
+indicate status information, typically related to the buffer displayed.
+
+
+@section (The Current Window)
+@index (Current window)
+@defun[fun {current-window}, args {}]
+@defhvar1[var {Set Window Hook}]
+@f[current-window] returns the window in which the cursor is currently
+displayed. The cursor always tracks the buffer-point of the corresponding
+buffer. If the point is moved to a position which would be off the screen the
+recentering process is invoked. Recentering shifts the starting point of the
+window so that the point is once again displayed. The current window may be
+changed with @f[setf]. Before the current window is changed, the hook @hid[Set
+Window Hook] is invoked with the new value.
+@enddefun
+
+@defvar[var {window-list}]
+Holds a list of all the window objects made with @funref[make-window].
+@enddefvar
+
+
+@section(Window Functions)
+
+@defun[fun {make-window}, args {@i[mark]},
+ keys {[modelinep][window][ask-user]},
+ morekeys {[x][y][width][height]},
+ morekeys {[proportion]}]
+@defhvar1[var {Default Window Width}]
+@defhvar1[var {Default Window Height}]
+@defhvar1[var {Make Window Hook}]
+
+@comment[NOTE, we purposefully do not document the font-family or device
+ arguments since we don't officially support fonts or devices.]
+
+@f[make-window] returns a window displaying text starting at @i[mark], which
+must point into a buffer. If it could not make a window on the device, it
+returns nil. The default action is to make the new window a proportion of the
+@f[current-window]'s height to make room for the new window.
+
+@i[Modelinep] specifies whether the window should display buffer modelines.
+
+@i[Window] is a device dependent window to be used with the Hemlock window.
+The device may not support this argument. @i[Window] becomes the parent window
+for a new group of windows that behave in a stack orientation as windows do on
+the terminal.
+
+If @i[ask-user] is non-@nil, @hemlock prompts the user for the missing
+dimensions (@i[x], @i[y], @i[width], and @i[height]) to make a new group of
+windows, as with the @i[window] argument. The device may not support this
+argument. Non-null values other than @f[t] may have device dependent meanings.
+@i[X] and @i[y] are in pixel units, but @i[width] and @i[height] are characters
+units. @hid[Default Window Width] and @hid[Default Window Height] are the
+default values for the @i[width] and @i[height] arguments.
+
+@i[Proportion] determines what proportion of the @f[current-window]'s height
+the new window will use. The @f[current-window] retains whatever space left
+after accommodating the new one. The default is to split the window in half.
+
+This invokes @hid[Make Window Hook] with the new window.
+@enddefun
+
+@defun[fun {windowp}, args {@i[window]}]
+This function returns @true if @i[window] is a @f[window] object, otherwise
+@nil.
+@enddefun
+
+@defun[fun {delete-window}, args {@i[window]}]
+@defhvar1[var {Delete Window Hook}]
+@f[delete-window] makes @i[window] go away, first invoking @hid[Delete Window
+Hook] with @i[window].
+@enddefun
+
+@defun[fun {window-buffer}, args {@i[window]}]
+@defhvar1[var {Window Buffer Hook}]
+@f[window-buffer] returns the buffer from which the window displays
+text. This may be changed with @f[setf], in which case the hook
+@hid[Window Buffer Hook] is invoked beforehand with the window and the
+new buffer.
+@enddefun
+
+@defun[fun {window-display-start}, args {@i[window]}]
+@defun1[fun {window-display-end}, args {@i[window]}]
+@f[window-display-start] returns the mark that points before the first
+character displayed in @i[window]. Note that if @i[window] is the current
+window, then moving the start may not prove much, since recentering may move it
+back to approximately where it was originally.
+
+@f[window-display-end] is similar, but points after the last character
+displayed. Moving the end is meaningless, since redisplay always moves it to
+after the last character.
+@enddefun
+
+@defun[fun {window-display-recentering}, args {@i[window]}]
+This function returns whether redisplay will ensure the buffer's point of
+@i[window]'s buffer is visible after redisplay. This is @f[setf]'able, and
+changing @i[window]'s buffer sets this to @nil via @hid[Window Buffer Hook].
+@enddefun
+
+@defun[fun {window-point}, args {@i[window]}]
+This function returns as a mark the position in the buffer where the cursor is
+displayed. This may be set with @f[setf]. If @i[window] is the current
+window, then setting the point will have little effect; it is forced to track
+the buffer point. When the window is not current, the window point is the
+position that the buffer point will be moved to when the window becomes
+current.
+@enddefun
+
+@defun[fun {center-window}, args {@i[window] @i[mark]}]
+This function attempts to adjust window's display start so the that @i[mark] is
+vertically centered within the window.
+@enddefun
+
+@defun[fun {scroll-window}, args {@i[window] @i[n]}]
+This function scrolls the window down @i[n] display lines; if @i[n] is negative
+scroll up. Leave the cursor at the same text position unless we scroll it off
+the screen, in which case the cursor is moved to the end of the window closest
+to its old position.
+@enddefun
+
+@defun[fun {displayed-p}, args {@i[mark] @i[window]}]
+Returns @true if either the character before or the character after @i[mark]
+is being displayed in @i[window], or @nil otherwise.
+@enddefun
+
+@defun[fun {window-height}, args {@i[window]}]
+@defun1[fun {window-width}, args {@i[window]}]
+Height or width of the area of the window used for displaying the
+buffer, in character positions. These values may be changed with
+@f[setf], but the setting attempt may fail, in which case nothing is done.
+@enddefun
+
+@defun[fun {next-window}, args {@i[window]}]
+@defun1[fun {previous-window}, args {@i[window]}]
+Return the next or previous window of @i[window]. The exact meaning of next
+and previous depends on the device displaying the window. It should be
+possible to cycle through all the windows displayed on a device using either
+next or previous (implying that these functions wrap around.)
+@enddefun
+
+
+@section(Cursor Positions)
+@index(Cursor positions)
+A cursor position is an absolute position within a window's coordinate
+system. The origin is in the upper-left-hand corner and the unit
+is character positions.
+
+@defun[fun {mark-to-cursorpos}, args {@i[mark] @i[window]}]
+Returns as multiple values the @f[X] and @f[Y] position on which
+@i[mark] is being displayed in @i[window], or @nil if it is not within the
+bounds displayed.
+@enddefun
+
+@defun[fun {cursorpos-to-mark}, args {@i[X] @i[Y] @i[window]}]
+Returns as a mark the text position which corresponds to the given
+(@i[X], @i[Y]) position within window, or @nil if that
+position does not correspond to any text within @i[window].
+@enddefun
+
+@defun[fun {last-key-event-cursorpos}]
+Interprets mouse input. It returns as multiple values the (@i[X], @i[Y])
+position and the window where the pointing device was the last time some key
+event happened. If the information is unavailable, this returns @nil.
+@enddefun
+
+@defun[fun {mark-column}, args {@i[mark]}]
+This function returns the @i[X] position at which @i[mark] would be displayed,
+supposing its line was displayed on an infinitely wide screen. This takes into
+consideration strange characters such as tabs.
+@enddefun
+
+@defun[fun {move-to-column}, args {@i[mark] @i[column] @optional @i[line]}]
+This function is analogous to @funref[move-to-position], except that
+it moves @i[mark] to the position on @i[line] which corresponds to the
+specified @i[column]. @i[Line] defaults to the line that @i[mark] is
+currently on. If the line would not reach to the specified column,
+then @nil is returned and @i[mark] is not modified. Note that since a
+character may be displayed on more than one column on the screen,
+several different values of @i[column] may cause @i[mark] to be moved
+to the same position.
+@enddefun
+
+@defun[fun {show-mark}, args {@i[mark] @i[window] @i[time]}]
+This function highlights the position of @i[mark] within @i[window] for
+@i[time] seconds, possibly by moving the cursor there. The wait may be aborted
+if there is pending input. If @i[mark] is positioned outside the text
+displayed by @i[window], then this returns @nil, otherwise @true.
+@enddefun
+
+
+@section(Redisplay)
+Redisplay translates changes in the internal representation of text into
+changes on the screen. Ideally this process finds the minimal transformation
+to make the screen correspond to the text in order to maximize the speed of
+redisplay.
+
+@defun[fun {redisplay}]
+@defhvar1[var "Redisplay Hook"]
+@f[redisplay] executes the redisplay process, and @hemlock typically invokes
+this whenever it looks for input. The redisplay process frequently checks for
+input, and if it detects any, it aborts. The return value is interpreted as
+follows:
+@begin[description]
+@false@\No update was needed.
+
+@true@\Update was needed, and completed successfully.
+
+@kwd[editor-input]@\Update is needed, but was aborted due to pending input.
+@end[description]
+
+This function invokes the functions in @hid[Redisplay Hook] on the current
+window after computing screen transformations but before executing them. After
+invoking the hook, this recomputes the redisplay and then executes it on the
+current window.
+
+For the current window and any window with @f[window-display-recentering] set,
+@f[redisplay] ensures the buffer's point for the window's buffer is visible
+after redisplay.
+@enddefun
+
+@defun[fun {redisplay-all}]
+This causes all editor windows to be completely redisplayed. For the current
+window and any window with @f[window-display-recentering] set, this ensures the
+buffer's point for the window's buffer is visible after redisplay. The return
+values are the same as for redisplay, except that @false is never returned.
+@enddefun
+
+@defun[fun {editor-finish-output}, args {@i[window]}]
+This makes sure the editor is synchronized with respect to redisplay output to
+@i[window]. This may do nothing on some devices.
+@enddefun
+
+
+
+@chapter(Logical Key-Events)
+@label[logical-key-events]
+@index[Logical key-events]
+
+
+@section[Introduction]
+Some primitives such as @funref[prompt-for-key] and commands such as EMACS
+query replace read key-events directly from the keyboard instead of using the
+command interpreter. To encourage consistency between these commands and to
+make them portable and easy to customize, there is a mechanism for defining
+@i[logical key-events].
+
+A logical key-event is a keyword which stands for some set of key-events. The
+system globally interprets these key-events as indicators a particular action.
+For example, the @kwd[help] logical key-event represents the set of key-events
+that request help in a given @hemlock implementation. This mapping is a
+many-to-many mapping, not one-to-one, so a given logical key-event may have
+multiple corresponding actual key-events. Also, any key-event may represent
+different logical key-events.
+
+
+@section[Logical Key-Event Functions]
+
+@defvar[var {logical-key-event-names}]
+This variable holds a string-table mapping all logical key-event names to the
+keyword identifying the logical key-event.
+@enddefvar
+
+@defun[fun {define-logical-key-event}, args {@i[string-name] @i[documentation]}]
+ This function defines a new logical key-event with name @i[string-name], a
+simple-string. Logical key-event operations take logical key-events arguments
+as a keyword whose name is @i[string-name] uppercased with spaces replaced by
+hyphens.
+
+@i[Documentation] describes the action indicated by the logical key-event.
+@enddefun
+
+@defun[fun {logical-key-event-key-events}, args {@i[keyword]}]
+This function returns the list of key-events representing the logical key-event
+@i[keyword].
+@enddefun
+
+@defun[fun {logical-key-event-name}, args {@i[keyword]}]
+@defun1[fun {logical-key-event-documentation}, args {@i[keyword]}]
+These functions return the string name and documentation given to
+@f[define-logical-key-event] for logical key-event @i[keyword].
+@enddefun
+
+@defun[fun {logical-key-event-p}, args {@i[key-event] @i[keyword]}]
+This function returns @f[t] if @i[key-event] is the logical key-event
+@i[keyword]. This is @f[setf]'able establishing or disestablishing key-events
+as particular logical key-events. It is a error for @i[keyword] to be an
+undefined logical key-event.
+@enddefun
+
+
+@section[System Defined Logical Key-Events]
+There are many default logical key-events, some of which are used by functions
+documented in this manual. If a command wants to read a single key-event
+command that fits one of these descriptions then the key-event read should be
+compared to the corresponding logical key-event instead of explicitly
+mentioning the particular key-event in the code. In many cases you can use the
+@macref[command-case] macro. It makes logical key-events easy to use and takes
+care of prompting and displaying help messages.
+
+@begin[description]
+@kwd[yes]@\
+ Indicates the prompter should take the action under consideration.
+
+@kwd[no]@\
+ Indicates the prompter should NOT take the action under consideration.
+
+@kwd[do-all]@\
+ Indicates the prompter should repeat the action under consideration as many
+times as possible.
+
+@kwd[do-once]@\
+ Indicates the prompter should execute the action under consideration once and
+then exit.
+
+@kwd[exit]@\
+ Indicates the prompter should terminate its activity in a normal fashion.
+
+@kwd[abort]@\
+ Indicates the prompter should terminate its activity without performing any
+closing actions of convenience, for example.
+
+@kwd[keep]@\
+ Indicates the prompter should preserve something.
+
+@kwd[help]@\
+ Indicates the prompter should display some help information.
+
+@kwd[confirm]@\
+ Indicates the prompter should take any input provided or use the default if
+the user entered nothing.
+
+@kwd[quote]@\
+ Indicates the prompter should take the following key-event as itself without
+any sort of command interpretation.
+
+@kwd[recursive-edit]@\
+ Indicates the prompter should enter a recursive edit in the current context.
+
+@kwd[cancel]@\
+ Indicates the prompter should cancel the effect of a previous key-event input.
+
+@kwd[forward-search]@\
+ Indicates the prompter should search forward in the current context.
+
+@kwd[backward-search]@\
+ Indicates the prompter should search backward in the current context.
+@end[description]
+
+@blankspace(1 line)
+Define a new logical key-event whenever:
+@begin[enumerate]
+The key-event concerned represents a general class of actions, and
+several commands may want to take a similar action of this type.
+
+The exact key-event a command implementor chooses may generate violent taste
+disputes among users, and then the users can trivially change the command in
+their init files.
+
+You are using @f[command-case] which prevents implementors from specifying
+non-standard characters for dispatching in otherwise possibly portable code,
+and you can define and set the logical key-event in a site dependent file where
+you can mention implementation dependent characters.
+@end[enumerate]
+
+
+
+@chapter(The Echo Area)
+
+@hemlock provides a number of facilities for displaying information and
+prompting the user for it. Most of these work through a small window displayed
+at the bottom of the screen. This is called the echo area and is supported by
+a buffer and a window. This buffer's modeline (see section @ref[modelines]) is
+referred to as the status line, which, unlike other buffers' modelines, is used
+to show general status about the editor, Lisp, or world.
+
+@defhvar[var {Default Status Line Fields}]
+This is the initial list of modeline-field objects stored in the echo area
+buffer.
+@enddefhvar
+
+@defhvar[var "Echo Area Height", val {3}]
+This variable determines the initial height in lines of the echo area window.
+@enddefhvar
+
+
+@section(Echo Area Functions)
+It is considered poor taste to perform text operations on the echo area buffer
+to display messages; the @f[message] function should be used instead. A
+command must use this function or set @funref[buffer-modified] for the
+@hid[Echo Area] buffer to @nil to cause @hemlock to leave text in the echo area
+after the command's execution.
+
+@defun[fun {clear-echo-area}]
+Clears the echo area.
+@enddefun
+
+@defun[fun {message}, args {@i[control-string] @rest @i[format-arguments]}]
+@defun1[fun {loud-message}, args {@i[control-string] @rest @i[format-arguments]}]
+@defhvar1[var {Message Pause}, val {0.5}]
+Displays a message in the echo area. The message is always displayed on a
+fresh line. @f[message] pauses for @hid[Message Pause] seconds before
+returning to assure that messages are not displayed too briefly to be seen.
+Because of this, @f[message] is the best way to display text in the echo area.
+
+@f[loud-message] is like @f[message], but it first clears the echo area and
+beeps.
+@enddefun
+
+@defvar[var {echo-area-window}]
+@defvar1[var {echo-area-buffer}]
+@f[echo-area-buffer] contains the buffer object for the echo area, which is
+named @hid[Echo Area]. This buffer is usually in @hid[Echo Area] mode.
+@f[echo-area-window] contains a window displaying @f[echo-area-buffer]. Its
+modeline is the status line, see the beginning of this chapter.
+@enddefvar
+
+@defvar[var {echo-area-stream}]
+@index (Echo area)
+This is a buffered @hemlock output stream
+(@pageref[make-hemlock-output-stream-fun]) which inserts text written to it at
+the point of the echo area buffer. Since this stream is buffered a
+@f[force-output] must be done when output is complete to assure that it is
+displayed.
+@enddefvar
+
+
+@section(Prompting Functions)
+@index(Prompting functions)
+Most of the prompting functions accept the following keyword arguments:
+@begin(description)
+@kwd[must-exist] @\If @kwd[must-exist] has a non-@nil value then the
+user is prompted until a valid response is obtained. If
+@kwd[must-exist] is @nil then return as a string whatever is input.
+The default is @true.
+
+@kwd[default] @\If null input is given when the user is prompted
+then this value is returned. If no default is given then
+some input must be given before anything interesting will happen.
+
+@kwd[default-string] @\If a @kwd[default] is given then this is a
+string to be printed to indicate what the default is. The default is
+some representation of the value for @kwd[default], for example for a
+buffer it is the name of the buffer.
+
+@kwd[prompt] @\This is the prompt string to display.
+
+@kwd[help] @\@multiple{
+This is similar to @kwd[prompt], except that it is displayed when
+the help command is typed during input. @comment{If there is some known number
+of options as in keyword parses, then they may be displayed, depending
+on the setting of @hvarref[Help Show Options].}
+
+This may also be a function. When called with no arguments, it should either
+return a string which is the help text or perform some action to help the user,
+returning @Nil.}
+@end(description)
+
+@defun[fun {prompt-for-buffer}, keys {[prompt][help][must-exist][default]},
+ morekeys {[default-string]}]
+Prompts with completion for a buffer name and returns the corresponding buffer.
+If @i[must-exist] is @nil, then it returns the input string if it is not a
+buffer name. This refuses to accept the empty string as input when
+@kwd[default] and @kwd[default-string] are @nil. @kwd[default-string] may be
+used to supply a default buffer name when @kwd[default] is @nil, but when
+@kwd[must-exist] is non-@nil, it must name an already existing buffer.
+@enddefun
+
+@defmac[fun {command-case}, Args {(@mstar<@i[key] @i[value]>) @Mstar<(@Mgroup"(@MSTAR'@i[tag]') @MOR @i[tag]" @i[help] @MSTAR'@i[form]')>}]
+ This macro is analogous to the Common Lisp @f[case] macro. Commands such as
+@hid[Query Replace] use this to get a key-event, translate it to a character,
+and then to dispatch on the character to some case. In addition to character
+dispatching, this supports logical key-events @w<(page
+@pageref[logical-key-events])> by using the input key-event directly without
+translating it to a character. Since the description of this macro is rather
+complex, first consider the following example:
+@lisp
+(defcommand "Save All Buffers" (p)
+ "Give the User a chance to save each modified buffer."
+ "Give the User a chance to save each modified buffer."
+ (dolist (b *buffer-list*)
+ (select-buffer-command () b)
+ (when (buffer-modified b)
+ (command-case (:prompt "Save this buffer: [Y] "
+ :help "Save buffer, or do something else:")
+ ((:yes :confirm)
+ "Save this buffer and go on to the next."
+ (save-file-command () b))
+ (:no "Skip saving this buffer, and go on to the next.")
+ (:recursive-edit
+ "Go into a recursive edit in this buffer."
+ (do-recursive-edit) (reprompt))
+ ((:exit #\p) "Punt this silly loop."
+ (return nil))))))
+@endlisp
+
+@f[command-case] prompts for a key-event and then executes the code in the
+first branch with a logical key-event or a character (called @i[tags]) matching
+the input. Each character must be a standard-character, one that satisfies the
+Common Lisp @f[standard-char-p] predicate, and the dispatching mechanism
+compares the input key-event to any character tags by mapping the key-event to
+a character with @f[ext:key-event-char]. If the tag is a logical key-event,
+then the search for an appropriate case compares the key-event read with the
+tag using @f[logical-key-event-p].
+
+All uses of @f[command-case] have two default cases, @kwd[help] and
+@kwd[abort]. You can override these easily by specifying your own branches
+that include these logical key-event tags. The @kwd[help] branch displays in a
+pop-up window the a description of the valid responses using the variously
+specified help strings. The @kwd[abort] branch signals an editor-error.
+
+The @i[key]/@i[value] arguments control the prompting. The following are valid
+values:
+@begin[description]
+@kwd[help]@\
+ The default @kwd[help] case displays this string in a pop-up window. In
+addition it formats a description of the valid input including each case's
+@i[help] string.
+
+@kwd[prompt]@\
+ This is the prompt used when reading the key-event.
+
+@kwd[change-window]@\
+ If this is non-nil (the default), then the echo area window becomes the
+current window while the prompting mechanism reads a key-event. Sometimes it
+is desirable to maintain the current window since it may be easier for users to
+answer the question if they can see where the current point is.
+
+@kwd[bind]@\
+ This specifies a variable to which the prompting mechanism binds the input
+key-event. Any case may reference this variable. If you wish to know what
+character corresponds to the key-event, use @f[ext:key-event-char].
+@end(description)
+
+Instead of specifying a tag or list of tags, you may use @true. This becomes
+the default branch, and its forms execute if no other branch is taken,
+including the default @kwd[help] and @kwd[abort] cases. This option has no
+@i[help] string, and the default @kwd[help] case does not describe the default
+branch. Every @f[command-case] has a default branch; if none is specified, the
+macro includes one that @f[system:beep]'s and @f[reprompt]'s (see below).
+
+Within the body of @f[command-case], there is a defined @f[reprompt] macro.
+It causes the prompting mechanism and dispatching mechanism to immediately
+repeat without further execution in the current branch.
+@enddefmac
+
+
+@defun[fun {prompt-for-key-event}, keys {[prompt][change-window]}]
+This function prompts for a key-event returning immediately when the user types
+the next key-event. @macref[command-case] is more useful for most purposes.
+When appropriate, use logical key-events @w<(page
+@pageref[logical-key-events])>.
+@enddefun
+
+@defun[fun {prompt-for-key}, keys {[prompt][help][must-exist][default]},
+ morekeys {[default-string]}]
+ This function prompts for a @i[key], a vector of key-events, suitable for
+passing to any of the functions that manipulate key bindings @w<(page
+@pageref[key-bindings])>. If @i[must-exist] is true, then the key must be
+bound in the current environment, and the command currently bound is returned
+as the second value.
+@enddefun
+
+@defun[fun {prompt-for-file}, keys {[prompt][help][must-exist][default]},
+ morekeys {[default-string]}]
+ This function prompts for an acceptable filename in some system dependent
+fashion. "Acceptable" means that it is a legal filename, and it exists if
+@i[must-exist] is non-@nil. @f[prompt-for-file] returns a Common Lisp
+pathname.
+
+If the file exists as entered, then this returns it, otherwise it is merged
+with @i[default] as by @f[merge-pathnames].
+@enddefun
+
+@defun[fun {prompt-for-integer}, keys {[prompt][help][must-exist][default]},
+ morekeys {[default-string]}]
+ This function prompts for a possibly signed integer. If @i[must-exist] is
+@nil, then @f[prompt-for-integer] returns the input as a string if it is not a
+valid integer.
+@enddefun
+
+@defun[fun {prompt-for-keyword}, args {@i[string-tables]},
+ keys {[prompt][help][must-exist]},
+ morekeys {[default][default-string]}]
+ This function prompts for a keyword with completion, using the string tables
+in the list @i[string-tables]. If @I[must-exist] is non-@nil, then the result
+must be an unambiguous prefix of a string in one of the @i[string-tables], and
+the returns the complete string even if only a prefix of the full string was
+typed. In addition, this returns the value of the corresponding entry in the
+string table as the second value.
+
+If @i[must-exist] is @nil, then this function returns the string exactly as
+entered. The difference between @f[prompt-for-keyword] with @i[must-exist]
+@nil, and @f[prompt-for-string], is the user may complete the input using the
+@hid and @hid commands.
+@enddefun
+
+@defun[fun {prompt-for-expression},
+ keys {[prompt][help][must-exist][default]},
+ morekeys {[default-string]}]
+ This function reads a Lisp expression. If @i[must-exist] is @nil, and a read
+error occurs, then this returns the string typed.
+@enddefun
+
+@defun[fun {prompt-for-string}, keys
+{[prompt][help][default][default-string]}]
+ This function prompts for a string; this cannot fail.
+@enddefun
+
+@defun[fun {prompt-for-variable}, keys {[prompt][help][must-exist][default]},
+ morekeys {[default-string]}]
+ This function prompts for a variable name. If @i[must-exist] is non-@nil,
+then the string must be a variable @i[defined in the current environment], in
+which case the symbol name of the variable found is returned as the second
+value.
+@enddefun
+
+@defun[fun {prompt-for-y-or-n}, keys {[prompt][help][must-exist][default]},
+ morekeys {[default-string]}]
+ This prompts for @binding[y], @binding[Y], @binding[n], or @binding[N],
+returning @true or @nil without waiting for confirmation. When the user types
+a confirmation key, this returns @i[default] if it is supplied. If
+@i[must-exist] is @nil, this returns whatever key-event the user first types;
+however, if the user types one of the above key-events, this returns @true or
+@nil. This is analogous to the Common Lisp function @f[y-or-n-p].
+@enddefun
+
+@defun[fun {prompt-for-yes-or-no}, keys {[prompt][help][must-exist][default]},
+ morekeys {[default-string]}]
+ This function is to @f[prompt-for-y-or-n] as @f[yes-or-no-p] is to
+@f[y-or-n-p]. "Yes" or "No" must be typed out in full and
+confirmation must be given.
+@enddefun
+
+
+@section(Control of Parsing Behavior)
+
+@defhvar[var {Beep On Ambiguity}, val {@true}]
+If this variable is true, then an attempt to complete a parse which is
+ambiguous will result in a "beep".
+@enddefhvar
+
+
+@begin(comment)
+@hemlock provides for limited control of parsing routine behaviour The
+character attribute @hid[Parse Field Separator] is a boolean attribute, a value
+of @f[1] indicating that the character is a field separator recognized by the
+@hid command.
+@end(comment)
+
+@begin(comment)
+@defhvar[var {Help Show Options}]
+During a keyword or similar parse, typing the help command may cause a
+list of options to be displayed. If displaying the help would take up
+more lines than the value of this variable then confirmation will be
+asked for before they will be displayed.
+@enddefhvar
+@end(comment)
+
+
+
+@section(Defining New Prompting Functions)
+Prompting functions are implemented as a recursive edit in the
+@hid[Echo Area] buffer. Completion, help, and other parsing features
+are implemented by commands which are bound in @hid[Echo Area Mode].
+
+A prompting function passes information down into the recursive edit
+by binding a collection of special variables.
+
+@defvar[var {parse-verification-function}]
+The system binds this to a function that @comref[Confirm Parse] calls. It does
+most of the work when parsing prompted input. @comref[Confirm Parse] passes
+one argument, which is the string that was in @var when the
+user invokes the command. The function should return a list of values which
+are to be the result of the recursive edit, or @nil indicating that the parse
+failed. In order to return zero values, a non-@nil second value may be
+returned along with a @nil first value.
+@enddefvar
+
+@defvar[var {parse-string-tables}]
+This is the list of @f[string-table]s, if any, that pertain to this parse.
+@enddefvar
+
+@defvar[var {parse-value-must-exist}]
+This is bound to the value of the @kwd[must-exist] argument, and is
+referred to by the verification function, and possibly some of the
+commands.
+@enddefvar
+
+@defvar[var {parse-default}]
+When prompting the user, this is bound to a string representing the default
+object, the value supplied as the @kwd[default] argument. @hid
+supplies this to the parse verification function when the
+@var is empty.
+@enddefvar
+
+@defvar[var {parse-default-string}]
+When prompting the user, if @var[parse-default] is @nil, @hemlock displays this
+string as a representation of the default object; for example, when prompting
+for a buffer, this variable would be bound to the buffer name.
+@enddefvar
+
+@defvar[var {parse-type}]
+The kind of parse in progress, one of @kwd[file], @kwd[keyword] or
+@kwd[string]. This tells the completion commands how to do completion, with
+@kwd[string] disabling completion.
+@enddefvar
+
+@defvar[var {parse-prompt}]
+The prompt being used for the current parse.
+@enddefvar
+
+@defvar[var {parse-help}]
+The help string or function being used for the current parse.
+@enddefvar
+
+@defvar[var {parse-starting-mark}]
+This variable holds a mark in the @varref[echo-area-buffer] which
+is the position at which the parse began.
+@enddefvar
+
+@defvar[var {parse-input-region}]
+This variable holds a region with @var[parse-starting-mark] as its
+start and the end of the echo-area buffer as its end. When
+@hid[Confirm Parse] is called, the text in this region is the text
+that will be parsed.
+@enddefvar
+
+
+@section(Some Echo Area Commands)
+
+These are some of the @hid[Echo Area] commands that coordinate with the
+prompting routines. @Hemlock binds other commands specific to the @hid[Echo
+Area], but they are uninteresting to mention here, such as deleting to the
+beginning of the line or deleting backwards a word.
+
+@defcom[com {Help On Parse},
+ stuff (bound to @bf[Home, C-_] in @hid[Echo Area] mode)]
+Display the help text for the parse currently in progress.
+@enddefcom
+
+@defcom[com {Complete Keyword},
+ stuff (bound to @bf[Escape] in @hid[Echo Area] mode)]
+This attempts to complete the current region as a keyword in
+@var[string-tables]. It signals an editor-error if the input is ambiguous
+or incorrect.
+@enddefcom
+
+@defcom[com {Complete Field},
+ stuff (bound to @bf[Space] in @hid[Echo Area] mode)]
+Similar to @hid[Complete Keyword], but only attempts to complete up to and
+including the first character in the keyword with a non-zero
+@kwd[parse-field-separator] attribute. If
+there is no field separator then attempt to complete the entire keyword.
+If it is not a keyword parse then just self-insert.
+@enddefcom
+
+@defcom[com {Confirm Parse},
+ stuff (bound to @bf[Return] in @hid[Echo Area] mode)]
+If @var[string-tables] is non-@nil find the string in the region in
+them. Call @var[parse-verification-function] with the current input.
+If it returns a non-@nil value then that is returned as the value of
+the parse. A parse may return a @nil value if the verification
+function returns a non-@nil second value.
+@enddefcom
+
+
+
+@chapter (Files)
+@index (Files)
+This chapter discusses ways to read and write files at various levels @dash at
+marks, into regions, and into buffers. This also treats automatic mechanisms
+that affect the state of buffers in which files are read.
+
+@section (File Options and Type Hooks)
+@index (File options)
+@index (Type hooks)
+@index (File type hooks)
+The user specifies file options with a special syntax on the first line of a
+file. If the first line contains the string "@f[-*-]", then @hemlock
+interprets the text between the first such occurrence and the second, which
+must be contained in one line , as a list of @w{"@f<@i[option]: @i[value]>"}
+pairs separated by semicolons. The following is a typical example:
+@begin[programexample]
+;;; -*- Mode: Lisp, Editor; Package: Hemlock -*-
+@end[programexample]
+See the @i[Hemlock User's Manual] for more details and predefined options.
+
+File type hooks are executed when @hemlock reads a file into a buffer based on
+the type of the pathname. When the user specifies a @hid[Mode] file option
+that turns on a major mode, @hemlock ignores type hooks. This mechanism is
+mostly used as a simple means for turning on some appropriate default major
+mode.
+
+@defmac[fun {define-file-option}, args
+{@i[name] (@i[buffer] @i[value]) @mstar<@i[declaration]> @mstar<@i[form]>}]
+This defines a new file option with the string name @i[name]. @i[Buffer] and
+@i[value] specify variable names for the buffer and the option value string,
+and @i[form]'s are evaluated with these bound.
+@enddefmac
+
+@defmac[fun {define-file-type-hook}, args
+{@i[type-list] (@i[buffer] @i[type]) @mstar<@i[declaration]> @mstar<@i[form]>}]
+
+This defines some code that @f[process-file-options] (below) executes when the
+file options fail to set a major mode. This associates each type, a
+@f[simple-string], in @i[type-list] with a routine that binds @i[buffer] to the
+buffer the file is in and @i[type] to the type of the pathname.
+@enddefmac
+
+@defun[fun {process-file-options}, args {@i[buffer] @optional @i[pathname]}]
+This checks for file options in buffer and invokes handlers if there are any.
+@i[Pathname] defaults to @i[buffer]'s pathname but may be @nil. If there is no
+@hid[Mode] file option that specifies a major mode, and @i[pathname] has a
+type, then this tries to invoke the appropriate file type hook.
+@f[read-buffer-file] calls this.
+@enddefun
+
+
+@section (Pathnames and Buffers)
+There is no good way to uniquely identify buffer names and pathnames. However,
+@hemlock has one way of mapping pathnames to buffer names that should be used
+for consistency among customizations and primitives. Independent of this,
+@hemlock provides a means for consistently generating prompting defaults when
+asking the user for pathnames.
+
+@defun[fun {pathname-to-buffer-name}, args {@i[pathname]}]
+This function returns a string of the form "@f[file-namestring]
+@f[directory-namestring]".
+@enddefun
+
+@defhvar[var "Pathname Defaults", val {(pathname "gazonk.del")}]
+@defhvar1[var "Last Resort Pathname Defaults Function"]
+@defhvar1[var "Last Resort Pathname Defaults", val {(pathname "gazonk")}]
+These variables control the computation of default pathnames when needed for
+promting the user. @hid[Pathname Defaults] is a @i[sticky] default.
+See the @i[Hemlock User's Manual] for more details.
+@enddefhvar
+
+@defun[fun {buffer-default-pathname}, args {@i[buffer]}]
+This returns @hid[Buffer Pathname] if it is bound. If it is not bound, and
+@i[buffer]'s name is composed solely of alphnumeric characters, then return a
+pathname formed from @i[buffer]'s name. If @i[buffer]'s name has other
+characters in it, then return the value of @hid[Last Resort Pathname Defaults
+Function] called on @i[buffer].
+@enddefun
+
+@section (File Groups)
+@index (File groups)
+File groups provide a simple way of collecting the files that compose a system
+and naming that collection. @Hemlock supports commands for searching,
+replacing, and compiling groups.
+
+@defvar[var {active-file-group}]
+This is the list of files that constitute the currently selected file group.
+If this is @nil, then there is no current group.
+@enddefvar
+
+@defmac[fun {do-active-group}, args {@mstar<@i[form]>}]
+@defhvar1[var "Group Find File", val {nil}]
+@defhvar1[var "Group Save File Confirm", val {t}]
+@f[do-active-group] iterates over @var[active-file-group] executing the forms
+once for each file. While the forms are executing, the file is in the current
+buffer, and the point is at the beginning. If there is no active group, this
+signals an editor-error.
+
+This reads each file into its own buffer using @f[find-file-buffer]. Since
+unwanted buffers may consume large amounts of memory, @hid[Group Find File]
+controls whether to delete the buffer after executing the forms. When the
+variable is false, this deletes the buffer if it did not previously exist;
+however, regardless of this variable, if the user leaves the buffer modified,
+the buffer persists after the forms have completed. Whenever this processes a
+buffer that already existed, it saves the location of the buffer's point before
+and restores it afterwards.
+
+After processing a buffer, if it is modified, @f[do-active-group] tries to save
+it. If @hid[Group Save File Confirm] is non-@nil, it asks for confirmation.
+@enddefmac
+
+
+@section (File Reading and Writing)
+Common Lisp pathnames are used by the file primitives. For probing, checking
+write dates, and so forth, all of the Common Lisp file functions are available.
+
+@defun[fun {read-file}, args {@i[pathname] @i[mark]}]
+This inserts the file named by @i[pathname] at @i[mark].
+@enddefun
+
+@defun[fun {write-file}, args {@i[region] @i[pathname]},
+ keys {[keep-backup][access][append]}]
+@defhvar1[var {Keep Backup Files}, val {@nil}]
+This function writes the contents of @i[region] to the file named by
+@i[pathname]. This writes @i[region] using a stream as if it were opened with
+@kwd[if-exists] supplied as @kwd[rename-and-delete].
+
+When @i[keep-backup], which defaults to the value of @hid[Keep Backup Files],
+is non-@nil, this opens the stream as if @kwd[if-exists] were @kwd[rename]. If
+@i[append] is non-@nil, this writes the file as if it were opened with
+@kwd[if-exists] supplied as @kwd[append].
+
+This signals an error if both @i[append] and @i[keep-backup] are supplied as
+non-@nil.
+
+@i[Access] is an implementation dependent value that is suitable for setting
+@i[pathname]'s access or protection bits.
+@enddefun
+
+
+@defun[fun {write-buffer-file}, args {@i[buffer] @i[pathname]}]
+@defhvar1[var {Write File Hook}]
+@defhvar1[var {Add Newline at EOF on Writing File}, val {@kwd[ask-user]}]
+@f[write-buffer-file] writes @i[buffer] to the file named by @i[pathname]
+including the following:
+@begin[itemize]
+It assumes pathname is somehow related to @i[buffer]'s pathname: if the
+@i[buffer]'s write date is not the same as @i[pathname]'s, then this prompts
+the user for confirmation before overwriting the file.
+
+It consults @hid[Add Newline at EOF on Writing File] (see @i[Hemlock User's
+Manual] for possible values) and interacts with the user if necessary.
+
+It sets @hid[Pathname Defaults], and after using @f[write-file], marks
+@i[buffer] unmodified.
+
+It updates @i[Buffer]'s pathname and write date.
+
+It renames the buffer according to the new pathname if possible.
+
+It invokes @hid[Write File Hook].
+@end[itemize]
+
+@hid[Write File Hook] is a list of functions that take the newly written buffer
+as an argument.
+@enddefun
+
+
+@defun[fun {read-buffer-file}, args {@i[pathname] @i[buffer]}]
+@defhvar1[var {Read File Hook}]
+@f[read-buffer-file] deletes @i[buffer]'s region and uses @f[read-file] to read
+@i[pathname] into it, including the following:
+@begin[itemize]
+It sets @i[buffer]'s write date to the file's write date if the file exists;
+otherwise, it @f[message]'s that this is a new file and sets @i[buffer]'s write
+date to @nil.
+
+It moves @i[buffer]'s point to the beginning.
+
+It sets @i[buffer]'s unmodified status.
+
+It sets @i[buffer]'s pathname to the result of probing @i[pathname] if the file
+exists; otherwise, this function sets @i[buffer]'s pathname to the result of
+merging @i[pathname] with @f[default-directory].
+
+It sets @hid[Pathname Defaults] to the result of the previous item.
+
+It processes the file options.
+
+It invokes @hid[Read File Hook].
+@end[itemize]
+
+@hid[Read File Hook] is a list functions that take two arguments @dash the
+buffer read into and whether the file existed, @true if so.
+@enddefun
+
+
+@defun[fun {find-file-buffer}, args {@i[pathname]}]
+This returns a buffer assoicated with the @i[pathname], reading the file into a
+new buffer if necessary. This returns a second value indicating whether a new
+buffer was created, @true if so. If the file has already been read, this
+checks to see if the file has been modified on disk since it was read, giving
+the user various recovery options. This is the basis of the @hid[Find File]
+command.
+@enddefun
+
+
+
+@chapter (Hemlock's Lisp Environment)
+
+@index (Lisp environment)
+This chapter is sort of a catch all for any functions and variables
+which concern @hemlock's interaction with the outside world.
+
+@section(Entering and Leaving the Editor)
+
+@defun[fun {ed}, args {@optional @i[x]}]
+@defhvar1[var "Entry Hook"]
+@f[ed] enters the editor. It is basically as specified in Common Lisp. If
+@i[x] is supplied and is a symbol, the definition of @i[x] is put into a
+buffer, and that buffer is selected. If @i[x] is a pathname, the file
+specified by @i[x] is visited in a new buffer. If @i[x] is not supplied or
+@nil, the editor is entered in the same state as when last exited.
+
+The @hid[Entry Hook] is invoked each time the editor is entered.
+@enddefhvar
+
+@defun[fun {exit-hemlock}, args {@optional @i[value]}]
+@defhvar1[var {Exit Hook}]
+@f[exit-hemlock] leaves @hemlock and return to Lisp; @i[value] is the
+value to return, which defaults to @true. The hook
+@hvarref[Exit Hook] is invoked before this is done.
+@enddefun
+
+@defun[fun {pause-hemlock}]
+@f[pause-hemlock] suspends the editor process and returns control to the shell.
+When the process is resumed, it will still be running @hemlock.
+@enddefun
+
+
+@section(Keyboard Input)
+@index(I/O)
+@index[keyboard input]
+@index[input, keyboard]
+
+Keyboard input interacts with a number of other parts of the editor. Since the
+command loop works by reading from the keyboard, keyboard input is the initial
+cause of everything that happens. Also, @hemlock redisplays in the low-level
+input loop when there is no available input from the user.
+
+
+@defvar[var {editor-input}]
+@defvar1[var {real-editor-input}]
+@defhvar1[var "Input Hook"]
+@defhvar1[var "Abort Hook"]
+@index[aborting]
+@var[editor-input] is an object on which @hemlock's I/O routines operate. You
+can get input, clear input, return input, and listen for input. Input appears
+as key-events.
+
+@var[real-editor-input] holds the initial value of @var[editor-input]. This is
+useful for reading from the user when @var[editor-input] is rebound (such as
+within a keyboard macro.)
+
+@Hemlock invokes the functions in @hid[Input Hook] each time someone reads a
+key-event from @var[real-editor-input]. These take no arguments.
+@enddefvar
+
+@defun[fun {get-key-event}, args {@i[editor-input] @optional @i[ignore-abort-attempts-p]}]
+This function returns a key-event as soon as it is available on
+@i[editor-input]. @i[Editor-input] is either @var[editor-input] or
+@var[real-editor-input]. @i[Ignore-abort-attempts-p] indicates whether
+@binding[C-g] and @binding[C-G] throw to the editor's top-level command loop;
+when this is non-nil, this function returns those key-events when the user
+types them. Otherwise, it aborts the editor's current state, returning to the
+command loop.
+
+When the user aborts, @Hemlock invokes the functions in @hid[Abort Hook].
+These functions take no arguments. When aborting, @Hemlock ignores the
+@hid[Input Hook].
+@enddefun
+
+
+@defun[fun {unget-key-event}, args {@i[key-event] @i[editor-input]}]
+This function returns @i[key-event] to @i[editor-input], so the next invocation
+of @f[get-key-event] will return @i[key-event]. If @i[key-event] is
+@f[#k"C-g"] or @f[#k"C-G"], then whether @f[get-key-event] returns it depends
+on that function's second argument. @i[Editor-input] is either
+@var[editor-input] or @var[real-editor-input].
+@enddefun
+
+@defun[fun {clear-editor-input}, args {@i[editor-input]}]
+This function flushes any pending input on @i[editor-input]. @i[Editor-input]
+is either @var[editor-input] or @var[real-editor-input].
+@enddefun
+
+@defun[fun {listen-editor-input}, args {@i[editor-input]}]
+This function returns whether there is any input available on @i[editor-input].
+@i[Editor-input] is either @var[editor-input] or @var[real-editor-input].
+@enddefun
+
+@defun[fun {editor-sleep}, args {@i[time]}]
+Return either after @i[time] seconds have elapsed or when input is available on
+@var[editor-input].
+@enddefun
+
+@defvar[var {key-event-history}]
+This is a @hemlock ring buffer (see page @pageref[rings]) that holds the last
+60 key-events read from the keyboard.
+@enddefvar
+
+@defvar[var {last-key-event-typed}]
+Commands use this variable to realize the last key-event the user typed to
+invoke the commands. Before @hemlock ever reads any input, the value is @nil.
+This variable usually holds the last key-event read from the keyboard, but it
+is also maintained within keyboard macros allowing commands to behave the same
+on each repetition as they did in the recording invocation.
+@enddefvar
+
+@defvar[var {input-transcript}]
+If this is non-@nil then it should be an adjustable vector with a fill-pointer.
+When it is non-@nil, @hemlock pushes all input read onto this vector.
+@enddefvar
+
+
+
+@section(Hemlock Streams)
+It is possible to create streams which output to or get input from a buffer.
+This mechanism is quite powerful and permits easy interfacing of @hemlock to
+Lisp.
+
+@defun[fun {make-hemlock-output-stream}, args
+ {@i[mark] @optional @i[buffered]}]
+@defun1[fun {hemlock-output-stream-p}, args {@i[object]}]
+@f[make-hemlock-output-stream] returns a stream that inserts at the permanent
+mark @i[mark] all output directed to it. @i[Buffered] controls whether the
+stream is buffered or not, and its valid values are the following keywords:
+@begin[description]
+@kwd[none]@\No buffering is done. This is the default.
+
+@kwd[line]@\The buffer is flushed whenever a newline is written or
+when it is explicitly done with @f[force-output].
+
+@kwd[full]@\The screen is only brought up to date when it is
+explicitly done with @f[force-output]
+@end[description]
+
+@f[hemlock-output-stream-p] returns @true if @i[object] is a
+@f[hemlock-output-stream] object.
+@enddefun
+
+@defun[fun {make-hemlock-region-stream}, args {@i[region]}]
+@defun1[fun {hemlock-region-stream-p}, args {@i[object]}]
+@f[make-hemlock-region-stream] returns a stream from which the text in
+@i[region] can be read. @f[hemlock-region-stream-p] returns @true if
+@i[object] is a @f[hemlock-region-stream] object.
+@enddefun
+
+@defmac[fun {with-input-from-region}, args
+{(@i[var] @i[region]) @mstar<@i[declaration]> @mstar<@i[form]>}]
+While evaluating @i[form]s, binds @i[var] to a stream which returns input
+from @i[region].
+@enddefmac
+
+@defmac[fun {with-output-to-mark}, args
+{(@i[var] @i[mark] @mopt<@i"buffered">) @mstar<@i[declaration]> @mstar<@i[form]>}]
+ During the evaluation of the @i[form]s, binds @i[var] to a stream which
+inserts output at the permanent @i[mark]. @i[Buffered] has the same meaning as
+for @f[make-hemlock-output-stream].
+@enddefmac
+
+@defmac[fun {with-pop-up-display}, args {(@i[var] @key @i[height name]) @mstar<@i[declaration]> @mstar<@i[form]>}]
+@defvar1[var {random-typeout-buffers}]
+ This macro executes @i[forms] in a context with @i[var] bound to a stream.
+@Hemlock collects output to this stream and tries to pop up a display of the
+appropriate height containing all the output. When @i[height] is supplied,
+@Hemlock creates the pop-up display immediately, forcing output on line breaks.
+The system saves the output in a buffer named @i[name], which defaults to
+@hid[Random Typeout]. When the window is the incorrect height, the display
+mechanism will scroll the window with more-style prompting. This is useful
+for displaying information of temporary interest.
+
+When a buffer with name @i[name] already exists and was not previously created
+by @f[with-pop-up-display], @Hemlock signals an error.
+
+@var[random-typeout-buffers] is an association list mapping random typeout
+buffers to the streams that operate on the buffers.
+@enddefmac
+
+
+@section (Interface to the Error System)
+The error system interface is minimal. There is a simple editor-error
+condition which is a subtype of error and a convenient means for signaling
+them. @Hemlock also provides a standard handler for error conditions while in
+the editor.
+
+@defun[fun {editor-error-format-string}, args {@i[condition]}]
+@defun1[fun {editor-error-format-arguments}, args {@i[condition]}]
+Handlers for editor-error conditions can access the condition object with
+these.
+@enddefun
+
+@defun[fun {editor-error}, args {@rest @i[args]}]
+This function is called to signal minor errors within Hemlock; these are errors
+that a normal user could encounter in the course of editing such as a search
+failing or an attempt to delete past the end of the buffer. This function
+@f[signal]'s an editor-error condition formed from @i[args], which are @nil or
+a @f[format] string possibly followed by @f[format] arguments. @Hemlock
+invokes commands in a dynamic context with an editor-error condition handler
+bound. This default handler beeps or flashes (or both) the display. If the
+condition passed to the handler has a non-@nil string slot, the handler also
+invokes @f[message] on it. The command in progress is always aborted, and this
+function never returns.
+@enddefun
+
+@defmac[fun {handle-lisp-errors}, args {@mstar<@i[form]>}]
+Within the body of this macro any Lisp errors that occur are handled in some
+fashion more gracefully than simply dumping the user in the debugger. This
+macro should be wrapped around code which may get an error due to some action
+of the user @dash for example, evaluating code fragments on the behalf of and
+supplied by the user. Using this in a command allows the established handler
+to shadow the default editor-error handler, so commands should take care to
+signal user errors (calls to @f[editor-errors]) outside of this context.
+@enddefmac
+
+
+@section (Definition Editing)
+@index (Definition editing)
+@hemlock provides commands for finding the definition of a function, macro, or
+command and placing the user at the definition in a buffer. This, of course,
+is implementation dependent, and if an implementation does not associate a
+source file with a routine, or if @hemlock cannot get at the information, then
+these commands do not work. If the Lisp system does not store an absolute
+pathname, independent of the machine on which the maintainer built the system,
+then users need a way of translating a source pathname to one that will be able
+to locate the source.
+
+@defun[fun {add-definition-dir-translation}, args {@i[dir1] @i[dir2]}]
+This maps directory pathname @i[dir1] to @i[dir2]. Successive invocations
+using the same @i[dir1] push into a translation list. When @hemlock seeks a
+definition source file, and it has a translation, then it tries the
+translations in order. This is useful if your sources are on various machines,
+some of which may be down. When @hemlock tries to find a translation, it first
+looks for translations of longer directory pathnames, finding more specific
+translations before shorter, more general ones.
+@enddefun
+
+@defun[fun {delete-definition-dir-translation}, args {@i[dir]}]
+This deletes the mapping of @i[dir] to all directories to which it has been
+mapped.
+@enddefun
+
+
+@section (Event Scheduling)
+@index (Event scheduling)
+@index (Scheduling events)
+The mechanism described in this chapter is only operative when the Lisp process
+is actually running inside of @hemlock, within the @f[ed] function. The
+designers intended its use to be associated with the editor, such as with
+auto-saving files, reminding the user, etc.
+
+@defun[fun {schedule-event}, args {@i[time] @i[function] @optional @i[repeat]}]
+This causes @hemlock to call @i[function] after @i[time] seconds have passed,
+optionally repeating every @i[time] seconds. @i[Repeat] defaults to @true.
+This is a rough mechanism since commands can take an arbitrary amount of time
+to run; @hemlock invokes @i[function] at the first possible moment after
+@i[time] has elapsed. @i[Function] takes the time in seconds that has elapsed
+since the last time it was called (or since it was scheduled for the first
+invocation).
+@enddefun
+
+@defun[fun {remove-scheduled-event}, args {@i[function]}]
+This removes @i[function] from the scheduling queue. @i[Function] does not
+have to be in the queue.
+@enddefun
+
+
+@section (Miscellaneous)
+
+@defun[fun {in-lisp}, args {@mstar<@i[form]>}]
+@index[Evaluating Lisp code]
+This evaluates @i[form]'s inside @f[handle-lisp-errors]. It also binds
+@var[package] to the package named by @hid[Current Package] if it is non-@nil.
+Use this when evaluating Lisp code on behalf of the user.
+@enddefun
+
+@defmac[fun {do-alpha-chars}, args {(@i[var] @i[kind] [@i[result]]) @mstar<@i[form]>}]
+This iterates over alphabetic characters in Common Lisp binding @i[var] to each
+character in order as specified under character relations in @i[Common Lisp the
+Language]. @i[Kind] is one of @kwd[lower], @kwd[upper], or @kwd[both]. When
+the user supplies @kwd[both], lowercase characters are processed first.
+@enddefmac
+
+
+
+@chapter (High-Level Text Primitives)
+This chapter discusses primitives that operate on higher level text forms than
+characters and words. For English text, there are functions that know about
+sentence and paragraph structures, and for Lisp sources, there are functions
+that understand this language. This chapter also describes mechanisms for
+organizing file sections into @i[logical pages] and for formatting text forms.
+
+
+@section (Indenting Text)
+@index (Indenting)
+@label(indenting)
+
+@defhvar[var "Indent Function", val {tab-to-tab-stop}]
+The value of this variable determines how indentation is done, and it is a
+function which is passed a mark as its argument. The function should indent
+the line that the mark points to. The function may move the mark around on
+the line. The mark will be @f[:left-inserting]. The default simply inserts a
+@binding[tab] character at the mark. A function for @hid[Lisp] mode probably
+moves the mark to the beginning of the line, deletes horizontal whitespace, and
+computes some appropriate indentation for Lisp code.
+@enddefhvar
+
+@defhvar[var "Indent with Tabs", val {indent-using-tabs}]
+@defhvar1[var "Spaces per Tab", val {8}]
+@hid[Indent with Tabs] holds a function that takes a mark and a number of
+spaces. The function will insert a maximum number of tabs and a minimum number
+of spaces at mark to move the specified number of columns. The default
+definition uses @hid[Spaces per Tab] to determine the size of a tab. @i[Note,]
+@hid[Spaces per Tab] @i[is not used everywhere in @hemlock yet, so changing
+this variable could have unexpected results.]
+@enddefhvar
+
+@defun[fun {indent-region}, args {@i[region]}]
+@defun1[fun {indent-region-for-commands}, args {@i[region]}]
+@f[indent-region] invokes the value of @hid[Indent Function] on every line of
+region. @f[indent-region-for-commands] uses @f[indent-region] but first saves
+the region for the @hid[Undo] command.
+@enddefun
+
+@defun[fun {delete-horizontal-space}, args {@i[mark]}]
+This deletes all characters with a @hid[Space] attribute (see section
+@ref[sys-def-chars]) of @f[1].
+@enddefun
+
+
+@section (Lisp Text Buffers)
+@index (Lisp text functions)
+@hemlock bases its Lisp primitives on parsing a block of the buffer and
+annotating lines as to what kind of Lisp syntax occurs on the line or what kind
+of form a mark might be in (for example, string, comment, list, etc.). These
+do not work well if the block of parsed forms is exceeded when moving marks
+around these forms, but the block that gets parsed is somewhat programmable.
+
+There is also a notion of a @i[top level form] which this documentation often
+uses synonymously with @i[defun], meaning a Lisp form occurring in a source
+file delimited by parentheses with the opening parenthesis at the beginning of
+some line. The names of the functions include this inconsistency.
+
+@defun[fun {pre-command-parse-check}, args {@i[mark] @i[for-sure]}]
+@defhvar1[var {Parse Start Function}, val {start-of-parse-block}]
+@defhvar1[var {Parse End Function}, val {end-of-parse-block}]
+@defhvar1[var {Minimum Lines Parsed}, val {50}]
+@defhvar1[var {Maximum Lines Parsed}, val {500}]
+@defhvar1[var {Defun Parse Goal}, val {2}]
+@f[pre-command-parse-check] calls @hid[Parse Start Function] and @hid[Parse End
+Function] on @i[mark] to get two marks. It then parses all the lines between
+the marks including the complete lines they point into. When @i[for-sure] is
+non-@nil, this parses the area regardless of any cached information about the
+lines. Every command that uses the following routines calls this before doing
+so.
+
+The default values of the start and end variables use @hid[Minimum Lines
+Parsed], @hid[Maximum Lines Parsed], and @hid[Defun Parse Goal] to determine
+how big a region to parse. These two functions always include at least the
+minimum number of lines before and after the mark passed to them. They try to
+include @hid[Defun Parse Goal] number of top level forms before and after the
+mark passed them, but these functions never return marks that include more than
+the maximum number of lines before or after the mark passed to them.
+@enddefun
+
+@defun[fun {form-offset}, args {@i[mark] @i[count]}]
+This tries to move @i[mark] @i[count] forms forward if positive or -@i[count]
+forms backwards if negative. @i[Mark] is always moved. If there were enough
+forms in the appropriate direction, this returns @i[mark], otherwise nil.
+@enddefun
+
+@defun[fun {top-level-offset}, args {@i[mark] @i[count]}]
+This tries to move @i[mark] @i[count] top level forms forward if positive or
+-@i[count] top level forms backwards if negative. If there were enough top
+level forms in the appropriate direction, this returns @i[mark], otherwise nil.
+@i[Mark] is moved only if this is successful.
+@enddefun
+
+@defun[fun {mark-top-level-form}, args {@i[mark1] @i[mark2]}]
+This moves @i[mark1] and @i[mark2] to the beginning and end, respectively, of
+the current or next top level form. @i[Mark1] is used as a reference to start
+looking. The marks may be altered even if unsuccessful. If successful, return
+@i[mark2], else nil. @i[Mark2] is left at the beginning of the line following
+the top level form if possible, but if the last line has text after the closing
+parenthesis, this leaves the mark immediately after the form.
+@enddefun
+
+@defun[fun {defun-region}, args {@i[mark]}]
+This returns a region around the current or next defun with respect to
+@i[mark]. @i[Mark] is not used to form the region. If there is no appropriate
+top level form, this signals an editor-error. This calls
+@f[pre-command-parse-check] first.
+@enddefun
+
+@defun[fun {inside-defun-p}, args {@i[mark]}]
+@defun1[fun {start-defun-p}, args {@i[mark]}]
+These return, respectively, whether @i[mark] is inside a top level form or at
+the beginning of a line immediately before a character whose @hid[Lisp Syntax]
+(see section @ref[sys-def-chars]) value is @kwd[opening-paren].
+@enddefun
+
+@defun[fun {forward-up-list}, args {@i[mark]}]
+@defun1[fun {backward-up-list}, args {@i[mark]}]
+Respectively, these move @i[mark] immediately past a character whose @hid[Lisp
+Syntax] (see section @ref[sys-def-chars]) value is @kwd[closing-paren] or
+immediately before a character whose @hid[Lisp Syntax] value is
+@kwd[opening-paren].
+@enddefun
+
+@defun[fun {valid-spot}, args {@i[mark] @i[forwardp]}]
+This returns @true or @nil depending on whether the character indicated by
+@i[mark] is a valid spot. When @i[forwardp] is set, use the character after
+mark and vice versa. Valid spots exclude commented text, inside strings, and
+character quoting.
+@enddefun
+
+@defun[fun {defindent}, args {@i[name] @i[count]}]
+This defines the function with @i[name] to have @i[count] special arguments.
+@f[indent-for-lisp], the value of @hid[Indent Function] (see section
+@ref[indenting]) in @hid[Lisp] mode, uses this to specially indent these
+arguments. For example, @f[do] has two, @f[with-open-file] has one, etc.
+There are many of these defined by the system including definitions for special
+@hemlock forms. @i[Name] is a simple-string, case insensitive and purely
+textual (that is, not read by the Lisp reader); therefore, @f["with-a-mumble"]
+is distinct from @f["mumble:with-a-mumble"].
+@enddefun
+
+
+@section (English Text Buffers)
+@index (English text functions)
+@label(text-functions)
+This section describes some routines that understand basic English language
+forms.
+
+@defun[fun {word-offset}, args {@i[mark] @i[count]}]
+This moves @i[mark] @i[count] words forward (if positive) or backwards (if
+negative). If @i[mark] is in the middle of a word, that counts as one. If
+there were @i[count] (-@i[count] if negative) words in the appropriate
+direction, this returns @i[mark], otherwise nil. This always moves @i[mark].
+A word lies between two characters whose @hid[Word Delimiter] attribute value
+is @f[1] (see section @ref[sys-def-chars]).
+@enddefun
+
+@defun[fun {sentence-offset}, args {@i[mark] @i[count]}]
+This moves @i[mark] @i[count] sentences forward (if positive) or backwards (if
+negative). If @i[mark] is in the middle of a sentence, that counts as one. If
+there were @i[count] (-@i[count] if negative) sentences in the appropriate
+direction, this returns @i[mark], otherwise nil. This always moves @i[mark].
+
+A sentence ends with a character whose @hid[Sentence Terminator] attribute is
+@f[1] followed by two spaces, a newline, or the end of the buffer. The
+terminating character is optionally followed by any number of characters whose
+@hid[Sentence Closing Char] attribute is @f[1]. A sentence begins after a
+previous sentence ends, at the beginning of a paragraph, or at the beginning of
+the buffer.
+@enddefun
+
+@defun[fun {paragraph-offset}, args {@i[mark] @i[count] @optional @i[prefix]}]
+@defhvar1[var {Paragraph Delimiter Function}, var {default-para-delim-function}]
+This moves @i[mark] @i[count] paragraphs forward (if positive) or backwards (if
+negative). If @i[mark] is in the middle of a paragraph, that counts as one.
+If there were @i[count] (-@i[count] if negative) paragraphs in the appropriate
+direction, this returns @i[mark], otherwise nil. This only moves @i[mark] if
+there were enough paragraphs.
+
+@hid[Paragraph Delimiter Function] holds a function that takes a mark,
+typically at the beginning of a line, and returns whether or not the current
+line should break the paragraph. @f[default-para-delim-function] returns @true
+if the next character, the first on the line, has a @hid[Paragraph Delimiter]
+attribute value of @f[1]. This is typically a space, for an indented
+paragraph, or a newline, for a block style. Some modes require a more
+complicated determinant; for example, @hid[Scribe] modes adds some characters
+to the set and special cases certain formatting commands.
+
+@i[Prefix] defaults to @hid[Fill Prefix] (see section @ref[filling]), and the
+right prefix is necessary to correctly skip paragraphs. If @i[prefix] is
+non-@nil, and a line begins with @i[prefix], then the scanning process skips
+the prefix before invoking the @hid[Paragraph Delimiter Function].
+Note, when scanning for paragraph bounds, and @i[prefix] is non-@nil, lines are
+potentially part of the paragraph regardless of whether they contain the prefix;
+only the result of invoking the delimiter function matters.
+
+The programmer should be aware of an idiom for finding the end of the current
+paragraph. Assume @f[paragraphp] is the result of moving @f[mark] one
+paragraph, then the following correctly determines whether there actually is a
+current paragraph:
+@begin[programexample]
+(or paragraphp
+ (and (last-line-p mark)
+ (end-line-p mark)
+ (not (blank-line-p (mark-line mark)))))
+@end[programexample]
+In this example @f[mark] is at the end of the last paragraph in the buffer, and
+there is no last newline character in the buffer. @f[paragraph-offset] would
+have returned @nil since it could not skip any paragraphs since @f[mark] was at
+the end of the current and last paragraph. However, you still have found a
+current paragraph on which to operate. @f[mark-paragraph] understands this
+problem.
+@enddefun
+
+@defun[fun {mark-paragraph}, args {@f[mark1] @f[mark2]}]
+This marks the next or current paragraph, setting @i[mark1] to the beginning
+and @i[mark2] to the end. This uses @hid[Fill Prefix] (see section
+@ref[filling]). @i[Mark1] is always on the first line of the paragraph,
+regardless of whether the previous line is blank. @i[Mark2] is typically at
+the beginning of the line after the line the paragraph ends on, this returns
+@i[mark2] on success. If this cannot find a paragraph, then the marks are left
+unmoved, and @nil is returned.
+@enddefun
+
+
+@section (Logical Pages)
+@index (Logical pages)
+@index (Page functions)
+@label(logical-pages)
+Logical pages are a way of dividing a file into coarse divisions. This is
+analogous to dividing a paper into sections, and @hemlock provides primitives
+for moving between the pages of a file and listing a directory of the page
+titles. Pages are separated by @hid[Page Delimiter] characters (see section
+@ref[sys-def-chars]) that appear at the beginning of a line.
+
+@defun[fun {goto-page}, args {@i[mark] @i[n]}]
+This moves @i[mark] to the absolute page numbered @i[n]. If there are less
+than @i[n] pages, it signals an editor-error. If it returns, it returns
+@i[mark]. @hemlock numbers pages starting with one for the page delimited by
+the beginning of the buffer and the first @hid[Page Delimiter] (or the end of
+the buffer).
+@enddefun
+
+@defun[fun {page-offset}, args {@i[mark] @i[n]}]
+This moves mark forward @i[n] (-@i[n] backwards, if @i[n] is negative)
+@hid[Page Delimiter] characters that are in the zero'th line position. If a
+@hid[Page Delimiter] is the immediately next character after mark (or before
+mark, if @i[n] is negative), then skip it before starting. This always moves
+@i[mark], and if there were enough pages to move over, it returns @i[mark];
+otherwise, it returns @nil.
+@enddefun
+
+@defun[fun {page-directory}, args {@i[buffer]}]
+This returns a list of each first non-blank line in @i[buffer] that follows a
+@hid[Page Delimiter] character that is in the zero'th line position. This
+includes the first line of the @i[buffer] as the first page title. If a page
+is empty, then its title is the empty string.
+@enddefun
+
+@defun[fun {display-page-directory}, args {@i[stream] @i[directory]}]
+This writes the list of strings, @i[directory], to @i[stream], enumerating them
+in a field three wide. The number and string are separated by two spaces, and
+the first line contains headings for the page numbers and title strings.
+@enddefun
+
+
+@section (Filling)
+@index (filling)
+@label(filling)
+Filling is an operation on text that breaks long lines at word boundaries
+before a given column and merges shorter lines together in an attempt to make
+each line roughly the specified length. This is different from justification
+which tries to add whitespace in awkward places to make each line exactly the
+same length. @Hemlock's filling optionally inserts a specified string at the
+beginning of each line. Also, it eliminates extra whitespace between lines and
+words, but it knows two spaces follow sentences (see section
+@ref[text-functions]).
+
+@defhvar[var "Fill Column", val {75}]
+@defhvar1[var "Fill Prefix", val {nil}]
+These variables hold the default values of the prefix and column arguments to
+@hemlock's filling primitives. If @hid[Fill Prefix] is @nil, then there is no
+fill prefix.
+@enddefhvar
+
+@defun[fun {fill-region}, args {@i[region] @optional @i[prefix] @i[column]}]
+This deletes any blank lines in region and fills it according to prefix and
+column. @i[Prefix] and @i[column] default to @hid[Fill Prefix] and @hid[Fill
+Column].
+@enddefun
+
+@defun[fun {fill-region-by-paragraphs},
+ args {@i[region] @optional @i[prefix] @i[column]}]
+This finds paragraphs (see section @ref[text-functions]) within region and
+fills them with @f[fill-region]. This ignores blank lines between paragraphs.
+@i[Prefix] and @i[column] default to @hid[Fill Prefix] and @hid[Fill Column].
+@enddefun
+
+
+
+@chapter (Utilities)
+@index (Utilities)
+This chapter describes a number of utilities for manipulating some types of
+objects @hemlock uses to record information. String-tables are used to store
+names of variables, commands, modes, and buffers. Ring lists can be used to
+provide a kill ring, recent command history, or other user-visible features.
+
+
+@section(String-table Functions)
+@index (String-tables)
+@label(string-tables)
+
+String tables are similar to Common Lisp hash tables in that they associate a
+value with an object. There are a few useful differences: in a string table
+the key is always a case insensitive string, and primitives are provided to
+facilitate keyword completion and recognition. Any type of string may be added
+to a string table, but the string table functions always return
+@f[simple-string]'s.
+
+A string entry in one of these tables may be thought of as being separated into
+fields or keywords. The interface provides keyword completion and recognition
+which is primarily used to implement some @hid[Echo Area] commands. These
+routines perform a prefix match on a field-by-field basis allowing the
+ambiguous specification of earlier fields while going on to enter later fields.
+While string tables may use any @f[string-char] as a separator, the use of
+characters other than @binding[space] may make the @hid[Echo Area] commands
+fail or work unexpectedly.
+
+@defun[fun {make-string-table}, keys {[separator][initial-contents]}]
+This function creates an empty string table that uses @i[separator] as the
+character, which must be a @f[string-char], that distinguishes fields.
+@i[Initial-contents] specifies an initial set of strings and their values in
+the form of a dotted @f[a-list], for example:
+@Begin[ProgramExample]
+'(("Global" . t) ("Mode" . t) ("Buffer" . t))
+@End[ProgramExample]
+@enddefun
+
+@defun[fun {string-table-p}, args {@i[string-table]}]
+This function returns @true if @i[string-table] is a @f[string-table] object,
+otherwise @nil.
+@enddefun
+
+@defun[fun {string-table-separator}, args {@i[string-table]}]
+This function returns the separator character given to @f[make-string-table].
+@enddefun
+
+@defun[fun {delete-string}, args {@i[string] @i[table]}]
+@defun1[fun {clrstring}, args {@i[table]}]
+@f[delete-string] removes any entry for @i[string] from the @f[string-table]
+@i[table], returning @true if there was an entry. @f[clrstring] removes all
+entries from @i[table].
+@enddefun
+
+@defun[fun {getstring}, args {@i[string] @i[table]}]
+This function returns as multiple values, first the value corresponding to the
+string if it is found and @nil if it isn't, and second @true if it is found and
+@nil if it isn't.
+
+This may be set with @f[setf] to add a new entry or to store a new value for a
+string. It is an error to try to insert a string with more than one
+field separator character occurring contiguously.
+@enddefun
+
+@defun[fun {complete-string}, args {@i[string] @i[tables]}]
+This function completes @i[string] as far as possible over the list of
+@i[tables], returning five values. It is an error for @i[tables] to have
+different separator characters. The five return values are as follows:
+@begin[itemize]
+The maximal completion of the string or @nil if there is none.
+
+An indication of the usefulness of the returned string:
+@begin[description]
+@kwd[none]@\
+There is no completion of @i[string].
+
+@kwd[complete]@\
+The completion is a valid entry, but other valid completions exist too. This
+occurs when the supplied string is an entry as well as initial substring of
+another entry.
+
+@kwd[unique]@\
+The completion is a valid entry and unique.
+
+@kwd[ambiguous]@\
+The completion is invalid; @f[get-string] would return @nil and @nil if given
+the returned string.
+@end[description]
+
+The value of the string when the completion is @kwd[unique] or @kwd[complete],
+otherwise @nil.
+
+An index, or nil, into the completion returned, indicating where the addition
+of a single field to @i[string] ends. The command @hid[Complete Field] uses
+this when the completion contains the addition to @i[string] of more than one
+field.
+
+An index to the separator following the first ambiguous field when the
+completion is @kwd[ambiguous] or @kwd[complete], otherwise @nil.
+@end[itemize]
+@enddefun
+
+@defun[fun {find-ambiguous}, args {@i[string] @i[table]}]
+@defun1[fun {find-containing}, args {@i[string] @i[table]}]
+@f[find-ambiguous] returns a list in alphabetical order of all the
+strings in @i[table] matching @i[string]. This considers an entry as matching
+if each field in @i[string], taken in order, is an initial substring of the
+entry's fields; entry may have fields remaining.
+
+@f[find-containing] is similar, but it ignores the order of the fields in
+@i[string], returning all strings in @i[table] matching any permutation of the
+fields in @i[string].
+@enddefun
+
+@defmac[fun {do-strings}, args {(@i[string-var] @i[value-var] @i[table] @MOPT<@i[result]>) @mstar<@i[declaration]> @mstar<@i[tag] @MOR @i[statement]>}]
+This macro iterates over the strings in @i[table] in alphabetical order. On
+each iteration, it binds @i[string-var] to an entry's string and @i[value-var]
+to an entry's value.
+@enddefmac
+
+
+@section (Ring Functions)
+@index (Rings)
+@label[rings]
+There are various purposes in an editor for which a ring of values can be used,
+so @hemlock provides a general ring buffer type. It is used for maintaining a
+ring of killed regions (see section @ref[kill-ring]), a ring of marks (see
+section @ref[mark-stack]), or a ring of command strings which various modes and
+commands maintain as a history mechanism.
+
+@defun[fun {make-ring}, args {@i[length] @optional @i[delete-function]}]
+Makes an empty ring object capable of holding up to @i[length] Lisp objects.
+@i[Delete-function] is a function that each object is passed to before it falls
+off the end. @i[Length] must be greater than zero.
+@enddefun
+
+@defun[fun {ringp}, args {@i[ring]}]
+Returns @true if @i[ring] is a @f[ring] object, otherwise @nil.
+@enddefun
+
+@defun[fun {ring-length}, args {@i[ring]}]
+Returns as multiple-values the number of elements which @i[ring]
+currently holds and the maximum number of elements which it may hold.
+@enddefun
+
+@defun[fun {ring-ref}, args {@i[ring] @i[index]}]
+Returns the @i[index]'th item in the @i[ring], where zero is the index
+of the most recently pushed. This may be set with @f[setf].
+@enddefun
+
+@defun[fun {ring-push}, args {@i[object] @i[ring]}]
+Pushes @i[object] into @i[ring], possibly causing the oldest item to
+go away.
+@enddefun
+
+@defun[fun {ring-pop}, args {@i[ring]}]
+Removes the most recently pushed object from @i[ring] and returns it.
+If the ring contains no elements then an error is signalled.
+@enddefun
+
+@defun[fun {rotate-ring}, args {@i[ring] @i[offset]}]
+With a positive @i[offset], rotates @i[ring] forward that many times.
+In a forward rotation the index of each element is reduced by one,
+except the one which initially had a zero index, which is made the
+last element. A negative offset rotates the ring the other way.
+@enddefun
+
+
+@section (Undoing commands)
+@index (Undo functions)
+@label(undo)
+
+@defun[fun {save-for-undo}, args {@i[name] @i[method] @optional @i[cleanup] @i[method-undo] @i[buffer]}]
+This saves information to undo a command. @i[Name] is a string to display when
+prompting the user for confirmation when he invokes the @hid[Undo] command (for
+example, @f["kill"] or @f["Fill Paragraph"]). @i[Method] is the function to
+invoke to undo the effect of the command. @i[Method-undo] is a function that
+undoes the undo function, or effectively re-establishes the state immediately
+after invoking the command. If there is any existing undo information, this
+invokes the @i[cleanup] function; typically @i[method] closes over or uses
+permanent marks into a buffer, and the @i[cleanup] function should delete such
+references. @i[Buffer] defaults to the @f[current-buffer], and the @hid[Undo]
+command only invokes undo methods when they were saved for the buffer that is
+current when the user invokes @hid[Undo].
+@enddefun
+
+@defun[fun {make-region-undo}, args {@i[kind] @i[name] @i[region] @optional @i[mark-or-region]}]
+This handles three common cases that commands fall into when setting up undo
+methods, including cleanup and method-undo functions (see @f[save-for-undo]).
+These cases are indicated by the @i[kind] argument:
+@begin[description]
+@kwd[twiddle]@\
+Use this kind when a command modifies a region, and the undo information
+indicates how to swap between two regions @dash the one before any modification
+occurs and the resulting region. @i[Region] is the resulting region, and it
+has permanent marks into the buffer. @i[Mark-or-region] is a region without
+marks into the buffer (for example, the result of @f[copy-region]). As a
+result of calling this, a first invocation of @hid[Undo] deletes @i[region],
+saving it, and inserts @i[mark-or-region] where @i[region] used to be. The
+undo method sets up for a second invocation of @hid[Undo] that will undo the
+effect of the undo; that is, after two calls, the buffer is exactly as it was
+after invoking the command. This activity is repeatable any number of times.
+This establishes a cleanup method that deletes the two permanent marks into the
+buffer used to locate the modified region.
+
+@kwd[insert]@\
+Use this kind when a command has deleted a region, and the undo information
+indicates how to re-insert the region. @i[Region] is the deleted and saved
+region, and it does not contain marks into any buffer. @i[Mark-or-region] is a
+permanent mark into the buffer where the undo method should insert @i[region].
+As a result of calling this, a first invocation of @hid[Undo] inserts
+@i[region] at @i[mark-or-region] and forms a region around the inserted text
+with permanent marks into the buffer. This allows a second invocation of
+@hid[Undo] to undo the effect of the undo; that is, after two calls, the buffer
+is exactly as it was after invoking the command. This activity is repeatable
+any number of times. This establishes a cleanup method that deletes either the
+permanent mark into the buffer or the two permanent marks of the region,
+depending on how many times the user used @hid[Undo].
+
+@kwd[delete]@\
+Use this kind when a command has inserted a block of text, and the undo
+information indicates how to delete the region. @i[Region] has permanent marks
+into the buffer and surrounds the inserted text. Leave @i[Mark-or-region]
+unspecified. As a result of calling this, a first invocation of @hid[Undo]
+deletes @i[region], saving it, and establishes a permanent mark into the buffer
+to remember where the @i[region] was. This allows a second invocation of
+@hid[Undo] to undo the effect of the undo; that is, after two calls, the buffer
+is exactly as it was after invoking the command. This activity is repeatable
+any number of times. This establishes a cleanup method that deletes either the
+permanent mark into the buffer or the two permanent marks of the region,
+depending on how many times the user used @hid[Undo].
+@end[description]
+
+@blankspace(1 line)
+@i[Name] in all cases is an appropriate string indicating what the command did.
+This is used by @hid[Undo] when prompting the user for confirmation before
+calling the undo method. The string used by @hid[Undo] alternates between this
+argument and something to indicate that the user is undoing an undo.
+@enddefun
+
+
+
+@chapter (Miscellaneous)
+This chapter is somewhat of a catch-all for comments and features that don't
+fit well anywhere else.
+
+
+@section (Generic Pointer Up)
+@hid[Generic Pointer Up] is a @hemlock command bound to mouse up-clicks. It
+invokes a function supplied with the interface described in this section. This
+command allows different commands to be bound to the same down-click in various
+modes with one command bound to the corresponding up-click.
+
+@defun[fun {supply-generic-pointer-up-function}, args {@i[function]}]
+@index[Generic Pointer Up]
+This function supplies a function that @hid[Generic Pointer Up] invokes the
+next time it executes.
+@enddefun
+
+
+@section (Using View Mode)
+@hid[View] mode supports scrolling through files automatically terminating the
+buffer at end-of-file as well as commands for quitting the mode and popping
+back to the buffer that spawned the @hid[View] mode buffer. Modes such as
+@hid[Dired] and @hid[Lisp-Lib] use this to view files and description of
+library entries.
+
+Modes that want similar commands should use @f[view-file-command] to view a
+file and get a handle on the view buffer. To allow the @hid[View Return] and
+@hid[View Quit] commands to return to the originating buffer, you must set the
+variable @hid[View Return Function] in the viewing buffer to a function that
+knows how to do this. Furthermore, since you now have a reference to the
+originating buffer, you must add a buffer local delete hook to it that will
+clear the view return function's reference. This needs to happen for two
+reasons in case the user deletes the originating buffer:
+@Begin[Enumerate]
+You don't want the return function to go to a non-existing, invalid buffer.
+
+Since the viewing buffer still exists, its @hid[View Return Function] buffer
+local variable still exists. This means the function still references the
+deleted originating buffer, and garbage collection cannot reclaim the memory
+locked down by the deleted buffer.
+@End[Enumerate]
+
+The following is a piece of code that could implement part of @hid[Dired View
+File] that uses two closures to accomplish that described above:
+@Begin[ProgramExample]
+(let* ((dired-buf (current-buffer))
+ (buffer (view-file-command nil pathname)))
+ (push #'(lambda (buffer)
+ (declare (ignore buffer))
+ (setf dired-buf nil))
+ (buffer-delete-hook dired-buf))
+ (setf (variable-value 'view-return-function :buffer buffer)
+ #'(lambda ()
+ (if dired-buf
+ (change-to-buffer dired-buf)
+ (dired-from-buffer-pathname-command nil)))))
+@End[ProgramExample]
+
+The @hid[Dired] buffer's delete hook clears the return function's reference to
+the @hid[Dired] buffer. The return function tests the variable to see if it
+still holds a buffer when the function executes.
+
+
+
+@comment[@chapter (Auxiliary Systems)]
+@include(aux-sys)
diff --git a/docs/hem/cim/cim.texi b/docs/hem/cim/cim.texi
new file mode 100644
index 0000000000000000000000000000000000000000..e342fc5fdf1d48098e88d5f32d23fe346eb87838
--- /dev/null
+++ b/docs/hem/cim/cim.texi
@@ -0,0 +1,52 @@
+\input texinfo
+
+@titlepage
+@title Hemlock Command Implementor's Manual
+@author Bill Chiles
+@author Rob MacLachlan
+@subtitle February 1992
+@subtitle CMU-CS-89-132-R1
+
+@center
+School of Computer Science
+Carnegie Mellon University
+Pittsburgh, PA 15213
+@end center
+
+@center
+This is a revised version of Technical Report CMU-CS-87-159.
+@end center
+
+@abstract
+This document describes how to write commands for the @Hemlock text editor, as
+of version M3.2. @Hemlock is a customizable, extensible text editor whose
+initial command set closely resembles that of ITS/TOPS-20 @Emacs. @Hemlock is
+written in the CMU Common Lisp and has been ported to other implementations.
+@end abstract
+
+This research was supported by the Defense Advanced Research Projects
+Agency (DOD), and monitored by the Avionics Laborotory, Air Force
+Wright Aeronatutical Laboratories, Aeronautical Systems Division
+(AFSC), Wright-Patterson AFB, Ohio 45344-6543 under Contract
+F33615-87-C-1499, ARPA Order No. 4976, Amendment 20.
+
+The views and conclusions contained in this document are those of the
+authros and should not be interpreted as respresnting the official
+policies, either rexpressed or implied, of the Defense Advanced
+Research Projects Agency or the U.S. government.
+
+@chapter
+@section Introduction
+Some primitives such as @funref[prompt-for-key] and commands such as EMACS
+query replace read key-events directly from the keyboard instead of using the
+command interpreter. To encourage consistency between these commands and to
+make them portable and easy to customize, there is a mechanism for defining
+@i[logical key-events].
+
+A logical key-event is a keyword which stands for some set of key-events. The
+system globally interprets these key-events as indicators a particular action.
+For example, the @kwd[help] logical key-event represents the set of key-events
+that request help in a given @hemlock implementation. This mapping is a
+many-to-many mapping, not one-to-one, so a given logical key-event may have
+multiple corresponding actual key-events. Also, any key-event may represent
+different logical key-events.
diff --git a/docs/hem/user/commands.mss b/docs/hem/user/commands.mss
new file mode 100644
index 0000000000000000000000000000000000000000..7d547bd04f4a89a5f4db8050f4d6b4eb07a12192
--- /dev/null
+++ b/docs/hem/user/commands.mss
@@ -0,0 +1,822 @@
+@comment{-*- Dictionary: hem; Mode: spell; Package: Hemlock -*-}
+@chap[Basic Commands]
+@section[Motion Commands]
+
+@index[commands, basic]@index[motion]There is a fairly small number of
+basic commands for moving around in the buffer. While there are many other
+more complex motion commands, these are by far the most commonly used and
+the easiest to learn.
+
+@defcom[com "Forward Character", bind (C-f, Rightarrow)]
+@defcom1[com "Backward Character", bind (C-b, Leftarrow)]
+@index[character, motion]
+@hid[Forward Character] moves the point forward by one character. If a prefix
+argument is supplied, then the point is moved by that many characters.
+@hid[Backward Character] is identical, except that it moves the point
+backwards.
+@enddefcom
+
+@defcom[com "Forward Word", bind {M-f}]
+@defcom1[com "Backward Word", bind {M-b}]
+@index[word, motion]These commands move the point forward and backward
+over words. The point is always left between the last word and first
+non-word character in the direction of motion. This means that after moving
+backward the cursor appears on the first character of the word, while after
+moving forward, the cursor appears on the delimiting character. Supplying
+a prefix argument moves the point by that many words.
+@enddefcom
+
+@defcom[com "Next Line", bind (C-n, Downarrow)]
+@defcom1[com "Previous Line", bind (C-p, Uparrow)]
+@defcom1[com "Goto Absolute Line"]
+@index[line, motion]
+@hid[Next Line] and @hid[Previous Line] move to adjacent lines, while remaining
+the same distance within a line. Note that this motion is by logical lines,
+each of which may take up many lines on the screen if it wraps. If a prefix
+argument is supplied, then the point is moved by that many lines.
+
+The position within the line at the start is recorded, and each successive
+use of @binding[C-p] or @binding[C-n] attempts to move the point to that
+position on the new line. If it is not possible to move to the recorded
+position because the line is shorter, then the point is left at the end of
+the line.
+
+@hid[Goto Absolute Line] moves to the indicated line, as if you counted them
+starting at the beginning of the buffer with number one. If the user supplies
+a prefix argument, it is the line number; otherwise, @Hemlock prompts the user
+for the line.
+@enddefcom
+
+@defcom[com "End of Line", bind {C-e}]
+@defcom1[com "Beginning of Line", bind {C-a}]
+@hid[End of Line] moves the point to the end of the current line, while
+@hid[Beginning of Line] moves to the beginning. If a prefix argument is
+supplied, then the point is moved to the end or beginning of the line that
+many lines below the current one.
+@enddefcom
+
+@defcom[com "Scroll Window Down", bind {C-v}]
+@defcom1[com "Scroll Window Up", bind {M-v}]
+@index[scrolling]
+@hid[Scroll Window Down] moves forward in the buffer by one screenful of text,
+the exact amount being determined by the size of the window. If a prefix
+argument is supplied, then this scrolls the screen that many lines. When this
+action scrolls the line with the point off the screen, it this command moves
+the point to the vertical center of the window. @hid[Scroll Window Up] is
+identical to @hid[Scroll Window Down], except that it moves backwards.
+@enddefcom
+
+@defhvar[var "Scroll Overlap", val {2}]
+This variable is used by @hid[Scroll Window Down] and @hid[Scroll Window Up] to
+determine the number of lines by which the new and old screen should overlap.
+@enddefhvar
+
+@defcom[com "End of Buffer", bind (M-<)]
+@defcom1[com "Beginning of Buffer", bind (@bf[M->])]
+These commands are used to conveniently get to the very beginning and end of the
+text in a buffer. Before the point is moved, its position is saved by
+pushing it on the mark stack (see page @pageref[marks]).
+@enddefcom
+
+@defcom[com "Top of Window", bind (M-,)]
+@defcom1[com "Bottom of Window", bind (M-.)]
+@index[window, motion]@hid[Top of Window] moves the point to the beginning of
+the first line displayed in the current window. @hid[Bottom of Window] moves
+to the beginning of the last line displayed.
+@enddefcom
+
+
+@section[The Mark and The Region]
+
+@label[marks]@index[marks]@index[region]@index[selection]Each buffer has a
+distinguished position known as the @i[mark]. The mark initially points to the
+beginning of the buffer. The area between the mark and the point is known as
+the @i[region]. Many @hemlock commands which manipulate large pieces of text
+use the text in the region. To use these commands, one must first use some
+command to mark the region.
+
+@index[active regions]Although the mark is always pointing somewhere (initially
+to the beginning of the buffer), region commands insist that the region be made
+@i[active] before it can be used. This prevents accidental use of a region
+command from mysteriously mangling large amounts of text.
+
+@defhvar[var "Active Regions Enabled", val {t}]
+When this variable is true, region commands beep unless the region is active.
+This may be set to @false for more traditional @emacs region semantics.
+@enddefhvar
+
+Once a marking command makes the region active, it remains active until:
+@begin[itemize]
+a command uses the region,
+
+a command modifies the buffer,
+
+a command changes the current window or buffer,
+
+a command signals an editor error,
+
+or the user types @binding[C-g].
+@end[itemize]
+Motion commands have the effect of redefining the region, since they move the
+point and leave the region active.
+
+@index[ephemerally active regions]Commands that insert a large chunk of
+text into the buffer usually set an @i[ephemerally active] region around
+the inserted text. An ephemerally active region is always deactivated by
+the next command, regardless of the kind of command. The ephemerally
+active region allows an immediately following region command to manipulate
+the inserted text, but doesn't persist annoyingly. This is also very
+useful with active region highlighting, since it visibly marks the inserted
+text.
+
+
+@defhvar[var "Highlight Active Region", val {t}]
+@defhvar1[var "Active Region Highlighting Font", val {nil}]
+When @hid[Highlight Active Region] is true, @hemlock displays the text in the
+region in a different font whenever the region is active. This provides a
+visible indication of what text will be manipulated by a region command.
+Active region highlighting is only supported under @windows.
+
+@hid[Active Region Highlighting Font] is the name of the font to use for active
+region highlighting. If unspecified, @hemlock uses an underline font.
+@enddefhvar
+
+
+@defcom[com "Set/Pop Mark", bind (C-@@)]
+This command moves the mark to the point (saving the old mark on the mark
+stack) and activates the region. After using this command to mark one end of
+the region, use motion commands to move to the other end, then do the region
+command. This is the traditional @emacs marking command; when running under a
+windowing system with mouse support, it is usually easier to use the mouse with
+the @comref[Point to Here] and @comref[Generic Pointer Up].
+
+For historical reasons, the prefix argument causes this command to do things
+that are distinct commands in @Hemlock. A prefix argument of four does
+@hid[Pop and Goto Mark], and a prefix argument of @f[16] does
+@hid[Pop Mark].
+@enddefcom
+
+@defcom[com "Mark Whole Buffer", bind (C-x h)]
+@defcom1[com "Mark to Beginning of Buffer", bind (C-<)]
+@defcom1[com "Mark to End of Buffer", bind (C->)]
+@hid[Mark Whole Buffer] sets the region around the whole buffer, with the point
+at the beginning and the mark at the end. If a prefix argument is supplied,
+then the mark is put at the beginning and the point at the end. The mark is
+pushed on the mark stack beforehand, so popping the stack twice will restore
+it.
+
+@hid[Mark to Beginning of Buffer] sets the current region from point to the
+beginning of the buffer.
+
+@hid[Mark to End of Buffer] sets the current region from the end of the buffer
+to point.
+@enddefcom
+
+@defcom[com "Activate Region", bind (C-x C-Space, C-x C-@@)]
+This command makes the region active, using whatever the current position of
+the mark happens to be. This is useful primarily when the region is
+accidentally deactivated.
+@enddefcom
+
+
+@subsection[The Mark Stack]
+
+@index[mark stack]As was hinted at earlier, each buffer has a @i[mark stack],
+providing a history of positions in that buffer. The current mark is the mark
+on the top of the stack; earlier values are recovered by popping the stack.
+Since commands that move a long distance save the old position on the mark
+stack, the mark stack commands are useful for jumping to interesting places in
+a buffer without having to do a search.
+
+@defcom[com "Pop Mark", bind (C-M-Space)]
+@defcom1[com "Pop and Goto Mark", bind (M-@@, M-Space)]
+@hid[Pop Mark] pops the mark stack, restoring the current mark to the next most
+recent value. @hid[Pop and Goto Mark] also pops the mark stack, but instead of
+discarding the current mark, it moves the point to that position. Both
+commands deactivate the region.
+@enddefcom
+
+@defcom[com "Exchange Point and Mark", bind (C-x C-x)]
+This command interchanges the position of the point and the mark, thus moving
+to where the mark was, and leaving the mark where the point was. This command
+can be used to switch between two positions in a buffer, since repeating it
+undoes its effect. The old mark isn't pushed on the mark stack, since it is
+saved in the point.
+@enddefcom
+
+
+@subsection[Using The Mouse]
+
+@index[mouse]It can be convenient to use the mouse to point to positions in
+text, especially when moving large distances. @hemlock defines several
+commands for using the mouse. These commands can only be used when running
+under @windows (see page @pageref[using-x].)
+
+@defcom[com "Here to Top of Window", bind (Rightdown)]
+@defcom1[com "Top Line to Here", bind (Leftdown)]
+@index[window, motion]@hid[Here to Top of Window] scrolls the window so as to
+move the line which is under the mouse cursor to the top of the window. This
+has the effect of moving forward in the buffer by the distance from the top of
+the window to the mouse cursor. @hid[Top Line to Here] is the inverse
+operation, it scrolls backward, moving current the top line underneath the
+mouse.
+
+If the mouse is near the left edge of a window, then these commands do smooth
+scrolling. @hid[Here To Top of Window] repeatedly scrolls the window up by one
+line until the mouse button is released. Similarly, @hid[Top Line to Here]
+smoothly scrolls down.
+@enddefcom
+
+@defcom[com "Point to Here", bind (Middledown, S-Leftdown)]
+This command moves the point to the position of the mouse, changing to a
+different window if necessary.
+
+When used in a window's modeline, this moves the point of the window's buffer
+to the position within the file that is the same percentage, start to end, as
+the horizontal position of the mouse within the modeline. This also makes this
+window current if necessary.
+
+This command supplies a function @hid[Generic Pointer Up] invokes if it runs
+without any intervening generic pointer up predecessors executing. If the
+position of the pointer is different than the current point when the user
+invokes @hid[Generic Pointer Up], then this function pushes a buffer mark at
+point and moves point to the pointer's position. This allows the user to mark
+off a region with the mouse.
+@enddefcom
+
+@defcom[com "Generic Pointer Up", bind (Middleup, S-Leftup)]
+Other commands determine this command's action by supplying functions that
+this command invokes. The following built-in commands supply the following
+generic up actions:
+@Begin[Description]
+@hid[Point to Here]@\
+ When the position of the pointer is different than the current point, the
+action pushes a buffer mark at point and moves point to the pointer's position.
+
+@hid[Bufed Goto and Quit]@\
+ The action is a no-op.
+@End[Description]
+@enddefcom
+
+@defcom[com "Insert Kill Buffer", bind (S-Rightdown)]
+This command is a combination of @hid[Point to Here] and @comref[Un-Kill]. It
+moves the point to the mouse location and inserts the most recently killed
+text.
+@enddefcom
+
+
+@section[Modification Commands]
+@index[commands, modification]
+
+There is a wide variety of basic text-modification commands, but once again the
+simplest ones are the most often used.
+
+@subsection[Inserting Characters]
+@index[character, insertion]
+@index[insertion, character]
+
+In @hemlock, you can insert characters with graphic representations by typing
+the corresponding key-event which you normally generate with the obvious
+keyboard key. You can only insert characters whose codes correspond to ASCII
+codes. To insert those without graphic representations, use @hid[Quoted
+Insert].
+
+@defcom[com "Self Insert"]
+@hid[Self Insert] inserts into the buffer the character corresponding to the
+key-event typed to invoke the command. This command is normally bound to all
+such key-events @binding[Space]. If a prefix argument is supplied, then this
+inserts the character that many times.
+@enddefcom
+
+@defcom[com "New Line", bind (Return)]
+This command, which has roughly the same effect as inserting a @bf[Newline],
+is used to move onto a new blank line. If there are at least two blank
+lines beneath the current one then @binding[Return] cleans off any
+whitespace on the next line and uses it, instead of inserting a newline.
+This behavior is desirable when inserting in the middle of text, because
+the bottom half of the screen does not scroll down each time @hid[New Line]
+is used.
+@enddefcom
+
+@defcom[com "Quoted Insert", bind {C-q}]
+Many key-events have corresponding ASCII characters, but these key-events are
+bound to commands other than @hid[Self Insert]. Sometimes they are otherwise
+encumbered such as with @binding[C-g]. @hid[Quoted Insert] prompts for a
+key-event, without any command interpretation semantics, and inserts the
+corresponding character. If the appropriate character has some code other than
+an ASCII code, this will beep and abort the command. A common use for this
+command is inserting a @bf[Formfeed] by typing @binding[C-q C-l]. If a prefix
+argument is supplied, then the character is inserted that many times.
+@enddefcom
+
+@defcom[com "Open Line", bind {C-o}]
+This command inserts a newline into the buffer without moving the point.
+This command may also be given a prefix argument to insert a number of
+newlines, thus opening up some room to work in the middle of a screen of
+text. See also @comref[Delete Blank Lines].
+@enddefcom
+
+
+@subsection[Deleting Characters]
+@index[deletion, character]
+@index[character, deletion]
+There are a number of commands for deleting characters as well.
+
+@defhvar[var "Character Deletion Threshold", val {5}]
+If more than this many characters are deleted by a character deletion command,
+then the deleted text is placed in the kill ring.
+@enddefhvar
+
+@defcom[com "Delete Next Character", bind {C-d}]
+@defcom1[com "Delete Previous Character", bind (Delete, Backspace)]
+@hid[Delete Next Character] deletes the character immediately following the
+point, that is, the character which appears under the cursor. When given a
+prefix argument, @binding[C-d] deletes that many characters after the
+point. @hid[Delete Previous Character] is identical, except that it
+deletes characters before the point.
+@enddefcom
+
+@defcom[com "Delete Previous Character Expanding Tabs"]
+@hid[Delete Previous Character Expanding Tabs] is identical to
+@hid[Delete Previous Character], except that it treats tabs as the
+equivalent number of spaces. Various language modes that use tabs for
+indentation bind @binding[Delete] to this command.
+@enddefcom
+
+
+@subsection[Killing and Deleting]
+
+@index[killing]@index[cutting]@index[pasting]@index[kill ring]@hemlock has many
+commands which kill text. Killing is a variety of deletion which saves the
+deleted text for later retrieval. The killed text is saved in a ring buffer
+known as the @i[kill ring]. Killing has two main advantages over deletion:
+@begin[enumerate]
+If text is accidentally killed, a not uncommon occurrence, then it can be
+restored.
+
+Text can be moved from one place to another by killing it and then
+restoring it in the new location.
+@end[enumerate]
+
+Killing is not the same as deleting. When a command is said to delete
+text, the text is permanently gone and is not pushed on the kill ring.
+Commands which delete text generally only delete things of little
+importance, such as single characters or whitespace.
+
+@subsection[Kill Ring Manipulation]
+@defcom[com "Un-Kill", bind {C-y}]
+@index[kill ring, manipulation]This command "yanks" back the most
+recently killed piece of text, leaving the mark before the inserted text
+and the point after. If a prefix argument is supplied, then the text that
+distance back in the kill ring is yanked.
+@enddefcom
+
+@defcom[com "Rotate Kill Ring", bind {M-y}]
+This command rotates the kill ring forward, replacing the most recently
+yanked text with the next most recent text in the kill ring. @binding[M-y]
+may only be used immediately after a use of @binding[C-y] or a previous
+use of @binding[M-y]. This command is used to step back through the text
+in the kill ring if the desired text was not the most recently killed, and
+thus could not be retrieved directly with a @binding[C-y]. If a prefix
+argument is supplied, then the kill ring is rotated that many times.
+@enddefcom
+
+@defcom[com "Kill Region", bind {C-w}]
+@index[region, killing]This command kills the text between the point and
+mark, pushing it onto the kill ring. This command is usually the best way
+to move or remove large quantities of text.
+@enddefcom
+
+@defcom[com "Save Region", bind {M-w}]
+This command pushes the text in the region on the kill ring, but doesn't
+actually kill it, giving an effect similar to typing @binding[C-w C-y].
+This command is useful for duplicating large pieces of text.
+@enddefcom
+
+@subsection[Killing Commands]
+
+@index[commands, killing]Most commands which kill text append into the
+kill ring, meaning that consecutive uses of killing commands will insert
+all text killed into the top entry in the kill ring. This allows large
+pieces of text to be killed by repeatedly using a killing command.
+
+@defcom[com "Kill Line", bind {C-k}]
+@defcom1[com "Backward Kill Line"]
+@index[line, killing]@hid[Kill Line] kills the text from the point to the
+end of the current line, deleting the line if it is empty. If a prefix
+argument is supplied, then that many lines are killed. Note that a prefix
+argument is not the same as a repeat count.
+
+@hid[Backward Kill Line] is similar, except that it kills from the point to the
+beginning of the line. If it is called at the beginning of the line, it kills
+the newline and any trailing whitespace on the previous line. With a prefix
+argument, this command is the same as @hid[Kill Line] with a negated argument.
+@enddefcom
+
+@defcom[com "Kill Next Word", bind {M-d}]
+@defcom1[com "Kill Previous Word", bind (M-Backspace, M-Delete)]
+@index[word, killing]@hid[Kill Next Word] kills from the point to the end
+of the current or next word. If a prefix argument is supplied, then that
+many words are killed. @hid[Kill Previous Word] is identical, except that
+it kills backward.
+@enddefcom
+
+@subsection[Case Modification Commands]
+
+@index[case modification]@hemlock provides a few case modification
+commands, which are often useful for correcting typos.
+
+@defcom[com "Capitalize Word", bind {M-c}]
+@defcom1[com "Lowercase Word", bind {M-l}]
+@defcom1[com "Uppercase Word", bind {M-u}]
+@index[word, case modification]These commands modify the case of the
+characters from the point to the end of the current or next word, leaving
+the point after the end of the word affected. A positive prefix argument
+modifies that many words, moving forward. A negative prefix argument
+modifies that many words before the point, but leaves the point unmoved.
+@enddefcom
+
+@defcom[com "Lowercase Region", bind (C-x C-l)]
+@defcom1[com "Uppercase Region", bind (C-x C-u)]
+@index[region, case modification]These commands case-fold the text in the
+region. Since these commands can damage large amounts of text, they ask for
+confirmation before modifying large regions and can be undone with @hid[Undo].
+@enddefcom
+
+@subsection[Transposition Commands]
+
+@index[transposition]@index[commands, transposition]@hemlock provides a
+number of transposition commands. A transposition command swaps the
+"things" before and after the point and moves forward one "thing". Just
+how a "thing" is defined depends on the particular transposition command.
+Transposition commands, particularly
+@hid[Transpose Characters] and @hid[Transpose Words], are useful for
+correcting typos. More obscure transposition commands can be used to amaze
+your friends and demonstrate your immense knowledge of exotic @emacs
+commands.
+
+To the uninitiated, the behavior of transposition commands may seem mysterious;
+this has led some implementors to attempt to improve the definition of
+transposition, but right-thinking people will accept no substitutes. The
+@emacs transposition definition used in @hemlock has two useful properties:
+@begin[enumerate]
+Repeated applications of a transposition command have a useful effect. The
+way to visualize this effect is that each use of the transposition command
+drags the previous thing over the next thing. It is possible to correct
+double transpositions easily using @hid[Transpose Characters].
+
+Transposition commands move backward with a negative prefix argument, thus
+undoing the effect of the equivalent positive argument.
+@end[enumerate]
+
+@defcom[com "Transpose Characters", bind {C-t}]
+@index[character, transposition]This command exchanges the characters on
+either side of the point and moves forward, unless at the end of a line, in
+which case it transposes the previous two characters without moving.
+@enddefcom
+
+@defcom[com "Transpose Lines", bind (C-x C-t)]
+@index[line, transposition]This command transposes the previous and
+current line, moving down to the next line. With a zero argument, it
+transposes the current line and the line the mark is on.
+@enddefcom
+
+@defcom[com "Transpose Words", bind {M-t}]
+@index[word, transposition]This command transposes the previous word and
+the current or next word.
+@enddefcom
+
+
+@defcom[com "Transpose Regions", bind (C-x t)]
+This command transposes two regions with endpoints defined by the mark stack
+and point. To use this command, place three marks (in order) at the start and
+end of the first region, and at the start of the second region, then place the
+point at the end of the second region. Unlike the other transposition
+commands, a second use will simply undo the effect of the first use, and to do
+even this, you must reactivate the current region.
+@enddefcom
+
+
+@subsection[Whitespace Manipulation]
+These commands change the amount of space between words. See also the
+indentation commands in section @ref[indentation].
+
+@defcom[com "Just One Space", bind (M-|)]
+@index[whitespace, manipulation]@index[indentation, manipulation]This
+command deletes all whitespace characters before and after the point and then
+inserts one space. If a prefix argument is supplied, then that number of
+spaces is inserted.
+@enddefcom
+
+@defcom[com "Delete Horizontal Space", bind (M-\)]
+This command deletes all blank characters around the point.
+@enddefcom
+
+@defcom[com "Delete Blank Lines", bind (C-x C-o)]
+This command deletes all blank lines surrounding the current line, leaving the
+point on a single blank line. If the point is already on a single blank line,
+then that line is deleted. If the point is on a non-blank line, then all blank
+lines immediately following that line are deleted. This command is often used
+to clean up after @comref[Open Line].
+@enddefcom
+
+@section[Filtering]
+
+@i[Filtering] is a simple way to perform a fairly arbitrary transformation
+on text. Filtering text replaces the string in each line with the result
+of applying a @llisp function of one argument to that string. The function must
+neither destructively modify the argument nor the return value. It is an
+error for the function to return a string containing newline characters.
+
+@defcom[com "Filter Region"]
+This function prompts for an expression which is evaluated to obtain a
+function to be used to filter the text in the region. For example, to
+capitalize all the words in the region one could respond:
+@begin[programexample]
+Function: #'@comment<>string-capitalize
+@end[programexample]
+Since the function may be called many times, it should probably be
+compiled. Functions for one-time use can be compiled using the compile
+function as in the following example which removes all the semicolons on any line
+which contains the string "@f[PASCAL]":
+@begin[programexample]
+Function: (compile nil '(lambda (s)
+ (if (search "PASCAL" s)
+ (remove #\; s)
+ s)))
+@end[programexample]
+@enddefcom
+
+@section[Searching and Replacing]
+@index[searching]@index[replacing]
+Searching for some string known to appear in the text is a commonly used method
+of moving long distances in a file. Replacing occurrences of one pattern with
+another is a useful way to make many simple changes to text. @hemlock provides
+powerful commands for doing both of these operations.
+
+@defhvar[var "String Search Ignore Case", val {t}]
+@index[case sensitivity]
+This variable determines the kind of search done by searching and replacing
+commands.
+@enddefhvar
+
+@defcom[com "Incremental Search", bind {C-s}]
+@defcom1[com "Reverse Incremental Search", bind {C-r}]
+@hid[Incremental Search] searches for an occurrence of a string after the
+current point. It is known as an incremental search because it reads
+key-events form the keyboard one at a time and immediately searches for the
+pattern of corresponding characters as you type. This is useful because
+it is possible to initially type in a very short pattern and then add more
+characters if it turns out that this pattern has too many spurious matches.
+
+This command dispatches on the following key-events as sub-commands:
+@begin[description]
+@binding[C-s]@\
+ Search forward for an occurrence of the current pattern. This can be used
+repeatedly to skip from one occurrence of the pattern to the next, or it can be
+used to change the direction of the search if it is currently a reverse search.
+If @binding[C-s] is typed when the search string is empty, then a search is
+done for the string that was used by the last searching command.
+
+@binding[C-r]@\
+ Similar to @binding[C-s], except that it searches backwards.
+
+@binding[Delete, Backspace]@\
+ Undoes the effect of the last key-event typed. If that key-event simply added
+to the search pattern, then this removes the character from the pattern, moving
+back to the last match found before entering the removed character. If the
+character was a @binding[C-s] or @binding[C-r], then this moves back to the
+previous match and possibly reverses the search direction.
+
+@binding[C-g]@\
+ If the search is currently failing, meaning that there is no occurrence of the
+search pattern in the direction of search, then @binding[C-g] deletes enough
+characters off the end of the pattern to make it successful. If the search
+is currently successful, then @binding[C-g] causes the search to be aborted,
+leaving the point where it was when the search started. Aborting the search
+inhibits the saving of the current search pattern as the last search string.
+
+@binding[Escape]@\
+ Exit at the current position in the text, unless the search string is empty,
+in which case a non-incremental string search is entered.
+
+@binding[C-q]@\
+ Search for the character corresponding to the next key-event, rather than
+treating it as a command.
+@end[description]
+Any key-event not corresponding to a graphic character, except those just
+described, causes the search to exit. @hemlock then uses the key-event in it
+normal command interpretation.
+
+For example, typing @binding[C-a] will exit the search @i[and] go to the
+beginning of the current line. When either of these commands successfully
+exits, they push the starting position (before the search) on the mark stack.
+If the current region was active when the search started, this foregoes pushing
+a mark.
+@enddefcom
+
+@defcom[com "Forward Search", bind (M-s)]
+@defcom1[com "Reverse Search", bind (M-r)]
+These commands do a normal dumb string search, prompting for the search
+string in a normal dumb fashion. One reason for using a non-incremental
+search is that it may be faster since it is possible to specify a long
+search string from the very start. Since @hemlock uses the Boyer--Moore
+search algorithm, the speed of the search increases with the size of the
+search string.
+When either of these commands successfully exits, they push the starting
+position (before the search) on the mark stack. This is inhibited when the
+current region is active.
+@enddefcom
+
+@defcom[com "Query Replace", bind (M-%)]
+This command prompts in the echo area for a target string and a replacement
+string. It then searches for an occurrence of the target after the point.
+When it finds a match, it prompts for a key-event indicating what action to
+take. The following are valid responses:
+@begin[description]
+@binding[Space, y]@\
+ Replace this occurrence of the target with the replacement string, and search
+again.
+
+@binding[Delete, Backspace, n]@\
+ Do not replace this occurrence, but continue the search.
+
+@binding[!]@\
+ Replace this and all remaining occurrences without prompting again.
+
+@binding[.]@\
+ Replace this occurrence and exit.
+
+@binding[C-r]@\
+ Go into a recursive edit (see page @pageref[recursive-edits]) at the current
+location. The search will be continued from wherever the point is left when
+the recursive edit is exited. This is useful for handling more complicated
+cases where a simple replacement will not achieve the desired effect.
+
+@binding[Escape]@\
+ Exit without doing any replacement.
+
+@binding[Home, C-_, ?, h]@\
+ Print a list of all the options available.
+@end[description]
+Any other key-event causes the command to exit, returning the key-event to the
+input stream; thus, @hemlock will interpret it normally for a command binding.
+
+When the current region is active, this command uses it instead of the region
+from point to the end of the buffer. This is especially useful when you expect
+to use the @binding[!] option.
+
+If the replacement string is all lowercase, then a heuristic is used that
+attempts to make the case of the replacement the same as that of the
+particular occurrence of the target pattern. If "@f[foo]" is being
+replaced with "@f[bar]" then "@f[Foo]" is replaced with "@f[Bar]" and
+"@f[FOO]" with "@f[BAR]".
+
+This command may be undone with @hid[Undo], but its undoing may not be undone.
+On a successful exit from this command, the starting position (before the
+search) is pushed on the mark stack.
+@enddefcom
+
+@defhvar[var "Case Replace", val {t}]
+@index[case sensitivity]
+If this variable is true then the case preserving heuristic in
+@hid[Query Replace] is enabled, otherwise all replacements are done with
+the replacement string exactly as specified.
+@enddefhvar
+
+@defcom[com "Replace String"]
+This command is the same as @hid[Query Replace] except it operates without ever
+querying the user before making replacements. After prompting for a target and
+replacement string, it replaces all occurrences of the target string following
+the point. If a prefix argument is specified, then only that many occurrences
+are replaced. When the current region is active, this command uses it instead
+of the region from point to the end of the buffer.
+@enddefcom
+
+@defcom[com "List Matching Lines"]
+This command prompts for a search string and displays in a pop-up window all
+the lines containing the string that are after the point. If a prefix argument
+is specified, then this displays that many lines before and after each matching
+line. When the current region is active, this command uses it instead of the
+region from point to the end of the buffer.
+@enddefcom
+
+@defcom[com "Delete Matching Lines"]
+@defcom1[com "Delete Non-Matching Lines"]
+@hid[Delete Matching Lines] prompts for a search string and deletes all lines
+containing the string that are after the point. Similarly, @hid[Delete
+Non-Matching Lines] deletes all lines following the point that do not contain
+the specified string. When the current region is active, these commands uses
+it instead of the region from point to the end of the buffer.
+@enddefcom
+
+
+@section[Page Commands]
+@index[page commands]
+Another unit of text recognized by @hemlock is the page. A @i[page] is a piece
+of text delimited by formfeeds (@f[^L]'s.) The first non-blank line after the
+page marker is the @i[page title]. The page commands are quite useful when
+logically distinct parts of a file are put on separate pages. See also
+@comref[Count Lines Page]. These commands only recognize @f[^L]'s at the
+beginning of a lines, so those quoted in string literals do not get in the way.
+
+@defcom[com "Previous Page", bind (C-x @bf<]>)]
+@defcom1[com "Next Page", bind (C-x [)]
+@hid[Previous Page] moves the point to the previous page delimiter, while
+@hid[Next Page] moves to the next one. Any page delimiters next to the point
+are skipped. The prefix argument is a repeat count.
+@enddefcom
+
+@defcom[com "Mark Page", bind (C-x C-p)]
+This command puts the point at the beginning of the current page and the mark
+at the end. If given a prefix argument, marks the page that many pages from the
+current one.
+@enddefcom
+
+@defcom[com "Goto Page"]
+This command does various things, depending on the prefix argument:
+@begin[description]
+@i[no argument]@\goes to the next page.
+
+@i[positive argument]@\goes to an absolute page number, moving that many pages
+from the beginning of the file.
+
+@i[zero argument]@\prompts for string and goes to the page with that string in
+its title. Repeated invocations in this manner continue searching from the
+point of the last find, and a first search with a particular pattern pushes a
+buffer mark.
+
+@i[negative argument]@\moves backward by that many pages, if possible.
+@end[description]
+@enddefcom
+
+@defcom[com "View Page Directory"]
+@defcom1[com "Insert Page Directory"]
+@hid[View Page Directory] uses a pop-up window to display the number and title
+of each page in the current buffer. @hid[Insert Page Directory] is the same
+except that it inserts the text at the beginning of the buffer. With a prefix
+argument, @hid[Insert Page Directory] inserts at the point.
+@enddefcom
+
+
+@section[Counting Commands]
+
+@defcom[com "Count Words"]
+This command counts the number of words from the current point to the end of
+the buffer, displaying a message in the echo area. When the current region is
+active, this uses it instead of the region from the point to the end of the
+buffer. Word delimiters are determined by the current major mode.
+@enddefcom
+
+@defcom[com "Count Lines"]
+This command counts the number of lines from the current point to the end of
+the buffer, displaying a message in the echo area. When the current region is
+active, this uses it instead of the region from the point to the end of the
+buffer.
+@enddefcom
+
+@defcom[com "Count Lines Page", bind (C-x l)]
+This command displays the number of lines in the current page and the number of
+lines before and after the point within that page. If given a prefix argument,
+the entire buffer is counted instead of just the current page.
+@enddefcom
+
+@defcom[com "Count Occurrences"]
+This command prompts for a search string and displays the number of occurrences
+of that string in the text from the point to the end of the buffer. When the
+current region is active, this uses it instead of the region from the point to
+the end of the buffer.
+@enddefcom
+
+
+@section[Registers]
+@index[registers]
+Registers allow you to save a text position or chunk of text associated with a
+key-event. This is a convenient way to repeatedly access a commonly-used
+location or text fragment. The concept and key bindings should be familiar to
+TECO users.
+
+@defcom[com "Save Position", bind (C-x s)]
+@defcom1[com "Jump to Saved Position", bind (C-x j)]
+These commands manipulate registers containing textual positions.
+@hid[Save Position] prompts for a register and saves the location of the
+current point in that register. @hid[Jump to Saved Position] prompts for a
+register and moves the point to the position saved in that register. If the
+saved position is in a different buffer, then that buffer is made current.
+@enddefcom
+
+@defcom[com "Put Register", bind (C-x x)]
+@defcom1[com "Get Register", bind (C-x g)]
+These commands manipulate registers containing text. @hid[Put Register]
+prompts for a register and puts the text in the current region into the
+register. @hid[Get Register] prompts for a register and inserts the text in
+that register at the current point.
+@enddefcom
+
+@defcom[com "List Registers"]
+@defcom1[com "Kill Register"]
+@hid[List Registers] displays a list of all the currently defined registers in
+a pop-up window, along with a brief description of their contents.
+@hid[Kill Register] prompts for the name of a register and deletes that
+register.
+@enddefcom
diff --git a/docs/hem/user/intro.mss b/docs/hem/user/intro.mss
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6ceeac039c0005d16d4470e31336d742126f5
--- /dev/null
+++ b/docs/hem/user/intro.mss
@@ -0,0 +1,1127 @@
+@comment{-*- Dictionary: target:scribe/hem/hem; Mode: spell; Package: Hemlock -*-}
+@chap[Introduction]
+
+@hemlock is a text editor which follows in the tradition of @emacs
+and the Lisp Machine editor ZWEI. In its basic form, @hemlock has almost
+the same command set as ITS/TOPS-20 @emacs@foot[In this document, "Emacs"
+refers to this, the original version, rather than to any of the large
+numbers of text editors inspired by it which may go by the same name.],
+and similar features such as multiple windows and extended commands, as
+well as built in documentation features. The reader should bear in mind
+that whenever some powerful feature of @hemlock is described, it has
+probably been directly inspired by @emacs.
+
+This manual describes @hemlock@comment{}'s commands and other user visible
+features and then goes on to tell how to make simple customizations. For
+complete documentation of the @hemlock primitives with which commands are
+written, the @i[Hemlock Command Implementor's Manual] is also available.
+
+
+
+@section[The Point and The Cursor]
+
+@index[point]
+@index[cursor]
+The @i[point] is the current focus of editing activity. Text typed in by the
+user is inserted at the point. Nearly all commands use the point as a
+indication of what text to examine or modify. Textual positions in @hemlock
+are between characters. This may seem a bit curious at first, but it is
+necessary since text must be inserted between characters. Although the point
+points between characters, it is sometimes said to point @i[at] a character, in
+which case the character after the point is referred to.
+
+The @i[cursor] is the visible indication of the current focus of attention: a
+rectangular blotch under @windows, or the hardware cursor on a terminal. The
+cursor is usually displayed on the character which is immediately after the
+point, but it may be displayed in other places. Wherever the cursor is
+displayed it indicates the current focus of attention. When input is being
+prompted for in the echo area, the cursor is displayed where the input is to
+go. Under @windows the cursor is only displayed when @hemlock is waiting
+for input.
+
+
+@section[Notation]
+
+There are a number of notational conventions used in this manual which need
+some explanation.
+
+
+@subsection[Key-events]
+
+@label[key-events]
+@index[key-events, notation]
+@index[bits, key-event]
+@index[modifiers, key-event]
+The canonical representation of editor input is a @i[key-event]. When you type
+on the keyboard, @hemlock receives key-events. Key-events have names for their
+basic form, and we refer to this name as a @i[keysym]. This manual displays
+keysyms in a @bf[Bold] font. For example, @bf[a] and @bf[b] are the keys that
+normally cause the editor to insert the characters @i[a] and @i[b].
+
+Key-events have @i[modifiers] or @i[bits] indicating a special interpretation
+of the root key-event. Although the keyboard places limitations on what
+key-events you can actually type, @hemlock understands arbitrary combinations
+of the following modifiers: @i[Control], @i[Meta], @i[Super], @i[Hyper],
+@i[Shift], and @i[Lock]. This manual represents the bits in a key-event by
+prefixing the keysym with combinations of @bf[C-], @bf[M-], @bf[S-], @bf[H-],
+@bf[Shift-], and @bf[Lock]. For example, @bf[a] with both the control and meta
+bits set appears as @bf[C-M-a]. In general, ignore the shift and lock
+modifiers since this manual never talks about keysyms that explicitly have
+these bits set; that is, it may talk about the key-event @bf[A], but it would
+never mention @bf[Shift-a]. These are actually distinct key-events, but
+typical input coercion turns presents @hemlock with the former, not the latter.
+
+Key-event modifiers are totally independent of the keysym. This may be new to
+you if you are used to thinking in terms of ASCII character codes. For
+example, with key-events you can distinctly identify both uppercase and
+lowercase keysyms with the control bit set; therefore, @bf[C-a] and @bf[C-A]
+may have different meanings to @hemlock.
+
+Some keysyms' names consist of more than a single character, and these usually
+correspond to the legend on the keyboard. For example, some keyboards let you
+enter @bf[Home], @bf[Return], @bf[F9], etc.
+
+In addition to a keyboard, you may have a mouse or pointer device. Key-events
+also represent this kind of input. For example, the down and up transitions of
+the @i[left button] correspond to the @bf[Leftdown] and @bf[Leftup] keysyms.
+
+See sections @ref[key-bindings], @ref[using-x], @ref[using-terminals]
+
+
+@subsection[Commands]
+
+@index[commands]@label[commands]Nearly everything that can be done in
+@hemlock is done using a command. Since there are many things worth
+doing, @hemlock provides many commands, currently nearly two hundred.
+Most of this manual is a description of what commands exist, how they are
+invoked, and what they do. This is the format of a command's
+documentation:
+
+@defcom[com "Sample Command", bind (C-M-q, C-`)]
+@begin[quotation, facecode i, leftmargin 8ems, rightmargin 3.5ems,
+below 0.8 lines]
+This command's name is @hid[Sample Command], and it is bound to
+@w(@bf(C-M-q)) and @bf[C-`], meaning that typing either of these will
+invoke it. After this header comes a description of what the command does:
+@end[quotation]
+
+This command replaces all occurrences following the point of the string
+"@f[Pascal]" with the string "@f[Lisp]". If a prefix argument is supplied,
+then it is interpreted as the maximum number of occurrences to replace. If
+the prefix argument is negative then the replacements are done backwards
+from the point.
+@comment<
+@begin[quotation, facecode i, leftmargin 8ems, rightmargin 3.5ems,
+above 0.8 lines, below 0.8 lines]
+Toward the end of the description there may be information primarily of
+interest to customizers and command implementors. If you don't understand
+this information, don't worry, the writer probably forgot to speak English.
+@end[quotation]
+
+@b[Arguments:]
+@begin[description]
+@i[target]@\The string to replace with "@f[Lisp]".
+
+@i[buffer]@\The buffer to do the replacement in. If this is @f[:all] then
+the replacement is done in all buffers.
+@end[description]>
+@enddefcom
+
+
+@subsection[Hemlock Variables]
+
+@index[variables, hemlock]@hemlock variables supply a simple
+customization mechanism by permitting commands to be parameterized. For
+details see page @pageref[vars].
+
+@defhvar[var "Sample Variable", val {36}]
+@begin[quotation, facecode i, leftmargin 8ems, below 0.8 lines]
+The name of this variable is @hid[Sample Variable] and its initial value is
+36.
+@end[quotation]
+This variable sets a lower limit on the number of replacements that be done
+by @hid[Sample Command]. If the prefix argument is supplied, and smaller
+in absolute value than @hid[Sample Variable], then the user is prompted as
+to whether that small a number of occurrences should be replaced, so as to
+avoid a possibly disastrous error.
+@enddefhvar
+
+
+@section[Invoking Commands]
+@index[invocation, command]
+In order to get a command to do its thing, it must be invoked. The user can do
+this two ways, by typing the @i[key] to which the command is @i[bound] or by
+using an @i[extended command]. Commonly used commands are invoked via their
+key bindings since they are faster to type, while less used commands are
+invoked as extended commands since they are easier to remember.
+
+
+@subsection[Key Bindings]
+@index[bindings, key]
+@index[key bindings]
+@label[key-bindings]
+A key is a sequence of key-events (see section @ref[key-events]) typed on the
+keyboard, usually only one or two in length. Sections @ref[using-x] and
+@ref[using-terminals] contain information on particular input devices.
+
+When a command is bound to a key, typing the key causes @hemlock to invoke the
+command. When the command completes its job, @hemlock returns to reading
+another key, and this continually repeats.
+
+Some commands read key-events interpreting them however each command desires.
+When commands do this, key bindings have no effect, but you can usually abort
+@hemlock whenever it is waiting for input by typing @binding[C-g] (see section
+@ref[aborting]). You can usually find out what options are available by typing
+@binding[C-_] or @binding[Home] (see section @ref[help]).
+
+The user can easily rebind keys to different commands, bind new keys to
+commands, or establish bindings for commands never bound before (see section
+@ref[binding-keys]).
+
+In addition to the key bindings explicitly listed with each command, there are
+some implicit bindings created by using key translations@foot[Key translations
+are documented in the @i[Hemlock Command Implementor's Manual].]. These
+bindings are not displayed by documentation commands such as @hid[Where Is].
+By default, there are only a few key translations. The modifier-prefix
+characters @bf[C-^], @bf[Escape], @bf[C-z], or @bf[C-c] may be used when typing
+keys to convert the following key-event to a control, meta, control-meta, or
+hyper key-event. For example, @bf[C-x Escape b] invokes the same commands as
+@bf[C-x M-b], and @bf[C-z u] is the same as @bf[C-M-u]. This allows user to
+type more interesting keys on limited keyboards that lack control, meta, and
+hyper keys.
+@index[bit-prefix key-events]
+
+
+@defhvar[var "Key Echo Delay", val {1.0}]
+A key binding may be composed of several key-events, especially when you enter
+it using modifier-prefix key-events. @hemlock provides feedback for partially
+entered keys by displaying the typed key-events in the echo area. In order to
+avoid excessive output and clearing of the echo area, this display is delayed
+by @hid[Key Echo Delay] seconds. If this variable is set to @nil, then
+@hemlock foregoes displaying initial subsequences of keys.
+@enddefhvar
+
+
+@subsection[Extended Commands]
+
+@index[commands, extended]A command is invoked as an extended command by
+typing its name to the @hid[Extended Command] command, which is invoked
+using its key binding, @binding[M-x].
+
+@defcom[com "Extended Command", bind {M-x}]
+This command prompts in the echo area for the name of a command, and then
+invokes that command. The prefix argument is passed through to the command
+invoked. The command name need not be typed out in full, as long as enough
+of its name is supplied to uniquely identify it. Completion is available
+using @binding[Escape] and @binding[Space], and a list of possible completions
+is given by @binding[Home] or @binding[C-_].
+@enddefcom
+
+
+@section[The Prefix Argument]
+
+@index[prefix argument]The prefix argument is an integer argument which
+may be supplied to a command. It is known as the prefix argument because
+it is specified by invoking some prefix argument setting command
+immediately before the command to be given the argument. The following
+statements about the interpretation of the prefix argument are true:
+@begin[itemize]
+When it is meaningful, most commands interpret the prefix argument as a
+repeat count, causing the same effect as invoking the command that many
+times.
+
+When it is meaningful, most commands that use the prefix argument interpret
+a negative prefix argument as meaning the same thing as a positive
+argument, but the action is done in the opposite direction.
+
+Most commands treat the absence of a prefix argument as meaning the same
+thing as a prefix argument of one.
+
+Many commands ignore the prefix argument entirely.
+
+Some commands do none of the above.
+@end[itemize]
+The following commands are used to set the prefix argument:
+
+@defcom[com "Argument Digit", stuff (bound to all control or meta digits)]
+Typing a number using this command sets the prefix argument to that number,
+for example, typing @binding[M-1 M-2] sets the prefix argument to twelve.
+@enddefcom
+
+@defcom[com "Negative Argument", bind {M--}]
+This command negates the prefix argument, or if there is none, sets it to
+negative one. For example, typing @binding[M-- M-7] sets the prefix
+argument to negative seven.
+@enddefcom
+
+@defcom[com "Universal Argument", bind {C-u}]
+@defhvar1[var "Universal Argument Default", val {4}]
+This command sets the prefix argument or multiplies it by four. If digits
+are typed immediately afterward, they are echoed in the echo area, and the
+prefix argument is set to the specified number. If no digits are typed
+then the prefix argument is multiplied by four. @binding[C-u - 7] sets the
+prefix argument to negative seven. @binding[C-u C-u] sets the prefix
+argument to sixteen. @binding[M-4 M-2 C-u] sets the prefix argument to one
+hundred and sixty-eight. @binding[C-u M-0] sets the prefix argument to
+forty.
+
+@hid[Universal Argument Default] determines the default value and multiplier
+for the @hid[Universal Argument] command.
+@enddefcom
+
+
+@section[Modes]
+
+@label[modes]@index[modes]A mode provides a way to change @hemlock@comment{}'s
+behavior by specifying a modification to current key bindings, values of
+variables, and other things. Modes are typically used to adjust @hemlock
+to suit a particular editing task, e.g. @hid[Lisp] mode is used for editing
+@llisp code.
+
+Modes in @hemlock are not like modes in most text editors; @hemlock is really a
+"modeless" editor. There are two ways that the @hemlock mode concept differs
+from the conventional one:
+@begin[enumerate]
+Modes do not usually alter the environment in a very big way, i.e. replace
+the set of commands bound with another totally disjoint one. When a mode
+redefines what a key does, it is usually redefined to have a slightly
+different meaning, rather than a totally different one. For this reason,
+typing a given key does pretty much the same thing no matter what modes are
+in effect. This property is the distinguishing characteristic of a
+modeless editor.
+
+Once the modes appropriate for editing a given file have been chosen, they
+are seldom, if ever, changed. One of the advantages of modeless editors is
+that time is not wasted changing modes.
+@end[enumerate]
+
+@index[major mode]A @i[major mode] is used to make some big change in the
+editing environment. Language modes such as @hid[Pascal] mode are major
+modes. A major mode is usually turned on by invoking the command
+@i{mode-name}@hid[ Mode] as an extended command. There is only one major
+mode present at a time. Turning on a major mode turns off the one that is
+currently in effect.
+
+@index[minor mode]A @i[minor mode] is used to make a small change in the
+environment, such as automatically breaking lines if they get too long.
+Unlike major modes, any number of minor modes may be present at once.
+Ideally minor modes should do the "right thing" no matter what major and
+minor modes are in effect, but this is may not be the case when key
+bindings conflict.
+
+Modes can be envisioned as switches, the major mode corresponding to one big
+switch which is thrown into the correct position for the type of editing being
+done, and each minor mode corresponding to an on-off switch which controls
+whether a certain characteristic is present.
+
+@defcom[com "Fundamental Mode"]
+This command puts the current buffer into @hid[Fundamental] mode.
+@hid[Fundamental] mode is the most basic major mode: it's the next best thing
+to no mode at all.
+@enddefcom
+
+
+@section[Display Conventions]
+@index[display conventions]
+There are two ways that @hemlock displays information on the screen; one is
+normal @i[buffer display], in which the text being edited is shown on the
+screen, and the other is a @i[pop-up window].
+
+
+@subsection[Pop-Up Windows]
+@index[pop-up windows]
+@index[random typeout]
+@label[pop-up]
+Some commands print out information that is of little permanent value, and
+these commands use a @i[pop-up] window to display the information. It is known
+as a @i[pop-up] window because it temporarily appears on the screen overlaying
+text already displayed. Most commands of this nature can generate their output
+quickly, but in case there is a lot of output, or the user wants to repeatedly
+refer to the same output while editing, @hemlock saves the output in a buffer.
+Different commands may use different buffers to save their output, and we refer
+to these as @i[random typeout] buffers.
+
+If the amount of output exceeds the size of the pop-up window, @Hemlock
+displays the message @w<"@f[--More--]"> after each window full. The following
+are valid responses to this prompt:
+@Begin[Description]
+@bf[Space], @bf[y]@\
+ Display the next window full of text.
+
+@bf[Delete], @bf[Backspace], @bf[n]@\
+ Abort any further output.
+
+@bf[Escape], @bf[!]@\
+ Remove the window and continue saving any further output in the buffer.
+
+@bf[k]@\
+ This is the same as @bf[!] or @bf[escape], but @hemlock makes a normal window
+over the pop-up window. This only works on bitmap devices.
+@End[Description]
+Any other input causes the system to abort using the key-event to determine
+the next command to execute.
+
+When the output is complete, @hemlock displays the string @w<"@f[--Flush--]">
+in the pop-up window's modeline, indicating that the user may flush the
+temporary display. Typing any of the key-events described above removes the
+pop-up window, but typing @bf[k] still produces a window suitable for normal
+editing. Any other input also flushes the display, but @hemlock uses the
+key-event to determine the next command to invoke.
+
+@defcom[com "Select Random Typeout Buffer", bind {H-t}]
+This command makes the most recently used random typeout buffer the current
+buffer in the current window.
+@enddefcom
+
+Random typeout buffers are always in @hid[Fundamental] mode.
+
+
+@subsection[Buffer Display]
+@index[buffer, display]
+@index[display, buffer]
+
+If a line of text is too long to fit within the screen width it is @i[wrapped],
+with @hemlock displaying consecutive pieces of the text line on as many screen
+lines as needed to hold the text. @hemlock indicates a wrapped line by placing
+a line-wrap character in the last column of each screen line. Currently, the
+line-wrap character is an exclamation point (@f[!]). It is possible for a line
+to wrap off the bottom of the screen or on to the top.
+
+@hemlock wraps screen lines when the line is completely full regardless of the
+line-wrap character. Most editors insert the line-wrap character and wrap a
+single character when a screen line would be full if the editor had avoided
+wrapping the line. In this situation, @hemlock would leave the screen line
+full. This means there are always at least two characters on the next screen
+line if @hemlock wraps a line of display. When the cursor is at the end of a
+line which is the full width of the screen, it is displayed in the last column,
+since it cannot be displayed off the edge.
+
+@hemlock displays most characters as themselves, but it treats some
+specially:
+@begin[itemize]
+Tabs are treated as tabs, with eight character tab-stops.
+
+Characters corresponding to ASCII control characters are printed as
+@f[^]@i[char]; for example, a formfeed is @f[^L].
+
+Characters with the most-significant bit on are displayed as
+@f[<]@i[hex-code]@f[>]; for example, @f[].
+@end[itemize]
+Since a character may be displayed using more than one printing character,
+there are some positions on the screen which are in the middle of a character.
+When the cursor is on a character with a multiple-character representation,
+@hemlock always displays the cursor on the first character.
+
+
+@subsection[Recentering Windows]
+@index[recentering windows]
+@index[windows, recentering]
+
+When redisplaying the current window, @hemlock makes sure the current point is
+visible. This is the behavior you see when you are entering text near the
+bottom of the window, and suddenly redisplay shifts your position to the
+window's center.
+
+Some buffers receive input from streams and other processes, and you might have
+windows displaying these. However, if those windows are not the current
+window, the output will run off the bottom of the windows, and you won't be
+able to see the output as it appears in the buffers. You can change to a
+window in which you want to track output and invoke the following command to
+remedy this situation.
+
+@defcom[com "Track Buffer Point"]
+This command makes the current window track the buffer's point. This means
+that each time Hemlock redisplays, it will make sure the buffer's point is
+visible in the window. This is useful for windows that are not current and
+that display buffer's that receive output from streams coming from other
+processes.
+@enddefcom
+
+
+@subsection[Modelines]
+@label[modelines]
+@index[modeline]
+A modeline is the line displayed at the bottom of each window where @hemlock
+shows information about the buffer displayed in that window. Here is a typical
+modeline:
+@begin[programexample]
+Hemlock USER: (Fundamental Fill) /usr/slisp/hemlock/user.mss
+@end[programexample]
+This tells us that the file associated with this buffer is
+"@f[/usr/slisp/hemlock/user.mss]", and the @hid[Current Package] for Lisp
+interaction commands is the @f["USER"] package. The modes currently present
+are @hid[Fundamental] and @hid[Fill]; the major mode is always displayed first,
+followed by any minor modes. If the buffer has no associated file, then the
+buffer name will be present instead:
+@begin[programexample]
+Hemlock PLAY: (Lisp) Silly:
+@end[programexample]
+In this case, the buffer is named @hid[Silly] and is in @hid[Lisp] mode. The
+user has set @hid[Current Package] for this buffer to @f["PLAY"].
+
+@defhvar[var "Maximum Modeline Pathname Length", val {nil}]
+This variable controls how much of a pathname @hemlock displays in a modeline.
+Some distributed file systems can have very long pathnames which leads to the
+more particular information in a pathname running off the end of a modeline.
+When set, the system chops off leading directories until the name is less than
+the integer value of this variable. Three dots, @f[...], indicate a truncated
+name. The user can establish this variable buffer locally with the
+@hid[Defhvar] command.
+@enddefhvar
+
+If the user has modified the buffer since the last time it was read from or
+save to a file, then the modeline contains an asterisk (@f[*]) between the
+modes list and the file or buffer name:
+@begin[programexample]
+Hemlock USER: (Fundamental Fill) * /usr/slisp/hemlock/user.mss
+@end[programexample]
+This serves as a reminder that the buffer should be saved eventually.
+
+@index[status line]
+There is a special modeline known as the @i[status line] which appears as the
+@hid[Echo Area]'s modeline. @Hemlock and user code use this area to display
+general information not particular to a buffer @dash recursive edits, whether
+you just received mail, etc.
+
+
+@section[Use with X Windows]
+@label[using-x]
+@index[X windows, use with]
+You should use @hemlock on a workstation with a bitmap display and a windowing
+system since @hemlock makes good use of a non-ASCII device, mouse, and the
+extra modifier keys typically associated with workstations. This section
+discusses using @hemlock under X windows, the only supported windowing system.
+
+
+@subsection[Window Groups]
+@index[window management]
+@label[groups]
+@hemlock manages windows under X in groups. This allows @hemlock to be more
+sophisticated in its window management without being rude in the X paradigm of
+screen usage. With window groups, @hemlock can ignore where the groups are,
+but within a group, it can maintain the window creation and deletion behavior
+users expect in editors without any interference from window managers.
+
+Initially there are two groups, a main window and the @hid[Echo Area]. If you
+keep a pop-up display, see section @ref[pop-up], @hemlock puts the window it
+creates in its own group. There are commands for creating new groups.
+
+@hemlock only links windows within a group for purposes of the @hid[Next
+Window], @hid[Previous Window], and @hid[Delete Next Window] commands. To move
+between groups, you must use the @hid[Point to Here] command bound to the
+mouse.
+
+Window manager commands can reshape and move groups on the screen.
+
+
+@subsection[Event Translation]
+@index[keyboard use under X]
+@index[translation of keys under X]
+Each X key event is translated into a canonical input representation, a
+key-event. The X key event consists of a scan-code and modifier bits, and
+these translate to an X keysym. This keysym and the modifier bits map to a
+key-event.
+
+If you type a key with a shift key held down, this typically maps to a distinct
+X keysym. For example, the shift of @bf[3] is @bf[#], and these have different
+X keysyms. Some keys map to the same X keysym regardless of the shift bit,
+such as @bf[Tab], @bf[Space], @bf[Return], etc. When the X lock bit is on, the
+system treats this as a caps-lock, only mapping keysyms for lowercase letters
+to shifted keysyms.
+
+The key-event has a keysym and a field of bits. The X keysyms map directly to
+the key-event keysyms. There is a distinct mapping for each CLX modifier bit
+to a key-event bit. This tends to eliminate shift and lock modifiers, so
+key-events usually only have control, meta, hyper, and super bits on. Hyper
+and super usually get turned on with prefix key-events that set them on the
+following key-event, but you can turn certain keys on the keyboard into hyper
+and super keys. See the X manuals and the @i[Hemlock Command Implementor's
+Manual] for details.
+
+The system also maps mouse input to key-events. Each mouse button has distinct
+key-event keysyms for whether the user pressed or released it. For
+convenience, @hemlock makes use of an odd property of converting mouse events
+to key-events. If you enter a mouse event with the shift key held down,
+@hemlock sees the key-event keysym for the mouse event, but the key-event has
+the super bit turned on. For example, if you press the left button with the
+shift key pressed, @hemlock sees @bf[S-Leftdown].
+
+Note that with the two button mouse on the IBM RT PC, the only way to to send
+@bf[Middledown] is to press both the left and right buttons simultaneously.
+This is awkward, and it often confuses the X server. For this reason, the
+commands bound to the middle button are also bound to the shifted left button,
+@bf[S-Leftdown], which is much easier to type.
+
+
+@subsection[Cut Buffer Commands]
+@index[cutting]@index[pasting] These commands allow the X cut buffer to be
+used from @hemlock . Although @hemlock can cut arbitrarily large regions,
+a bug in the standard version 10 xterm prevents large regions from being
+pasted into an xterm window.
+
+@defcom[com "Region to Cut Buffer", bind {M-Insert}]
+@defcom1[com "Insert Cut Buffer", bind {Insert}]
+These commands manipulate the X cut buffer. @hid[Region to Cut Buffer] puts
+the text in the region into the cut buffer. @hid[Insert Cut Buffer] inserts
+the contents of the cut buffer at the point.
+@enddefcom
+
+@subsection[Redisplay and Screen Management]
+
+These variables control a number of the characteristics of @hemlock bitmap
+screen management.
+
+@defhvar[var "Bell Style", val {:border-flash}]
+@defhvar1[var "Beep Border Width", val {20}]
+@hid[Bell Style] determines what beeps do in @hemlock. Acceptable values are
+@kwd[border-flash], @kwd[feep], @kwd[border-flash-and-feep], @kwd[flash],
+@kwd[flash-and-feep], and @nil (do nothing).
+
+@hid[Beep Border Width] is the width in pixels of the border flashed by border
+flash beep styles.
+@enddefhvar
+
+@defhvar[var "Reverse Video", val {nil}]
+If this variable is true, then @hemlock paints white on black in window
+bodies, black on white in modelines.
+@enddefhvar
+
+@defhvar[var "Thumb Bar Meter", val {t}]
+If this variable is true, then windows will be created to be displayed with a
+ruler in the bottom border of the window.
+@enddefhvar
+
+@defhvar[var "Set Window Autoraise", val {:echo-only}]
+When true, changing the current window will automatically raise the new current
+window. If the value is @kwd[echo-only], then only the echo area window will
+be raised automatically upon becoming current.
+@enddefhvar
+
+@defhvar[var "Default Initial Window Width", val {80}]
+@defhvar1[var "Default Initial Window Height", val {24}]
+@defhvar1[var "Default Initial Window X"]
+@defhvar1[var "Default Initial Window Y"]
+@defhvar1[var "Default Window Height", val {24}]
+@defhvar1[var "Default Window Width", val {80}]
+@index[window placement]
+@Hemlock uses the variables with "@hid[Initial]" in their names when it first
+starts up to make its first window. The width and height are specified in
+character units, but the x and y are specified in pixels. The other variables
+determine the width and height for interactive window creation, such as making
+a window with @comref[New Window].
+@enddefhvar
+
+@defhvar[var "Cursor Bitmap File", val {"library:hemlock.cursor"}]
+This variable determines where the mouse cursor bitmap is read from when
+@hemlock starts up. The mask is found by merging this name with "@f[.mask]".
+This has to be a full pathname for the C routine.
+@enddefhvar
+
+
+@defhvar[var "Default Font"]
+This variable holds the string name of the font to be used for normal text
+display: buffer text, modelines, random typeout, etc. The font is loaded at
+initialization time, so this variable must be set before entering @hemlock.
+When @nil, the display type is used to choose a font.
+@enddefhvar
+
+
+@section[Use With Terminals]
+@label[using-terminals]@index[terminals, use with] @hemlock can also be used
+with ASCII terminals and terminal emulators. Capabilities that depend on
+@windows (such as mouse commands) are not available, but nearly everything else
+can be done.
+
+@subsection[Terminal Initialization]
+
+@index[terminal speed]
+@index[speed, terminal]
+@index[slow terminals]
+@index[incremental redisplay]
+For best redisplay performance, it is very important to set the terminal speed:
+@lisp
+stty 2400
+@endlisp
+Often when running @hemlock using TTY redisplay, Hemlock will actually be
+talking to a PTY whose speed is initialized to infinity. In reality, the
+terminal will be much slower, resulting in @hemlock's output getting way ahead
+of the terminal. This prevents @hemlock from briefly stopping redisplay to
+allow the terminal to catch up. See also @hvarref.
+
+The terminal control sequences are obtained from the termcap database using the
+normal Unix conventions. The @f["TERM"] environment variable holds the
+terminal type. The @f["TERMCAP"] environment variable can be used to override
+the default termcap database (in @f["/etc/termcap"]). The size of the terminal
+can be altered from the termcap default through the use of:
+@lisp
+stty rows @i{height} columns @i{width}
+@endlisp
+
+@subsection[Terminal Input]
+@index[ASCII keyboard translation]
+@index[bit-prefix key-events]
+@index[prefix key-events]
+@index[key-event, prefix]
+The most important limitation of a terminal is its input capabilities. On a
+workstation with function keys and independent control, meta, and shift
+modifiers, it is possible to type 800 or so distinct single keystrokes.
+Although by default, @hemlock uses only a fraction of these combinations, there
+are many more than the 128 key-events available in ASCII.
+
+On a terminal, @hemlock attempts to translate ASCII control characters into the
+most useful key-event:
+@begin[itemize]
+On a terminal, control does not compose with shift. If the control key is down
+when you type a letter keys, the terminal always sends one code regardless of
+whether the shift key is held. Since @hemlock primarily binds commands to
+key-events with keysyms representing lowercase letters regardless of what bits
+are set in the key-event, the system translates the ASCII control codes to a
+keysym representing the appropriate lowercase characters. This keysym then
+forms a key-event with the control bit set. Users can type @bf[C-c] followed
+by an uppercase character to form a key-event with a keysym representing an
+uppercase character and bits with the control bit set.
+
+On a terminal, some of the named keys generate an ASCII control code. For
+example, @f[Return] usually sends a @f[C-m]. The system translates these ASCII
+codes to a key-event with an appropriate keysym instead of the keysym named by
+the character which names the ASCII code. In the above example, typing the
+@f[Return] key would generate a key-event with the @bf[Return] keysym and no
+bits. It would NOT translate to a key-event with the @bf[m] keysym and the
+control bit.
+@end[itemize]
+
+Since terminals have no meta key, you must use the @bf[Escape] and @bf[C-Z]
+modifier-prefix key-events to invoke commands bound to key-events with the meta
+bit or meta and control bits set. ASCII terminals cannot generate all
+key-events which have the control bit on, so you can use the @bf[C-^]
+modifier-prefix. The @bf[C-c] prefix sets the hyper bit on the next key-event
+typed.
+
+When running @hemlock from a terminal @f[^\] is the interrupt key-event.
+Typing this will place you in the Lisp debugger.
+
+When using a terminal, pop-up output windows cannot be retained after the
+completion of the command.
+
+
+@subsection[Terminal Redisplay]
+
+Redisplay is substantially different on a terminal. @Hemlock uses different
+algorithms, and different parameters control redisplay and screen management.
+
+Terminal redisplay uses the Unix termcap database to find out how to use a
+terminal. @hemlock is useful with terminals that lack capabilities for
+inserting and deleting lines and characters, and some terminal emulators
+implement these operations very inefficiently (such as xterm).
+If you realize poor performance when scrolling, create a termcap entry that
+excludes these capabilities.
+
+@defhvar[var "Scroll Redraw Ratio", val {nil}]
+This is a ratio of "inserted" lines to the size of a window. When this ratio
+is exceeded, insert/delete line terminal optimization is aborted, and every
+altered line is simply redrawn as efficiently as possible. For example,
+setting this to 1/4 will cause scrolling commands to redraw the entire window
+instead of moving the bottom two lines of the window to the top (typically 3/4
+of the window is being deleted upward and inserted downward, hence a redraw);
+however, commands like @hid[New Line] and @hid[Open Line] will still work
+efficiently, inserting a line and moving the rest of the window's text
+downward.
+@enddefhvar
+
+
+@section[The Echo Area]
+
+@index[echo area]
+@index[prompting]
+The echo area is the region which occupies the bottom few lines on the screen.
+It is used for two purposes: displaying brief messages to the user and
+prompting.
+
+When a command needs some information from the user, it requests it by
+displaying a @i[prompt] in the echo area. The following is a typical prompt:
+@begin[programexample]
+Select Buffer: [hemlock-init.lisp /usr/foo/]
+@end[programexample]
+The general format of a prompt is a one or two word description of the input
+requested, possibly followed by a @i[default] in brackets. The default is a
+standard response to the prompt that @hemlock uses if you type @bf[Return]
+without giving any other input.
+
+There are four general kinds of prompts: @comment
+@begin[description]
+@i[key-event]@\
+ The response is a single key-event and no confirming @binding[Return] is
+needed.
+
+@i[keyword]@\
+ The response is a selection from one of a limited number of choices.
+Completion is available using @binding[Space] and @binding[Escape], and you
+only need to supply enough of the keyword to distinguish it from any other
+choice. In some cases a keyword prompt accepts unknown input, indicating the
+prompter should create a new entry. If this is the case, then you must enter
+the keyword fully specified or completed using @binding[Escape]; this
+distinguishes entering an old keyword from making a new keyword which is a
+prefix of an old one since the system completes partial input automatically.
+
+@i[file]@\
+ The response is the name of a file, which may have to exist. Unlike other
+prompts, the default has some effect even after the user supplies some input:
+the system @i[merges] the default with the input filename. See page
+@pageref(merging) for a description of filename merging. @bf[Escape] and
+@bf[Space] complete the input for a file parse.
+
+@i[string]@\
+ The response is a string which must satisfy some property, such as being the
+name of an existing file.
+@end[description]
+
+@index[history, echo area]
+These key-events have special meanings when prompting:
+@begin[description]
+@binding[Return]@\
+ Confirm the current parse. If no input has been entered, then use the
+default. If for some reason the input is unacceptable, @hemlock does two
+things:
+@Begin[enumerate]
+beeps, if the variable @hid[Beep on Ambiguity] set, and
+
+moves the point to the end of the first word requiring disambiguation.
+@End[enumerate]
+This allows you to add to the input before confirming the it again.
+
+@binding[Home, C-_]@\
+ Print some sort of help message. If the parse is a keyword parse, then print
+all the possible completions of the current input in a pop-up window.
+
+@binding[Escape]@\
+ Attempt to complete the input to a keyword or file parse as far as possible,
+beeping if the result is ambiguous. When the result is ambiguous, @hemlock
+moves the point to the first ambiguous field, which may be the end of the
+completed input.
+
+@binding[Space]@\
+ In a keyword parse, attempt to complete the input up to the next space. This
+is useful for completing the names of @hemlock commands and similar things
+without beeping a lot, and you can continue entering fields while leaving
+previous fields ambiguous. For example, you can invoke @hid[Forward Word] as
+an extended command by typing @binding[M-X f Space w Return]. Each time the
+user enters space, @Hemlock attempts to complete the current field and all
+previous fields.
+
+@binding[C-i, Tab]@\
+ In a string or keyword parse, insert the default so that it may be edited.
+
+@binding[C-p]@\
+ Retrieve the text of the last string input from a history of echo area inputs.
+Repeating this moves to successively earlier inputs.
+
+@binding[C-n]@\
+ Go the other way in the echo area history.
+
+@binding[C-q]@\
+ Quote the next key-event so that it is not interpreted as a command.
+@end[description]
+
+@defhvar[var "Ignore File Types"]
+This variable is a list of file types (or extensions), represented as a string
+without the dot, e.g. @f["fasl"]. Files having any of the specified types will
+be considered nonexistent for completion purposes, making an unambiguous
+completion more likely. The initial value contains most common binary and
+output file types.
+@enddefhvar
+
+
+@section[Online Help]
+
+@label[help]
+@index[online help]
+@index[documentation, hemlock]
+@hemlock has a fairly good online documentation facility. You can get brief
+documentation for every command, variable, character attribute, and key
+by typing a key.
+
+@defcom[com "Help", bind (Home, C-_)]
+This command prompt for a key-event indicating one of a number of other
+documentation commands. The following are valid responses:
+@begin[description]
+@bf[a]@\
+ List commands and other things whose names contain a specified keyword.
+
+@bf[d]@\
+ Give the documentation and bindings for a specified command.
+
+@bf[g]@\
+ Give the documentation for any @hemlock thing.
+
+@bf[v]@\
+ Give the documentation for a @hemlock variable and its values.
+
+@bf[c]@\
+ Give the documentation for a command bound to some key.
+
+@bf[l]@\
+ List the last sixty key-events typed.
+
+@bf[m]@\
+ Give the documentation for a mode followed by a short description of its
+mode-specific bindings.
+
+@bf[p]@\
+ Give the documentation and bindings for commands that have at least one
+binding involving a mouse/pointer key-event.
+
+@bf[w]@\
+ List all the key bindings for a specified command.
+
+@bf[t]@\
+ Describe a @llisp object.
+
+@binding[q]@\
+ Quit without doing anything.
+
+@binding[Home, C-_, ?, h]@\
+ List all of the options and what they do.
+@end[description]
+@enddefcom
+
+@defcom[com "Apropos", bind (Home a, C-_ a)]
+This command prints brief documentation for all commands, variables, and
+character attributes whose names match the input. This performs a prefix match
+on each supplied word separately, intersecting the names in each word's result.
+For example, giving @hid[Apropos] "@f[f m]" causes it to tersely describe
+following commands and variables:
+@Begin[Itemize]
+@hid[Auto Fill Mode]
+
+@hid[Fundamental Mode]
+
+@hid[Mark Form]
+
+@hid[Default Modeline Fields]
+
+@hid[Fill Mode Hook]
+
+@hid[Fundamental Mode Hook]
+@End[Itemize]
+Notice @hid[Mark Form] demonstrates that the "@f[f]" words may follow the
+"@f[m]" order of the fields does not matter for @hid[Apropos].
+
+The bindings of commands and values of variables are printed with the
+documentation.
+@enddefcom
+
+@defcom[com "Describe Command", bind (Home d, C-_ d)]
+This command prompts for a command and prints its full documentation and all
+the keys bound to it.
+@enddefcom
+
+@defcom[com "Describe Key", bind (Home c, C-_ c, M-?)]
+This command prints full documentation for the command which is bound to
+the specified key in the current environment.
+@enddefcom
+
+@defcom[com "Describe Mode", bind (Home m, C-_ m)]
+This command prints the documentation for a mode followed by a short
+description of each of its mode-specific bindings.
+@enddefcom
+
+@defcom[com "Show Variable"]
+@defcom1[com "Describe and Show Variable"]
+@hid[Show Variable] prompts for the name of a variable and displays
+the global value of the variable, the value local to the current buffer (if
+any), and the value of the variable in all defined modes that have it as a
+local variable. @hid[Describe and Show Variable] displays the variable's
+documentation in addition to the values.
+@enddefcom
+
+@defcom[com "What Lossage", bind (Home l, C-_ l)]
+This command displays the last sixty key-events typed. This can be useful
+if, for example, you are curious what the command was that you typed by
+accident.
+@enddefcom
+
+@defcom[com "Describe Pointer"]
+This command displays the documentation and bindings for commands that have
+some binding involving a mouse/pointer key-event. It will not show the
+documentation for the @hid[Illegal] command regardless of whether it has a
+pointer binding.
+@enddefcom
+
+@defcom[com "Where Is", bind (Home w, C-_ w)]
+This command prompts for the name of a command and displays its key
+bindings in a pop-up window. If a key binding is not global, the
+environment in which it is available is displayed.
+@enddefcom
+
+@defcom[com "Generic Describe", bind (Home g, C-_ g)]
+This command prints full documentation for any thing that has
+documentation. It first prompts for the kind of thing to document, the
+following options being available:
+@begin[description]
+@i[attribute]@\Describe a character attribute, given its name.
+
+@i[command]@\Describe a command, given its name.
+
+@i[key]@\Describe a command, given a key to which it is bound.
+
+@i[variable]@\Describe a variable, given its name. This is the default.
+@end[description]
+@enddefcom
+
+
+@section[Entering and Exiting]
+
+@index[entering hemlock]@hemlock is entered by using the @clisp @f[ed]
+function. Simply typing @f[(ed)] will enter @hemlock, leaving you in the state
+that you were in when you left it. If @hemlock has never been entered before
+then the current buffer will be @hid[Main]. The @f[-edit] command-line switch
+may also be used to enter @hemlock: see page @pageref[edit-switch].
+
+@f[ed] may optionally be given a file name or a symbol argument. Typing
+@f[(ed @i[filename])] will cause the specified file to be read into @hemlock,
+as though by @hid[Find File]. Typing @w<@f[(ed @i[symbol])]> will pretty-print
+the definition of the symbol into a buffer whose name is obtained by adding
+"@f[Edit ]" to the beginning of the symbol's name.
+
+@defcom[com "Exit Hemlock", bind (C-c, C-x C-z)]
+@defcom1[com "Pause Hemlock"]
+@index[exiting hemlock]@hid[Exit Hemlock] exits @hemlock, returning @f[t].
+@hid[Exit Hemlock] does not by default save modified buffers, or do
+anything else that you might think it should do; it simply exits. At any time
+after exiting you may reenter by typing @f[(ed)] to @llisp without losing
+anything. Before you quit from @llisp using @f[(quit)], you should
+save any modified files that you want to be saved.
+
+@hid[Pause Hemlock] is similar, but it suspends the @llisp process and returns
+control to the shell. When the process is resumed, it will still be running
+@hemlock.
+@enddefcom
+
+
+@section[Helpful Information]
+
+@label[aborting]
+@index[aborting]
+@index[undoing]
+@index[error recovery]
+This section contains assorted helpful information which may be useful in
+staying out of trouble or getting out of trouble.
+
+@begin[itemize]
+It is possible to get some sort of help nearly everywhere by typing
+@binding[Home] or @binding[C-_].
+
+Various commands take over the keyboard and insist that you type the key-events
+that they want as input. If you get in such a situation and want to get out,
+you can usually do so by typing @bf[C-g] some small number of times. If this
+fails you can try typing @binding[C-x C-z] to exit @hemlock and then "@f[(ed)]"
+to re-enter it.
+
+Before you quit, make sure you have saved all your changes. @binding[C-u C-x
+C-b] will display a list of all modified buffers. If you exit using @bf[C-x
+M-z], then @hemlock will save all modified buffers with associated files.
+
+If you lose changes to a file due to a crash or accidental failure to save,
+look for backup ("@i[file]@f[.BAK]") or checkpoint ("@i[file]@f[.CKP]") files
+in the same directory where the file was.
+
+If the screen changes unexpectedly, you may have accidentally typed an
+incorrect command. Use @binding[Home l] to see what it was. If you are
+not familiar with the command, use @binding[Home c] to see what it is so that
+you know what damage has been done. Many interesting commands can be found
+in this fashion. This is an example of the much-underrated learning
+technique known as "Learning by serendipitous malcoordination". Who would
+ever think of looking for a command that deletes all files in the current
+directory?
+
+If you accidentally type a "killing" command such as @binding[C-w], you can
+get the lost text back using @binding[C-y]. The @hid[Undo] command is also
+useful for recovering from this sort of problem.
+@end[itemize]
+
+@defhvar[var "Region Query Size", val {30}]
+@index[large region]
+Various commands ask for confirmation before modifying a region containing more
+than this number of lines. If this is @nil, then these commands refrain from
+asking, no matter how large the region is.
+@enddefhvar
+
+@defcom[com "Undo"]
+This command undoes the last major modification. Killing commands and some
+other commands save information about their modifications, so accidental uses
+may be retracted. This command displays the name of the operation to be undone
+and asks for confirmation. If the affected text has been modified between the
+invocations of @hid[Undo] and the command to be undone, then the result may be
+somewhat incorrect but useful. Often @hid[Undo] itself can be undone by
+invoking it again.
+@enddefcom
+
+
+@section[Recursive Edits]
+@label[recursive-edits]
+@index[recursive edits]
+Some sophisticated commands, such as @hid[Query Replace], can place you in a
+@i[recursive edit]. A recursive edit is simply a recursive invocation of
+@hemlock done within a command. A recursive edit is useful because it allows
+arbitrary editing to be done during the execution of a command without losing
+any state that the command might have. When the user exits a recursive edit,
+the command that entered it proceeds as though nothing happened. @Hemlock
+notes recursive edits in the @hid[Echo Area] modeline, or status line. A
+counter reflects the number of pending recursive edits.
+
+@defcom[com "Exit Recursive Edit", bind (C-M-z)]
+This command exits the current recursive edit, returning @nil. If invoked when
+not in a recursive edit, then this signals an user error.
+@enddefcom
+
+@defcom[com "Abort Recursive Edit", bind (@bf)]
+This command causes the command which invoked the recursive edit to get an
+error. If not in a recursive edit, this signals an user error.
+@enddefcom
+
+
+@section[User Errors]
+@index[beeping]
+@index[errors, user]
+When in the course of editing, @hemlock is unable to do what it thinks you want
+to do, then it brings this to your attention by a beep or a screen flash
+(possibly accompanied by an explanatory echo area message such as @w<"@f[No
+next line.]">.) Although the exact attention-getting mechanism may vary on the
+output device and variable settings, this is always called @i[beeping].
+
+Whatever the circumstances, you had best try something else since @hemlock,
+being far more stupid than you, is far more stubborn. @hemlock is an
+extensible editor, so it is always possible to change the command that
+complained to do what you wanted it to do.
+
+@section[Internal Errors]
+
+@index[errors, internal]A message of this form may appear in the echo
+area, accompanied by a beep:
+@begin[programexample]
+Internal error:
+Wrong type argument, NIL, should have been of type SIMPLE-VECTOR.
+@end[programexample]
+If the error message is a file related error such as the following, then
+you have probably done something illegal which @hemlock did not catch,
+but was detected by the file system:
+@begin[programexample]
+Internal error:
+No access to "/lisp2/emacs/teco.mid"
+@end[programexample]
+Otherwise, you have found a bug. Try to avoid the behavior that resulted
+in the error and report the problem to your system maintainer. Since @llisp
+has fairly robust error recovery mechanisms, probably no damage has been
+done.
+
+If a truly abominable error from which @hemlock cannot recover occurs,
+then you will be thrown into the @llisp debugger. At this point it would be
+a good idea to save any changes with @f[save-all-buffers] and then start
+a new @llisp.
+
+@index[save-all-buffers, function]The @llisp function @f[save-all-buffers] may
+be used to save modified buffers in a seriously broken @hemlock. To use this,
+type "@f[(save-all-buffers)]" to the top-level ("@f[* ]") or debugger
+("@f<1] >") prompt and confirm saving of each buffer that should be saved.
+Since this function will prompt in the "@f[Lisp]" window, it isn't very useful
+when called inside of @hemlock.
diff --git a/docs/hem/user/lisp.mss b/docs/hem/user/lisp.mss
new file mode 100644
index 0000000000000000000000000000000000000000..fc749caa9313f9e06f51ccbceb3bb99987156583
--- /dev/null
+++ b/docs/hem/user/lisp.mss
@@ -0,0 +1,822 @@
+@comment{-*- Dictionary: /afs/cs/project/clisp/scribe/hem/hem; Mode: spell; Package: Hemlock -*-}
+@chap[Interacting With Lisp]
+@index[lisp, interaction with]
+
+Lisp encourages highly interactive programming environments by requiring
+decisions about object type and function definition to be postponed until run
+time. @hemlock supports interactive programming in @llisp by providing
+incremental redefinition and environment examination commands. @hemlock also
+uses Unix TCP sockets to support multiple Lisp processes, each of which may be
+on any machine.
+
+
+@section[Eval Servers]
+@label[eval-servers]
+@index[eval servers]
+
+@hemlock runs in the editor process and interacts with other Lisp processes
+called @i[eval servers]. A user's Lisp program normally runs in an eval
+server process. The separation between editor and eval server has several
+advantages:
+@begin[itemize]
+The editor is protected from any bad things which may happen while debugging a
+Lisp program.
+
+Editing may occur while running a Lisp program.
+
+The eval server may be on a different machine, removing the load from the
+editing machine.
+
+Multiple eval servers allow the use of several distinct Lisp environments.
+@end[itemize]
+Instead of providing an interface to a single Lisp environment, @hemlock
+coordinates multiple Lisp environments.
+
+
+@subsection[The Current Eval Server]
+@index[current eval server]
+Although @hemlock can be connected to several eval servers simultaneously, one
+eval server is designated as the @i[current eval server]. This is the eval
+server used to handle evaluation and compilation requests. Eval servers are
+referred to by name so that there is a convenient way to discriminate between
+servers when the editor is connected to more than one. The current eval server
+is normally globally specified, but it may also be shadowed locally in specific
+buffers.
+
+@defcom[com "Set Eval Server"]
+@defcom1[com "Set Buffer Eval Server"]
+@defcom1[com "Current Eval Server"]
+@hid[Set Eval Server] prompts for the name of an eval server and makes it the
+the current eval server. @hid[Set Buffer Eval Server] is the same except that
+is sets the eval server for the current buffer only. @hid[Current Eval Server]
+displays the name of the current eval server in the echo area, taking any
+buffer eval server into consideration. See also @comref[Set Compile Server].
+@enddefcom
+
+
+@subsection[Slaves]
+@index[slave buffers]
+@index[slaves]
+For now, all eval servers are @i[slaves]. A slave is a Lisp process that uses
+a typescript (see page @pageref[typescripts]) to run its top-level
+@f[read-eval-print] loop in a @hemlock buffer. We refer to the buffer that a
+slave uses for I/O as its @i[interactive] or @i[slave] buffer. The name of the
+interactive buffer is the same as the eval server's name.
+
+@index[background buffers]
+@hemlock creates a @i[background] buffer for each eval server. The background
+buffer's name is @w<@hid[Background ]@i{name}>, where @i[name] is the name of
+the eval server. Slaves direct compiler warning output to the background
+buffer to avoid cluttering up the interactive buffer.
+
+@hemlock locally sets @hid[Current Eval Server] in interactive and background
+buffers to their associated slave. When in a slave or background buffer, eval
+server requests will go to the associated slave, regardless of the global value
+of @hid[Current Eval Server].
+
+@defcom[com "Select Slave", bind (C-M-c)]
+This command changes the current buffer to the current eval server's
+interactive buffer. If the current eval server is not a slave, then it beeps.
+If there is no current eval server, then this creates a slave (see section
+@ref[slave-creation]). If a prefix argument is supplied, then this creates a
+new slave regardless of whether there is a current eval server. This command
+is the standard way to create a slave.
+
+The slave buffer is a typescript (see page @pageref[typescripts]) the slave
+uses for its top-level @f[read-eval-print] loop.
+@enddefcom
+
+@defcom[com "Select Background", bind (C-M-C)]
+This command changes the current buffer to the current eval server's background
+buffer. If there is no current eval server, then it beeps.
+@enddefcom
+
+
+@subsection[Slave Creation and Destruction]
+@label[slave-creation]
+When @hemlock first starts up, there is no current eval server. If there is no
+a current eval server, commands that need to use the current eval server will
+create a slave as the current eval server.
+
+If an eval server's Lisp process terminates, then we say the eval server is
+dead. @hemlock displays a message in the echo area, interactive, and
+background buffers whenever an eval server dies. If the user deletes an
+interactive or background buffer, the associated eval server effectively
+becomes impotent, but @hemlock does not try to kill the process. If a command
+attempts to use a dead eval server, then the command will beep and display a
+message.
+
+@defhvar[var "Confirm Slave Creation", val {t}]
+If this variable is true, then @hemlock always prompts the user for
+confirmation before creating a slave.
+@enddefhvar
+
+@defhvar[var "Ask About Old Servers", val {t}]
+If this variable is true, and some slave already exists, @hemlock prompts the
+user for the name of an existing server when there is no current server,
+instead of creating a new one.
+@enddefhvar
+
+@defcom[com "Editor Server Name"]
+This command echos the editor server's name, the machine and port of the
+editor, which is suitable for use with the Lisp processes -slave switch.
+See section @ref[slave-switch].
+@enddefcom
+
+@defcom[com "Accept Slave Connections"]
+This command cause @hemlock to accept slave connections, and it displays the
+editor server's name, which is suitable for use with the Lisp processes -slave
+switch. See section @ref[slave-switch]. Supplying an argument causes this
+command to inhibit slave connections.
+@enddefcom
+
+@defhvar[var "Slave Utility", val {"/usr/misc/.lisp/bin/lisp"}]
+@defhvar1[var "Slave Utility Switches"]
+A slave is started by running the program @hid[Slave Utility Name] with
+arguments specified by the list of strings @hid[Slave Utility Switches]. This
+is useful primarily when running customized Lisp systems. For example,
+setting @hid[Slave Utility Switches] to @f[("-core" "my.core")] will cause
+"@f[/usr/hqb/my.core]" to be used instead of the default core image.
+
+The @f[-slave] switch and the editor name are always supplied as arguments, and
+should remain unspecified in @hid[Slave Utility Switches].
+@enddefhvar
+
+@defcom[com "Kill Slave"]
+@defcom1[com "Kill Slave and Buffers"]
+@hid[Kill Slave] prompts for a slave name, aborts any operations in the slave,
+tells the slave to @f[quit], and shuts down the connection to the specified
+eval server. This makes no attempt to assure the eval server actually dies.
+
+@hid[Kill Slave and Buffers] is the same as @hid[Kill Slave], but it also
+deletes the interactive and background buffers.
+@enddefcom
+
+
+@subsection[Eval Server Operations]
+
+@label[operations]
+@index[eval server operations]@index[operations, eval server]
+@hemlock handles requests for compilation or evaluation by queuing an
+@i[operation] on the current eval server. Any number of operations may be
+queued, but each eval server can only service one operation at a time.
+Information about the progress of operations is displayed in the echo area.
+
+@defcom[com "Abort Operations", bind (C-c a)]
+This command aborts all operations on the current eval server, either queued or
+in progress. Any operations already in the @f[Aborted] state will be flushed.
+@enddefcom
+
+@defcom[com "List Operations", bind (C-c l)]
+This command lists all operations which have not yet completed. Along with a
+description of the operation, the state and eval server is displayed. The
+following states are used:
+@begin[description]
+@f[Unsent]@\The operation is in local queue in the editor, and hasn't been sent
+yet.
+
+@f[Pending]@\The operation has been sent, but has not yet started execution.
+
+@f[Running]@\The operation is currently being processed.
+
+@f[Aborted]@\The operation has been aborted, but the eval server has not yet
+indicated termination.
+@end[description]
+@enddefcom
+
+
+@section[Typescripts]
+@label[typescripts]
+@index[typescripts]
+
+Both slave buffers and background buffers are typescripts. The typescript
+protocol allows other processes to do stream-oriented interaction in a @hemlock
+buffer similar to that of a terminal. When there is a typescript in a buffer,
+the @hid[Typescript] minor mode is present. Some of the commands described in
+this section are also used by @hid[Eval] mode (page @pageref[eval-mode].)
+
+Typescripts are simple to use. @hemlock inserts output from the process into
+the buffer. To give the process input, use normal editing to insert the input
+at the end of the buffer, and then type @bf[Return] to confirm sending the
+input to the process.
+
+@defcom[com "Confirm Typescript Input",
+ stuff (bound to @bf[Return] in @hid[Typescript] mode)]
+@defhvar1[var "Unwedge Interactive Input Confirm", val {t}]
+This command sends text that has been inserted at the end of the current buffer
+to the process reading on the buffer's typescript. Before sending the text,
+@hemlock moves the point to the end of the buffer and inserts a newline.
+
+Input may be edited as much as is desired before it is confirmed; the result
+of editing input after it has been confirmed is unpredictable. For this reason,
+it is desirable to postpone confirming of input until it is actually complete.
+The @hid[Indent New Line] command is often useful for inserting newlines
+without confirming the input.
+
+If the process reading on the buffer's typescript is not waiting for input,
+then the text is queued instead of being sent immediately. Any number of
+inputs may be typed ahead in this fashion. @hemlock makes sure that the inputs
+and outputs get interleaved correctly so that when all input has been read, the
+buffer looks the same as it would have if the input had not been typed ahead.
+
+If the buffer's point is before the start of the input area, then various
+actions can occur. When set, @hid[Unwedge Interactive Input Confirm] causes
+@hemlock to ask the user if it should fix the input buffer which typically
+results in ignoring any current input and refreshing the input area at the end
+of the buffer. This also has the effect of throwing the slave Lisp to top
+level, which aborts any pending operations or queued input. This is the only
+way to be sure the user is cleanly set up again after messing up the input
+region. When this is @nil, @hemlock simply beeps and tells the user in the
+@hid[Echo Area] that the input area is invalid.
+@enddefcom
+
+@defcom[com "Kill Interactive Input",
+ stuff (bound to @bf[M-i] in @hid[Typescript] and @hid[Eval] modes)]
+This command kills any input that would have been confirmed by @bf[Return].
+@enddefcom
+
+@defcom[com "Next Interactive Input",
+ stuff (bound to @bf[M-n] in @hid[Typescript] and @hid[Eval] modes)]
+@defcom1[com "Previous Interactive Input",
+ stuff (bound to @bf[M-p] in @hid[Typescript] and @hid[Eval] modes)]
+@defcom1[com "Search Previous Interactive Input",
+ stuff (bound to @bf[M-P] in @hid[Typescript] and @hid[Eval] modes)]
+@defhvar1[var "Interactive History Length", val {10}]
+@defhvar1[var "Minimum Interactive Input Length", val {2}]
+@index[history, typescript]
+@Hemlock maintains a history of interactive inputs. @hid[Next Interactive
+Input] and @hid[Previous Interactive Input] step forward and backward in the
+history, inserting the current entry in the buffer. The prefix argument is
+used as a repeat count.
+
+@hid[Search Previous Interactive Input] searches backward through the
+interactive history using the current input as a search string. Consecutive
+invocations repeat the previous search.
+
+@hid[Interactive History Length] determines the number of entries with which
+@hemlock creates the buffer-specific histories. @Hemlock only adds an input
+region to the history if its number of characters exceeds @hid[Minimum
+Interactive Input Length].
+@enddefcom
+
+@defcom[com "Reenter Interactive Input",
+ stuff (bound to @bf[C-Return] in @hid[Typescript] and @hid[Eval] modes)]
+ This copies to the end of the buffer the form to the left of the buffer's
+point. When the current region is active, this copies it instead. This is
+sometimes easier to use to get a previous input that is either so far back that
+it has fallen off the history or is visible and more readily @i[yanked] than
+gotten with successive invocations of the history commands.
+@enddefcom
+
+@defcom[com "Interactive Beginning of Line",
+ stuff (bound to @bf[C-a] in @hid[Typescript] and @hid[Eval] modes)]
+This command is identical to @hid[Beginning of Line] unless there is no
+prefix argument and the point is on the same line as the start of the current
+input; then it moves to the beginning of the input. This is useful since it
+skips over any prompt which may be present.
+@enddefcom
+
+@defhvar[var "Input Wait Alarm", val {:loud-message}]
+@defhvar1[var "Slave GC Alarm", val {:message}]
+@hid[Input Wait Alarm] determines what action to take when a slave Lisp goes
+into an input wait on a typescript that isn't currently displayed in any
+window. @hid[Slave GC Alarm] determines what action to take when a slave
+notifies that it is GC'ing.
+
+The following are legal values:
+@begin[description]
+@kwd[loud-message]@\Beep and display a message in the echo area indicating
+which buffer is waiting for input.
+
+@kwd[message]@\Display a message, but don't beep.
+
+@nil@\Don't do anything.
+@end[description]
+@enddefhvar
+
+@defcom[com "Typescript Slave BREAK", bind (Typescript: H-b)]
+@defcom1[com "Typescript Slave to Top Level", bind (Typescript: H-g)]
+@defcom1[com "Typescript Slave Status", bind (Typescript: H-s)]
+Some typescripts have associated information which these commands access
+allowing @hemlock to control the process which uses the typescript.
+
+@hid[Typescript Slave BREAK] puts the current process in a break loop so that
+you can be debug it. This is similar in effect to an interrupt signal (@f[^C]
+or @f[^\] in the editor process).
+
+@hid[Typescript Slave to Top Level] causes the current process to throw to the
+top-level @f[read-eval-print] loop. This is similar in effect to a quit signal
+(@f[^\]).
+
+@hid[Typescript Slave Status] causes the current process to print status
+information on @var[error-output]:
+@lisp
+; Used 0:06:03, 3851 faults. In: SYSTEM:SERVE-EVENT
+@endlisp
+The message displays the process run-time, the total number of page faults and
+the name of the currently running function. This command is useful for
+determining whether the slave is in an infinite loop, waiting for input, or
+whatever.
+@enddefcom
+
+
+@section[The Current Package]
+@label[lisp-package]
+@index[package]
+The current package is the package which Lisp interaction commands use. The
+current package is specified on a per-buffer basis, and defaults to "@f[USER]".
+If the current package does not exist in the eval server, then it is created.
+If evaluation is being done in the editor process and the current package
+doesn't exist, then the value of @f[*package*] is used. The current package is
+displayed in the modeline (see section @ref[modelines].) Normally the package
+for each file is specified using the @f[Package] file option (see page
+@pageref[file-options].)
+
+When in a slave buffer, the current package is controlled by the value of
+@var[package] in that Lisp process. Modeline display of the current package
+is inhibited in this case.
+
+@defcom[com "Set Buffer Package"]
+This command prompts for the name of a package to make the local package in the
+current buffer. If the current buffer is a slave, background, or eval buffer,
+then this sets the current package in the associated eval server or editor
+Lisp. When in an interactive buffer, do not use @f[in-package]; use this
+command instead.
+@enddefcom
+
+
+@section[Compiling and Evaluating Lisp Code]
+
+@index[compilation]@index[evaluation]These commands can greatly speed up
+the edit/debug cycle since they enable incremental reevaluation or
+recompilation of changed code, avoiding the need to compile and load an
+entire file.
+
+@defcom[com "Evaluate Expression", bind (M-Escape)]
+This command prompts for an expression and prints the result of its evaluation
+in the echo area. If an error happens during evaluation, the evaluation is
+simply aborted, instead of going into the debugger. This command doesn't
+return until the evaluation is complete.
+@enddefcom
+
+@defcom[com "Evaluate Defun", bind (C-x C-e)]
+@defcom1[com "Evaluate Region"]
+@defcom1[com "Evaluate Buffer"]
+These commands evaluate text out of the current buffer, reading the current
+defun, the region and the entire buffer, respectively. The result of the
+evaluation of each form is displayed in the echo area. If the region is
+active, then @hid[Evaluate Defun] evaluates the current region, just like
+@hid[Evaluate Region].
+@enddefcom
+
+@defcom[com "Macroexpand Expression", bind (C-M)]
+This command shows the macroexpansion of the next expression in the null
+environment in a pop-up window. With an argument, it uses @f[macroexpand]
+instead of @f[macroexpand-1].
+@enddefcom
+
+@defcom[com "Re-evaluate Defvar"]
+This command is similar to @hid[Evaluate Defun]. It is used for force the
+re-evaluation of a @f[defvar] init form. If the current top-level form is a
+@f[defvar], then it does a @f[makunbound] on the variable, and evaluates the
+form.
+@enddefcom
+
+@defcom[com "Compile Defun", bind (C-x C-c)]
+@defcom1[com "Compile Region"]
+These commands compile the text in the current defun and the region,
+respectively. If the region is active, then @hid[Compile Defun] compiles the
+current region, just like @hid[Compile Region].
+@enddefcom
+
+@defcom[com "Load File"]
+@defhvar1[var "Load Pathname Defaults", val {nil}]
+This command prompts for a file and loads it into the current eval server using
+@f[load]. @hid[Load Pathname Defaults] contains the default pathname for this
+command. This variable is set to the file loaded; if it is @nil, then there is
+no default. This command also uses the @hid[Remote Compile File] variable.
+@enddefcom
+
+
+@section[Compiling Files]
+These commands are used to compile source ("@f[.lisp]") files, producing binary
+("@f[.fasl]") output files. Note that unlike the other compiling and evalating
+commands, this does not have the effect of placing the definitions in the
+environment; to do so, the binary file must be loaded.
+
+@defcom[com "Compile Buffer File", bind (C-x c)]
+@defhvar1[var "Compile Buffer File Confirm", val {t}]
+This command asks for confirmation, then saves the current buffer (when
+modified) and compiles the associated file. The confirmation prompt indicates
+intent to save and compile or just compile. If the buffer wasn't modified, and
+a comparison of the write dates for the source and corresponding binary
+("@f[.fasl]") file suggests that recompilation is unnecessary, the confirmation
+also indicates this. A prefix argument overrides this test and forces
+recompilation. Since there is a complete log of output in the background
+buffer, the creation of the normal error output ("@f[.err]") file is inhibited.
+
+Setting @hid[Compile Buffer File Confirm] to @nil inhibits confirmation, except
+when the binary is up to date and a prefix argument is not supplied.
+@enddefcom
+
+@defcom[com "Compile File"]
+This command prompts for a file and compiles that file, providing a convenient
+way to compile a file that isn't in any buffer. Unlike
+@hid[Compile Buffer File], this command doesn't do any consistency checks such
+as checking whether the source is in a modified buffer or the binary is up to
+date.
+@enddefcom
+
+@defcom[com "Compile Group"]
+@defcom1[com "List Compile Group"]
+@label[compile-group-command]@index[group, compilation]@hid[Compile Group] does
+a @hid[Save All Files] and then compiles every "@f[.lisp]" file for which the
+corresponding "@f[.fasl]" file is older or nonexistent. The files are compiled
+in the order in which they appear in the group definition. A prefix argument
+forces compilation of all "@f[.lisp]" files.
+
+@hid[List Compile Group] lists any files that would be compiled by
+@hid[Compile Group]. All Modified files are saved before checking to generate
+a consistent list.
+@enddefcom
+
+@defcom[com "Set Compile Server"]
+@defcom1[com "Set Buffer Compile Server"]
+@defcom1[com "Current Compile Server"]
+These commands are analogous to @hid[Set Eval Server], @comref[Set Buffer Eval
+Server] and @hid[Current Eval Server], but they determine the eval server used
+for file compilation requests. If the user specifies a compile server, then
+the file compilation commands send compilation requests to that server instead
+of the current eval server.
+
+Having a separate compile server makes it easy to do compilations in the
+background while continuing to interact with your eval server and editor. The
+compile server can also run on a remote machine relieving your active
+development machine of the compilation effort.
+@enddefcom
+
+@defcom[com "Next Compiler Error", bind (H-n)]
+@defcom1[com "Previous Compiler Error", bind (H-p)]
+These commands provides a convenient way to inspect compiler errors. First it
+splits the current window if there is only one window present. @hemlock
+positions the current point in the first window at the erroneous source code
+for the next (or previous) error. Then in the second window, it displays the
+error beginning at the top of the window. Given an argument, this command
+skips that many errors.
+@enddefcom
+
+@defcom[com "Flush Compiler Error Information"]
+This command relieves the current eval server of all infomation about errors
+encountered while compiling. This is convenient if you have been compiling a
+lot, but you were ignoring errors and warnings. You don't want to step through
+all the old errors, so you can use this command immediately before compiling a
+file whose errors you intend to edit.
+@enddefcom
+
+
+@defhvar[var "Remote Compile File", val {nil}]
+When true, this variable causes file compilations to be done using the RFS
+remote file system mechanism by prepending "@f[/../]@i[host]" to the file being
+compiled. This allows the compile server to be run on a different machine, but
+requires that the source be world readable. If false, commands use source
+filenames directly. Do NOT use this to compile files in AFS.
+@enddefhvar
+
+
+@section[Querying the Environment]
+@index[documentation, lisp]
+These commands are useful for obtaining various random information from the
+Lisp environment.
+
+@defcom[com "Describe Function Call", bind (C-M-A)]
+@defcom1[com "Describe Symbol", bind (C-M-S)]
+@hid[Describe Function Call] uses the current eval server to describe the
+symbol found at the head of the currently enclosing list, displaying the output
+in a pop-up window. @hid[Describe Symbol] is the same except that it describes
+the symbol at or before the point. These commands are primarily useful for
+finding the documentation for functions and variables. If there is no
+currently valid eval server, then this command uses the editor Lisp's
+environment instead of trying to spawn a slave.
+@enddefcom
+
+
+@section[Editing Definitions]
+The Lisp compiler annotates each compiled function object with the source
+file that the function was originally defined from. The definition editing
+commands use this information to locate and edit the source for functions
+defined in the environment.
+
+@defcom[com "Edit Definition"]
+@defcom1[com "Goto Definition", bind (C-M-F)]
+@defcom1[com "Edit Command Definition"]
+@hid[Edit Definition] prompts for the name of a function, and then uses the
+current eval server to find out in which file the function is defined. If
+something other than @f[defun] or @f[defmacro] defined the function, then this
+simply reads in the file, without trying to find its definition point within
+the file. If the function is uncompiled, then this looks for it in the current
+buffer. If there is no currently valid eval server, then this command uses the
+editor Lisp's environment instead of trying to spawn a slave.
+
+@hid[Goto Definition] edits the definition of the symbol at the beginning of
+the current list.
+
+@hid[Edit Command Definition] edits the definition of a @hemlock command. By
+default, this command does a keyword prompt for the command name (as in an
+extended command). If a prefix argument is specified, then instead prompt for
+a key and edit the definition of the command bound to that key.
+@enddefcom
+
+@defcom[com "Add Definition Directory Translation"]
+@defcom1[com "Delete Definition Directory Translation"]
+The defining file is recorded as an absolute pathname. The definition editing
+commands have a directory translation mechanism that allow the sources to be
+found when they are not in the location where compilation was originally done.
+@hid[Add Definition Directory Translation] prompts for two directory
+namestrings and causes the first to be mapped to the second. Longer (more
+specific) directory specifications are matched before shorter (more general)
+ones.
+
+@hid[Delete Definition Directory Translation] prompts for a directory
+namestring and deletes it from the directory translation table.
+@enddefcom
+
+@defhvar[var "Editor Definition Info", val {nil}]
+When this variable is true, the editor Lisp is used to determine definition
+editing information, otherwise the current eval server is used. This variable
+is true in @hid[Eval] and @hid[Editor] modes.
+@enddefhvar
+
+
+@section[Debugging]
+These commands manipulate the slave when it is in the debugger and provide
+source editing based on the debugger's current frame. These all affect the
+@hid[Current Eval Server].
+
+
+@subsection[Changing Frames]
+
+@defcom[com "Debug Down", bind (C-M-H-d)]
+This command moves down one debugger frame.
+@enddefcom
+
+@defcom[com "Debug Up", bind (C-M-H-u)]
+This command moves up one debugger frame.
+@enddefcom
+
+@defcom[com "Debug Top", bind (C-M-H-t)]
+This command moves to the top of the debugging stack.
+@enddefcom
+
+@defcom[com "Debug Bottom", bind (C-M-H-b)]
+This command moves to the bottom of the debugging stack.
+@enddefcom
+
+@defcom[com "Debug Frame", bind (C-M-H-f)]
+This command moves to the absolute debugger frame number indicated by the
+prefix argument.
+@enddefcom
+
+
+@subsection[Getting out of the Debugger]
+
+@defcom[com "Debug Quit", bind (C-M-H-q)]
+This command throws to top level out of the debugger in the @hid[Current Eval
+Server].
+@enddefcom
+
+@defcom[com "Debug Go", bind (C-M-H-g)]
+This command tries the @f[continue] restart in the @hid[Current Eval Server].
+@enddefcom
+
+@defcom[com "Debug Abort", bind (C-M-H-a)]
+This command executes the ABORT restart in the @hid[Current Eval Server].
+@enddefcom
+
+@defcom[com "Debug Restart", bind (C-M-H-r)]
+This command executes the restart indicated by the prefix argument in the
+@hid[Current Eval Server]. The debugger enumerates the restart cases upon
+entering it.
+@enddefcom
+
+
+@subsection[Getting Information]
+
+@defcom[com "Debug Help", bind (C-M-H-h)]
+This command in prints the debugger's help text.
+@enddefcom
+
+@defcom[com "Debug Error", bind (C-M-H-e)]
+This command prints the error condition and restart cases displayed upon
+entering the debugger.
+@enddefcom
+
+@defcom[com "Debug Backtrace", bind (C-M-H-B)]
+This command executes the debugger's @f[backtrace] command.
+@enddefcom
+
+@defcom[com "Debug Print", bind (C-M-H-p)]
+This command prints the debugger's current frame in the same fashion as the
+frame motion commands.
+@enddefcom
+
+@defcom[com "Debug Verbose Print", bind (C-M-H-P)]
+This command prints the debugger's current frame without elipsis.
+@enddefcom
+
+@defcom[com "Debug Source", bind (C-M-H-s)]
+This command prints the source form for the debugger's current frame.
+@enddefcom
+
+@defcom[com "Debug Verbose Source"]
+This command prints the source form for the debugger's current frame with
+surrounding forms for context.
+@enddefcom
+
+@defcom[com "Debug List Locals", bind (C-M-H-l)]
+This prints the local variables for the debugger's current frame.
+@enddefcom
+
+
+@subsection[Editing Sources]
+
+@defcom[com "Debug Edit Source", bind (C-M-H-S)]
+This command attempts to place you at the source location of the debugger's
+current frame. Not all debugger frames represent function's that were compiled
+with the appropriate debug-info policy. This beeps with a message if it is
+unsuccessful.
+@enddefcom
+
+
+@subsection[Miscellaneous]
+
+@defcom[com "Debug Flush Errors", bind (C-M-H-F)]
+This command toggles whether the debugger ignores errors or recursively enters
+itself.
+@enddefcom
+
+
+
+
+@section[Manipulating the Editor Process]
+When developing @hemlock customizations, it is useful to be able to manipulate
+the editor Lisp environment from @hemlock.
+
+@defcom[com "Editor Describe", bind (Home t, C-_ t)]
+This command prompts for an expression, and then evaluates and describes it
+in the editor process.
+@enddefcom
+
+@defcom[com "Room"]
+Call the @f[room] function in the editor process, displaying information
+about allocated storage in a pop-up window.
+@enddefcom
+
+@defcom[com "Editor Load File"]
+This command is analogous to @comref[Load File], but loads the file into the
+editor process.
+@enddefcom
+
+
+@subsection[Editor Mode]
+When @hid[Editor] mode is on, alternate versions of the Lisp interaction
+commands are bound in place of the eval server based commands. These commands
+manipulate the editor process instead of the current eval server. Turning on
+editor mode in a buffer allows incremental development of code within the
+running editor.
+
+@defcom[com "Editor Mode"]
+This command turns on @hid[Editor] minor mode in the current buffer. If it is
+already on, it is turned off. @hid[Editor] mode may also be turned on using
+the @f[Mode] file option (see page @pageref[file-options].)
+@enddefcom
+
+@defcom[com "Editor Compile Defun",
+ stuff (bound to @bf[C-x C-c] in @hid[Editor] mode)]
+@defcom1[com "Editor Compile Region"]
+@defcom1[com "Editor Evaluate Buffer"]
+@defcom1[com "Editor Evaluate Defun",
+ stuff (bound to @bf[C-x C-e] in @hid[Editor] mode)]
+@defcom1[com "Editor Evaluate Region"]
+@defcom1[com "Editor Macroexpand Expression", bind (Editor: C-M)]
+@defcom1[com "Editor Re-evaluate Defvar"]
+@defcom1[com "Editor Describe Function Call",
+ stuff (bound to @bf[C-M-A] in @hid[Editor] mode)]
+@defcom1[com "Editor Describe Symbol",
+ stuff (bound to @bf[C-M-S] in @hid[Editor] mode)]
+These commands are similar to the standard commands, but modify or examine the
+Lisp process that @hemlock is running in. Terminal I/O is done on the
+initial window for the editor's Lisp process. Output is directed to a pop-up
+window or the editor's window instead of to the background buffer.
+@enddefcom
+
+@defcom[com "Editor Compile Buffer File"]
+@defcom1[com "Editor Compile File"]
+@defcom1[com "Editor Compile Group"]
+In addition to compiling in the editor process, these commands differ from the
+eval server versions in that they direct output to the the
+@hid[Compiler Warnings] buffer.
+@enddefcom
+
+@defcom[com "Editor Evaluate Expression",
+ stuff (bound to @bf[M-Escape] in @hid[Editor] mode and @bf[C-M-Escape])]
+This command prompts for an expression and evaluates it in the editor process.
+The results of the evaluation are displayed in the echo area.
+@enddefcom
+
+
+@subsection[Eval Mode]
+@label[eval-mode]
+@index[modes, eval]@hid[Eval] mode is a minor mode that simulates a @f[read]
+@f[eval] @f[print] loop running within the editor process. Since Lisp
+program development is usually done in a separate eval server process (see page
+@pageref[eval-servers]), @hid[Eval] mode is used primarily for debugging code
+that must run in the editor process. @hid[Eval] mode shares some commands with
+@hid[Typescript] mode: see section @ref[typescripts].
+
+@hid[Eval] mode doesn't completely support terminal I/O: it binds
+@var[standard-output] to a stream that inserts into the buffer and
+@var[standard-input] to a stream that signals an error for all operations.
+@hemlock cannot correctly support the interactive evaluation of forms that read
+from the @hid[Eval] interactive buffer.
+
+@defcom[com "Select Eval Buffer"]
+This command changes to the @hid[Eval] buffer, creating one if it doesn't
+already exist. The @hid[Eval] buffer is created with @hid[Lisp] as the major
+mode and @hid[Eval] and @hid[Editor] as minor modes.
+@enddefcom
+
+@defcom[com "Confirm Eval Input",
+ stuff (bound to @bf[Return] in @hid[Eval] mode)]
+This command evaluates all the forms between the end of the last output and
+the end of the buffer, inserting the results of their evaluation in the buffer.
+This beeps if the form is incomplete. Use @binding[Linefeed] to insert line
+breaks in the middle of a form.
+
+This command uses @hid[Unwedge Interactive Input Confirm] in the same way
+@hid[Confirm Interactive Input] does.
+@enddefcom
+
+@defcom[com "Abort Eval Input",
+ stuff (bound to @bf[M-i] in @hid[Eval] mode)]
+This command moves the the end of the buffer and prompts, ignoring any
+input already typed in.
+@enddefcom
+
+
+@subsection[Error Handling]
+@index[error handling]
+When an error happens inside of @hemlock, @hemlock will trap the error and
+display the error message in the echo area, possibly along with the
+"@f[Internal error:]" prefix. If you want to debug the error, type @bf[?].
+This causes the prompt "@f[Debug:]" to appear in the echo area. The following
+commands are recognized:
+@begin[description]
+@bf[d]@\Enter a break-loop so that you can use the Lisp debugger.
+Proceeding with "@f[go]" will reenter @hemlock and give the "@f[Debug:]"
+prompt again.
+
+@bf[e]@\Display the original error message in a pop-up window.
+
+@bf[b]@\Show a stack backtrace in a pop-up window.
+
+@bf[q, Escape]@\Quit from this error to the nearest command loop.
+
+@bf[r]@\Display a list of the restart cases and prompt for the number of a
+@f[restart-case] with which to continue. Restarting may result in prompting in
+the window in which Lisp started.
+@end[description]
+
+Only errors within the editor process are handled in this way. Errors during
+eval server operations are handled using normal terminal I/O on a typescript in
+the eval server's slave buffer or background buffer (see page
+@pageref[operations]). Errors due to interaction in a slave buffer will cause
+the debugger to be entered in the slave buffer.
+
+
+@section[Command Line Switches]
+@label[slave-switch]
+Two command line switches control the initialization of editor and eval servers
+for a Lisp process:
+@begin[description]
+@f<-edit>@\
+@label[edit-switch]
+This switch starts up @hemlock. If there is a non-switch command line word
+immediately following the program name, then the system interprets it as a file
+to edit. For example, given
+@Begin[ProgramExample]
+lisp file.txt -edit
+@End[ProgramExample]
+Lisp will go immediately into @hemlock finding the file @f[file.txt].
+
+@f<-slave [>@i[name]@f<]>@\
+ This switch causes the Lisp process to become a slave of the editor process
+@i[name]. An editor Lisp determines @i[name] when it allows connections from
+slaves. Once the editor chooses a name, it keeps the same name until the
+editor's Lisp process terminates. Since the editor can automatically create
+slaves on its own machine, this switch is useful primarily for creating slaves
+that run on a different machine. @f[hqb]'s machine is @f[ME.CS.CMU.EDU], and
+he wants want to run a slave on @f[SLAVE.CS.CMU.EDU], then he should use the
+@hid[Accept Slave Connections] command, telnet to the machine, and invoke Lisp
+supplying @f[-slave] and the editor's name. The command displays the editor's
+name.
+@end[description]
diff --git a/docs/hem/user/mail.mss b/docs/hem/user/mail.mss
new file mode 100644
index 0000000000000000000000000000000000000000..6d1c7a7b9a62768093fd0bd939bdcaab4f901e67
--- /dev/null
+++ b/docs/hem/user/mail.mss
@@ -0,0 +1,1343 @@
+@comment{-*- Dictionary: /afs/cs/project/clisp/scribe/hem/hem; Mode: spell; Package: Hemlock -*-}
+@chap[The Mail Interface]
+@section[Introduction to Mail in Hemlock]
+
+@index[MH interface]@label[introduction]
+@hemlock provides an electronic mail handling facility via an interface to the
+public domain @i[Rand MH Message Handling System]. This chapter assumes that
+the user is familiar with the basic features and operation of @mh, but it
+attempts to make allowances for beginners. Later sections of this chapter
+discuss setting up @mh, profile components and special files for formatting
+outgoing mail headers, and backing up protected mail directories on a
+workstation. For more information on @mh, see the @i[Rand MH Message Handling
+System Tutorial] and the @i[Rand MH Message Handling System Manual].
+
+The @hemlock interface to @mh provides a means for generating header (@f[scan])
+lines for messages and displaying these headers in a @hid[Headers] buffer.
+This allows the user to operate on the @i[current message] as indicated by the
+position of the cursor in the @hid[Headers] buffer. The user can read, reply
+to, forward, refile, or perform various other operations on the current
+message. A user typically generates a @hid[Headers] buffer with the commands
+@hid[Message Headers] or @hid[Incorporate and Read New Mail], and multiple such
+buffers may exist simultaneously.
+
+Reading a message places its text in a @hid[Message] buffer. In a manner
+similar to a @hid[Headers] buffer, this allows the user to operate on that
+message. Most @hid[Headers] buffer commands behave the same in a @hid[Message]
+buffer. For example, the @hid[Reply to Message] command has the same effect in
+both @hid[Headers] mode and @hid[Message] mode. It creates a @hid[Draft]
+buffer and makes it the current buffer so that the user may type a reply to the
+current message.
+
+The @hid[Send Message] command originates outgoing mail. It generates a
+@hid[Draft] buffer in which the user composes a mail message. Each @hid[Draft]
+buffer has an associated pathname, so the user can save the buffer to a file as
+necessary. Invoking @hid[Send Message] in a @hid[Headers] or @hid[Message]
+buffer associates the @hid[Draft] buffer with a @hid[Message] buffer. This
+allows the user to easily refer to the message being replied to with the
+command @hid[Goto Message Buffer]. After the user composes a draft message, he
+can deliver the message by invoking the @hid[Deliver Message] command in the
+@hid[Draft] buffer (which deletes both the this buffer and any associated
+@hid[Message] buffer), or he can delay this action. Invoking @hid[Deliver
+Message] when not in a @hid[Draft] buffer causes it to prompt for a draft
+message ID, allowing previously composed and saved messages to be delivered
+(even across distinct Lisp invocations).
+
+@index[virtual message deletion]
+The @hemlock mail system provides a mechanism for @i[virtual message deletion].
+That is, the @hid[Delete Message] command does not immediately delete a message
+but merely flags the message for future deletion. This allows the user to
+undelete the messages with the @hid[Undelete Message] command. The
+@hid[Expunge Messages] command actually removes messages flagged for deletion.
+After expunging a deleted message, @hid[Undelete Messages] can no longer
+retrieve it. Commands that read messages by sequencing through a @hid[Headers]
+buffer typically ignore those marked for deletion, which makes for more fluid
+reading if a first pass has been made to delete uninteresting messages.
+
+After handling messages in a @hid[Headers] buffer, there may be messages
+flagged for deletion and possibly multiple @hid[Message] buffers lying around.
+There is a variety of commands that help @i[terminate] a mail session.
+@hid[Expunge Messages] will flush the messages to be deleted, leaving the
+buffer in an updated state. @hid[Delete Headers Buffer and Message Buffers]
+will delete the @hid[Headers] buffer and its corresponding @hid[Message]
+buffers. @hid[Quit Headers] is a combination of these two commands in that it
+first expunges messages and then deletes all the appropriate buffers.
+
+One does not have to operate only on messages represented in a @hid[Headers]
+buffer. This is merely the nominal mode of interaction. There are commands
+that prompt for a folder, an @mh message specification (for example, "@f[1 3 6
+last]", "@f[1-3 5 6]", "@f[all]", "@f[unseen]"), and possibly a @f[pick]
+expression. @f[Pick] expressions allow messages to be selected based on header
+field pattern matching, body text searching, and date comparisons; these can be
+specified using either a Unix shell-like/switch notation or a Lisp syntax,
+according to one's preference. See section @ref[scanning] for more details.
+
+A @i[mail-drop] is a file where a Unix-based mail system stores all messages a
+user receives. The user's mail handling program then fetches these from the
+mail-drop, allowing the user to operate on them. Traditionally one locates his
+mail-drop and mail directory on a mainframe machine because the information on
+mainframes is backed up on magnetic tape at least once per day. Since @hemlock
+only runs under CMU @clisp on workstations, and one's mail directory is not
+usually world writable, it is not possible to adhere to a standard arrangement.
+Since @mh provides for a remote mail-drop, and CMU's Remote File System has a
+feature allowing authentication across a local area network, one can use
+@hemlock to fetch his mail from a mainframe mail-drop (where it is backed up
+before @hemlock grabs it) and store it on his workstation. Reading mail on a
+workstation is often much faster and more comfortable because typically it is a
+single user machine. Section @ref[backing-up] describes how to back up one's
+mail directory from a workstation to a mainframe.
+
+
+@section[Constraints on MH to use Hemlock's Interface]
+
+@index[constraints for mail interface]@label[constraints]
+There are a couple constaints placed on the user of the @hemlock interface to
+@mh. The first is that there must be a draft folder specified in one's @mh
+profile to use any command that sends mail. Also, to read new mail, there must
+be an @f[Unseen-Sequence:] component in one's @mh profile. The default @mh
+profile does not specify these components, so they must be added by the user.
+The next section of this chapter describes how to add these components.
+Another constraint is that @hemlock requires its own @f[scan] line format to
+display headers lines in a @hid[Headers] buffer. See the description of the
+variable @hid[MH Scan Line Form] for details.
+
+
+@section[Setting up MH]
+
+@index[setting up the mail interface]@label[setting-up]
+@index[mail profile]@index[MH profile]
+Get an @mh default profile and mail directory by executing the @mh @f[folder]
+utility in a Unix shell. When it asks if it should make the "@f[inbox]"
+folder, answer "@b[yes]". This creates a file called "@f[.mh_profile]" in the
+user's home directory and a directory named "@f[Mail]".
+
+Edit the "@f[.mh_profile]" file inserting two additional lines. To send mail
+in @hemlock, the user must indicate a draft folder by adding a
+@f[Draft-Folder:] line with a draft folder name @dash "@f[drafts]" is a common
+name:
+@begin[example]
+Draft-Folder: drafts
+@end[example]
+
+Since the mail-drop exists on a remote machine, the following line must
+also be added:
+@begin[example]
+MailDrop: /..//usr/spool/mail/
+@end[example]
+
+Since the user's mail-drop is on a separate machine from his mail directory
+(and where the user runs @hemlock), it is necessary to issue the following
+command from the Unix shell (on the workstation). This only needs to be done
+once.
+@begin[programexample]
+/usr/cs/etc/rfslink -host /usr/spool/mail/
+@end[programexample]
+Note that @b[] is not a full ARPANET domain-style name. Use an
+abbreviated CMU host name (for example, "@b[spice]" not
+"@b[spice.cs.cmu.edu]").
+
+
+@section[Profile Components and Customized Files]
+
+@subsection[Profile Components]
+
+@label[Profile]
+The following are short descriptions about profile components that are either
+necessary to using @hemlock's interface to @mh or convenient for using @mh in
+general:
+
+@begin[description]
+@f[Path:]@\
+This specifies the user's mail directory. It can be either a full pathname or
+a pathname relative to the user's home directory. This component is
+@i[necessary] for using @mh.
+
+@f[MailDrop:]@\
+This is used to specify one's remote mail-drop. It is @i[necessary] for
+@hemlock only when using a mail-drop other than "@f[/usr/spool/mail/]" on
+the local machine.
+
+@f[Folder-Protect:], @f[Msg-Protect:]@\
+These are set to 700 and 600 respectively to keep others from reading one's
+mail. At one time the default values were set for public visibility of mail
+folders. Though this is no longer true, these can be set for certainty. The
+700 protection allows only user read, write, and execute (list access for
+directories), and 600 allows only user read and write. These are not necessary
+for either @mh or the @hemlock interface.
+
+@f[Unseen-Sequence:]@\
+When mail is incorporated, new messages are added to this sequence, and as
+these messages are read they are removed from it. This allows the user at any
+time to invoke an @mh program on all the unseen messges of a folder easily. An
+example definition is:
+@begin[example]
+Unseen-Sequence: unseen
+@end[example]
+Specifying an unseen-sequence is @i[necessary] to use @hemlock's
+interface to @mh.
+
+@f[Alternate-Mailboxes:]@\
+This is not necessary for either @mh or the @hemlock interface. This
+component tells @mh which addresses that it should recognize as the user. This
+is used for @f[scan] output formatting when the mail was sent by the user. It
+is also used by @f[repl] when it sets up headers to know who the user is for
+inclusion or exclusion from @b[cc]: lists. This is case sensitive and takes
+wildcards. One example is:
+@begin[example]
+Alternate-Mailboxes: *FRED*, *Fred*, *fred*
+@end[example]
+
+@f[Draft-Folder:]@\
+This makes multiple draft creation possible and trivial to use. Just supply a
+folder name (for example, "@f[drafts]"). Specifying a draft-folder is
+@i[necessary] to use @hemlock's interface to @mh.
+
+@f[repl: -cc all -nocc me -fcc out-copy]@\
+This tells the @f[repl] utility to include everyone but the user in the
+@b[cc:] list when replying to mail. It also makes @f[repl] keep an copy of the
+message the user sends. This is mentioned because one probably wants to reply
+to everyone receiving a piece of mail except oneself. Unlike other utilities
+that send mail, @f[repl] stores personal copies of outgoing mail based on a
+command line switch. Other @mh utilities use different mechanisms. This line
+is not necessary to use either @mh or the @hemlock interface.
+
+@f[rmmproc: /usr/cs/bin/rm]@\
+This is not necessary to use @hemlock's interface to @mh, but due to
+@hemlock's virtual message deletion feature, this causes messages to be deleted
+from folder directories in a cleaner fashion when they actually get removed.
+Note that setting this makes @f[rmm] more treacherous if used in the Unix
+shell.
+@end[description]
+@;
+
+
+@subsection[Components Files]
+@index[components]
+@label[components-files]
+@i[Components] files are templates for outgoing mail header fields that specify
+position and sometimes values for specified fields. Example files are shown
+for each one discussed here. These should exist in the user's mail directory.
+
+For originating mail there is a components file named "@f[components]", and it
+is used by the @mh utility @f[comp]. An example follows:
+@begin[example]
+ To:
+ cc:
+ fcc: out-copy
+ Subject:
+ --------
+@end[example]
+This example file differs from the default by including the @f[fcc:] line.
+This causes @mh to keep a copy of the outgoing draft message. Also, though it
+isn't visible here, the @f[To:], @f[cc:], and @f[Subject:] lines have a space
+at the end.
+
+@index[forwarding components]
+The "@f[forwcomps]" components file is a template for the header fields of any
+forwarded message. Though it may be different, our example is the same as the
+previous one. These are distinct files for @mh's purposes, and it is more
+flexible since the user might not want to keep copies of forwarded messages.
+
+@index[reply components]
+The "@f[replcomps]" components file is a template for the header fields of any
+draft message composed when replying to a message. An example
+follows:
+@begin[example]
+ %(lit)%(formataddr %<{reply-to}%|%<{from}%|%{sender}%>%>)\
+ %<(nonnull)%(void(width))%(putaddr To: )\n%>\
+ %(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\
+ %(formataddr{resent-to})\
+ %<(nonnull)%(void(width))%(putaddr cc: )\n%>\
+ %<{fcc}Fcc: %{fcc}\n%>\
+ %<{subject}Subject: Re: %{subject}\n%>\
+ %<{date}In-reply-to: Your message of \
+ %<(nodate{date})%{date}%|%(tws{date})%>.%<{message-id}
+ %{message-id}%>\n%>\
+ --------
+@end[example]
+This example file differs from the default by including the @b[resent-to:]
+field (in addition to the @b[to:] and @b[cc:] fields) of the message being
+replied to in the @b[cc:] field of the draft. This is necessary for replying
+to all recipients of a distributed message. Keeping a copy of the outgoing
+draft message works a little differently with reply components. @mh expects a
+switch which the user can put in his profile (see section @ref[Profile] of this
+chapter), and using the @mh formatting language, this file tests for the
+@f[fcc] value as does the standard file.
+
+
+@section[Backing up the Mail Directory]
+@index[backing up mail directories]
+@label[backing-up]
+The easiest method of backing up a protected mail directory is to copy it into
+an Andrew File System (AFS) directory since these are backed up daily as with
+mainframes. The only problem with this is that the file servers may be down
+when one wants to copy his mail directory since, at the time of this writing,
+these servers are still under active development; however, they are becoming
+more robust daily. One can read about the current AFS status in the file
+@f[/../fac/usr/gripe/doc/vice/status].
+
+Using AFS, one could keep his actual mail directory (not a copy thereof) in his
+AFS home directory which eliminates the issue of backing it up. This is
+additionally beneficial if the user does not use the same workstation everyday
+(that is, he does not have his own but shares project owned machines). Two
+problems with this arrangement result from the AFS being a distributed file
+system. Besides the chance that the server will be down when the user wants to
+read mail, performance degrades since messages must always be referenced across
+the local area network.
+
+Facilities' official mechanism for backing up protected directories is called
+@f[sup]. This is awkward to use and hard to set up, but a subsection here
+describes a particular arrangement suitable for the user's mail directory.
+
+
+@subsection[Andrew File System]
+If the user choses to use AFS, he should get copies of @i[Getting Started with
+the Andrew File System] and @i[Protecting AFS files and directories]. To use
+AFS, send mail to Gripe requesting an account. When Gripe replies with a
+password, change it to be the same as the account's password on the
+workstation. This causes the user to be authenticated into AFS when he logs
+into his workstation (that is, he is automatically logged into his AFS
+account). To change the password, first log into the AFS account:
+@begin[programexample]
+log
+@end[programexample]
+Then issue the @f[vpasswd] command.
+
+All of the example command lines in this section assume the user has
+@f[/usr/misc/bin] on his Unix shell @f[PATH] environment variable.
+
+@paragraph[Copy into AFS:]
+
+Make an AFS directory to copy into:
+@begin[programexample]
+mkdir /afs/cs.cmu.edu/user//mail-backup
+@end[programexample]
+
+This will be readable by everyone, so protect it with the following:
+@begin[programexample]
+fs sa /afs/cs.cmu.edu/user//mail-backup System:AnyUser none
+@end[programexample]
+
+Once the AFS account and directory to backup into have been established, the
+user needs a means to recursively copy his mail directory updating only those
+file that have changed and deleting those that no longer exist. To do this,
+issue the following command:
+@begin[programexample]
+copy -2 -v -R
+@end[programexample]
+Do not terminate either of these directory specifications with a @f[/]. The
+@f[-v] switch causes @f[copy] to output a line for copy and deletion, so this
+may be eliminated if the user desires.
+
+@paragraph[Mail Directory Lives in AFS:]
+
+Assuming the AFS account has been established, and the user has followed the
+directions in @ref[setting-up], now make an AFS directory to serve as the mail
+directory:
+@begin[programexample]
+mkdir /afs/cs.cmu.edu/user//Mail
+@end[programexample]
+
+This will be readable by everyone, so protect it with the following:
+@begin[programexample]
+fs sa /afs/cs.cmu.edu/user//Mail System:AnyUser none
+@end[programexample]
+
+Tell @mh where the mail directory is by modifying the profile's
+"@f[.mh_profile]" (see section @ref[setting-up]) @f[Path:] component (see
+section @ref[Profile]):
+@begin[programexample]
+Path: /afs/cs.cmu.edu/user//Mail
+@end[programexample]
+
+
+@subsection[Sup to a Mainframe]
+To use @f[sup] the user must set up a directory named "@f[sup]" on the
+workstation in the user's home directory. This contains different directories
+for the various trees that will be backed up, so there will be a "@f[Mail]"
+directory. This directory will contain two files: "@f[crypt]" and "@f[list]".
+The "@f[crypt]" file contains one line, terminated with a new line, that
+contains a single word @dash an encryption key. "@f[list]" contains one line,
+terminated with a new line, that contains two words @dash "@b[upgrade Mail]".
+
+On the user's mainframe, a file must be created that will be supplied to the
+@f[sup] program. It should contain the following line to backup the mail
+directory:
+
+@begin[example]
+Mail delete host= hostbase=/usr/ base=/usr/ \
+crypt=WordInCryptFile login= password=LoginPasswordOnWorkstation
+@end[example]
+Warning: @i[This file contains the user's password and should be
+protected appropriately.]
+
+The following Unix shell command issued on the mainframe will backup the
+mail directory:
+
+@begin[programexample]
+ sup
+@end[programexample]
+
+As a specific example, assume user "@f[fred]" has a workstation called
+"@f[fred]", and his mainframe is the "@f[gpa]" machine where he has another
+user account named "@f[fred]". The password on his workstation is
+"@f[purple]". On his workstation, he creates the directory
+"@f[/usr/fred/sup/Mail/]" with the two files "@f[crypt]" and "@f[list]".
+The file "@f[/usr/fred/sup/Mail/crypt]" contains only the encryption key:
+@programexample[steppenwolf]
+The file "@f[/usr/fred/sup/Mail/list]" contains the command to upgrade the
+"@f[Mail]" directory:
+@programexample[upgrade Mail]
+
+On the "@f[gpa]" machine, the file "@f[/usr/fred/supfile]" contains the
+following line:
+@begin[programexample]
+Mail delete host=fred hostbase=/usr/fred base=/usr/fred \
+crypt=steppenwolf login=fred password=purple
+@end[programexample]
+This file is protected on "@f[gpa]", so others cannot see @f[fred's] password
+on his workstation.
+
+On the gpa-vax, issuing
+@begin[programexample]
+ sup /usr/fred/supfile
+@end[programexample]
+to the Unix shell will update the @mh mail directory from @f[fred's]
+workstation deleting any files that exist on the gpa that do not exist on the
+workstation.
+
+For a more complete description of the features of @f[sup], see the @i[UNIX
+Workstation Owner's Guide] and @i[The SUP Software Upgrade Protocol].
+
+@section[Introduction to Commands and Variables]
+
+@index[mail commands]@index[mail variables]@label[mhcommands]
+Unless otherwise specified, any command which prompts for a folder name will
+offer the user a default. Usually this is @mh's idea of the current folder,
+but sometimes it is the folder name associated with the current buffer if there
+is one. When prompting for a message, any valid @mh message expression may be
+entered (for example, "@f[1 3 6]", "@f[1-3 5 6]", "@f[unseen]", "@f[all]").
+Unless otherwise specified, a default will be offered (usually the current
+message).
+
+Some commands mention specific @mh utilities, so the user knows how the
+@hemlock command affects the state of @mh and what profile components and
+special formatting files will be used. @hemlock runs the @mh utility programs
+from a directory indicated by the following variable:
+
+@defhvar[var "MH Utility Pathname", val {"/usr/misc/.mh/bin/"}]
+@mh utility names are merged with this pathname to find the executable
+files.
+@enddefhvar
+
+
+@section[Scanning and Picking Messages]
+@label[scanning]
+As pointed out in the introduction of this chapter, users typically generate
+headers or @f[scan] listings of messages with @hid[Message Headers], using
+commands that operate on the messages represented by the headers. @hid[Pick
+Headers] (bound to @bf[h] in @hid[Headers] mode) can be used to narrow down (or
+further select over) the headers in the buffer.
+
+A @f[pick] expression may be entered using either a Lisp syntax or a Unix
+shell-like/switch notation as described in the @mh documentation. The Lisp
+syntax is as follows:
+
+@begin[example]
+ ::= {(not ) | (and *) | (or *)
+ | (cc ) | (date )
+ | (from ) | (search )
+ | (subject ) | (to )
+ | (-- )
+ | (before ) | (after )
+ | (datefield )}
+
+ ::= { | }
+
+ ::= { | }
+
+ ::= { | | }
+
+ ::=
+@end[example]
+
+Anywhere the user enters a @f[], its symbol name is used as a string.
+Since @hemlock @f[read]s the expression without evaluating it, single quotes
+("@bf[']") are unnecessary. From the @mh documentation,
+
+@begin[itemize]
+ A @f[] is a Unix @f[ed] regular expression. When using a string to
+ input these, remember that @f[\] is an escape character in Common Lisp.
+
+ A @f[] is a header field name (for example, @b[reply-to] or
+ @b[resent-to]).
+
+ A @f[] is an @i[822]-style specification, a day of the week,
+ "@b[today]", "@b[yesterday]", "@b[tomorrow]", or a number indicating @i[n]
+ days ago. The @i[822] standard is basically:
+ @begin[example]
+ dd mmm yy hh:mm:ss zzz
+ @end[example]
+ which is a two digit day, three letter month (first letter capitalized), two
+ digit year, two digit hour (@f[00] through @f[23]), two digit minute, two
+ digit second (this is optional), and a three letter zone (all capitalized).
+ For
+ example:
+ @begin[example]
+ 21 Mar 88 16:00 EST
+ @end[example]
+
+ A @f[] is an alternate @f[Date:] field to use with @f[(before
+ )] and @f[(after )] such as @f[BB-Posted:] or
+ @f[Delivery-Date:].
+
+ Using @f[(before )] and @f[(after )] causes date field parsing,
+ while @f[(date )] does string pattern matching.
+@end[itemize]
+
+Since a @f[] may be a symbol or string, it should be noted that the
+symbol name is probably all uppercase characters, and @mh will match these
+only against upper case. @mh will match lowercase characters against lower
+and upper case. Some examples are:
+@begin[example]
+ ;;; All messages to Gripe.
+ (to "gripe")
+
+ ;;; All messages to Gripe or about Hemlock.
+ (or (to "gripe") (subject "hemlock"))
+
+ ;;; All messages to Gripe with "Hemlock" in the body.
+ (and (to "gripe") (search "hemlock"))
+@end[example]
+
+Matching of @f[] fields is case sensitive, so this example will
+@f[pick] over all messages that have been replied to.
+@example[(or (-- "replied" "") (-- "Replied" ""))]
+
+
+@defhvar[var "MH Scan Line Form", val {"library:mh-scan"}]
+This is a pathname of a file containing an @mh format expression used for
+header lines.
+
+The header line format must display the message ID as the first non-whitespace
+item. If the user uses the virtual message deletion feature which is on by
+default, there must be a space three characters to the right of the message ID.
+This location is used on header lines to note that a message is flagged for
+deletion. The second space after the message ID is used for notating answered
+or replied-to messages.
+@enddefhvar
+
+@defcom[com "Message Headers", bind (C-x r)]
+This command prompts for a folder, message (defaulting to "@b[all]"), and an
+optional @f[pick] expression. Typically this will simply be used to generate
+headers for an entire folder or sequence, and the @f[pick] expression will not
+be used. A new @hid[Headers] buffer is made, and the output of @f[scan] on the
+messages indicated is inserted into the buffer. The current window is used,
+the buffer's point is moved to the first header, and the @hid[Headers] buffer
+becomes current. The current value of the @hemlock @hid[Fill Column] variable
+is supplied to @f[scan] as the @f[-width] switch. The buffer name is set to a
+string of the form @w<"@f[Headers ]">, so the
+modeline will show what is in the buffer. If no @f[pick] expression was
+supplied, none will be shown in the buffer's name. As described in the
+introduction to this section, the expression may be entered using either a Lisp
+syntax or a Unix shell-like/switch notation.
+@enddefcom
+
+@defhvar[var "MH Lisp Expression", val {t}]
+When this is set, @mh expression prompts are read in a Lisp syntax. Otherwise,
+the input is of the form of a Unix shell-like/switch notation as described in
+the @mh documentation.
+@enddefhvar
+
+@defcom[com "Pick Headers", stuff (bound to @bf[h] in @hid[Headers] mode) ]
+This command is only valid in a @hid[Headers] buffer. It prompts for a
+@f[pick] expression, and the messages shown in the buffer are supplied to
+@f[pick] with the expression. The resulting messages are @f[scan]'ed, deleting
+the previous contents of the buffer. The current value of @hid[Fill Column] is
+used for the @f[scan]'ing. The buffer's point is moved to the first header.
+The buffer's name is set to a string of the form @w<"@f[Headers ]">, so the modeline will show what is in the
+buffer. As described in the introduction to this section, the expression may
+be entered using either a Lisp syntax or a Unix shell-like/switch notation.
+@enddefcom
+
+@defcom[com "Headers Help", bind (Headers: ?)]
+This command displays documentation on @hid[Headers] mode.
+@enddefcom
+
+
+@section[Reading New Mail]
+
+@index[reading new mail]@label[reading-new-mail]
+
+@defcom[com "Incorporate and Read New Mail", stuff (bound to @bf[C-x i] globally and @bf[i] in @hid[Headers] and @hid[Message] modes) ]
+This command incorporates new mail into @hid[New Mail Folder] and creates a
+@hid[Headers] buffer with the new messages. An unseen-sequence must be define
+in the user's @mh profile to use this. Any headers generated due to
+@hid[Unseen Headers Message Spec] are inserted as well. The buffer's point is
+positioned on the headers line representing the first unseen message of the
+newly incorporated mail.
+@enddefcom
+
+@defcom[com "Incorporate New Mail" ]
+This command incorporates new mail into @hid[New Mail Folder], displaying
+@f[inc] output in a pop-up window. This is similar to @hid[Incorporate and
+Read New Mail] except that no @hid[Headers] buffer is generated.
+@enddefcom
+
+@defhvar[var "New Mail Folder", val {"+inbox"}]
+This is the folder into which @mh incorporates new mail.
+@enddefhvar
+
+@defhvar[var "Unseen Headers Message Spec", val {nil}]
+This is an @mh message specification that is suitable for any message prompt.
+When incorporating new mail and after expunging messages, @hemlock uses this
+specification in addition to the unseen-sequence name that is taken from the
+user's @mh profile to generate headers for the unseen @hid[Headers] buffer.
+This value is a string.
+@enddefhvar
+
+@defhvar[var "Incorporate New Mail Hook", val {nil}]
+This is a list of functions which are invoked immediately after new mail is
+incorporated. The functions should take no arguments.
+@enddefhvar
+
+@defhvar[var "Store Password", val {nil}]
+When this is set, the user is only prompted once for his password, and the
+password is stored for future use.
+@enddefhvar
+
+@defhvar[var "Authenticate Incorporation", val {nil}]
+@defhvar1[var "Authentication User Name", val {nil}]
+When @hid[Authenticate Incorporation] is set, incorporating new mail prompts
+for a password to access a remote mail-drop.
+
+When incorporating new mail accesses a remote mail-drop, @hid[Authentication
+User Name] is the user name supplied for authentication on the remote machine.
+If this is @nil, @hemlock uses the local name.
+@enddefhvar
+
+
+@section[Reading Messages]
+@index[reading messages]
+@label[reading-messages]
+This section describes basic commands that show the current, next, and previous
+messages, as well as a couple advanced commands. @hid[Show Message] (bound to
+@bf[SPACE] in @hid[Headers] mode) will display the message represented by the
+@f[scan] line the @hemlock cursor is on. Deleted messages are considered
+special, and the more conveniently bound commands for viewing the next and
+previous messages (@hid[Next Undeleted Message] bound to @bf[n] and
+@hid[Previous Undeleted Message] bound to @bf[p], both in @hid[Headers] and
+@hid[Message] modes) will ignore them. @hid[Next Message] and @hid[Previous
+Message] (bound to @bf[M-n] and @bf[M-p] in @hid[Headers] and @hid[Message]
+modes) may be invoked if reading a message is desired regardless of whether it
+has been deleted.
+
+
+@defcom[com "Show Message", stuff (bound to @bf[SPACE] and @bf[.] in @hid[Headers] mode) ]
+ This command, when invoked in a @hid[Headers] buffer, displays the current
+message (the message the cursor is on), by replacing any previous message that
+has not been preserved with @hid[Keep Message]. The current message is also
+removed from the unseen sequence. The @hid[Message] buffer becomes the current
+buffer using the current window. The buffer's point will be moved to the
+beginning of the buffer, and the buffer's name will be set to a string of the
+form @w<"@f[Message ]">.
+
+The @hid[Message] buffer is read-only and may not be modified. The command
+@hid[Goto Headers Buffer] issued in the @hid[Message] buffer makes the
+associated @hid[Headers] buffer current.
+
+When not in a @hid[Headers] buffer, this command prompts for a folder and
+message. A unique @hid[Message] buffer is obtained, and its name is set to a
+string of the form @w<"@f[Message ]">. The buffer's point is
+moved to the beginning of the buffer, and the current window is used to display
+the message.
+
+Specifying multiple messages inserts all the messages into the same buffer. If
+the user wishes to show more than one message, it is expected that he will
+generate a @hid[headers] buffer with the intended messages, and then use the
+message sequencing commands described below.
+@enddefcom
+
+@defcom[com "Next Message", stuff (bound to @bf[M-n] in @hid[Headers] and @hid[Message] modes) ]
+ This command is only meaningful in a @hid[Headers] buffer or a @hid[Message]
+buffer associated with a @hid[Headers] buffer. In a @hid[Headers] buffer, the
+point is moved to the next message, and if there is one, it is shown as
+described in the @hid[Show Message] command.
+
+In a @hid[Message] buffer, the message after the currently visible message is
+displayed. This clobbers the buffer's contents. Note, if the @hid[Message]
+buffer is associated with a @hid[Draft] buffer, invoking this command breaks
+that association. Using @hid[Keep Message] preserves the @hid[Message] buffer
+and any association with a @hid[Draft] buffer.
+
+The @hid[Message] buffer's name is set as described in the @hid[Show Message]
+command.
+@enddefcom
+
+@defcom[com "Previous Message", stuff (bound to @bf[M-p] in @hid[Headers] and @hid[Message] modes) ]
+ This command is only meaningful in a @hid[Headers] buffer or a @hid[Message]
+buffer associated with a @hid[Headers] buffer. In a @hid[Headers] buffer, the
+point is moved to the previous message, and if there is one, it is shown as
+described in the @hid[Show Message] command.
+
+In a @hid[Message] buffer, the message before the currently visible message is
+displayed. This clobbers the buffer's contents. Note, if the @hid[Message]
+buffer is associated with a @hid[Draft] buffer, invoking this command breaks
+that association. Using @hid[Keep Message] preserves the @hid[Message] buffer
+and any association with a @hid[Draft] buffer.
+
+The @hid[Message] buffer's name is set as described in the @hid[Show Message]
+command.
+@enddefcom
+
+@defcom[com "Next Undeleted Message", stuff (bound to @bf[n] in @hid[Headers] and @hid[Message] modes) ]
+ This command is only meaningful in a @hid[Headers] buffer or a @hid[Message]
+buffer associated with a @hid[Headers] buffer. In a @hid[Headers] buffer, the
+point is moved to the next undeleted message, and if there is one, it is shown
+as described in the @hid[Show Message] command.
+
+In a @hid[Message] buffer, the first undeleted message after the currently
+visible message is displayed. This clobbers the buffer's contents. Note, if
+the @hid[Message] buffer is associated with a @hid[Draft] buffer, invoking this
+command breaks that association. The @hid[Keep Message] command preserves the
+@hid[Message] buffer and any association with a @hid[Draft] buffer.
+
+The @hid[Message] buffer's name is set as described in the @hid[Show Message]
+command.
+@enddefcom
+
+@defcom[com "Previous Undeleted Message", stuff (bound to @bf[p] in @hid[Headers] and @hid[Message] modes) ]
+ This command is only meaningful in a @hid[Headers] buffer or a @hid[Message]
+buffer associated with a @hid[Headers] buffer. In a @hid[Headers] buffer, the
+point is moved to the previous undeleted message, and if there is one, it is
+shown as described in the @hid[Show Message] command.
+
+In a @hid[Message] buffer, the first undeleted message before the currently
+visible message is displayed. This clobbers the buffer's contents. Note, if
+the @hid[Message] buffer is associated with a @hid[Draft] buffer, invoking this
+command breaks that association. The @hid[Keep Message] command preserves the
+@hid[Message] buffer and any association with a @hid[Draft] buffer.
+
+The @hid[Message] buffer's name is set as described in the @hid[Show Message]
+command.
+@enddefcom
+
+@defcom[com "Scroll Message", stuff (bound to @bf[SPACE] and @bf[C-v] in @hid[Message] mode) ]
+@defhvar1[var "Scroll Message Showing Next", val {t}]
+ This command scrolls the current window down through the current message. If
+the end of the message is visible and @hid[Scroll Message Showing Next] is not
+@nil, then show the next undeleted message.
+@enddefcom
+
+@defcom[com "Keep Message" ]
+This command can only be invoked in a @hid[Message] buffer. It causes the
+@hid[Message] buffer to continue to exist when the user invokes commands to
+view other messages either within the kept @hid[Message] buffer or its
+associated @hid[Headers] buffer. This is useful for getting two messages into
+different buffers. It is also useful for retaining @hid[Message] buffers which
+would otherwise be deleted when an associated draft message is delivered.
+@enddefcom
+
+@defcom[com "Message Help", bind (Message: ?)]
+This command displays documentation on @hid[Message] mode.
+@enddefcom
+
+
+@section[Sending Messages]
+@index[sending messages]
+@label[sending-messages]
+The most useful commands for sending mail are @hid[Send Message] (bound to
+@bf[m] and @bf[s] in @hid[Headers] and @hid[Message] modes), @hid[Reply to
+Message] (bound to @bf[r] in @hid[Headers] mode), and @hid[Reply to Message in
+Other Window] (bound to @bf[r] in @hid[Message] mode). These commands set up a
+@hid[Draft] buffer and associate a @hid[Message] buffer with the draft when
+possible. To actually deliver the message to its recipient(s), use
+@hid[Deliver Message] (bound to @bf[H-s] in @hid[Draft] mode). To abort
+sending mail, use @hid[Delete Draft and Buffer] (bound to @bf[H-q] in
+@hid[Draft] mode). If one wants to temporarily stop composing a draft with the
+intention of finishing it later, then the @hid[Save File] command (bound to
+@bf[C-x C-s]) will save the draft to the user's draft folder.
+
+@hid[Draft] buffers have a special @hemlock minor mode called @hid[Draft] mode.
+The major mode of a @hid[Draft] buffer is taken from the @hid[Default Modes]
+variable. The user may wish to arrange that @hid[Text] mode (and possibly
+@hid[Fill] mode or @hid[Save] mode) be turned on whenever @hid[Draft] mode is
+set. For a further description of how to manipulate modes in @hemlock see the
+@i[Hemlock Command Implementor's Manual].
+
+
+@defcom[com "Send Message", stuff (bound to @bf[s] and @bf[m] in @hid[Headers] and @hid[Message] modes and @bf[C-x m] globally) ]
+ This command, when invoked in a @hid[Headers] buffer, creates a unique
+@hid[Draft] buffer and a unique @hid[Message] buffer. The current message is
+inserted in the @hid[Message] buffer, and the @hid[Draft] buffer is displayed
+in the current window. The @hid[Draft] buffer's point is moved to the end of
+the line containing @f[To:] if it exists. The name of the draft message file
+is used to produce the buffer's name. A pathname is associated with the
+@hid[Draft] buffer so that @hid[Save File] can be used to incrementally save a
+composition before delivering it. The @f[comp] utility will be used to
+allocate a draft message in the user's @mh draft folder and to insert the
+proper header components into the draft message. Both the @hid[Draft] and
+@hid[Message] buffers are associated with the @hid[Headers] buffer, and the
+@hid[Draft] buffer is associated with the @hid[Message] buffer.
+
+When invoked in a @hid[Message] buffer, a unique @hid[Draft] buffer is created,
+and these two buffers are associated. If the @hid[Message] buffer is
+associated with a @hid[Headers] buffer, this association is propagated to the
+@hid[Draft] buffer. Showing other messages while in this @hid[Headers] buffer
+will not affect this @hid[Message] buffer.
+
+When not in a @hid[Headers] or @hid[Message] buffer, this command does the same
+thing as described in the previous two cases, but there are no @hid[Message] or
+@hid[Headers] buffer manipulations.
+
+@hid[Deliver Message] will deliver the draft to its intended recipient(s).
+
+The @hid[Goto Headers Buffer] command, when invoked in a @hid[Draft] or
+@hid[Message] buffer, makes the associated @hid[Headers] buffer current. The
+@hid[Goto Message Buffer] command, when invoked in a @hid[Draft] buffer, makes
+the associated @hid[Message] buffer current.
+@enddefcom
+
+@defcom[com "Reply to Message", stuff (bound to @bf[r] in @hid[Headers] mode) ]
+@defcom1[com "Reply to Message in Other Window", stuff (bound to @bf[r] in @hid[Message] mode) ]
+@defhvar1[var "Reply to Message Prefix Action"]
+ @hid[Reply to Message], when invoked in a @hid[Headers] buffer, creates a
+unique @hid[Draft] buffer and a unique @hid[Message] buffer. The current
+message is inserted in the @hid[Message] buffer, and the @hid[Draft] buffer is
+displayed in the current window. The draft components are set up in reply to
+the message, and the @hid[Draft] buffer's point is moved to the end of the
+buffer. The name of the draft message file is used to produce the buffer's
+name. A pathname is associated with the @hid[Draft] buffer so that @hid[Save
+File] can be used to incrementally save a composition before delivering it.
+The @f[repl] utility will be used to allocate a draft message file in the
+user's @mh draft folder and to insert the proper header components into the
+draft message. Both the @hid[Draft] and @hid[Message] buffers are associated
+with the @hid[Headers] buffer, and the @hid[Draft] buffer is associated with
+the @hid[Message] buffer.
+
+When invoked in a @hid[Message] buffer, a unique @hid[Draft] buffer is set up
+using the message in the buffer as the associated message. Any previous
+association between the @hid[Message] buffer and a @hid[Draft] buffer is
+removed. Any association of the @hid[Message] buffer with a @hid[Headers]
+buffer is propagated to the @hid[Draft] buffer.
+
+When not in a @hid[Headers] buffer or @hid[Message] buffer, this command
+prompts for a folder and message to reply to. This message is inserted into a
+unique @hid[Message] buffer, and a unique @hid[Draft] buffer is created as in
+the previous two cases. There is no association of either the @hid[Message]
+buffer or the @hid[Draft] buffer with a @hid[Headers] buffer.
+
+When a prefix argument is supplied, @hid[Reply to Message Prefix Action] is
+considered with respect to supplying carbon copy switches to @f[repl]. This
+variable's value is one of @b[:cc-all], :@b[no-cc-all], or @nil. See section
+@ref[Styles] for examples of how to use this.
+
+@hid[Reply to Message in Other Window] is identical to @hid[Reply to Message],
+but the current window is split showing the @hid[Draft] buffer in the new
+window. The split window displays the @hid[Message] buffer.
+
+@hid[Deliver Message] will deliver the draft to its intended recipient(s).
+
+The @hid[Goto Headers Buffer] commmand, when invoked in a @hid[Draft] or
+@hid[Message] buffer, makes the associated @hid[Headers] buffer current. The
+@hid[Goto Message Buffer] command, when invoked in a @hid[Draft] buffer, makes
+the associated @hid[Message] buffer current.
+@enddefcom
+
+@defcom[com "Forward Message", stuff (bound to @bf[f] in @hid[Headers] and @hid[Message] modes) ]
+ This command, when invoked in a @hid[Headers] buffer, creates a unique
+@hid[Draft] buffer. The current message is inserted in the draft by using the
+@f[forw] utility, and the @hid[Draft] buffer is shown in the current window.
+The name of the draft message file is used to produce the buffer's name. A
+pathname is associated with the @hid[Draft] buffer so that @hid[Save File] can
+be used to incrementally save a composition before delivering it. The
+@hid[Draft] buffer is associated with the @hid[Headers] buffer, but no
+@hid[Message] buffer is created since the message is already a part of the
+draft.
+
+When invoked in a @hid[Message] buffer, a unique @hid[Draft] buffer is set up
+inserting the message into the @hid[Draft] buffer. The @hid[Message] buffer is
+not associated with the @hid[Draft] buffer because the message is already a
+part of the draft. However, any association of the @hid[Message] buffer with a
+@hid[Headers] buffer is propagated to the @hid[Draft] buffer.
+
+When not in a @hid[Headers] buffer or @hid[Message] buffer, this command
+prompts for a folder and message to forward. A @hid[Draft] buffer is created
+as described in the previous two cases.
+
+@hid[Deliver Message] will deliver the draft to its intended recipient(s).
+@enddefcom
+
+@defcom[com "Deliver Message", stuff (bound to @bf[H-s] and @bf[H-c] in @hid[Draft] mode) ]
+@defhvar1[var "Deliver Message Confirm", val {nil}]
+ This command, when invoked in a @hid[Draft] buffer, saves the file and uses
+the @mh @f[send] utility to deliver the draft. If the draft is a reply to some
+message, then @f[anno] is used to annotate that message with a "@f[replied]"
+component. Any @hid[Headers] buffers containing the replied-to message are
+updated with an "@b[A]" placed in the appropriate headers line two characters
+after the message ID. Before doing any of this, confirmation is asked for
+based on @hid[Deliver Message Confirm].
+
+When not in a @hid[Draft] buffer, this prompts for a draft message ID and
+invokes @f[send] on that draft message to deliver it. Sending a draft in this
+way severs any association that draft may have had with a message being replied
+to, so no annotation will occur.
+@enddefcom
+
+@defcom[com "Delete Draft and Buffer", stuff (bound to @bf[H-q] in @hid[Draft] mode) ]
+This command, when invoked in a @hid[Draft] buffer, deletes the draft message
+file and the buffer. This also deletes any associated message buffer unless
+the user preserved it with @hid[Keep Message].
+@enddefcom
+
+@defcom[com "Remail Message", stuff (bound to @bf[H-r] in @hid[Headers] and @hid[Message] modes) ]
+ This command, when invoked in a @hid[Headers] or @hid[Message] buffer, prompts
+for resend @f[To:] and resend @f[Cc:] addresses, remailing the current message.
+When invoked in any other kind of buffer, this command prompts for a folder and
+message as well. @mh's @f[dist] sets up a draft folder message which is then
+modified. The above mentioned addresses are inserted on the @f[Resent-To:] and
+@f[Resent-Cc:] lines. Then the message is delivered.
+
+There is no mechanism for annotating messages as having been remailed.
+@enddefcom
+
+@defcom[com "Draft Help", bind (Draft: H-?)]
+This command displays documentation on @hid[Draft] mode.
+@enddefcom
+
+
+@section[Convenience Commands for Message and Draft Buffers]
+@index[message buffer commands]
+@index[draft buffer commands]
+@index[convenience commands for mail interface]
+@label[convenience-coms]
+This section describes how to switch from a @hid[Message] or @hid[Draft] buffer
+to its associated @hid[Headers] buffer, or from a @hid[Draft] buffer to its
+associated @hid[Message] buffer. There are also commands for various styles of
+inserting text from a @hid[Message] buffer into a @hid[Draft] buffer.
+
+@defcom[com "Goto Headers Buffer", stuff (bound to @bf[^] in @hid[Message] mode and @bf[H-^] in @hid[Draft] mode) ]
+This command, when invoked in a @hid[Message] or @hid[Draft] buffer with an
+associated @hid[Headers] buffer, places the associated @hid[Headers] buffer in
+the current window.
+
+The cursor is moved to the headers line of the associated message.
+@enddefcom
+
+@defcom[com "Goto Message Buffer", stuff (bound to @bf[H-m] in @hid[Draft] mode) ]
+This command, when invoked in a @hid[Draft] buffer with an associated
+@hid[Message] buffer, places the associated @hid[Message] buffer in the current
+window.
+@enddefcom
+
+@defcom[com "Insert Message Region", stuff (bound to @bf[H-y] in appropriate modes) ]
+@defhvar1[var "Message Insertion Prefix", val {" "}]
+@defhvar1[var "Message Insertion Column", val {75}]
+This command, when invoked in a @hid[Message] or @hid[News-Message] (where it
+is bound) buffer that has an associated @hid[Draft] or @hid[Post] buffer,
+copies the current active region into the @hid[Draft] or @hid[Post] buffer. It
+is filled using @hid[Message Insertion Prefix] (which defaults to three spaces)
+and @hid[Message Insertion Column]. If an argument is supplied, the filling is
+inhibited.
+@enddefcom
+
+@defcom[com "Insert Message Buffer", stuff (bound to @bf[H-y] in appropriate modes) ]
+@defhvar1[var "Message Buffer Insertion Prefix", val {" "}]
+This command, when invoked in a @hid[Draft] or @hid[Post] (where it is bound)
+buffer with an associated @hid[Message] or @hid[News-Message] buffer, or when
+in a @hid[Message] (or @hid[News-Message]) buffer that has an associated
+@hid[Draft] buffer, inserts the @hid[Message] buffer into the @hid[Draft] (or
+@hid[Post]) buffer. Each inserted line is modified by prefixing it with
+@hid[Message Buffer Insertion Prefix] (which defaults to four spaces) . If an
+argument is supplied, the prefixing is inhibited.
+@enddefcom
+
+@defcom[com "Edit Message Buffer", stuff (bound to @bf[e] in @hid[Message] mode) ]
+This command puts the current @hid[Message] buffer in @hid[Text] mode and makes
+it writable (@hid[Message] buffers are normally read-only). The pathname of
+the file which the message is in is associated with the buffer making saving
+possible. A recursive edit is entered, and the user is allowed to make changes
+to the message. When the recursive edit is exited, if the buffer is modified,
+the user is asked if the changes should be saved. The buffer is marked
+unmodified, and the pathname is disassociated from the buffer. The buffer
+otherwise returns to its previous state as a @hid[Message] buffer. If the
+recursive edit is aborted, the user is not asked to save the file, and the
+buffer remains changed though it is marked unmodified.
+@enddefcom
+
+
+@section[Deleting Messages]
+@index[deleting messages]
+@label[deleting]
+The main command described in this section is @hid[Headers Delete Message]
+(bound to @bf[k] in @hid[Headers] and @hid[Message] modes). A useful command
+for reading new mail is @hid[Delete Message and Show Next] (bound to @bf[d] in
+@hid[Message] mode) which deletes the current message and shows the next
+undeleted message.
+
+Since messages are by default deleted using a virtual message deletion
+mechanism, @hid[Expunge Messages] (bound to @bf[!] in @hid[Headers] mode)
+should be mentioned here. This is described in section @ref[terminating].
+
+
+@defhvar[var "Virtual Message Deletion", val {t}]
+When set, @hid[Delete Message] adds a message to the "@f[hemlockdeleted]"
+sequence; otherwise, @f[rmm] is invoked on the message immediately.
+@enddefhvar
+
+@defcom[com "Delete Message" ]
+This command prompts for a folder, messages, and an optional @f[pick]
+expression. When invoked in a @hid[Headers] buffer of the specified folder,
+the prompt for a message specification will default to the those messages in
+that @hid[Headers] buffer.
+
+When the variable @hid[Virtual Message Deletion] is set, this command merely
+flags the messages for deletion by adding them to the "@f[hemlockdeleted]"
+sequence. Then this updates any @hid[Headers] buffers representing the folder.
+It notates each headers line referring to a deleted message with a "@b[D]" in
+the third character position after the message ID.
+
+When @hid[Virtual Message Deletion] is not set, @f[rmm] is invoked on the
+message, and each headers line referring to the deleted message is deleted from
+its buffer
+@enddefcom
+
+@defcom[com "Headers Delete Message", stuff (bound to @bf[k] in @hid[Headers] and @hid[Message] modes) ]
+This command, when invoked in a @hid[Headers] buffer, deletes the message on
+the current line as described in @hid[Delete Message].
+
+When invoked in a @hid[Message] buffer, the message displayed in it is deleted
+as described in @hid[Delete Message].
+@enddefcom
+
+@defcom[com "Delete Message and Show Next", stuff (bound to @bf[k] in @hid[Headers] and @hid[Message] modes) ]
+This command is only valid in a @hid[Headers] buffer or a @hid[Message] buffer
+associated with some @hid[Headers] buffer. The current message is deleted as
+with the @hid[Delete Message] command. Then the next message is shown as with
+@hid[Next Undeleted Message].
+@enddefcom
+
+@defcom[com "Delete Message and Down Line", stuff (bound to @bf[d] in @hid[Headers mode])]
+This command, when invoked in a @hid[Headers] buffer, deletes the message on
+the current line. Then the point is moved to the next non-blank line.
+@enddefcom
+
+@defcom[com "Undelete Message" ]
+This command is only meaningful when @hid[Virtual Message Deletion] is set.
+This prompts for a folder, messages, and an optional @f[pick] expression. When
+in a @hid[Headers] buffer of the specified folder, the messages prompt defaults
+to those messages in the buffer. All @hid[Headers] buffers representing the
+folder are updated. Each headers line referring to an undeleted message is
+notated by replacing the "@b[D]" in the third character position after the
+message ID with a space.
+@enddefcom
+
+@defcom[com "Headers Undelete Message", stuff (bound to @bf[u] in @hid[Headers] and @hid[Message] modes) ]
+This command is only meaningful when @hid[Virtual Message Deletion] is set.
+When invoked in a @hid[Headers] buffer, the message on the current line is
+undeleted as described in @hid[Undelete Message].
+
+When invoked in a @hid[Message] buffer, the message displayed in it is
+undeleted as described in @hid[Undelete Message].
+@enddefcom
+
+
+@section[Folder Operations]
+
+@index[folder operations]@label[folder]
+@defcom[com "List Folders" ]
+This command displays a list of all current mail folders in the user's
+top-level mail directory in a @hemlock pop-up window.
+@enddefcom
+
+@defcom[com "Create Folder"]
+This command prompts for and creates a folder. If the folder already exists,
+an error is signaled.
+@enddefcom
+
+@defcom[com "Delete Folder" ]
+This command prompts for a folder and uses @f[rmf] to delete it. Note that no
+confirmation is asked for.
+@enddefcom
+
+
+@section[Refiling Messages]
+
+@index[refiling messages]@label[refiling]
+@defcom[com "Refile Message" ]
+This command prompts for a folder, messages, an optional @f[pick] expression,
+and a destination folder. When invoked in a @hid[Headers] buffer of the
+specified folder, the message prompt offers a default of those messages in the
+buffer. If the destination folder does not exist, the user is asked to create
+it. The resulting messages are refiled with the @f[refile] utility. All
+@hid[Headers] buffers for the folder are updated. Each line referring to a
+refiled message is deleted from its buffer.
+@enddefcom
+
+@defcom[com "Headers Refile Message", stuff (bound to @bf[o] in @hid[Headers] and @hid[Message] modes) ]
+This command, when invoked in a @hid[Headers] buffer, prompts for a destination
+folder, refiling the message on the current line with @f[refile]. If the
+destination folder does not exist, the user is asked to create it. Any
+@hid[Headers] buffers containing messages for that folder are updated. Each
+headers line referring to the refiled message is deleted from its buffer.
+
+When invoked in a @hid[Message] buffer, that message is refiled as described
+above.
+@enddefcom
+
+
+@section[Marking Messages]
+@index[marking messages]
+@label[marking]
+@defcom[com "Mark Message" ]
+This command prompts for a folder, message, and sequence and adds (deletes) the
+message specification to (from) the sequence. By default this adds the
+message, but if an argument is supplied, this deletes the message. When
+invoked in a @hid[Headers] buffer or @hid[Message] buffer, this only prompts
+for a sequence and uses the current message.
+@enddefcom
+
+
+@section[Terminating Headers Buffers]
+@label[terminating]
+The user never actually @i[exits] the mailer. He can leave mail buffers lying
+around while conducting other editing tasks, selecting them and continuing his
+mail handling whenever. There still is a need for various methods of
+terminating or cleaning up @hid[Headers] buffers. The two most useful commands
+in this section are @hid[Expunge Messages] and @hid[Quit Headers].
+
+
+@defhvar[var "Expunge Messages Confirm", val {t}]
+When this is set, @hid[Quit Headers] and @hid[Expunge Messages] will ask for
+confirmation before expunging messages and packing the folder's message ID's.
+@enddefhvar
+
+@defhvar[var "Temporary Draft Folder", val {nil}]
+This is a folder name where @mh @f[fcc:] messages are kept with the intention
+that this folder's messages will be deleted and expunged whenever messages from
+any folder are expunged (for example, when @hid[Expunge Messages] or @hid[Quit
+Headers] is invoked.
+@enddefhvar
+
+@defcom[com "Expunge Messages", stuff (bound to @bf[!] in @hid[Headers] mode) ]
+This command deletes messages @f[mark]'ed for deletion, and compacts the
+folder's message ID's. If there are messages to expunge, ask the user for
+confirmation, displaying the folder name. This can be inhibited by setting
+@hid[Expunge Messages Confirm] to @nil. When @hid[Temporary Draft Folder] is
+not @nil, this command deletes and expunges that folder's messages regardless
+of the folder in which the user invokes it, and a negative response to the
+request for confirmation inhibits this.
+
+When invoked in a @hid[Headers] buffer, the messages in that folder's
+"@f[hemlockdeleted]" sequence are deleted by invoking @f[rmm]. Then the ID's
+of the folder's remaining messages are compacted using the @f[folder] utility.
+Since headers must be regenerated due to renumbering or reassigning message
+ID's, and because @hid[Headers] buffers become inconsistent after messages are
+deleted, @hemlock must regenerate all the headers for the folder. Multiple
+@hid[Headers] buffers for the same folder are then collapsed into one buffer,
+deleting unnecessary duplicates. Any @hid[Message] buffers associated with
+these @hid[Headers] buffers are deleted.
+
+If there is an unseen @hid[Headers] buffer for the folder, it is handled
+separately from the @hid[Headers] buffers described above. @hemlock tries to
+update it by filling it only with remaining unseen message headers.
+Additionally, any headers generated due to @hid[Unseen Headers Message Spec]
+are inserted. If there are no headers, unseen or otherwise, the buffer is left
+blank.
+
+Any @hid[Draft] buffer set up as a reply to a message in the folder is affected
+as well since the associated message has possibly been deleted. When a draft
+of this type is delivered, no message will be annotated as having been replied
+to.
+
+When invoked in a @hid[Message] buffer, this uses its corresponding folder as
+the folder argument. The same updating as described above occurs.
+
+In any other type of buffer, a folder is prompted for.
+@enddefcom
+
+@defcom[com "Quit Headers", stuff (bound to @bf[q] in @hid[Headers] and @hid[Message] modes) ]
+This command affects the current @hid[Headers] buffer. When there are deleted
+messages, ask the user for confirmation on expunging the messages and packing
+the folder's message ID's. This prompting can be inhibited by setting
+@hid[Expunge Messages Confirm] to @nil. After deleting and packing, this
+deletes the buffer and all its associated @hid[Message] buffers.
+
+Other @hid[Headers] buffers regarding the same folder are handled as described
+in @hid[Expunge Messages], but the buffer this command is invoked in is always
+deleted.
+
+When @hid[Temporary Draft Folder] is not @nil, this folder's messages are
+deleted and expunged regardless of the folder in which the user invokes this
+command. A negative response to the above mentioned request for confirmation
+inhibits this.
+@enddefcom
+
+@defcom[com "Delete Headers Buffer and Message Buffers" ]
+This command prompts for a @hid[Headers] buffer to delete along with its
+associated @hid[Message] buffers. Any associated @hid[Draft] buffers are left
+intact, but their corresponding @hid[Message] buffers will be deleted. When
+invoked in a @hid[Headers] buffer or a @hid[Message] buffer associated with a
+@hid[Headers] buffer, that @hid[Headers] buffer is offered as a default.
+@enddefcom
+
+
+@section[Miscellaneous Commands]
+@label[miscellaneous mail commands]
+@label[miscellaneous]
+
+@defcom[com "List Mail Buffers", stuff (bound to @bf[l] in @hid[Headers] and @hid[Message] modes @bf[H-l] in @hid[Draft] mode) ]
+This command shows a list of all mail @hid[Message], @hid[Headers], and
+@hid[Draft] buffers.
+
+If a @hid[Message] buffer has an associated @hid[Headers] buffer, it is
+displayed to the right of the @hid[Message] buffer's name.
+
+If a @hid[Draft] buffer has an associated @hid[Message] buffer, it is displayed
+to the right of the @hid[Draft] buffer's name. If a @hid[Draft] buffer has no
+associated @hid[Message] buffer, but it is associated with a @hid[Headers]
+buffer, then the name of the @hid[Headers] buffer is displayed to the right of
+the @hid[Draft] buffer.
+
+For each buffer listed, if it is modified, then an asterisk is displayed before
+the name of the buffer.
+@enddefcom
+
+
+@section[Styles of Usage]
+@index[styles of mail interface usage]
+@label[Styles]
+This section discusses some styles of usage or ways to make use of some of the
+features of @hemlock's interface to @mh that might not be obvious. In each
+case, setting some variables and/or remembering an extra side effect of a
+command will lend greater flexibility and functionality to the user.
+
+@subsection[Unseen Headers Message Spec]
+The unseen @hid[Headers] buffer by default only shows unseen headers which is
+adequate for one folder, simple mail handling. Some people use their @hid[New
+Mail Folder] only for incoming mail, refiling or otherwise dispatching a
+message immediately. Under this mode it is easy to conceive of the user not
+having time to respond to a message, but he would like to leave it in this
+folder to remind him to take care of it. Using the @hid[Unseen Headers Message
+Spec] variable, the user can cause all the messages the @hid[New Mail Folder] to
+be inserted into the unseen @hid[Headers] buffer whenever just unseen headers
+would be. This way he sees all the messages that require immediate attention.
+
+To achieve the above effect, @hid[Unseen Headers Message Spec] should be set to
+the string @f["all"]. This variable can be set to any general @mh message
+specification (see section @ref[mhcommands] of this chapter), so the user can
+include headers of messages other than those that have not been seen without
+having to insert all of them. For example, the user could set the variable to
+@f["flagged"] and use the @hid[Mark Message] command to add messages he's
+concerned about to the @f["flagged"] sequence. Then the user would see new
+mail and interesting mail in his unseen @hid[Headers] buffer, but he doesn't
+have to see everything in his @hid[New Mail Folder].
+
+
+@subsection[Temporary Draft Folder]
+Section @ref[components-files] of this chapter discusses how to make @mh keep
+personal copies of outgoing mail. The method described will cause a copy of
+every outgoing message to be saved forever and requires the user to go through
+his @f[Fcc:] folder, weeding out those he does not need. The @hid[Temporary
+Draft Folder] variable can name a folder whose messages will be deleted and
+expunged whenever any folder's messages are expunged. By naming this folder in
+the @mh profile and components files, copies of outgoing messages can be saved
+temporarily. They will be cleaned up automatically, but the user still has a
+time frame in which he can permanently save a copy of an outgoing message.
+This folder can be visited with @hid[Message Headers], and messages can be
+refiled just like any other folder.
+
+
+@subsection[Reply to Message Prefix Action]
+Depending on the kinds of messages one tends to handle, the user may find
+himself usually replying to everyone who receives a certain message, or he may
+find that this is only desired occasionally. In either case, the user
+can set up his @mh profile to do one thing by default, using the @hid[Reply
+to Message Prefix Action] variable in combination with a prefix argument to the
+@hid[Reply to Message] command to get the other effect.
+
+For example, the following line in one's @mh profile will cause @mh to reply to
+everyone receiving a certain message (except for the user himself since he
+saves personal copies with the @f[-fcc] switch):
+@begin[programexample]
+repl: -cc all -nocc me -fcc out-copy
+@end[programexample]
+This user can set @hid[Reply to Message Prefix Action] to be @f[:no-cc-all].
+Then whenever he invokes @hid[Reply to Message] with a prefix argument, instead
+of replying to everyone, the draft will be set up in reply only to the person
+who sent the mail.
+
+As an alternative example, not specifying anything in one's @mh profile and
+setting this variable to @f[:cc-all] will have a default effect of replying
+only to the sender of a piece of mail. Then invoking @hid[Reply to Message]
+with a prefix argument will cause everyone who received the mail to get a copy
+of the reply. If the user does not want a @f[cc:] copy, then he can add
+@f[-nocc me] as a default switch and value in his @mh profile.
+
+
+@newpage
+@section[Wallchart]
+
+@tabclear
+@tabdivide(3)
+
+@begin[format, spacing 1.5]
+
+@Begin[Center] @b[Global bindings:] @End[Center]
+
+@hid[Incorporate and Read New Mail]@\@\@bf[C-x i]
+@hid[Send Message]@\@\@bf[C-x m]
+@hid[Message Headers]@\@\@bf[C-x r]
+
+
+@Begin[Center] @b[Headers and Message modes bindings:] @End[Center]
+
+@hid[Next Undeleted Message]@\@\@bf[n]
+@hid[Previous Undeleted Message]@\@\@bf[p]
+@hid[Send Message]@\@\@bf[s], @bf[m]
+@hid[Forward Message]@\@\@bf[f]
+@hid[Headers Delete Message]@\@\@bf[k]
+@hid[Headers Undelete Message]@\@\@bf[u]
+@hid[Headers Refile Message]@\@\@bf[o]
+@hid[List Mail Buffers]@\@\@bf[l]
+@hid[Quit Headers]@\@\@bf[q]
+@hid[Incorporate and Read New Mail]@\@\@bf[i]
+@hid[Next Message]@\@\@bf[M-n]
+@hid[Previous Message]@\@\@bf[M-p]
+@hid[Beginning of Buffer]@\@\@bf[<]
+@hid[End of Buffer]@\@\@bf[>]
+
+
+@Begin[Center] @b[Headers mode bindings:] @End[Center]
+
+@hid[Delete Message and Down Line]@\@\@bf[d]
+@hid[Pick Headers]@\@\@bf[h]
+@hid[Show Message]@\@\@bf[space], @bf[.]
+@hid[Reply to Message]@\@\@bf[r]
+@hid[Expunge Messages]@\@\@bf[!]
+
+
+@Begin[Center] @b[Message mode bindings:] @End[Center]
+
+@hid[Delete Message and Show Next]@\@\@bf[d]
+@hid[Goto Headers Buffer]@\@\@bf[^]
+@hid[Scroll Message]@\@\@bf[space]
+@hid[Scroll Message]@\@\@bf[C-v]
+@hid[Scroll Window Up]@\@\@bf[backspace], @bf[delete]
+@hid[Reply to Message in Other Window]@\@bf[r]
+@hid[Edit Message Buffer]@\@\@bf[e]
+@hid[Insert Message Region]@\@\@bf[H-y]
+
+
+@Begin[Center] @b[Draft mode bindings:] @End[Center]
+
+@hid[Goto Headers Buffer]@\@\@bf[H-^]
+@hid[Goto Message Buffer]@\@\@bf[H-m]
+@hid[Deliver Message]@\@\@bf[H-s], @bf[H-c]
+@hid[Insert Message Buffer]@\@\@bf[H-y]
+@hid[Delete Draft and Buffer]@\@\@bf[H-q]
+@hid[List Mail Buffers]@\@\@bf[H-l]
+
+@end[format]
+@tabclear
diff --git a/docs/hem/user/netnews.mss b/docs/hem/user/netnews.mss
new file mode 100644
index 0000000000000000000000000000000000000000..cc3b2d59da3c19b4a678b029b569a865904873e2
--- /dev/null
+++ b/docs/hem/user/netnews.mss
@@ -0,0 +1,488 @@
+@comment{-*- Dictionary: /afs/cs/project/clisp/docs/hem/hem; Mode: spell; Package: Hemlock -*-}
+
+@chap[The Hemlock Netnews Interface]
+@section[Introduction to Netnews in Hemlock]
+
+
+@hemlock provides a facility for reading bulletin boards through the
+NetNews Transfer Protocol (NNTP). You can easily read Netnews, reply to
+news posts, post messages, etc. The news reading interface is consistent
+with that of the @hemlock mailer, and most Netnews commands function in the
+same manner as their mailer counterparts.
+
+Netnews can be read in one of two different modes. The first mode, invoked
+by the @hid(Netnews) command, allows the user to read new messages in
+groups which the user has specified. This method of reading netnews will
+track the highest numbered message in each newsgroup and only show new
+messages which have arrived since then. The @hid(Netnews Browse) command
+invokes the other method of reading netnews. This mode displays a list of
+all newsgroups, and the user may choose to read messages in any of them.
+By default, the news reader will not track the latest message read when
+browsing, and it will always display the last few messages.
+
+
+@section[Setting Up Netnews]
+
+To start reading bulletin boards from @hemlock you probably need to create a
+file containing the newsgroups you want to read.
+
+@defhvar[var "Netnews Group File", val {".hemlock-groups"}]
+ When you invoke the @hid(Netnews) command, @hemlock merges the value of
+ this variable with your home directory and looks there for a list of
+ groups (one per line) to read.
+@enddefhvar
+
+@defhvar[var "Netnews Database File", val{".hemlock-netnews"}]
+When you invoke the @hid(Netnews) command, @hemlock merges the value of
+this variable with your home directory. This file maintains a pointer to
+the highest numbered message read in each group in @hid(Netnews Group
+File).
+@enddefhvar
+
+@defcom[com "List All Groups"]
+ When you invoke this command, @hemlock creates a buffer called
+ @hid(Netnews Groups) and inserts the names of all accessible Netnews
+ groups into it alphabetically. You may find this useful if you choose to set
+ up your @hid(Netnews Group File) manually.
+@enddefcom
+
+@defhvar[var "Netnews NNTP Server", val{"netnews.srv.cs.cmu.edu"}]
+This variable stores the host name of the machine which @hemlock will use
+as the NNTP server.
+@enddefhvar
+
+@defhvar[var "Netnews NNTP Timeout Period", val{30}]
+This is the number of seconds @hemlock will wait trying to connect to the
+NNTP server. If a connection is not made within this time period, the
+connection will time out and an error will be signalled.
+@enddefhvar
+
+@subsection[News-Browse Mode]
+
+ @hid(News-Browse) mode provides an easy method of adding groups to
+ your @hid(Netnews Group File).
+
+@defcom[com "Netnews Browse"]
+ This command sets up a buffer in @hid{News-Browse} mode with all
+ available groups listed one per line. Groups may be read or added
+ to your group file using various commands in this mode.
+@enddefcom
+
+@defcom[com "Netnews Browse Add Group To File", stuff (bound to @bf[a] in @hid[News-Browse] mode)]
+@defcom1[com "Netnews Browse Pointer Add Group to File"]
+@hid(Netnews Browse Add Group to File) adds the group under the point to
+your group file, and @hid(Netnews Browse Pointer Add Group To File) adds
+the group under the mouse pointer without moving the point.
+@enddefcom
+
+@defcom[com "Netnews Browse Read Group", stuff (bound to @bf[space] in @hid[News-Browse] mode)]
+@defcom1[com "Netnews Browse Pointer Read Group"]
+@hid(Netnews Browse Read Group) and @hid(Netnews Browse Pointer Read Group)
+read the group under the cursor and the group under the mouse pointer,
+respectively. These commands neither use nor modify the contents of your
+@hid(Netnews Database File); they will always present the last few messages
+in the newsgroup, regardless of the last message read. @hid(Netnews Browse
+Pointer Read Group) does not modify the position of the point.
+@enddefcom
+
+@defcom[com "Netnews Quit Browse"]
+ This command exits @hid(News-Browse) mode.
+@enddefcom
+
+The @hid(Next Line) and @hid(Previous Line) commands are conveniently bound to
+@bf[n] and @bf[p] in this mode.
+
+@section[Starting Netnews]
+
+Once your @hid(Netnews Group File) is set up, you may begin reading netnews.
+
+@defcom[com "Netnews"]
+ This command is the main entry point for reading bulletin boards in
+ @hemlock. Without an argument, the system looks for what bulletin boards to
+ read in the value of @hid(Netnews Group File) and reads each of them in
+ succession. @hemlock keeps a pointer to the last message you read in each
+ of these groups in your @hid(Netnews Database File). Bulletin boards may
+ be added to your @hid(Netnews Group File) manually or by using
+ the @hid(Netnews Browse) facility. With an argument, @hemlock prompts the
+ user for the name of a bulletin board and reads it.
+@enddefcom
+
+@defcom[com "Netnews Look at Group"]
+ This command prompts for a group and reads it, ignoring the information
+ in your @hid(Netnews Database File).
+@enddefcom
+
+When you read a group, @hemlock creates a buffer that contains important
+header information for the messages in that group. There are four fields
+in each header, one each for the @i(date), @i(lines), @i(from), and
+@i(subject). The @i(date) field shows when the message was sent, the
+@i(lines) field displays how long the message is in lines, the @i(from)
+field shows who sent the message, and the @i(subject) field displays the
+subject of this message. If a field for a message is not available, @f(NA)
+will appear instead. You may alter the length of each of these fields by
+modifying the following @hemlock variables:
+
+@defhvar[var "Netnews Before Date Field Pad", val 1]
+ How many spaces should be inserted before the date in @hid(News-Headers)
+ buffers.
+@enddefhvar
+
+@defhvar[var "Netnews Date Field Length", val 6]
+@defhvar1[var "Netnews Line Field Length", val 3]
+@defhvar1[var "Netnews From Field Length", val 20]
+@defhvar1[var "Netnews Subject Field Length", val 43]
+ These variables control how long the @i(date), @i(line), @i(from), and
+ @i(subject) fields should be in @hid{News-Headers} buffers.
+@enddefhvar
+
+@defhvar[var "Netnews Field Padding", val 2]
+ How many spaces should be left between the Netnews @i(date), @i(from),
+ @i(lines), and @i(subject) fields after padding to the required length.
+@enddefhvar
+
+For increased speed, @hemlock only inserts headers for a subset of the
+messages in each group. If you have never read a certain group, and the
+value of @hid(Netnews New Group Style) is @f(:from-end) (the default),
+@hemlock inserts some number of the last messages in the group, determined
+by the value of @hid(Netnews Batch Count). If the value of @hid(Netnews
+New Group Style) is @f(:from-start), @hemlock will insert the first batch
+of messages in the group. If you have read a group before, @hemlock will
+insert the batch of messages following the highest numbered message that
+you had read previously.
+
+@defhvar[var "Netnews Start Over Threshold", val {350}]
+ If the number of new messages in a group exceeds the value of this
+ variable and @hid(Netnews New Group Style) is @f(:from-end), @hemlock asks
+ if you would like to start reading this group from the end.
+@enddefhvar
+
+You may at any time go beyond the messages that are visible using the
+@hid(Netnews Next Line), @hid(Netnews Previous Line),
+@hid(Netnews Headers Scroll Window Up), and
+@hid(Netnews Headers Scroll Down) commands in @hid(News-Headers) mode,
+or the @hid(Netnews Next Article) and @hid(Netnews Previous Article)
+commands in @hid(News-Message) mode.
+
+@defhvar[var "Netnews Fetch All Headers", val {nil}]
+This variable determines whether Netnews will fetch all headers immediately
+upon entering a new group.
+@enddefhvar
+
+@defhvar[var "Netnews Batch Count", val {50}]
+ This variable determines how many headers the Netnews facility will fetch
+ at a time.
+@enddefhvar
+
+@defhvar[var "Netnews New Group Style", val {:from-end}]
+This variable determines what happens when you read a group that you have
+never read before. When it is @f(:from-start), the @hid(Netnews) command
+will read from the beginning of a new group forward. When it is @f(:from-end),
+the default, @hid(Netnews) will read the group from the end backward.
+@enddefhvar
+
+@section[Reading Messages]
+
+From a @hid{News-Headers} buffer, you may read messages, reply to messages
+via the @hemlock mailer, or reply to messages via post. Some commands are
+also bound to ease getting from one header to another.
+
+@defcom[com "Netnews Show Article", stuff (bound to @bf[space] in @hid{News-Headers} mode)]
+@defhvar1[var "Netnews Read Style", val {:multiple}]
+@defhvar1[var "Netnews Headers Proportion", val {0.25}]
+This command puts the body of the message header under the current point
+into a @hid{News-Message} buffer. If the value of @hid(Netnews Read
+Style) is @f(:single), @hemlock changes to the @hid{News-Message}
+buffer. If it is @f(:multiple), then @hemlock splits the current window
+into two windows, one for headers and one for message bodies. The headers
+window takes up a proportion of the current window based on the value of
+@hid(Netnews Headers Proportion). If the window displaying the
+@hid(News-Headers) buffer has already been split, and the message
+currently displayed in the @hid(News-Message) window is the same as the
+one under the current point, this command behaves just like @hid(Netnews
+Message Scroll Down).
+@enddefcom
+
+@defhvar[var "Netnews Message Header Fields", val {nil}]
+ When this variable is @nil, all available fields are displayed in the
+ header of a message. Otherwise, this variable should containt a list of
+ fields to include in message headers. If an element of this
+ list is an atom, then it should be the string name of a field. If it is
+ a cons, then the car should be the string name of a field, and the cdr
+ should be the length to which this field should be limited. Any string
+ name is acceptable, and fields that do not exist are ignored.
+@enddefhvar
+
+@defcom[com "Netnews Show Whole Header", stuff (bound to @bf[w] in @hid{News-Headers} and @hid{News-Message} modes.)]
+This command displays the entire header for the message currently being
+read. This is to undo the effects of @hid{Netnews Message Header Fields}
+for the current message.
+@enddefcom
+
+@defcom[com "Netnews Next Line", stuff (bound to @bf[C-n] and @bf[Downarrow] in @hid{News-Headers} mode)]
+@defhvar1[var "Netnews Last Header Style", val {:next-headers}]
+This command moves the current point to the next line. If you are on the
+last visible message, and there are more in the current group, headers for
+these messages will be inserted. If you are on the last header and there
+are no more messages in this group, then @hemlock will take some action
+based on the value of @hid(Netnews Last Header Style). If the value of
+this variable is @f(:feep), @hemlock feeps you indicating there are no
+more messages. If the value is @f(:next-headers), @hemlock reads in the
+headers for the next group in your @hid(Netnews Group File). If the value
+is @f(:next-article), @hemlock goes on to the next group and shows you
+the first unread message.
+@enddefcom
+
+@defcom[com "Netnews Previous Line", stuff (bound to @bf[C-p] and @bf[Uparrow] in @hid{News-Headers} mode)]
+This command moves the current point to the previous line. If you are on
+the first visible header, and there are more previous messages, @hemlock
+inserts the headers for these messages.
+@enddefcom
+
+@defcom[com "Netnews Headers Scroll Window Down", stuff (bound to @bf[C-v] in @hid{News-Headers} mode)]
+@defcom1[com "Netnews Headers Scroll Window Up", stuff (bound to @bf[M-v] in @hid{News-Headers} mode)]
+ These commands scroll the headers window up or down one screenfull. If the
+ end of the buffer is visible, @hemlock inserts the next batch of headers.
+@enddefcom
+
+@defcom[com "Netnews Next Article", stuff (bound to @bf[n] in @hid{News-Message} and @hid{News-Headers} modes)]
+@defcom1[com "Netnews Previous Article", stuff (bound to @bf[p] in @hid{News-Message} and @hid{News-Headers} modes)]
+ These commands insert the next or previous message into a message buffer.
+@enddefcom
+
+@defcom[com "Netnews Message Scroll Down", stuff (bound to @bf[space] in @hid{News-Message} mode)]
+@defhvar1[var "Netnews Scroll Show Next Message", val {t}]
+If the end of the current message is visible, @hemlock feeps the user if
+the value of @hid(Netnews Scroll Show Next Message) is non-@nil, or it
+inserts the next message into this message buffer if that variable is @nil.
+If the end of the message is not visible, then @hemlock shows the next
+screenfull of the current message.
+@enddefcom
+
+@defcom[com "Netnews Message Quit", stuff (bound to @bf[q] in @hid{News-Message} mode)]
+ This command deletes the current message buffer and makes the associated
+ @hid{News-Headers} buffer current.
+@enddefcom
+
+@defcom[com "Netnews Goto Headers Buffer", stuff (bound to @bf[H-h] in @hid{News-Message} mode)]
+ This command, when invoked from a @hid(News-Message) buffer with an
+ associated @hid(News-Headers) buffer, places the associated
+ @hid(News-Headers) buffer into the current window.
+@enddefcom
+
+@defcom[com "Netnews Message Keep Buffer", stuff (bound to @bf[k] in @hid{News-Message} mode)]
+ By default, @hemlock uses one buffer to display all messages in a group,
+ one at a time. This command tells @hemlock to keep the current message
+ buffer intact and start reading messages in another buffer.
+@enddefcom
+
+@defcom[com "Netnews Select Message Buffer", stuff (bound to @bf[H-m] in @hid{News-Headers} and @hid{Post} modes.)]
+ In @hid{News-Headers} mode, this command selects the buffer
+ containing the last message read. In @hid{Post} mode, it selects the
+ associated @hid{News-Message} buffer, if there is one.
+@enddefcom
+
+@defcom[com "Netnews Append to File", stuff (bound to @bf[a] in @hid{News-Headers} and @hid{News-Message} modes.)]
+@defhvar1[var "Netnews Message File", val {"netnews-messages.txt"}]
+This command prompts for a file which the current message will be appended
+to. The default file is the value of @hid(Netnews Message File) merged
+with your home directory.
+@enddefcom
+
+@defcom[com "Netnews Headers File Message", stuff (bound to @bf[o] in @hid{News-Headers} mode)]
+This command prompts for a mail folder and files the message under the
+point into it. If the folder does not exist, @hemlock will ask if it should
+be created.
+@enddefcom
+
+@defcom[com "Netnews Message File Message", stuff (bound to @bf[o] in @hid{News-Message} mode)]
+This command prompts for a mail folder and files the current message there.
+If the folder does not exist, @hemlock will ask if it should be created.
+@enddefcom
+
+@defcom[com "Fetch All Headers", stuff (bound to @bf[f] in @hid{Netnews Headers} mode)]
+ In a forward reading @hid(Netnews headers) buffer, this command inserts
+ all headers after the last visible one into the headers buffer. If
+ @hemlock is reading this group backward, the system inserts all headers
+ before the first visible one into the headers buffer.
+@enddefcom
+
+@defcom[com "Netnews Go to Next Group", stuff (bound to @bf[g] in @hid{News-Headers} and @hid{News-Message} modes.)]
+This command goes to the next group in your @hid(Netnews Group File).
+Before going on, it sets the group pointer in @hid(Netnews Database
+Filename) to the last message you read. With an argument, the command does
+not modify the group pointer for the current group.
+@enddefcom
+
+@defcom[com "Netnews Quit Starting Here", stuff (bound to @bf[.] in @hid{News-Headers} and @hid{News-Message} modes)]
+ This command goes to the next group in your @hid(Netnews Group File),
+ setting the netnews pointer for this group to the message before the one
+ under the current point, so the next time you read this group, the message
+ indicated by the point will appear first.
+@enddefcom
+
+@defcom[com "Netnews Group Punt Messages", stuff (bound to @bf[G] in @hid{News-Headers} mode)]
+ This command goes on to the next bulletin board in your group
+ file. Without an argument, the system sets the pointer for the current
+ group to the last message. With an argument, @hemlock sets the
+ pointer to the last visible message in the group.
+@enddefcom
+
+@defcom[com "Netnews Exit", stuff (bound to @bf[q] in @hid{News-Headers} mode)]
+@defhvar1[var "Netnews Exit Confirm", val {t}]
+ This command cleans up and deletes the @hid(News-Headers) buffer and
+ all associated @hid(News-Message) buffers. If the value of
+ @hid(Netnews Exit Confirm) is @nil, then @hemlock will not prompt before
+ exiting.
+@enddefcom
+
+@section[Replying to Messages]
+
+The @hemlock Netnews interface also provides an easy way of replying to
+messages through the @hemlock Mailer or via @hid{Post} mode.
+
+@defcom[com "Netnews Reply to Sender"]
+ When you invoke this command, @hemlock creates a @hid(Draft) buffer and
+ tries to fill in the @i(to) and @i(subject) fields of the draft. For
+ the @i(to) field, @hemlock looks at the @i(reply-to) field of the
+ message you are replying to, or failing that, the @i(from) field. If
+ the @i(subject) field does not start with @f(Re:), @hemlock inserts this
+ string, signifying that this is a reply.
+@enddefcom
+
+@defcom[com "Netnews Reply to Sender in Other Window", stuff (bound to @bf[r] in @hid{News-Headers} and @hid{News-Message}.)]
+This command splits the current window, placing the message you are
+replying to in the top window and a new @hid{Draft} buffer in the bottom
+one. This command fills in the header fields in the same manner as
+@hid(Netnews Reply to Sender).
+@enddefcom
+
+@defcom[com "Netnews Reply to Group"]
+This command creates a @hid{Post} buffer with the @i(newsgroups) field set
+to the current group and the @i(subject) field constructed in the same way
+as in @hid(Netnews Reply to Sender).
+@enddefcom
+
+@defcom[com "Netnews Reply to Group in Other Window", stuff (bound to @bf[R] in @hid{News-Headers} and @hid{News-Message}.)]
+ This command splits the current window, placing the message you are
+ replying to in the top window and a new @hid{Post} buffer in the bottom
+ one. This command will fill in the header fields in the same manner as
+ @hid(Netnews Reply to Group).
+@enddefcom
+
+@defcom[com "Netnews Post Message", stuff (bound to @bf[C-x P])]
+ This command creates a @hid{Post} buffer. If you are in a
+ @hid(News-Headers) or @hid{News-Message} buffer, @hemlock fills in the
+ @i(newsgroups) field with the current group.
+@enddefcom
+
+@defcom[com "Netnews Forward Message", stuff (bound to @bf[f] in @hid{News-Headers} and @hid{News-Message} modes.)]
+This command creates a @hid{Post} buffer. If you are in a @hid{Netnews
+Headers} or @hid{News-Message} buffer, @hemlock will put the text of the
+current message into the buffer along with lines delimiting the forwarded
+message.
+@enddefcom
+
+@defcom[com "Netnews Goto Post Buffer", stuff (bound to @bf[H-p] in @hid{News-Message} mode)]
+ This command, when invoked in a @hid(News-Message) or @hid(Draft) buffer
+ with an associated @hid(News-Headers) buffer, places the associated
+ @hid(News-Headers) buffer into the current window.
+@enddefcom
+
+@defcom[com "Netnews Goto Draft Buffer", stuff (bound to @bf[H-d] in @hid{News-Message} mode)]
+ This command, when invoked in a @hid(News-Message) buffer with an
+ associated @hid(Draft) buffer, places the @hid(Draft) buffer into the
+ current window.
+@enddefcom
+
+@section[Posting Messages]
+
+@defcom[com "Netnews Deliver Post", stuff (bound to @bf[H-s] in @hid{Post} mode)]
+@defhvar1[var "Netnews Deliver Post Confirm", val "t"]
+This command delivers the contents of a @hid(Post) buffer to the NNTP
+server. If @hid(Netnews Deliver Post Confirm) is @f(t), @hemlock will ask for
+confirmation before posting the message. @hemlock feeps you if NNTP does
+not accept the message.
+@enddefcom
+
+@defcom[com "Netnews Abort Post", stuff (bound to @bf[H-q] in @hid{Post} mode)]
+ This command deletes the current @hid(Post) buffer.
+@enddefcom
+
+
+As in the mailer, when replying to a message you can be excerpt sections of
+it using @hid(Insert Message Buffer) and @hid(Insert Message Region) in
+@hid(Post) and @hid(News-Message) modes, respectively. You can also use
+these commands when replying to a message via mail in a @hid(Draft) buffer.
+In all cases, the same binding is used: @bf[H-y].
+
+@newpage
+@section[Wallchart]
+
+@tabclear
+@tabdivide(5)
+
+@begin[format, spacing 1.5]
+
+
+@Begin[Center] @b[Global bindings:] @End[Center]
+
+@hid[Netnews Post Message]@\@\@bf[C-x P]
+
+
+@Begin[Center] @b[News-Headers and News-Message modes bindings:] @End[Center]
+
+@hid[Netnews Next Article]@\@\@\@bf[n]
+@hid[Netnews Previous Article]@\@\@bf[p]
+@hid[Netnews Go to Next Group]@\@\@bf[g]
+@hid[Netnews Group Punt Messages]@\@\@bf[G]
+@hid[List All Groups]@\@\@\@bf[l]
+@hid[Netnews Append to File]@\@\@bf[a]
+@hid[Netnews Forward Message]@\@\@bf[f]
+@hid[Netnews Reply to Sender in Other Window]@\@\@bf[r]
+@hid[Netnews Reply to Group in Other Window]@\@\@bf[R]
+@hid[Netnews Quit Starting Here]@\@\@bf[.]
+
+@Begin[Center] @b[News-Headers mode bindings:] @End[Center]
+
+@hid[Netnews Show Article]@\@\@bf[Space]
+@hid[Netnews Previous Line]@\@\@bf[C-p], @bf[Uparrow]
+@hid[Netnews Next Line]@\@\@\@bf[C-n], @bf[Downarrow]
+@hid[Netnews Headers Scroll Window Down]@\@\@bf[C-v]
+@hid[Netnews Headers Scroll Window Up]@\@\@bf[M-v]
+@hid[Netnews Select Message Buffer]@\@\@bf[H-m]
+@hid[Netnews Exit]@\@\@\@bf[q]
+@hid[Netnews Headers File Message]@\@\@bf[o]
+
+
+@Begin[Center] @b[News-Message mode bindings:] @End[Center]
+
+@hid[Netnews Message Scroll Down]@\@\@bf[Space]
+@hid[Scroll Window Up]@\@\@\@bf[Backspace]
+@hid[Netnews Goto Headers Buffer]@\@\@bf[H-h], @bf[^]
+@hid[Netnews Message Keep Buffer]@\@\@bf[k]
+@hid[Netnews Message Quit]@\@\@bf[q]
+@hid[Netnews Message File Message]@\@\@bf[o]
+@hid[Netnews Goto Post Buffer]@\@\@bf[H-p]
+@hid[Netnews Goto Draft Buffer]@\@\@bf[H-d]
+@hid[Insert Message Region]@\@\@bf[H-y]
+
+
+@Begin[Center] @b[Post mode bindings:] @End[Center]
+
+@hid[Netnews Select Message Buffer]@\@\@bf[H-m]
+@hid[Netnews Deliver Post]@\@\@bf[H-s]
+@hid[Netnews Abort Post]@\@\@\@bf[H-q]
+@hid[Insert Message Buffer]@\@\@bf[H-y]
+
+
+@Begin[Center] @b[News-Browse mode bindings:] @End[Center]
+
+@hid[Netnews Quit Browse]@\@\@bf[q]
+@hid[Netnews Browse Add Group To File]@\@\@bf[a]
+@hid[Netnews Browse Read Group]@\@\@bf[Space]
+@hid[Next Line]@\@\@\@bf[n]
+@hid[Previous Line]@\@\@\@bf[p]
+
+
+@end[format]
+@tabclear
diff --git a/docs/hem/user/special-modes.mss b/docs/hem/user/special-modes.mss
new file mode 100644
index 0000000000000000000000000000000000000000..262b44bf8f93ea28f5c31ebdb089eda6b1c4846c
--- /dev/null
+++ b/docs/hem/user/special-modes.mss
@@ -0,0 +1,738 @@
+@comment{-*- Dictionary: bld:scribe/hem/hem; Mode: spell; Package: Hemlock -*-}
+@chap[Special Modes]
+
+@section[Dired Mode]
+@label[dired]
+@index[directory editing]
+
+@hemlock provides a directory editing mechanism. The user can flag files and
+directories for deletion, undelete flagged files, and with a keystroke read in
+files and descend into directories. In some implementations, it also supports
+copying, renaming, and a simple wildcard feature.
+
+
+@subsection[Inspecting Directories]
+@defcom[com "Dired", bind (C-x C-M-d)]
+This command prompts for a directory and fills a buffer with a verbose listing
+of that directory. When the prefix argument is supplied, this includes Unix
+dot files. If a dired buffer already exists for the directory, this switches
+to the buffer and makes sure it displays dot files if appropriate.
+@enddefcom
+
+@defcom[com "Dired with Pattern", bind (C-x C-M-d)]
+This command prompts for a directory and a pattern that may contain at most one
+wildcard, an asterisk, and it fills a buffer with a verbose listing of the
+files in the directory matching the pattern. When the prefix argument is
+supplied, this includes Unix dot files. If a dired buffer already exists for
+this directory, this switches to the buffer and makes sure it displays dot
+files if appropriate.
+@enddefcom
+
+@defcom[com "Dired from Buffer Pathname"]
+This command invokes @hid[Dired] on the directory name of the current buffer's
+pathname.
+@enddefcom
+
+@defcom[com "Dired Help", bind (Dired: ?)]
+This command pops up a help window listing the various @hid[Dired] commands.
+@enddefcom
+
+@defcom[com "Dired View File", bind (Dired: Space)]
+@defcom1[com "Dired Edit File", bind (Dired: e)]
+These command read in the file on the current line with the point. If the line
+describes a directory instead of a file, then this command effectively invokes
+@hid[Dired] on the specification. This associates the file's buffer with the
+@hid[Dired] buffer.
+
+@hid[Dired View File] reads in the file as if by @hid[View File], and
+@hid[Dired Edit File] as if by @hid[Find File].
+
+@hid[Dired View File] always reads into a newly created buffer, warning if the
+file already exists in some buffer.
+@enddefcom
+
+@defcom[com "Dired Up Directory", bind (Dired: ^)]
+This command invokes @hid[Dired] on the directory up one level from the current
+@hid[Dired] buffer. This is useful for going backwards after repeatedly
+invoking @hid[Dired View File] and descending into a series of subdirectories.
+Remember, @hid[Dired] only generates directory listings when no buffer contains
+a dired for the specified directory.
+@enddefcom
+
+@defcom[com "Dired Update Buffer", bind (Dired: H-u)]
+This command is useful when the user knows the directory in the current
+@hid[Dired] buffer has changed. @hemlock cannot know the directory structure
+has changed, but the user can explicitly update the buffer with this command
+instead of having to delete it and invoke @hid[Dired] again.
+@enddefcom
+
+@defcom[com "Dired Next File"]
+@defcom1[com "Dired Previous File"]
+These commands move to next or previous undeleted file.
+@enddefcom
+
+
+@subsection[Deleting Files]
+@defcom[com "Dired Delete File and Down Line", bind (Dired: d)]
+This command marks for deletion the file on the current line with the point and
+moves point down a line.
+@enddefcom
+
+@defcom[com "Dired Delete File with Pattern", bind (Dired: D)]
+This command prompts for a name pattern that may contain at most one wildcard,
+an asterisk, and marks for deletion all the names matching the pattern.
+@enddefcom
+
+@defcom[com "Dired Delete File", bind (Dired: C-d)]
+This command marks for deletion the file on the current line with the point
+without moving the point.
+@enddefcom
+
+
+@subsection[Undeleting Files]
+@defcom[com "Dired Undelete File and Down Line", bind (Dired: u)]
+This command unmarks for deletion the file on the current line with the point
+and moves point down a line.
+@enddefcom
+
+@defcom[com "Dired Undelete File with Pattern", bind (Dired: U)]
+This command prompts for a name pattern that may contain at most one wildcard,
+an asterisk, and unmarks for deletion all the names matching the pattern.
+@enddefcom
+
+@defcom[com "Dired Undelete File", bind (Dired: C-u)]
+This command unmarks for deletion the file on the current line with the point
+without moving the point.
+@enddefcom
+
+
+@subsection[Expunging and Quitting]
+@defcom[com "Dired Expunge Files", bind (Dired: !)]
+@defhvar1[var "Dired File Expunge Confirm", val {t}]
+@defhvar1[var "Dired Directory Expunge Confirm", val {t}]
+This command deletes files marked for deletion, asking the user for
+confirmation once for all the files flagged. It recursively deletes any marked
+directories, asking the user for confirmation once for all those marked.
+@hid[Dired File Expunge Confirm] and @hid[Dired Directory Expunge Confirm] when
+set to @nil individually inhibit the confirmation prompting for the appropriate
+deleting.
+@enddefcom
+
+@defcom[com "Dired Quit", bind (Dired: q)]
+This command expunges any marked files or directories as if by @hid[Expunge
+Dired Files] before deleting the @hid[Dired] buffer.
+@enddefcom
+
+
+@subsection[Copying Files]
+@defcom[com "Dired Copy File", bind (Dired: c)]
+This command prompts for a destination specification and copies the file on the
+line with the point. When prompting, the current line's specification is the
+default, which provides some convenience in supplying the destination. The
+destination is either a directory specification or a file name, and when it is
+the former, the source is copied into the directory under its current file name
+and extension.
+@enddefcom
+
+@defcom[com "Dired Copy with Wildcard", bind (Dired: C)]
+This command prompts for a name pattern that may contain at most one wildcard,
+an asterisk, and copies all the names matching the pattern. When prompting for
+a destination, this provides the @hid[Dired] buffer's directory as a default.
+The destination is either a directory specification or a file name with a
+wildcard. When it is the former, all the source files are copied into the
+directory under their current file names and extensions. When it is the later,
+each sources file's substitution for the wildcard causing it to match the first
+pattern replaces the wildcard in the destination pattern; for example, you
+might want to copy @f["*.txt"] to @f["*.text"].
+@enddefcom
+
+@defhvar[var "Dired Copy File Confirm", val {t}]
+@label[copy-confirm]
+This variable controls interaction with the user when it is not obvious what
+the copying process should do. This takes one of the following values:
+@Begin[Description]
+@true@\
+When the destination specification exists, the copying process stops and asks
+the user if it should overwrite the destination.
+
+@nil@\
+The copying process always copies the source file to the destination
+specification without interacting with the user.
+
+@kwd[update]@\
+When the destination specification exists, and its write date is newer than
+the source's write date, then the copying process stops and asks the user if it
+should overwrite the destination.
+@End[Description]
+@enddefhvar
+
+
+@subsection[Renaming Files]
+@defcom[com "Dired Rename File", bind (Dired: r)]
+Rename the file or directory under the point
+@enddefcom
+
+@defcom[com "Dired Rename with Wildcard", bind (Dired: R)]
+Rename files that match a pattern containing ONE wildcard.
+@enddefcom
+
+@defhvar[var "Dired Rename File Confirm", val {t}]
+When non-nil, @hid[Dired] will query before clobbering an existing file.
+@enddefhvar
+
+
+@section[View Mode]
+@hid[View] mode provides for scrolling through a file read-only, terminating
+the buffer upon reaching the end.
+
+@defcom[com "View File"]
+This command reads a file into a new buffer as if by "Visit File", but
+read-only. Bindings exist for scrolling and backing up in a single key stroke.
+@enddefcom
+
+@defcom[com "View Help", bind (View: ?)]
+This command shows a help message for @hid[View] mode.
+@enddefcom
+
+@defcom[com "View Edit File", bind (View: e)]
+This commands makes a buffer in @hid[View] mode a normal editing buffer,
+warning if the file exists in another buffer simultaneously.
+@enddefcom
+
+@defcom[com "View Scroll Down", bind (View: Space)]
+@defhvar1[var "View Scroll Deleting Buffer", val {t}]
+This command scrolls the current window down through its buffer. If the end of
+the file is visible, then this deletes the buffer if @hid[View Scroll Deleting
+Buffer] is set. If the buffer is associated with a @hid[Dired] buffer, this
+returns there instead of to the previous buffer.
+@enddefcom
+
+@defcom[com "View Return", bind (View: ^)]
+@defcom1[com "View Quit", bind (View: q)]
+These commands invoke a function that returns to the buffer that created the
+current buffer in @hid[View] mode. Sometimes this function does nothing, but
+it is useful for returning to @hid[Dired] buffers and similar @hemlock
+features.
+
+After invoking the viewing return function if there is one, @hid[View Quit]
+deletes the buffer that is current when the user invokes it.
+@enddefcom
+
+Also, bound in @hid[View] mode are the following commands:
+@Begin[Description]
+@binding[backspace], @binding[delete]@\Scrolls the window up.
+
+@binding[<]@\Goes to the beginning of the buffer.
+
+@binding[>]@\Goes to the end of the buffer.
+@End[Description]
+
+
+@section[Process Mode]
+@Label[process]
+@Index[shells]
+@Index[processes]
+
+@hid[Process] mode allows the user to execute a Unix process within a @hemlock
+buffer. These commands and default bindings cater to running Unix shells in
+buffers. For example, @hid[Stop Buffer Subprocess] is bound to @binding[H-z]
+to stop the process you are running in the shell instead of binding @hid[Stop
+Main Process] to this key which would stop the shell itself.
+
+@defcom[com "Shell", bind (C-M-s)]
+@defhvar1[var "Shell Utility", val {"/bin/csh"}]
+@defhvar1[var "Shell Utility Switches", val {@nil}]
+@defhvar1[var "Current Shell"]
+@defhvar1[var "Ask about Old Shells"]
+This command executes the process determined by the values of @hid(Shell
+Utility) and @hid(Shell Utility Switches) in a new buffer named @f["Shell n"]
+where @f["n"] is some distinguishing integer.
+
+@hid[Current Shell] is a @hemlock variable that holds to the current shell
+buffer. When @hid[Shell] is invoked, if there is a @hid[Current Shell], the
+command goes to that buffer.
+
+When there is no @hid[Current Shell], but shell buffers do exist, if @hid[Ask
+about Old Shells] is set, the @hid[Shell] command prompts for one of them,
+setting @hid[Current Shell] to the indicated shell, and goes to the buffer.
+
+Invoking @hid[Shell] with an argument forces the creation of a new shell
+buffer.
+
+@hid[Shell Utility] is the string name of the process to execute.
+
+@hid[Shell Utility Switches] is a string containing the default command line
+arguments to @hid[Shell Utility]. This is a string since the utility is
+typically @f["/bin/csh"], and this string can contain I/O redirection and other
+shell directives.
+@enddefcom
+
+@defcom[com "Shell Command Line in Buffer"]
+This command prompts for a buffer and a shell command line. It then runs a
+shell, giving it the command line, in the buffer.
+@enddefcom
+
+@defcom[com "Set Current Shell"]
+This command sets the value of @hid[Current Shell].
+@enddefcom
+
+@defcom[com "Stop Main Process"]
+This command stops the process running in the current buffer by sending a
+@f[:SIGTSTP] to that process. With an argument, stops the process using
+@f[:SIGSTOP].
+@enddefcom
+
+@defcom[com "Continue Main Process"]
+If the process in the current buffer is stopped, this command continues it.
+@enddefcom
+
+@defcom[com "Kill Main Process"]
+@defhvar1[var "Kill Process Confirm", val {t}]
+This command prompts for confirmation and kills the process running in the
+current buffer.
+
+Setting this variable to @nil inhibits @hemlock's prompting for confirmation.
+@enddefcom
+
+@defcom[com "Stop Buffer Subprocess", stuff (bound to @bf[H-z] in @hid[Process] mode)]
+This command stops the foreground subprocess of the process in the current
+buffer, similar to the effect of @binding[C-Z] in a shell.
+@enddefcom
+
+@defcom[com "Kill Buffer Subprocess"]
+This command kills the foreground subprocess of the process in the current
+buffer.
+@enddefcom
+
+@defcom[com "Interrupt Buffer Subprocess", stuff (bound to @bf[H-c] in @hid[Process] mode)]
+This command interrupts the foreground subprocess of the process in the
+current buffer, similar to the effect of @binding[C-C] in a shell.
+@enddefcom
+
+@defcom[com "Quit Buffer Subprocess", stuff (bound to @bf[H-\] in @hid[Process] mode)]
+This command dumps the core of the foreground subprocess of the processs in
+the current buffer, similar to the effect of @binding[C-\] in a shell.
+@enddefcom
+
+@defcom[com "Send EOF to Process", stuff (bound to @bf[H-d] in @hid[Process] mode)]
+This command sends the end of file character to the process in the current
+buffer, similar to the effect of @binding[C-D] in a shell.
+@enddefcom
+
+@defcom[com "Confirm Process Input", stuff (bound to @bf[Return] in @hid[Process] mode)]
+This command sends the text the user has inserted at the end of a process
+buffer to the process in that buffer. Resulting output is inserted at the end
+of the process buffer.
+@enddefcom
+
+The user may edit process input using commands that are shared with
+@hid[Typescript] mode, see section @ref[typescripts].
+
+
+@section[Bufed Mode]
+@hemlock provides a mechanism for managing buffers as an itemized list.
+@hid[Bufed] supports conveniently deleting several buffers at once, saving
+them, going to one, etc., all in a key stroke.
+
+@defcom[com "Bufed", bind (C-x C-M-b)]
+This command creates a list of buffers in a buffer supporting operations such
+as deletion, saving, and selection. If there already is a @hid[Bufed] buffer,
+this just goes to it.
+@enddefcom
+
+@defcom[com "Bufed Help"]
+This command pops up a display of @hid[Bufed] help.
+@enddefcom
+
+@defcom[com "Bufed Delete", bind (Bufed: C-d, C-D, D, d)]
+@defhvar1[var "Virtual Buffer Deletion", val {t}]
+@defhvar1[var "Bufed Delete Confirm", val {t}]
+@hid[Bufed Delete] deletes the buffer on the current line.
+
+When @hid[Virtual Buffer Deletion] is set, this merely flags the buffer for
+deletion until @hid[Bufed Expunge] or @hid[Bufed Quit] executes.
+
+Whenever these commands actually delete a buffer, if @hid[Bufed Delete Confirm]
+is set, then @hemlock prompts the user for permission; if more than one buffer
+is flagged for deletion, this only prompts once. For each modified buffer,
+@hemlock asks to save the buffer before deleting it.
+@enddefcom
+
+@defcom[com "Bufed Undelete", bind (Bufed: U, u)]
+This command undeletes the buffer on the current line.
+@enddefcom
+
+@defcom[com "Bufed Expunge", bind (Bufed: !)]
+This command expunges any buffers marked for deletion regarding @hid[Bufed
+Delete Confirm].
+@enddefcom
+
+@defcom[com "Bufed Quit", bind (Bufed: q)]
+This command kills the @hid[Bufed] buffer, expunging any buffers marked for
+deletion.
+@enddefcom
+
+@defcom[com "Bufed Goto", bind (Bufed: Space)]
+This command selects the buffer on the current line, switching to it.
+@enddefcom
+
+@defcom[com "Bufed Goto and Quit", bind (Bufed: S-leftdown)]
+This command goes to the buffer under the pointer, quitting @hid[Bufed]. It
+supplies a function for @hid[Generic Pointer Up] which is a no-op.
+@enddefcom
+
+@defcom[com "Bufed Save File", bind (Bufed: s)]
+This command saves the buffer on the current line.
+@enddefcom
+
+
+@section[Completion]
+This is a minor mode that saves words greater than three characters in length,
+allowing later completion of those words. This is very useful for the often
+long identifiers used in Lisp programs. As you type a word, such as a Lisp
+symbol when in @hid[Lisp] mode, and you progress to typing the third letter,
+@hemlock displays a possible completion in the status line. You can then
+rotate through the possible completions or type some more letters to narrow
+down the possibilities. If you choose a completion, you can also rotate
+through the possibilities in the buffer instead of in the status line.
+Choosing a completion or inserting a character that delimits words moves the
+word forward in the ring of possible completions, so the next time you enter
+its initial characters, @hemlock will prefer it over less recently used
+completions.
+
+@defcom[com "Completion Mode"]
+This command toggles @hid[Completion] mode in the current buffer.
+@enddefcom
+
+@defcom[com "Completion Self Insert"]
+This command is like @hid[Self Insert], but it also checks for possible
+completions displaying any result in the status line. This is bound to most of
+the key-events with corresponding graphic characters.
+@enddefcom
+
+@defcom[com "Completion Complete Word", bind (Completion: End)]
+This command selects the currently displayed completion if there is one,
+guessing the case of the inserted text as with @hid[Query Replace]. Invoking
+this immediately in succession rotates through possible completions in the
+buffer. If there is no currently displayed completion on a first invocation,
+this tries to find a completion from text immediately before the point and
+displays the completion if found.
+@enddefcom
+
+@defcom[com "Completion Rotate Completions", bind (Completion: M-End)]
+This command displays the next possible completion in the status line. If
+there is no currently displayed completion, this tries to find a completion
+from text immediately before the point and displays the completion if found.
+@enddefcom
+
+@defcom[com "List Possible Completions"]
+This command lists all the possible completions for the text immediately before
+the point in a pop-up display. Sometimes this is more useful than rotating
+through several completions to see if what you want is available.
+@enddefcom
+
+@defhvar[var "Completion Bucket Size", val {20}]
+Completions are stored in buckets determined by the first three letters of a
+word. This variable limits the number of completions saved for each combination
+of the first three letters of a word. If you have many identifier in some
+module beginning with the same first three letters, you'll need increase this
+variable to accommodate all the names.
+@enddefhvar
+
+
+@defcom[com "Save Completions"]
+@defcom1[com "Read Completions"]
+@defhvar1[var "Completion Database Filename", val {nil}]
+@hid[Save Completions] writes the current completions to the file
+@hid[Completion Database Filename]. It writes them, so @hid[Read Completions]
+can read them back in preserving the most-recently-used order. If the user
+supplies an argument, then this prompts for a pathname.
+
+@hid[Read Completions] reads completions saved in @hid[Completion Database
+Filename]. It moves any current completions to a less-recently-used status,
+and it removes any in a given bucket that exceed the limit @hid[Completion
+Bucket Size].
+@enddefcom
+
+@defcom[com "Parse Buffer for Completions"]
+This command passes over the current buffer putting each valid completion word
+into the database. This is a good way of picking up many useful completions
+upon visiting a new file for which there are no saved completions.
+@enddefcom
+
+
+@section[CAPS-LOCK Mode]
+
+@hid[CAPS-LOCK] is a minor mode in which @hemlock that inserts all alphabetic
+characters as uppercase letters.
+
+@defcom[com "Caps Lock Mode"]
+This command toggles @hid[CAPS-LOCK] mode for the current buffer; it is most
+useful when bound to a key, so you can enter and leave @hid[CAPS-LOCK] mode
+casually.
+@enddefcom
+
+@defcom[com "Self Insert Caps Lock"]
+This command inserts the uppercase version of the character corresponding to
+the last key-event typed.
+@enddefcom
+
+
+
+@section[Overwrite Mode]
+
+@hid[Overwrite] mode is a minor mode which is useful for creating figures and
+tables out of text. In this mode, typing a key-event with a corresponding
+graphic character replaces the character at the point instead of inserting the
+character. @hid[Quoted Insert] can be used to insert characters normally.
+
+@defcom[com "Overwrite Mode"]
+This command turns on @hid[Overwrite] mode in the current buffer. If it is
+already on, then it is turned off. A positive argument turns @hid[Overwrite]
+mode on, while zero or a negative argument turns it off.
+@enddefcom
+
+@defcom[com "Self Overwrite"]
+This command replaces the next character with the character corresponding to
+the key-event used to invoke the command. After replacing the character, this
+moves past it. If the next character is a tab, this first expands the tab into
+the appropriate number of spaces, replacing just the next space character.
+At the end of the line, it inserts the
+character instead of clobbering the newline.
+
+This is bound to key-events with corresponding graphic characters in
+@hid[Overwrite] mode.
+@enddefcom
+
+@defcom[com "Overwrite Delete Previous Character",
+ stuff (bound to @bf[Delete] and @bf[Backspace] in @hid[Overwrite] mode)]
+This command replaces the previous character with a space and moves backwards.
+This deletes tabs and newlines.
+@enddefcom
+
+
+@section[Word Abbreviation]
+@index[word abbreviation]
+Word abbreviation provides a way to speed the typing of frequently used words
+and phrases. When in @hid[Abbrev] mode, typing a word delimiter causes the
+previous word to be replaced with its @i[expansion] if there is one currently
+defined. The expansion for an abbrev may be any string, so this mode can be
+used for abbreviating programming language constructs and other more obscure
+uses. For example, @hid[Abbrev] mode can be used to automatically correct
+common spelling mistakes and to enforce consistent capitalization of
+identifiers in programs.
+
+@i[Abbrev] is an abbreviation for @i[abbreviation], which is used for
+historical reasons. Obviously the original writer of @hid[Abbrev] mode hated
+to type long words and could hardly use @hid[Abbrev] mode while writing
+@hid[Abbrev] mode.
+
+A word abbrev can be either global or local to a major mode. A global word
+abbrev is defined no matter what the current major mode is, while a mode word
+abbrev is only defined when its mode is the major mode in the current buffer.
+Mode word abbrevs can be used to prevent abbrev expansion in inappropriate
+contexts.
+
+
+@subsection[Basic Commands]
+
+@defcom[com "Abbrev Mode"]
+This command turns on @hid[Abbrev] mode in the current buffer. If @hid[Abbrev]
+mode is already on, it is turned off. @hid[Abbrev] mode must be on for the
+automatic expansion of word abbrevs to occur, but the abbreviation commands are
+bound globally and may be used at any time.
+@enddefcom
+
+@defcom[com "Abbrev Expand Only",
+ stuff (bound to word-delimiters in @hid[Abbrev] mode)]
+This is the word abbrev expansion command. If the word before the point is a
+defined word abbrev, then it is replaced with its expansion. The replacement
+is done using the same case-preserving heuristic as is used by
+@hid[Query Replace]. This command is globally bound to @binding[M-Space] so
+that abbrevs can be expanded when @hid[Abbrev] mode is off. An undesirable
+expansion may be inhibited by using @binding[C-q] to insert the delimiter.
+@enddefcom
+
+@defcom[com "Inverse Add Global Word Abbrev", bind (C-x -)]
+@defcom1[com "Inverse Add Mode Word Abbrev", bind (C-x C-h, C-x Backspace)]
+@hid[Inverse Add Global Word Abbrev] prompts for a string and makes it the
+global word abbrev expansion for the word before the point.
+
+@hid[Inverse Add Mode Word Abbrev] is identical to
+@hid[Inverse Add Global Word Abbrev] except that it defines an expansion which
+is local to the current major mode.
+@enddefcom
+
+@defcom[com "Make Word Abbrev"]
+This command defines an arbitrary word abbreviation. It prompts for the mode,
+abbreviation and expansion. If the mode @f["Global"] is specified, then it
+makes a global abbrev.
+@enddefcom
+
+@defcom[com "Add Global Word Abbrev", bind (C-x +)]
+@defcom1[com "Add Mode Word Abbrev", bind (C-x C-a)]
+@hid[Add Global Word Abbrev] prompts for a word and defines it to be a global
+word abbreviation. The prefix argument determines which text is used as the
+expansion:
+@begin[description]
+@i[no prefix argument]@\The word before the point is used as the expansion of
+the abbreviation.
+
+@i[zero prefix argument]@\The text in the region is used as the expansion of the
+abbreviation.
+
+@i[positive prefix argument]@\That many words before the point are made the
+expansion of the abbreviation.
+
+@i[negative prefix argument]@\Do the same thing as
+@hid[Delete Global Word Abbrev] instead of defining an abbreviation.
+@end[description]
+
+@hid[Add Mode Word Abbrev] is identical to @hid[Add Global Word Abbrev] except
+that it defines or deletes mode word abbrevs in the current major mode.
+@enddefcom
+
+@defcom[com "Word Abbrev Prefix Mark", bind (M-")]
+This command allows @hid[Abbrev Expand Only] to recognize abbreviations when
+they have prefixes attached. First type the prefix, then use this command. A
+hyphen (@f[-]) will be inserted in the buffer. Now type the abbreviation and
+the word delimiter. @hid[Abbrev Expand Only] will expand the abbreviation and
+remove the hyphen.
+
+Note that there is no need for a suffixing command, since
+@hid[Abbrev Expand Only] may be used explicitly by typing @binding[M-Space].
+@enddefcom
+
+@defcom[com "Unexpand Last Word", bind (C-x u)]
+This command undoes the last word abbrev expansion. If repeated, undoes its
+own effect.
+@enddefcom
+
+
+@subsection[Word Abbrev Files]
+A word abbrev file is a file which holds word abbrev definitions. Word abbrev
+files allow abbrevs to be saved so that they may be used across many editing
+sessions.
+
+@defhvar[var "Abbrev Pathname Defaults", val {(pathname "abbrev.defns")}]
+This is sticky default for the following commands. When they prompt for a file
+to write, they offer this and set it for the next time one of them executes.
+@enddefhvar
+
+@defcom[com "Read Word Abbrev File"]
+This command reads in a word abbrev file, adding all the definitions to those
+currently defined. If a definition in the file is different from the current
+one, the current definition is replaced.
+@enddefcom
+
+@defcom[com "Write Word Abbrev File"]
+This command prompts for a file and writes all currently defined word abbrevs
+out to it.
+@enddefcom
+
+@defcom[com "Append to Word Abbrev File"]
+This command prompts for a word abbrev file and appends any new definitions to
+it. An abbrev is new if it has been defined or redefined since the last use of
+this command. Definitions made by reading word abbrev files are not
+considered.
+@enddefcom
+
+
+@subsection[Listing Word Abbrevs]
+@defcom[com "List Word Abbrevs"]
+@defcom1[com "Word Abbrev Apropos"]
+@hid[List Word Abbrevs] displays a list of each defined word abbrev, with its
+mode and expansion.
+
+@hid[Word Abbrev Apropos] is similar, except that it only displays abbrevs
+which contain a specified string, either in the definition, expansion or mode.
+@enddefcom
+
+@subsection[Editing Word Abbrevs]
+Word abbrev definition lists are edited by editing the text representation
+of the definitions. Word abbrev files may be edited directly, like any other
+text file. The set of abbrevs currently defined in @hemlock may be edited
+using the commands described in this section.
+
+The text representation of a word abbrev is fairly simple. Each definition
+begins at the beginning of a line. Each line has three fields which are
+separated by ASCII tab characters. The fields are the abbreviation, the mode
+of the abbreviation and the expansion. The mode is represented as the mode
+name inside of parentheses. If the abbrev is global, then the mode field is
+empty. The expansion is represented as a quoted string since it may contain
+any character. The string is quoted with double-quotes (@f["]); double-quotes
+in the expansion are represented by doubled double-quotes. The expansion may
+contain newline characters, in which case the definition will take up more than
+one line.
+
+@defcom[com "Edit Word Abbrevs"]
+This command inserts the current word abbrev definitions into the
+@hid[Edit Word Abbrevs] buffer and then enters a recursive edit on the buffer.
+When the recursive edit is exited, the definitions in the buffer become the new
+current abbrev definitions.
+@enddefcom
+
+@defcom[com "Insert Word Abbrevs"]
+This command inserts at the point the text representation of the currently
+defined word abbrevs.
+@enddefcom
+
+@defcom[com "Define Word Abbrevs"]
+This command interprets the text of the current buffer as a word abbrev
+definition list, adding all the definitions to those currently defined.
+@enddefcom
+
+
+@subsection[Deleting Word Abbrevs]
+The user may delete word abbrevs either individually or collectively.
+Individual abbrev deletion neutralizes single abbrevs which have outlived their
+usefulness; collective deletion provides a clean slate from which to initiate
+abbrev definitions.
+
+@defcom[com "Delete All Word Abbrevs"]
+This command deletes all word abbrevs which are currently defined.
+@enddefcom
+
+@defcom[com "Delete Global Word Abbrev"]
+@defcom1[com "Delete Mode Word Abbrev"]
+@hid[Delete Global Word Abbrev] prompts for a word abbreviation and deletes its
+global definition. If given a prefix argument, deletes all global abbrev
+definitions.
+
+@hid[Delete Mode Word Abbrev] is identical to @hid[Delete Global Word Abbrev]
+except that it deletes definitions in the current major mode.
+@enddefcom
+
+
+@section[Lisp Library]
+This is an implementation dependent feature. The Lisp library is a collection
+of local hacks that users can submit and share that is maintained by the Lisp
+group. These commands help peruse the catalog or description files and figure
+out how to load the entries.
+
+@defcom[com "Lisp Library"]
+This command finds all the library entries and lists them in a buffer. The
+following commands describe and load those entries.
+@enddefcom
+
+@defcom[com "Describe Library Entry", bind (Lisp-Lib: space)]
+@defcom1[com "Describe Pointer Library Entry", bind (Lisp-Lib: leftdown)]
+@defcom1[com "Load Library Entry", bind (Lisp-Lib: rightdown)]
+@defcom1[com "Load Pointer Library Entry", bind (Lisp-Lib: l)]
+@defcom1[com "Editor Load Library Entry"]
+@defcom1[com "Editor Load Pointer Library Entry"]
+@hid[Load Library Entry] and @hid[Load Pointer Library Entry] load the library
+entry indicated by the line on which the point lies or where the user clicked
+the pointer, respectively. These load the entry into the current slave Lisp.
+
+@hid[Editor Load Library Entry] and @hid[Editor Load Pointer Library Entry] are
+the same, but they load the entry into the editor Lisp.
+@enddefcom
+
+@defcom[com "Exit Lisp Library", bind (Lisp-Lib: q)]
+This command deletes the @hid[Lisp Library] buffer.
+@enddefcom
+
+@defcom[com "Lisp Library Help", bind (Lisp-Lib: ?)]
+This command pops up a help window listing @hid[Lisp-Lib] commands.
+@enddefcom
diff --git a/docs/hem/user/user.mss b/docs/hem/user/user.mss
new file mode 100644
index 0000000000000000000000000000000000000000..b7c2bd6ec2a11abb4990594944c5bff86e198da1
--- /dev/null
+++ b/docs/hem/user/user.mss
@@ -0,0 +1,2003 @@
+@make[Manual] @comment{-*- Dictionary: /afs/cs/project/clisp/scribe/hem/hem; Mode: spell; Package: Hemlock -*-}
+@Device[postscript]
+@Style(Spacing = 1.2 lines)
+@Style(StringMax = 5000)
+@Use(Database "/afs/cs/project/clisp/docs/database/")
+@Style(FontFamily=TimesRoman)
+@Style(Date="March 1952")
+@style(DOUBLESIDED)
+@Libraryfile[ArpaCredit]
+@libraryfile[hem]
+@Libraryfile[Spice]
+@Libraryfile[Uttir]
+
+@String(REPORTTITLE "Hemlock User's Manual")
+
+@comment<@begin[TitlePage]
+@begin[TitleBox]
+>
+@blankspace(1.3inches)
+@heading[Hemlock User's Manual]
+
+@center[@b
+@b
+
+
+@b<@value[date]>
+
+@b
+]
+@comment<@end[TitleBox]>
+@blankspace(2lines)
+@begin[Center]
+School of Computer Science
+Carnegie Mellon University
+Pittsburgh, PA 15213
+@end[Center]
+@blankspace[2lines]
+
+@begin[Center]
+This is a revised version of Technical Report CMU-CS-87-158.
+@end[Center]
+
+@heading
+@begin(Text, indent 0)
+This document describes the @Hemlock text editor, version M3.2. @Hemlock is a
+customizable, extensible text editor whose initial command set closely
+resembles that of ITS/TOPS-20 @Emacs. @Hemlock is written in CMU Common Lisp
+and has been ported to other implementations.
+@end(Text)
+
+@begin[ResearchCredit]
+@ArpaCredit[Contract=Basic87-90]
+@end[ResearchCredit]
+@comment<@end[TitlePage]>
+
+
+@commandstring(mh = "@f1(MH)")
+@commandstring(dash = "@Y[M]")
+
+@comment[This tabclear is necessary since the definition macros don't
+ take care of the own tabbing needs]
+@tabclear
+
+
+@comment[@chap (Introduction)]
+@include(intro)
+
+
+@comment[@chap (Basic Commands)]
+@include(commands)
+
+
+
+@chap[Files, Buffers, and Windows]
+
+@section[Introduction]
+
+@index[files]
+@index[buffers]
+@index[windows]
+@hemlock provides three different abstractions which are used in combination to
+solve the text-editing problem, while other editors tend to mash these ideas
+together into two or even one.
+@begin[description]
+File@\A file provides permanent storage of text. @hemlock has commands
+to read files into buffers and write buffers out into files.
+
+Buffer@\A buffer provides temporary storage of text and a capability to
+edit it. A buffer may or may not have a file associated with it; if it
+does, the text in the buffer need bear no particular relation to the text
+in the file. In addition, text in a buffer may be displayed in any number
+of windows, or may not be displayed at all.
+
+Window@\A window displays some portion of a buffer on the screen. There
+may be any number of windows on the screen, each of which may display any
+position in any buffer. It is thus possible, and often useful, to have
+several windows displaying different places in the same buffer.
+@end[description]
+
+
+@section[Buffers]
+In addition to some text, a buffer has several other user-visible attributes:
+@begin[description]
+A name@\
+A buffer is identified by its name, which allows it to be selected, destroyed,
+or otherwise manipulated.
+
+A collection of modes@\
+The modes present in a buffer alter the set of commands available and
+otherwise alter the behavior of the editor. For details see page
+@pageref[modes].
+
+A modification flag @\
+This flag is set whenever the text in a buffer is modified. It is often
+useful to know whether a buffer has been changed, since if it has it should
+probably be saved in its associated file eventually.
+
+A write-protect flag @\
+If this flag is true, then any attempt to modify the buffer will result in an
+error.
+@end[description]
+
+@defcom[com "Select Buffer", bind (C-x b)]
+This command prompts for the name of a existing buffer and makes that buffer
+the @i[current buffer]. The newly selected buffer is displayed in the
+current window, and editing commands now edit the text in that buffer.
+Each buffer has its own point, thus the point will be in the place it was
+the last time the buffer was selected. When prompting for the buffer, the
+default is the buffer that was selected before the current one.
+@enddefcom
+
+@defcom[com "Select Previous Buffer", bind (C-M-l)]
+@defcom1[com "Circulate Buffers", bind (C-M-L)]
+With no prefix argument, @hid[Select Previous Buffer] selects the buffer that
+has been selected most recently, similar to @binding[C-x b Return]. If given a
+prefix argument, then it does the same thing as @hid[Circulate Buffers].
+
+@hid[Circulate Buffers] moves back into successively earlier buffers in the
+buffer history. If the previous command was not @hid[Circulate Buffers] or
+@hid[Select Previous Buffer], then it does the same thing as
+@hid[Select Previous Buffer], otherwise it moves to the next most recent
+buffer. The original buffer at the start of the excursion is made the previous
+buffer, so @hid[Select Previous Buffer] will always take you back to where you
+started.
+
+These commands are generally used together. Often @hid[Select Previous Buffer]
+will take you where you want to go. If you don't end up there, then using
+@hid[Circulate Buffers] will do the trick.
+@enddefcom
+
+@defcom[com "Create Buffer", bind (C-x M-b)]
+This command is very similar to @hid[Select Buffer], but the buffer need not
+already exist. If the buffer does not exist, a new empty buffer is created
+with the specified name.
+@enddefcom
+
+@defcom[com "Kill Buffer", bind (C-x k)]
+This command is used to make a buffer go away. There is no way to restore
+a buffer that has been accidentally deleted, so the user is given a chance
+to save the hapless buffer if it has been modified. This command is poorly
+named, since it has nothing to do with killing text.
+@enddefcom
+
+@defcom[com "List Buffers", bind (C-x C-b)]
+This command displays a list of all existing buffers in a pop-up window. A
+"@f[*]" is displayed before the name of each modified buffer. A buffer with no
+associated file is represented by the buffer name followed by the number of
+lines in the buffer. A buffer with an associated file are is represented by
+the name and type of the file, a space, and the device and directory. If the
+buffer name doesn't match the associated file, then the buffer name is also
+displayed. When given a prefix argument, this command lists only the modified
+buffers.
+@enddefcom
+
+@defcom[com "Buffer Not Modified", bind (M-~)]
+This command resets the current buffer's modification flag @dash @i[it does not
+save any changes]. This is primarily useful in cases where a user accidentally
+modifies a buffer and then undoes the change. Resetting the modified flag
+indicates that the buffer has no changes that need to be written out.
+@enddefcom
+
+@defcom[com "Check Buffer Modified", bind (C-x ~)]
+This command displays a message indicating whether the current buffer is modified.
+@enddefcom
+
+@defcom[com "Set Buffer Read-Only"]
+This command changes the flag that allows the current buffer to be modified.
+If a buffer is read-only, any attempt to modify it will result in an error. The
+buffer may be made writable again by repeating this command.
+@enddefcom
+
+@defcom[com "Set Buffer Writable"]
+This command ensures the current buffer is modifiable.
+@enddefcom
+
+@defcom[com "Insert Buffer"]
+This command prompts for the name of a buffer and inserts its contents at the
+point, pushing a buffer mark before inserting. The buffer inserted is
+unaffected.
+@enddefcom
+
+@defcom[com "Rename Buffer"]
+This command prompts for a new name for the current buffer, which defaults
+to a name derived from the associated filename.
+@enddefcom
+
+
+@section[Files]
+@index[files]
+These commands either read a file into the current buffer or write it out to
+some file. Various other bookkeeping operations are performed as well.
+
+@defcom[com "Find File", bind (C-x C-f)]
+This is the command normally used to get a file into @hemlock. It prompts
+for the name of a file, and if that file has already been read in, selects
+that buffer; otherwise, it reads file into a new buffer whose name is
+derived from the name of the file. If the file does not exist, then the
+buffer is left empty, and @w<"@f[(New File)]"> is displayed in the echo area;
+the file may then be created by saving the buffer.
+
+The buffer name created is in the form @w<"@i[name] @i[type] @i[directory]">.
+This means that the filename "@f[/sys/emacs/teco.mid]" has
+@w<"@f[Teco Mid /Sys/Emacs/]"> as its the corresponding buffer name. The
+reason for rearranging the fields in this fashion is that it facilitates
+recognition since the components most likely to differ are placed first. If
+the buffer cannot be created because it already exists, but has another file in
+it (an unlikely occurrence), then the user is prompted for the buffer to use,
+as by @hid[Create Buffer].
+
+@hid[Find File] takes special action if the file has been modified on disk
+since it was read into @hemlock. This usually happens when several people are
+simultaneously editing a file, an unhealthy circumstance. If the buffer is
+unmodified, @hid[Find File] just asks for confirmation before reading in the
+new version. If the buffer is modified, then @hid[Find File] beeps and prompts
+for a single key-event to indicate what action to take. It recognizes
+the following key-events:
+@begin[description]
+@binding[Return, Space, y]@\
+ Prompt for a file in which to save the current buffer and then read in the
+file found to be modified on disk.
+
+@binding[Delete, Backspace, n]@\
+ Forego reading the file.
+
+@binding[r]@\
+ Read the file found to be modified on disk into the buffer containing the
+earlier version with modifications. This loses all changes you had in the
+buffer.
+@end[description]
+@enddefcom
+
+@defcom[com "Save File", bind (C-x C-s)]
+This command writes the current buffer out to its associated file and
+resets the buffer modification flag. If there is no associated file, then
+the user is prompted for a file, which is made the associated file. If
+the buffer is not modified, then the user is asked whether to actually
+write it or not.
+
+If the file has been modified on disk since the last time it was read,
+@hid[Save File] prompts for confirmation before overwriting the file.
+@enddefcom
+
+@defcom[com "Save All Files", bind (C-x C-m)]
+@defcom1[com "Save All Files and Exit", bind (C-x M-z)]
+@defhvar1[var "Save All Files Confirm", val {t}]
+@hid[Save All Files] does a @hid[Save File] on all buffers which have an
+associated file. @hid[Save All Files and Exit] does the same thing and then
+exits @hemlock.
+
+When @hid[Save All Files Confirm] is true, these commands will ask for
+confirmation before saving a file.
+@enddefcom
+
+@defcom[com "Visit File", bind (C-x C-v)]
+This command prompts for a file and reads it into the current buffer,
+setting the associated filename. Since the old contents of the buffer are
+destroyed, the user is given a chance to save the buffer if it is modified.
+As for @hid[Find File], the file need not actually exist. This command warns
+if some other buffer also contains the file.
+@enddefcom
+
+@defcom[com "Write File", bind (C-x C-w)] This command prompts for a file
+and writes the current buffer out to it, changing the associated filename
+and resetting the modification flag. When the buffer's associated file is
+specified this command does the same thing as @hid[Save File]. @enddefcom
+
+@defcom[com "Backup File"]
+This command is similar to @hid[Write File], but it neither sets the
+associated filename nor clears the modification flag. This is useful for
+saving the current state somewhere else, perhaps on a reliable machine.
+
+Since @hid[Backup File] doesn't update the write date for the buffer,
+@hid[Find File] and @hid[Save File] will get all upset if you back up
+a buffer on any file that has been read into @hemlock.
+@enddefcom
+
+@defcom[com "Revert File"]
+@defhvar1[var "Revert File Confirm", val {t}]
+This command replaces the text in the current buffer with the contents of the
+associated file or the checkpoint file for that file, whichever is more recent.
+The point is put in approximately the same place that it was before the file
+was read. If the original file is reverted to, then clear the modified flag,
+otherwise leave it set. If a prefix argument is specified, then always revert
+to the original file, ignoring any checkpoint file.
+
+If the buffer is modified and @hid[Revert File Confirm] is true, then the user
+is asked for confirmation.
+@enddefcom
+
+@defcom[com "Insert File", bind (C-x C-r)]
+This command prompts for a file and inserts it at the point, pushing a buffer
+mark before inserting.
+@enddefcom
+
+@defcom[com "Write Region"]
+This command prompts for a file and writes the text in the region out to it.
+@enddefcom
+
+@defhvar[var "Add Newline at EOF on Writing File", val {:ask-user}]
+This variable controls whether some file writing commands add a newline at the
+end of the file if the last line is non-empty.
+@begin[description]
+@f[:ask-user]@\Ask the user whether to add a newline.
+
+@f[t]@\Automatically add a newline and inform the user.
+
+@nil@\Never add a newline and do not ask.
+@end[description]
+Some programs will lose the text on the last line or get an
+error when the last line does not have a newline at the end.
+@enddefhvar
+
+@defhvar[var "Keep Backup Files", val {nil}]
+Whenever a file is written by @hid[Save File] and similar commands, the old
+file is renamed by appending "@f[.BAK]" to the name, ensuring that some version
+of the file will survive a system crash during the write. If set to true, this
+backup file will not deleted even when the write successfully completes.
+@enddefhvar
+
+
+@subsection[Auto Save Mode]
+
+@hid[Save] mode protects against loss of work in system crashes by periodically
+saving modified buffers in checkpoint files.
+
+@defcom[com "Auto Save Mode"]
+This command turns on @hid[Save] mode if it is not on, and turns off when it is
+on. @hid[Save] mode is on by default.
+@enddefcom
+
+@defhvar[var "Auto Save Checkpoint Frequency", val {120}]
+@defhvar1[var "Auto Save Key Count Threshold", val {256}]
+These variables determine how often modified buffers in @hid[Save] mode will be
+checkpointed. Checkpointing is done after
+@hid[Auto Save Checkpoint Frequency] seconds, or after
+@hid[Auto Save Key Count Threshold] keystrokes that modify the buffer
+(whichever comes first). Either kind of checkpointing may be disabled by
+setting the corresponding variable to @nil.
+@enddefhvar
+
+@defhvar[var "Auto Save Cleanup Checkpoints", val {t}]
+If this variable is true, then any checkpoint file for a buffer will be deleted
+when the buffer is successfully saved in its associated file.
+@enddefhvar
+
+@defhvar[var "Auto Save Filename Pattern", val {"~A~A.CKP"}]
+@defhvar1[var "Auto Save Pathname Hook", val {make-unique-save-pathname}]
+These variables determine the naming of checkpoint files.
+@hid[Auto Save Filename Pattern] is a format string used to name the checkpoint
+files for buffers with associated files. Format is called with two arguments:
+the directory and file namestrings of the associated file.
+
+@hid[Auto Save Pathname Hook] is a function called by @hid[Save] mode to get a
+checkpoint pathname when there is no pathname associated with a buffer. It
+should take a buffer as its argument and return either a pathname or @nil. If
+a pathname is returned, then it is used as the name of the checkpoint file. If
+the function returns @nil, or if the hook variable is @nil, then @hid[Save]
+mode is turned off in the buffer. The default value for this variable returns
+a pathname in the default directory of the form "@w<@f[save-]@i[number]>",
+where @i[number] is a number used to make the file unique.
+@enddefhvar
+
+
+@subsection[Filename Defaulting and Merging]
+@index[merging, filename]
+@index[defaulting, filename]
+@index[filename defaulting]
+@label[merging]
+@index[pathnames]
+When @hemlock prompts for the name of a file, it always offers a default.
+Except for a few commands that have their own defaults, filename defaults are
+computed in a standard way. If it exists, the associated file for the current
+buffer is used as the default, otherwise a more complex mechanism creates a
+default.
+
+@defhvar[var "Pathname Defaults", val {(pathname "gazonk.del")}]
+@defhvar1[var "Last Resort Pathname Defaults Function"]
+@defhvar1[var "Last Resort Pathname Defaults", val {(pathname "gazonk")}]
+These variables control the computation of default filename defaults when the
+current buffer has no associated file.
+
+@hid[Pathname Defaults] holds a "sticky" filename default. Commands that
+prompt for files set this to the file specified, and the value is used as a
+basis for filename defaults. It is undesirable to offer the unmodified value
+as a default, since it is usually the name of an existing file that we don't
+want to overwrite. If the current buffer's name is all alphanumeric, then the
+default is computed by substituting the buffer name for the the name portion of
+@hid[Pathname Defaults]. Otherwise, the default is computed by calling
+@hid[Last Resort Pathname Defaults Function] with the buffer as an argument.
+
+The default value of @hid[Last Resort Pathname Defaults Function] merges
+@hid[Last Resort Pathname Defaults] with @hid[Pathname Defaults].
+Unlike @hid[Pathname Defaults], @hid[Last Resort Pathname Defaults] is not
+modified by file commands, so setting it to a silly name ensures that real
+files aren't inappropriately offered as defaults.
+@enddefhvar
+
+When a default is present in the prompt for a file, @hemlock @i[merges] the
+given input with the default filename. The semantics of merging, described in
+the Common Lisp manual, is somewhat involved, but @hemlock has a few rules it
+uses:
+@begin[enumerate]
+If @hemlock can find the user's input as a file on the @f["default:"] search
+list, then it forgoes merging with the displayed default. Basically, the
+system favors the files in your current working directory over those found by
+merging with the defaults offered in the prompt.
+
+Merging comes in two flavors, just merge with the displayed default's directory
+or just merge with the displayed default's @f[file-namestring]. If the user
+only responds with a directory specification, without any name or type
+information, then @hemlock merges the default's @f[file-namestring]. If the
+user responds with any name or type information, then @hemlock only merges with
+the default's directory. Specifying relative directories in this second
+situation coordinates with the displayed defaults, not the current working
+directory.
+@end[enumerate]
+
+
+@subsection[Type Hooks and File Options]
+@index[mode comment]
+@index[type hooks]
+When a file is read either by @hid[Find File] or @hid[Visit File], @hemlock
+attempts to guess the correct mode in which to put the buffer, based on the
+file's @i[type] (the part of the filename after the last dot). Any default
+action may be overridden by specifying the mode in the file's @i[file
+options].@index[modes]@index[package]
+
+@label[file-options]@index[file options]
+The user specifies file options with a special syntax on the first line of a
+file. If the first line contains the string "@f[-*-]", then @hemlock
+interprets the text between the first such occurrence and the second, which
+must be contained in one line , as a list of @w{"@f<@i[option]: @i[value]>"}
+pairs separated by semicolons. The following is a typical example:
+@begin[programexample]
+;;; -*- Mode: Lisp, Editor; Package: Hemlock -*-
+@end[programexample]
+
+These options are currently defined:
+@begin[description]
+Dictionary@\The argument is the filename of a spelling dictionary associated
+with this file. The handler for this option merges the argument with the
+name of this file. See @comref[Set Buffer Spelling Dictionary].
+
+Log@\The argument is the name of the change log file associated with this file
+(see page @pageref[log-files]). The handler for this option merges the
+argument with the name of this file.
+
+Mode@\The argument is a comma-separated list of the names of modes to turn on
+in the buffer that the file is read into.
+
+Package@\The argument is the name of the package to be used for reading code in
+the file. This is only meaningful for Lisp code (see page
+@pageref[lisp-package].)
+
+Editor@\The handler for this option ignores its argument and turns on
+@hid[Editor] mode (see @comref[Editor Mode]).
+
+@end[description]
+If the option list contains no "@f[:]" then the entire string is used as
+the name of the major mode for the buffer.
+
+@defcom[com "Process File Options"]
+This command processes the file options in the current buffer as described
+above. This is useful when the options have been changed or when a file is
+created.
+@enddefcom
+
+
+@section[Windows]
+@index[windows]
+
+@hemlock windows display a portion of a buffer's text. See the section on
+@i[window groups], @ref[groups], for a discussion of managing windows on bitmap
+device.
+
+@defcom[com "New Window", bind (C-x C-n)]
+This command prompts users for a new window which they can place anywhere on
+the screen. This window is in its own group. This only works with bitmap
+devices.
+@enddefcom
+
+@defcom[com "Split Window", bind (C-x 2)]
+This command splits the current window roughly in half to make two windows. If
+the current window is too small to be split, the command signals a user error.
+@enddefcom
+
+@defcom[com "Next Window", bind (C-x n)]
+@defcom1[com "Previous Window", bind (C-x p)]
+These commands make the next or previous window the new current window, often
+changing the current buffer in the process. When a window is created, it is
+arbitrarily made the next window of the current window. The location of the
+next window is, in general, unrelated to that of the current window.
+@enddefcom
+
+@defcom[com "Delete Window", bind (C-x C-d, C-x d)]
+@defcom1[com "Delete Next Window", bind (C-x 1)]
+@hid[Delete Window] makes the current window go away, making the next window
+current. @hid[Delete Next Window] deletes the next window, leaving the current
+window unaffected.
+
+On bitmap devices, if there is only one window in the group, either command
+deletes the group, making some window in another group the current window. If
+there are no other groups, they signal a user error.
+@enddefcom
+
+@defcom[com "Go to One Window"]
+This command deletes all window groups leaving one with the @hid[Default
+Initial Window X], @hid[Default Initial Window Y], @hid[Default Initial Window
+Width], and @hid[Default Initial Window Height]. This remaining window
+retains the contents of the current window.
+@enddefcom
+
+@defcom[com "Line to Top of Window", bind (M-!)]
+@defcom1[com "Line to Center of Window", bind (M-#)]
+@index[scrolling]@hid[Line to Top of Window] scrolls the current window up
+until the current line is at the top of the screen.
+
+@hid[Line to Center of Window] attempts to scroll the current window so that
+the current line is vertically centered.
+@enddefcom
+
+@defcom[com "Scroll Next Window Down", bind (C-M-v)]
+@defcom1[com "Scroll Next Window Up", bind (C-M-V)]
+These commands are the same as @hid[Scroll Window Up] and
+@hid[Scroll Window Down] except that they operate on the next window.
+@enddefcom
+
+@defcom[com "Refresh Screen", bind {C-l}]
+This command refreshes all windows, which is useful if the screen got trashed,
+centering the current window about the current line. When the user supplies a
+positive argument, it scrolls that line to the top of the window. When the
+argument is negative, the line that far from the bottom of the window is moved
+to the bottom of the window. In either case when an argument is supplied, this
+command only refreshes the current window.
+@enddefcom
+
+
+@chap[Editing Documents]
+@index[documents, editing]
+Although @hemlock is not dedicated to editing documents as word processing
+systems are, it provides a number of commands for this purpose. If @hemlock is
+used in conjunction with a text-formatting program, then its lack of complex
+formatting commands is no liability.
+
+
+@defcom[com "Text Mode"]
+This commands puts the current buffer into "Text" mode.
+@enddefcom
+
+
+@section[Sentence Commands]
+@index[sentence commands]
+A sentence is defined as a sequence of characters ending with a period,
+question mark or exclamation point, followed by either two spaces or a newline.
+A sentence may also be terminated by the end of a paragraph. Any number of
+closing delimiters, such as brackets or quotes, may be between the punctuation
+and the whitespace. This somewhat complex definition of a sentence is used so
+that periods in abbreviations are not misinterpreted as sentence ends.
+
+@defcom[com "Forward Sentence", bind {M-a}]
+@defcom1[com "Backward Sentence", bind {M-e}]
+@index[motion, sentence]@hid[Forward Sentence] moves the point forward
+past the next sentence end. @hid[Backward Sentence] moves to the beginning
+of the current sentence. A prefix argument may be used as a repeat count.
+@enddefcom
+
+@defcom[com "Forward Kill Sentence", bind {M-k}]
+@defcom1[com "Backward Kill Sentence", bind (C-x Delete, C-x Backspace)]
+@index[killing, sentence]@hid[Forward Kill Sentence] kills text from the
+point through to the end of the current sentence. @hid[Backward Kill Sentence]
+kills from the point to the beginning of the current sentence. A
+prefix argument may be used as a repeat count.
+@enddefcom
+
+@defcom[com "Mark Sentence"]
+This command puts the point at the beginning and the mark at the end of the
+next or current sentence.
+@enddefcom
+
+
+@section[Paragraph Commands]
+
+@index[paragraph commands]A paragraph may be delimited by a blank line or a
+line beginning with "@f[']" or "@f[.]", in which case the delimiting line is
+not part of the paragraph. Other characters may be paragraph delimiters in
+some modes. A line with at least one leading whitespace character may also
+introduce a paragraph and is considered to be part of the paragraph. Any
+fill-prefix which is present on a line is disregarded for the purpose of
+locating a paragraph boundary.
+
+@defcom[com "Forward Paragraph", bind (@bf)]
+@defcom1[com "Backward Paragraph", bind (M-[)]
+@index[motion, paragraph]@index[paragraph, motion]@hid[Forward Paragraph]
+moves to the end of the current or next paragraph. @hid[Backward Paragraph]
+moves to the beginning of the current or previous paragraph. A prefix
+argument may be used as a repeat count.
+@enddefcom
+
+@defcom[com "Mark Paragraph", bind {M-h}]
+This command puts the point at the beginning and the mark at the end of the
+current paragraph.
+@enddefcom
+
+@defhvar[var "Paragraph Delimiter Function", val {default-para-delim-function}]
+This variable holds a function that takes a mark as its argument and returns
+true when the line it points to should break the paragraph.
+@enddefhvar
+
+@section[Filling]
+
+@index[filling]@index[formatting]Filling is a coarse text-formatting
+process which attempts to make all the lines roughly the same length, but
+doesn't vary the amount of space between words. Editing text may leave
+lines with all sorts of strange lengths; filling this text will return it
+to a moderately aesthetic form.
+
+@defcom[com "Set Fill Column", bind (C-x f)]
+This command sets the fill column to the column that the point is currently at,
+or the one specified by the absolute value of prefix argument, if it is
+supplied. The fill column is the column past which no text is permitted to
+extend.
+@enddefcom
+
+@defcom[com "Set Fill Prefix", bind (C-x .)]
+This command sets the fill prefix to the text from the beginning of the
+current line to the point. The fill-prefix is a string which filling commands
+leave at the beginning of every line filled. This feature is useful for
+filling indented text or comments.
+@enddefcom
+
+@defhvar[var "Fill Column", val {75}]
+@defhvar1[var "Fill Prefix", val {nil}]
+These variables hold the value of the fill prefix and fill column, thus
+setting these variables will change the way filling is done. If
+@hid[Fill Prefix] is @nil, then there is no fill prefix.
+@enddefcom
+
+@defcom[com "Fill Paragraph", bind {M-q}]
+@index[paragraph, filling]This command fills the text in the current or next
+paragraph. The point is not moved.
+@enddefcom
+
+@defcom[com "Fill Region", bind {M-g}]
+@index[region, filling]This command fills the text in the region. Since
+filling can mangle a large quantity of text, this command asks for confirmation
+before filling a large region (see @hid[Region Query Size].)
+@enddefcom
+
+
+@defcom[com "Auto Fill Mode"]
+@index[modes, auto fill]This command turns on or off the @hid[Fill]
+minor mode in the current buffer. When in @hid[Fill] mode, @bf[Space],
+@bf[Return] and @bf[Linefeed] are rebound to commands that check whether
+the point is past the fill column and fill the current line if it is.
+This enables typing text without having to break the lines manually.
+
+If a prefix argument is supplied, then instead of toggling, the sign
+determines whether @hid[Fill] mode is turned off; a positive argument
+argument turns in on, and a negative one turns it off.
+@enddefcom
+
+@defcom[com "Auto Fill Linefeed", stuff (bound to @bf[Linefeed] in @hid[Fill] mode)]
+@defcom1[com "Auto Fill Return", stuff (bound to @bf[Return] in @hid[Fill] mode)]
+@hid[Auto Fill Linefeed] fills the current line if it needs it and then goes to
+a new line and inserts the fill prefix. @hid[Auto Fill Return] is similar, but
+does not insert the fill prefix on the new line.
+@enddefcom
+
+@defcom[com "Auto Fill Space", stuff (bound to @bf[Space] in @hid[Fill] mode)]
+If no prefix argument is supplied, this command inserts a space and
+fills the current line if it extends past the fill column. If the argument is
+zero, then it fills the line if needed, but does not insert a space. If the
+argument is positive, then that many spaces are inserted without filling.
+@enddefcom
+
+@defhvar[var "Auto Fill Space Indent", val {nil}]
+This variable determines how lines are broken by the auto fill commands. If it
+is true, new lines are created using the @hid[Indent New Comment Line] command,
+otherwise the @hid[New Line] command is used. Language modes should define
+this variable to be true so that auto fill mode can be used on code.
+@enddefhvar
+
+
+@section[Scribe Mode]
+
+@hid[Scribe] mode provides a number of facilities useful for editing Scribe
+documents. It is also sufficiently parameterizable to be adapted to other
+similar syntaxes.
+
+@defcom[com "Scribe Mode"]
+@index[modes, scribe]This command puts the current buffer in @hid[Scribe] mode.
+Except for special Scribe commands, the only difference between @hid[Scribe]
+mode and @hid[Text] mode is that the rules for determining paragraph breaks are
+different. In @hid[Scribe] mode, paragraphs delimited by Scribe commands are
+normally placed on their own line, in addition to the normal paragraph breaks.
+The main reason for doing this is that it prevents @hid[Fill Paragraph] from
+mashing these commands into the body of a paragraph.
+@enddefcom
+
+@defcom[com "Insert Scribe Directive", stuff (@bf[C-h] in @hid[Scribe] mode)]
+This command prompts for a key-event to determine which Scribe directive to
+insert. Directives are inserted differently depending on their kind:
+@begin[description]
+@i[environment]@\
+The current or next paragraph is enclosed in a begin-end pair:
+@f<@@begin[@i{directive}]> @i[paragraph] @f<@@end[@i{directive}]>. If the
+current region is active, then this command encloses the region instead of the
+paragraph it would otherwise chose.
+
+@i[command]@\
+The previous word is enclosed by @f<@@@i[directive][@i[word]]>. If the
+previous word is already enclosed by a use of the same command, then the
+beginning of the command is extended backward by one word.
+@end[description]
+
+Typing @bf[Home] or @bf[C-_] to this command's prompt will display a list of
+all the defined key-events on which it dispatches.
+@enddefcom
+
+@defcom[com "Add Scribe Directive"]
+This command adds to the database of directives recognized by the
+@hid[Insert Scribe Directive] command. It prompts for the directive's name,
+the kind of directive (environment or command) and the key-event on which to
+dispatch.
+@enddefcom
+
+@defcom[com "Add Scribe Paragraph Delimiter"]
+@defcom1[com "List Scribe Paragraph Delimiters"]
+@hid[Add Scribe Paragraph Delimiter] prompts for a string to add to the list of
+formatting commands that delimit paragraphs in @hid[Scribe] mode. If the user
+supplies a prefix argument, then this command removes the string as a
+delimiter.
+
+@hid[List Scribe Paragraph Delimiters] displays in a pop-up window the Scribe
+commands that delimit paragraphs.
+@enddefcom
+
+@defhvar[var "Escape Character", val {#\@@}]
+@defhvar1[var "Close Paren Character", val {#\]}]
+@defhvar1[var "Open Paren Character", val {#\[}]
+These variables determine the characters used when a Scribe directive is
+inserted.
+@enddefhvar
+
+@defcom[com "Scribe Insert Bracket"]
+@defhvar1[var "Scribe Bracket Table"]
+@hid[Scribe Insert Bracket] inserts a bracket (@bf[>], @bf[}], @bf[)], or
+@bf<]>), that caused its invocation, and then shows the matching bracket.
+
+@hid[Scribe Bracket Table] holds a @f[simple-vector] indexed by character
+codes. If a character is a bracket, then the entry for its @f[char-code]
+should be the opposite bracket. If a character is not a bracket, then the
+entry should be @nil.
+@enddefcom
+
+
+@section[Spelling Correction]
+@index[spelling correction]
+@hemlock has a spelling correction facility based on the dictionary for the ITS
+spell program. This dictionary is fairly small, having only 45,000 word or so,
+which means it fits on your disk, but it also means that many reasonably common
+words are not in the dictionary. A correct spelling for a misspelled word will
+be found if the word is in the dictionary and is only erroneous in that it has
+a wrong character, a missing character, an extra character or a transposition
+of two characters.
+
+
+@defcom[com "Check Word Spelling", bind (M-$)]
+This command looks up the previous or current word in the dictionary and
+attempts to correct the spelling if it is misspelled. There are four possible
+results of invoking this command:
+@begin[enumerate]
+This command displays the message "@f[Found it.]" in the echo area. This means
+it found the word in the dictionary exactly as given.
+
+This command displays the message "@f[Found it because of @i[word].]", where
+@i[word] is some other word with the same root but a different ending. The
+word is no less correct than if the first message is given, but an additional
+piece of useless information is supplied to make you feel like you are using a
+computer.
+
+The command prompts with "@f[Correction choice:]" in the echo area and lists
+possible correct spellings associated with numbers in a pop-up display. Typing
+a number selects the corresponding correction, and the command replaces the
+erroneous word, preserving case as though by @hid[Query Replace]. Typing
+anything else rejects all the choices.
+
+This commands displays the message "@f[Word not found.]". The word is not in
+the dictionary and possibly spelled correctly anyway. Furthermore, no
+similarly spelled words were found to offer as possible corrections. If this
+happens, it is worth trying some alternate spellings since one of them might
+be close enough to some known words that this command could display.
+@end[enumerate]
+@enddefcom
+
+@defcom[com "Correct Buffer Spelling"]
+This command scans the entire buffer looking for misspelled words and offers to
+correct them. It creates a window into the @hid[Spell Corrections] buffer, and
+in this buffer it maintains a log of any actions taken by the user. When this
+finds an unknown word, it prompts for a key-event. The user has the following
+options:
+@begin[description]
+@bf[a]@\
+ Ignore this word. If the command finds the word again, it will prompt again.
+
+@bf[i]@\
+ Insert this word in the dictionary.
+
+@bf[c]@\
+ Choose one of the corrections displayed in the @hid[Spell Corrections] window
+by specifying the correction number. If the same misspelling is encountered
+again, then the command will make the same correction automatically, leaving a
+note in the log window.
+
+@bf[r]@\
+ Prompt for a word to use instead of the misspelled one, remembering the
+correction as with @bf[c].
+
+@binding[C-r]@\
+ Go into a recursive edit at the current position, and resume checking when the
+recursive edit is exited.
+@end[description]
+After this command completes, it deletes the log window leaving the buffer
+around for future reference.
+@enddefcom
+
+@defhvar[var "Spell Ignore Uppercase", val {nil}]
+@index[case sensitivity]
+If this variable is true, then @hid[Auto Check Word Spelling] and @hid[Correct
+Buffer Spelling] will ignore unknown words that are all uppercase. This is
+useful for acronyms and cryptic formatter directives.
+@enddefhvar
+
+@defcom[com "Add Word to Spelling Dictionary", bind (C-x $)]
+This command adds the previous or current word to the spelling dictionary.
+@enddefcom
+
+@defcom[com "Remove Word from Spelling Dictionary"]
+This command prompts for a word to remove from the spelling dictionary. Due to
+the dictionary representation, removal of a word in the initial spelling
+dictionary will remove all words with the same root. The user is asked for
+confirmation before removing a root word with valid suffix flags.
+@enddefcom
+
+@defcom[com "List Incremental Spelling Insertions"]
+This command displays the incremental spelling insertions for the current
+buffer's associated spelling dictionary file.
+@enddefcom
+
+@defcom[com "Read Spelling Dictionary"]
+This command adds some words from a file to the spelling dictionary. The
+format of the file is a list of words, one on each line.
+@enddefcom
+
+@defcom[com "Save Incremental Spelling Insertions"]
+This command appends incremental dictionary insertions to a file. Any words
+added to the dictionary since the last time this was done will be appended to
+the file. Except for @hid[Augment Spelling Dictionary], all the commands that
+add words to the dictionary put their insertions in this list. The file is
+prompted for unless @hid[Set Buffer Spelling Dictionary] has been executed in
+the buffer.
+@enddefcom
+
+@defcom[com "Set Buffer Spelling Dictionary"]
+This command Prompts for the dictionary file to associate with the current
+buffer. If the specified dictionary file has not been read for any other
+buffer, then it is read. Incremental spelling insertions from this buffer
+can be appended to this file with @hid[Save Incremental Spelling
+Insertions]. If a buffer has an associated spelling dictionary, then
+saving the buffer's associated file also saves any incremental dictionary
+insertions. The @w<"@f[Dictionary: ]@i[file]"> file option may also be
+used to specify the dictionary for a buffer (see section
+@ref[file-options]).
+@enddefcom
+
+@defhvar[var "Default User Spelling Dictionary", val {nil}]
+This variable holds the pathname of a dictionary to read the first time
+@hid[Spell] mode is entered in a given editing session. When
+@hid[Set Buffer Spelling Dictionary] or the "@f[dictionary]" file option is
+used to specify a dictionary, this default one is read also. It defaults to
+nil.
+@enddefhvar
+
+
+@subsection[Auto Spell Mode]
+@hid[Auto Spell Mode] checks the spelling of each word as it is typed.
+When an unknown word is typed the user is notified and allowed to take a
+number of actions to correct the word.
+
+@defcom[com "Auto Spell Mode"]
+This command turns @hid[Spell] mode on or off in the current buffer.
+@enddefcom
+
+@defcom[com "Auto Check Word Spelling",
+ stuff (bound to word delimiters in @hid[Spell] mode)]
+@defhvar1[var "Check Word Spelling Beep", val {t}]
+@defhvar1[var "Correct Unique Spelling Immediately", val {t}]
+This command checks the spelling of the word before the point, doing nothing if
+the word is in the dictionary. If the word is misspelled but has a known
+correction previously supplied by the user, then this command corrects the
+spelling. If there is no correction, then this displays a message in the echo
+area indicating the word is unknown. An unknown word detected by this command
+may be corrected using the @hid[Correct Last Misspelled Word] command. This
+command executes in addition to others bound to the same key; for example, if
+@hid[Fill] mode is on, any of its commands bound to the same keys as this
+command also run.
+
+If @hid[Check Word Spelling Beep] is true, then this command will beep when an
+unknown word is found. If @hid[Correct Unique Spelling Immediately] is true,
+then this command will immediately attempt to correct any unknown word,
+automatically making the correction if there is only one possible.
+@enddefhvar
+
+@defcom[com "Undo Last Spelling Correction", bind (C-x a)]
+@defhvar1[var "Spelling Un-Correct Prompt for Insert", val {nil}]
+@hid[Undo Last Spelling Correction] undoes the last incremental spelling
+correction. The "correction" is replaced with the old word, and the old word
+is inserted in the dictionary. Any automatic replacement for the old word is
+eliminated. When @hid[Spelling Un-Correct Prompt for Insert] is true, the user
+is asked to confirm the insertion into the dictionary.
+@enddefcom
+
+@defcom[com "Correct Last Misspelled Word", bind (M-:)]
+This command places the cursor after the last misspelled word detected by the
+@hid[Auto Check Word Spelling] command and then prompts for a key-event on
+which it dispatches:
+@begin[description]
+@bf[c]@\
+ Display possible corrections in a pop-up window, and prompt for the one to
+make according to the corresponding displayed digit or letter.
+
+@i[any digit]@\
+ Similar to @bf[c] @i[digit], but immediately makes the correction, dispensing
+with display of the possible corrections. This is shorter, but only works when
+there are less than ten corrections.
+
+@bf[i]@\
+ Insert the word in the dictionary.
+
+@bf[r]@\
+ Replace the word with another.
+
+@binding[Backspace, Delete, n]@\
+ Skip this word and try again on the next most recently misspelled word.
+
+@binding[C-r]@\
+ Enter a recursive edit at the word, exiting the command when the recursive
+edit is exited.
+
+@binding[Escape]@\
+ Exit and forget about this word.
+@end[description]
+As in @hid[Correct Buffer Spelling], the @bf[c] and @bf[r] commands add the
+correction to the known corrections.
+@enddefcom
+
+
+
+@chap[Managing Large Systems]
+
+@hemlock provides three tools which help to manage large systems:
+@begin[enumerate]
+File groups, which provide several commands that operate on all the files
+in a possibly large collection, instead of merely on a single buffer.
+
+A source comparison facility with semi-automatic merging, which can be used
+to compare and merge divergent versions of a source file.
+
+A change log facility, which maintains a single file containing a record of the
+edits done on a system.
+@end[enumerate]
+
+
+@section[File Groups]
+
+@index[file groups]@index[searching, group]@index[replacing, group]
+A file group is a set of files, upon which various editing operations can be
+performed. The files in a group are specified by a file in the following
+format:
+@begin[itemize]
+Any line which begins with one "@f[@@]" is ignored.
+
+Any line which does not begin with an "@f[@@]" is the name of a file in the
+group.
+
+A line which begins with "@f[@@@@]" specifies another file having this
+syntax, which is recursively examined to find more files in the group.
+@end[itemize]
+This syntax is used for historical reasons. Although any number of file groups
+may be read into @hemlock, there is only one @i[active group], which is the
+file group implicitly used by all of the file group commands.
+Page @pageref[compile-group-command] describes the @hid[Compile Group] command.
+
+@defcom[com "Select Group"]
+This command prompts for the name of a file group to make the active group.
+If the name entered is not the name of a group whose definition has been
+read, then the user is prompted for the name of a file to read the group
+definition from. The name of the default pathname is the name of the
+group, and the type is "@f[upd]".
+@enddefcom
+
+@defcom[com "Group Query Replace"]
+This command prompts for target and replacement strings and then executes an
+interactive string replace on each file in the active group. This reads in
+each file as if @hid[Find File] were used and processes it as if @hid[Query
+Replace] were executing.
+@enddefcom
+
+@defcom[com "Group Replace"]
+This is like @hid[Group Query Replace] except that it executes a
+non-interactive replacement, similar to @hid[Replace String].
+@enddefcom
+
+@defcom[com "Group Search"]
+This command prompts for a string and then searches for it in each file in the
+active group. This reads in each file as if @hid[Find File] were used. When
+it finds an occurrence, it prompts the user for a key-event indicating what
+action to take. The following commands are defined:
+@begin[description]
+@binding[Escape, Space, y]@\
+ Exit @hid[Group Search].
+
+@binding[Delete, Backspace, n]@\
+ Continue searching for the next occurrence of the string.
+
+@binding[!]@\
+ Continue the search at the beginning of the next file, skipping the remainder
+of the current file.
+
+@binding[C-r]@\
+ Go into a recursive edit at the current location, and continue the search when
+it is exited.
+@end[description]
+@enddefcom
+
+@defhvar[var "Group Find File", val {nil}]
+The group searching and replacing commands read each file into its own buffer
+using @hid[Find File]. Since this may result in large amounts of memory being
+consumed by unwanted buffers, this variable controls whether to delete the
+buffer after processing it. When this variable is false, the default, the
+commands delete the buffer if it did not previously exist; however, regardless
+of this variable, if the user leaves the buffer modified, the commands will not
+delete it.
+@enddefhvar
+
+@defhvar[var "Group Save File Confirm", val {t}]
+If this variable is true, the group searching and replacing commands ask for
+confirmation before saving any modified file. The commands attempt to save
+each file processed before going on to the next one in the group.
+@enddefhvar
+
+
+@section[Source Comparison]
+@index[buffer, merging]
+@index[buffer, comparison]
+@index[source comparison]
+
+These commands can be used to find exactly how the text in two buffers differs,
+and to generate a new version that combines features of both versions.
+
+@defhvar[var "Source Compare Default Destination", val {"Differences"}]
+This is a sticky default buffer name to offer when comparison commands prompt
+for a buffer in which to insert the results.
+@enddefhvar
+
+@defcom[com "Compare Buffers"]
+This command prompts for three buffers and then does a buffer comparison.
+The first two buffers must exist, as they are the buffers to be compared.
+The last buffer, which is created if it does not exist, is the buffer to
+which output is directed. The output buffer is selected during the
+comparison so that its progress can be monitored. There are various variables
+that control exactly how the comparison is done.
+
+If a prefix argument is specified, then only only the lines in the the regions
+of the two buffers are compared.
+@enddefcom
+
+@defcom[com "Buffer Changes"]
+This command compares the contents of the current buffer with the disk version
+of the associated file. It reads the file into the buffer
+@hid[Buffer Changes File], and generates the comparison in the buffer
+@hid[Buffer Changes Result]. As with @hid[Compare Buffers], the output buffer
+is displayed in the current window.
+@enddefcom
+
+@defcom[com "Merge Buffers"]
+This command functions in a very similar fashion to @hid[Compare Buffers], the
+difference being that a version which is a combination of the two buffers being
+compared is generated in the output buffer. This copies text that is identical
+in the two comparison buffers to the output buffer. When it encounters a
+difference, it displays the two differing sections in the output buffer and
+prompts the user for a key-event indicating what action to take. The following
+commands are defined:
+@begin[description]
+@bf[1]@\
+ Use the first version of the text.
+
+@bf[2]@\
+ Use the second version.
+
+@bf[b]@\
+ Insert the string @w<"@f[**** MERGE LOSSAGE ****]"> followed by both versions.
+This is useful if the differing sections are too complex, or it is unclear
+which is the correct version. If you cannot make the decision conveniently at
+this point, you can later search for the marking string above.
+
+@binding[C-r]@\
+ Do a recursive edit and ask again when the edit is exited.
+@end[description]
+@enddefcom
+
+
+@defhvar[var "Source Compare Ignore Case", val {nil}]
+@index[case sensitivity]
+If this variable is non-@nil, @hid[Compare Buffers] and @hid[Merge Buffers]
+will do comparisons case-insensitively.
+@enddefhvar
+
+@defhvar[var "Source Compare Ignore Indentation", val {nil}]
+If this variable is non-@nil, @hid[Compare Buffers] and @hid[Merge Buffers]
+ignore initial whitespace when comparing lines.
+@enddefhvar
+
+@defhvar[var "Source Compare Ignore Extra Newlines", val {t}]
+If this variable is true, @hid[Compare Buffers] and @hid[Merge Buffers]
+will treat all groups of newlines as if they were a single newline.
+@enddefhvar
+
+@defhvar[var "Source Compare Number of Lines", val {3}]
+This variable controls the number of lines @hid[Compare Buffers] and
+@hid[Merge Buffers] will compare when resynchronizing after a difference
+has been encountered.
+@enddefhvar
+
+
+@section[Change Logs]
+@label[log-files]
+@index[edit history]
+@index[change log]
+
+The @hemlock change log facility encourages the recording of changes to a
+system by making it easy to do so. The change log is kept in a separate file
+so that it doesn't clutter up the source code. The name of the log for a file
+is specified by the @f[Log] file option (see page @pageref[file-options].)
+
+@defcom[com "Log Change"]
+@defhvar1[var "Log Entry Template"]
+@hid[Log Change] makes a new entry in the change log associated with the file.
+Any changes in the current buffer are saved, and the associated log file is
+read into its own buffer. The name of the log file is determined by merging
+the name specified in the @f[Log] option with the current buffer's file name,
+so it is not usually necessary to put the full name there. After inserting a
+template for the log entry at the beginning of the buffer, the command enters a
+recursive edit (see page @pageref[recursive-edits]) so that the text of the
+entry may be filled in. When the user exits the recursive edit, the log file
+is saved.
+
+The variable @hid[Log Entry Template] determines the format of the change log
+entry. Its value is a @clisp @f[format] control string. The format string is
+passed three string arguments: the full name of the file, the creation date for
+the file and the name of the file author. If the creation date is not
+available, the current date is used. If the author is not available then @nil
+is passed. If there is an @f[@@] in the template, then it is deleted and the
+point is left at that position.
+@enddefcom
+
+
+
+@comment[@chap (Special Modes)]
+@include(special-modes)
+
+
+
+@chap[Editing Programs]
+
+
+@section[Comment Manipulation]
+@index[comment manipulation]
+@hemlock has commenting commands which can be used in almost any language. The
+behavior of these commands is determined by several @hemlock variables which
+language modes should define appropriately.
+
+@defcom[com "Indent for Comment", bind (M-;)]
+@index[indentation, comment]@label[comment-indentation]
+This is the most basic commenting command. If there is already a comment on
+the current line, then this moves the point to the start of the comment. If
+there no comment, this creates an empty one.
+
+This command normally indents the comment to start at @hid[Comment Column].
+The comment indents differently in the following cases:
+@begin[enumerate]
+If the comment currently starts at the beginning of the line, or if the last
+character in the @hid[Comment Start] appears three times, then the comment
+remains unmoved.
+
+If the last character in the @hid[Comment Start] appears two times, then the
+comment is indented like a line of code.
+
+If text on the line prevents the comment occurring in the desired position,
+this places the comment at the end of the line, separated from the text by a
+space.
+@end[enumerate]
+Although the rules about replication in the comment start are oriented toward
+Lisp commenting styles, you can exploit these properties in other languages.
+
+When given a prefix argument, this command indents any existing comment on that
+many consecutive lines. This is useful for fixing up the indentation of a
+group of comments.
+@enddefcom
+
+@defcom[com "Indent New Comment Line", bind {M-j, M-Linefeed}]
+This commend ends the current comment and starts a new comment on a blank line,
+indenting the comment the same way that @hid[Indent for Comment] does.
+When not in a comment, this command is the same as @hid[Indent New Line].
+@enddefcom
+
+@defcom[com "Up Comment Line", bind {M-p}]
+@defcom1[com "Down Comment Line", bind {M-n}]
+These commands are similar to @hid[Previous Line] or @hid[Next Line]
+followed by @hid[Indent for Comment]. Any empty comment on the current line is
+deleted before moving to the new line.
+@enddefcom
+
+@defcom[com "Kill Comment", bind (C-M-;)]
+This command kills any comment on the current line. When given a prefix
+argument, it kills comments on that many consecutive lines. @hid[Undo] will
+restore the unmodified text.
+@enddefcom
+
+@defcom[com "Set Comment Column", bind (C-x ;)]
+This command sets the comment column to its prefix argument. If used without a
+prefix argument, it sets the comment column to the column the point is at.
+@enddefcom
+
+@defhvar[var "Comment Start", val {nil}]
+@defhvar1[var "Comment End", val {nil}]
+@defhvar1[var "Comment Begin", val {nil}]
+@defhvar1[var "Comment Column", val {0}]
+These variables determine the behavior of the comment commands.
+@begin[description]
+@hid[Comment Start]@\The string which indicates the start of a comment. If
+this is @nil, then there is no defined comment syntax.
+
+@hid[Comment End]@\The string which ends a comment. If this is @nil, then
+the comment is terminated by the end of the line.
+
+@hid[Comment Begin]@\The string inserted to begin a new comment.
+
+@hid[Comment Column]@\The column that normal comments start at.
+@end[description]
+@enddefcom
+
+
+@section[Indentation]
+@label[indentation]
+@index[indentation]
+Nearly all programming languages have conventions for indentation or leading
+whitespace at the beginning of lines. The @hemlock indentation facility is
+integrated into the command set so that it interacts well with other features
+such as filling and commenting.
+
+@defcom[com "Indent", bind (Tab, C-i)]
+This command indents the current line. With a prefix argument, indents that
+many lines and moves down. Exactly what constitutes indentation depends on the
+current mode (see @hid[Indent Function]).
+@enddefcom
+
+@defcom[com "Indent New Line", bind (Linefeed)]
+This command starts a new indented line. Deletes any whitespace before the
+point and inserts indentation on a blank line. The effect of this is similar
+to @binding[Return] followed by @binding[Tab]. The prefix argument is passed
+to @hid[New Line], which is used to insert the blank line.
+@enddefcom
+
+@defcom[com "Indent Region", bind (C-M-\)]
+This command indents every line in the region. It may be undone with
+@hid[Undo].
+@enddefcom
+
+@defcom[com "Back to Indentation", bind {M-m, C-M-m}]
+@index[motion, indentation]
+This command moves point to the first non-whitespace character on the current
+line.
+@enddefcom
+
+@defcom[com "Delete Indentation", bind (M-^, C-M-^)]
+@hid[Delete Indentation] joins the current line with the previous one, deleting
+excess whitespace. This operation is the inverse of the @bf[Linefeed] command
+in most modes. Usually this leaves one space between the two joined lines, but
+there are several exceptions.
+
+The non-whitespace immediately surrounding the deleted line break determine the
+amount of space inserted.
+@begin[enumerate]
+If the preceding character is an "@f[(]" or the following character is a
+"@f[)]", then this inserts no space.
+
+If the preceding character is a newline, then this inserts no space. This will
+happen if the previous line was blank.
+
+If the preceding character is a sentence terminator, then this inserts two
+spaces.
+@end[enumerate]
+
+When given a prefix argument, this command joins the current and next lines,
+rather than the previous and current lines.
+@enddefcom
+
+@defcom[com "Quote Tab", bind (M-Tab)]
+This command inserts a tab character.
+@enddefcom
+
+@defcom[com "Indent Rigidly", bind (C-x Tab, C-x C-i)]
+This command changes the indentation of all the lines in the region. Each
+line is moved to the right by the number of spaces specified by the prefix
+argument, which defaults to eight. A negative prefix argument moves lines
+left.
+@enddefcom
+
+@defcom[com "Center Line"]
+This indents the current line so that it is centered between the left margin
+and @hvarref[Fill Column]. If a prefix argument is supplied, then it is used
+as the width instead of @hid[Fill Column].
+@enddefcom
+
+@defhvar[var "Indent Function", val {tab-to-tab-stop}]
+The value of this variable determines how indentation is done, and it is a
+function which is passed a mark as its argument. The function should indent
+the line which the mark points to. The function may move the mark around on
+the line. The mark will be @f[:left-inserting]. The default simply inserts a
+tab character at the mark.
+@enddefhvar
+
+@defhvar[var "Indent with Tabs", val {indent-using-tabs}]
+@defhvar1[var "Spaces per Tab", val {8}]
+@hid[Indent with Tabs] holds a function that takes a mark and a number of
+spaces. The function will insert a maximum number of tabs and a minimum number
+of spaces at mark to move the specified number of columns. The default
+definition uses @hid[Spaces per Tab] to determine the size of a tab. @i[Note,]
+@hid[Spaces per Tab] @i[is not used everywhere in @hemlock yet, so changing
+this variable could have unexpected results.]
+@enddefhvar
+
+
+@section[Language Modes]
+
+@hemlock@comment{}'s language modes are currently fairly crude, but probably
+provide better programming support than most non-extensible editors.
+
+@defcom[com "Pascal Mode"]
+@index[indentation, pascal]@index[modes, pascal]This command sets the current
+buffer's major mode to @hid[Pascal]. @hid[Pascal] mode borrows parenthesis
+matching from Scribe mode and indents lines under the previous line.
+@enddefcom
+
+
+@chap[Editing Lisp]
+@index[lisp, editing]
+@hemlock provides a large number of powerful commands for editing Lisp code.
+It is possible for a text editor to provide a much higher level of support for
+editing Lisp than ordinary programming languages, since its syntax is much
+simpler.
+
+
+@section[Lisp Mode]
+@index[lisp mode]
+@index[modes, lisp]
+@hid[Lisp] mode is a major mode used for editing Lisp code. Although most
+Lisp specific commands are globally bound, @hid[Lisp] mode is necessary to
+enable Lisp indentation, commenting, and parenthesis-matching. Whenever the
+user or some @hemlock mechanism turns on @hid[Lisp] mode, the mode's setup
+includes locally setting @hid[Current Package] (see section @ref[lisp-package])
+in that buffer if its value is non-existent there; the value used is
+@f["USER"].
+
+@defcom[com "Lisp Mode"]
+This command sets the major mode of the current buffer to @hid[Lisp].
+@enddefcom
+
+
+@section[Form Manipulation]
+@index[form manipulation]
+These commands manipulate Lisp forms, the printed representations of Lisp
+objects. A form is either an expression balanced with respect to parentheses
+or an atom such as a symbol or string.
+
+@defcom[com "Forward Form", bind (C-M-f)]
+@defcom1[com "Backward Form", bind (C-M-b)]
+@index[motion, form]@hid[Forward Form] moves to the end of the current or
+next form, while @hid[Backward Form] moves to the beginning of the current
+or previous form. A prefix argument is treated as a repeat count.
+@enddefcom
+
+@defcom[com "Forward Kill Form", bind (C-M-k)]
+@defcom1[com "Backward Kill Form", bind (C-M-Delete, C-M-Backspace)]
+@index[killing, form]@hid[Forward Kill Form] kills text from the point to
+the end of the current form. If at the end of a list, but inside the close
+parenthesis, then kill the close parenthesis. @hid[Backward Kill Form] is
+the same, except it goes in the other direction. A prefix argument is
+treated as a repeat count.
+@enddefcom
+
+@defcom[com "Mark Form", bind (C-M-@@)]
+This command sets the mark at the end of the current or next form.
+@enddefcom
+
+@defcom[com "Transpose Forms", bind (C-M-t)]
+This command transposes the forms before and after the point and moves
+forward. A prefix argument is treated as a repeat count. If the prefix
+argument is negative, then the point is moved backward after the
+transposition is done, reversing the effect of the equivalent positive
+argument.
+@enddefcom
+
+@defcom[com "Insert ()", bind {M-(}]
+This command inserts an open and a close parenthesis, leaving the point
+inside the open parenthesis. If a prefix argument is supplied, then the
+close parenthesis is put at the end of the form that many forms from the
+point.
+@enddefcom
+
+@defcom[com "Extract Form"]
+This command replaces the current containing list with the next form. The
+entire affected area is pushed onto the kill ring. If an argument is supplied,
+that many upward levels of list nesting is replaced by the next form. This is
+similar to @hid[Extract List], but this command is more generally useful since
+it works on any kind of form; it is also more intuitive since it operates on
+the next form as many @hid[Lisp] mode commands do.
+@enddefcom
+
+
+@section[List Manipulation]
+
+@index[list manipulation]List commands are similar to form commands, but
+they only pay attention to lists, ignoring any atomic objects that may
+appear. These commands are useful because they can skip over many symbols
+and move up and down in the list structure.
+
+@defcom[com "Forward List", bind (C-M-n)]
+@defcom1[com "Backward List", bind (C-M-p)]
+@index[motion, list]@hid[Forward List] moves the point to immediately
+after the end of the next list at the current level of list structure. If
+there is not another list at the current level, then it moves up past
+the end of the containing list.
+@hid[Backward List] is identical, except that it moves backward and leaves
+the point at the beginning of the list. The prefix argument is used as a
+repeat count.
+@enddefcom
+
+@defcom[com "Forward Up List", bind {C-M-@bf<)>}]
+@defcom1[com "Backward Up List", bind (C-M-@bf<(>, C-M-u)]
+@hid[Forward Up List] moves to after the end of the enclosing list.
+@hid[Backward Up List] moves to the beginning. The prefix argument is used
+as a repeat count.
+@enddefcom
+
+@defcom[com "Down List", bind (C-M-d)]
+This command moves to just after the beginning of the next list. The
+prefix argument is used as a repeat count.
+@enddefcom
+
+@defcom[com "Extract List", bind (C-M-x)]
+This command "extracts" the current list from the list which contains it.
+The outer list is deleted, leaving behind the current list. The entire
+affected area is pushed on the kill ring, so that this possibly catastrophic
+operation can be undone. The prefix argument is used as a repeat count.
+@enddefcom
+
+
+
+@section[Defun Manipulation]
+
+@index[defun manipulation]A @i[defun] is a list whose open parenthesis is
+against the left margin. It is called this because an occurrence of the
+@f[defun] top level form usually satisfies this definition, but
+other top level forms such as a @f[defstruct] and @f[defmacro] work just as
+well.
+
+@defcom[com "End of Defun", bind (@bf)]
+@defcom1[com "Beginning of Defun", bind (C-M-a, C-M-[)]
+@index[motion, defun]@hid[End of Defun] moves to the end of the current
+or next defun. @hid[Beginning of Defun] moves to the beginning of the
+current or previous defun. @hid[End of Defun] will not work if the
+parentheses are not balanced.
+@enddefcom
+
+@defcom[com "Mark Defun", bind (C-M-h)]
+This command puts the point at the beginning and the mark at the end of the
+current or next defun.
+@enddefcom
+
+
+
+@section[Indentation]
+
+@index[indentation, lisp]
+One of the most important features provided by @hid[Lisp] mode is automatic
+indentation of Lisp code. Since unindented Lisp is unreadable, poorly indented
+Lisp is hard to manage, and inconsistently indented Lisp is subtly misleading.
+See section @ref[indentation] for a description of the general-purpose
+indentation commands. @hid[Lisp] mode uses these indentation rules:
+@begin[itemize]
+If in a semicolon (@f[;]) comment, then use the standard comment indentation
+rules. See page @pageref[comment-indentation].
+
+If in a quoted string, then indent to the column one greater than the column
+containing the opening double quote. This is exactly what you want in function
+documentation strings and wrapping @f[error] strings.
+
+If there is no enclosing list, then use no indentation.
+
+If enclosing list resembles a call to a known macro or special-form, then the
+first few arguments are given greater indentation and the first body form is
+indented two spaces. If the first special argument is on the same line as the
+beginning of the form, then following special arguments will be indented to the
+start of the first special argument, otherwise all special arguments are
+indented four spaces.
+
+If the previous form starts on its own line, then the indentation is copied
+from that form. This rule allows the default indentation to be overridden:
+once a form has been manually indented to the user's satisfaction, subsequent
+forms will be indented in the same way.
+
+If the enclosing list has some arguments on the same line as the form start,
+then subsequent arguments will be indented to the start of the first argument.
+
+If the enclosing list has no argument on the same line as the form start, then
+arguments will be indented one space.
+@end[itemize]
+
+
+@defcom[com "Indent Form", bind (C-M-q)]
+This command indents all the lines in the current form, leaving the point
+unmoved. This is undo-able.
+@enddefcom
+
+@defcom[com "Fill Lisp Comment Paragraph",
+ stuff ]
+@defhvar1[var "Fill Lisp Comment Paragraph Confirm", val {t}]
+This fills a flushleft or indented Lisp comment. This also fills Lisp string
+literals using the proper indentation as a filling prefix. When invoked
+outside of a comment or string, this tries to fill all contiguous lines
+beginning with the same initial, non-empty blankspace. When filling a comment,
+the current line is used to determine a fill prefix by taking all the initial
+whitespace on the line, the semicolons, and any whitespace following the
+semicolons.
+
+When invoked outside of a comment or string, this command prompts for
+confirmation before filling. It is useful to use this for filling long
+@f[export] lists or other indented text or symbols, but since this is a less
+common use, this command tries to make sure that is what you wanted. Setting
+@hid[Fill Lisp Comment Paragraph Confirm] to @nil inhibits the confirmation
+prompt.
+@enddefcom
+
+@defcom[com "Defindent", bind (C-M-#)]
+This command prompts for the number of special arguments to associate with
+the symbol at the beginning of the current or containing list.
+@enddefcom
+
+@defhvar[var "Indent Defanything", val {2}]
+This is the number of special arguments implicitly assumed to be supplied in
+calls to functions whose names begin with "@f[def]". If set to @nil, this
+feature is disabled.
+@enddefhvar
+
+@defcom[com "Move Over )", bind {M-)}]
+This command moves past the next close parenthesis and then does the equivalent
+of @hid[Indent New Line].
+@enddefcom
+
+
+@section[Parenthesis Matching]
+
+@index[parenthesis matching]Another very important facility provided by
+@hid[Lisp] mode is @i[parenthesis matching]. Two different styles of
+parenthesis matching are supported: highlighting and pausing.
+
+@defhvar[var "Highlight Open Parens", val {t}]
+@defhvar1[var "Open Paren Highlighting Font", val {nil}]
+When @hid[Highlight Open Parens] is true, and a close paren is immediately
+before the point, then @hemlock displays the matching open paren in @hid[Open
+Paren Highlighting Font].
+
+@hid[Open Paren Highlighting Font] is the string name of the font used for
+paren highlighting. Only the "@f[(]" character is used in this font. If null,
+then a reasonable default is chosen. The highlighting font is read at
+initialization time, so this variable must be set before the editor is first
+entered to have any effect.
+@enddefhvar
+
+@defcom[com "Lisp Insert )", stuff ]
+@defhvar1[var "Paren Pause Period", val {0.5}]
+This command inserts a close parenthesis and then attempts to display the
+matching open parenthesis by placing the cursor on top of it for
+@hid[Paren Pause Period] seconds. If there is no matching parenthesis then
+beep. If the matching parenthesis is off the top of the screen, then the line
+on which it appears is displayed in the echo area. Paren pausing may be
+disabled by setting @hid[Paren Pause Period] to @nil.
+@enddefcom
+
+The initial values shown for @hid[Highlight Open Parens] and @hid[Paren Pause
+Period] are only approximately correct. Since paren highlighting is only
+meaningful in Lisp mode, @hid[Highlight Open Parens] is false globally, and
+has a mode-local value of @true in Lisp mode. It it redundant to do both
+kinds of paren matching, so there is also a binding of @hid[Paren Pause Period]
+to @false in Lisp mode.
+
+Paren highlighting is only supported under @windows, so the above defaults are
+conditional on the device type. If @hemlock is started on a terminal, the
+initialization code makes Lisp mode bindings of @false and @f[0.5] for
+@hid[Highlight Open Parens] and @hid[Paren Pause Period]. Since these
+alternate default bindings are made at initialization time, the only way to
+affect them is to use the @f[after-editor-initializations] macro.
+
+
+@section[Parsing Lisp]
+Lisp mode has a fairly complete knowledge of Lisp syntax, but since it does
+not use the reader, and must work incrementally, it can be confused by legal
+constructs. Lisp mode totally ignores the read-table, so user-defined read
+macros have no effect on the editor. In some cases, the values the @hid[Lisp
+Syntax] character attribute can be changed to get a similar effect.
+
+Lisp commands consistently treat semicolon (@f[;]) style comments as
+whitespace when parsing, so a Lisp command used in a comment will affect the
+next (or previous) form outside of the comment. Since @f[#| ... |#] comments
+are not recognized, they can used to comment out code, while still allowing
+Lisp editing commands to be used.
+
+Strings are parsed similarly to symbols. When within a string, the next form
+is after the end of the string, and the previous form is the beginning of the
+string.
+
+
+@defhvar[var "Defun Parse Goal", val {2}]
+@defhvar1[var "Maximum Lines Parsed", val {500}]
+@defhvar1[var "Minimum Lines Parsed", val {50}]
+In order to save time, Lisp mode does not parse the entire buffer every time
+a Lisp command is used. Instead, it uses a heuristic to guess the region of
+the buffer that is likely to be interesting. These variables control the
+heuristic.
+
+Normally, parsing begins and ends on defun boundaries (an open parenthesis at
+the beginning of a line). @hid[Defun Parse Goal] specifies the number of
+defuns before and after the point to parse. If this parses fewer lines than
+@hid[Minimum Lines Parsed], then parsing continues until this lower limit is
+reached. If we cannot find enough defuns within @hid[Maximum Lines Parsed]
+lines then we stop on the farthest defun found, or at the point where we
+stopped if no defuns were found.
+
+When the heuristic fails, and does not parse enough of the buffer, then
+commands usually act as though a syntax error was detected. If the parse
+starts in a bad place (such as in the middle of a string), then Lisp commands
+will be totally confused. Such problems can usually be eliminated by
+increasing the values of some of these variables.
+@enddefhvar
+
+@defhvar[var "Parse Start Function", val {start-of-parse-block}]
+@defhvar1[var "Parse End Function", val {end-of-parse-block}]
+These variables determine the region of the buffer parsed. The values are
+functions that take a mark and move it to the start or end of the parse region.
+The default values implement the heuristic described above.
+@enddefhvar
+
+
+
+@comment[@chap(Interacting With Lisp)]
+@include(lisp)
+
+
+@comment[@chap(Mail Interface)]
+@include(mail)
+
+
+@comment[@chap(Netnews Interface)]
+@include(netnews)
+
+
+
+@chap[System Interface]
+
+@hemlock provides a number of commands that access operating system resources
+such as the filesystem and print servers. These commands offer an alternative
+to leaving the editor and using the normal operating system command language
+(such as the Unix shell), but they are implementation dependent. Therefore,
+they might not even exist in some implementations.
+
+
+@section[File Utility Commands]
+This section describes some general file operation commands and quick directory
+commands.
+
+See section @ref[dired] for a description @hemlock's directory editing
+mechanism, @hid[Dired] mode.
+
+@defcom[com "Copy File"]
+This command copies a file, allowing one wildcard in the filename. It prompts
+for source and destination specifications.
+
+If these are both directories, then the copying process is recursive on the
+source, and if the destination is in the subdirectory structure of the source,
+the recursion excludes this portion of the directory tree. Use
+@f[dir-spec-1/*] to copy only the files in a source directory without
+recursively descending into subdirectories.
+
+If the destination specification is a directory, and the source is a file, then
+it is copied into the destination with the same filename.
+
+The copying process copies files maintaining the source's write date.
+
+See the description of @hid[Dired Copy File Confirm], page
+@pageref[copy-confirm], for controlling user interaction when the destination
+exists.
+@enddefcom
+
+@defcom[com "Rename File"]
+This command renames a file, allowing one wildcard in the filename. It prompts
+for source and destination specifications.
+
+If the destination is a directory, then the renaming process moves file(s)
+indicated by the source into the directory with their original filenames.
+
+For Unix-based implementations, if you want to rename a directory, do not
+specify the trailing slash in the source specification.
+@enddefcom
+
+@defcom[com "Delete File"]
+This command prompts for the name of a file and deletes it.
+@enddefcom
+
+@defcom[com "Directory", bind (C-x C-d)]
+@defcom1[com "Verbose Directory", bind (C-x C-D)]
+These commands prompt for a pathname (which may contain wildcards), and display
+a directory listing in a pop-up window. If a prefix argument is supplied, then
+normally hidden files such as Unix dot-files will also be displayed.
+@hid[Directory] uses a compact, multiple-column format;
+@hid[Verbose Directory] displays one file on a line, with information about
+protection, size, etc.
+@enddefcom
+
+
+@section[Printing]
+
+@defcom[com "Print Region"]
+@defcom1[com "Print Buffer"]
+@defcom1[com "Print File"]
+@hid[Print Region] and @hid[Print Buffer] print the contents of the current
+region and the current buffer, respectively. @hid[Print File] prompts for a
+the name of a file and prints that file. Any error messages will be displayed
+in the echo area.
+@enddefcom
+
+@defhvar[var "Print Utility", val {"/usr/cs/bin/lpr"}]
+@defhvar1[var "Print Utility Switches", val {()}]
+@hid[Print Utility] is the program the print commands use to send files to the
+printer. The program should act like @f[lpr]: if a filename is given as an
+argument, it should print that file, and if no name appears, standard input
+should be assumed. @hid[Print Utility Switches] is a list of strings
+specifying the options to pass to the program.
+@enddefhvar
+
+
+@section[Scribe]
+@defcom[com "Scribe Buffer File",
+ stuff (bound to @bf[C-x c] in @hid[Scribe] mode)]
+@defhvar1[var "Scribe Buffer File Confirm", val {t}]
+@defcom1[com "Scribe File"]
+@hid[Scribe Buffer File] invokes @hid[Scribe Utility] on the file associated
+with the current buffer. That process's default directory is the directory of
+the file. The process sends its output to the @hid[Scribe Warnings] buffer.
+Before doing anything, this asks the user to confirm saving and formatting the
+file. This prompting can be inhibited with "Scribe Buffer File Confirm".
+
+@hid[Scribe File] invokes @hid[Scribe Utility] on a file supplied by the user
+in the same manner as describe above.
+@enddefcom
+
+@defhvar[var "Scribe Utility", val {"/usr/misc/bin/scribe"}]
+@defhvar1[var "Scribe Utility Switches"]
+@hid[Scribe Utility] is the program the Scribe commands use to compile the text
+formatting. @hid[Scribe Utility Switches] is a list of strings whose contents
+would be contiguous characters, other than space, had the user invoked this
+program on a command line outside of @hemlock. Do not include the name of the
+file to compile in this variable; the Scribe commands supply this.
+@enddefhvar
+
+@defcom[com "Select Scribe Warnings", bind (Scribe: C-M-C)]
+This command makes the @hid[Scribe Warnings] buffer current if it exists.
+@enddefcom
+
+
+@section[Miscellaneous]
+
+@defcom[com "Manual Page"]
+This command displays a Unix manual page in a buffer which is in @hid[View]
+mode. When given an argument, this puts the manual page in a pop-up display.
+@enddefcom
+
+@defcom[com "Unix Filter Region"]
+This command prompts for a UNIX program and then passes the current region to
+the program as standard input. The standard output from the program is used to
+replace the region. This command is undoable.
+@enddefcom
+
+
+
+@chap[Simple Customization]
+
+@index[customization]@hemlock can be customized and extended to a very
+large degree, but in order to do much of this a knowledge of Lisp is
+required. These advanced aspects of customization are discussed in the
+@i[Hemlock Command Implementor's Manual], while simpler methods of
+customization are discussed here.
+
+
+@section[Keyboard Macros]
+@index[keyboard macros]
+Keyboard macros provide a facility to turn a sequence of commands into one
+command.
+
+@defcom[com "Define Keyboard Macro", bind {C-x (}]
+@defcom1[com "End Keyboard Macro", bind {C-x )}]
+@hid[Define Keyboard Macro] starts the definition of a keyboard macro. The
+commands which are invoked up until @hid[End Keyboard Macro] is invoked
+become the definition for the keyboard macro, thus replaying the keyboard
+macro is synonymous with invoking that sequence of commands.
+@enddefcom
+
+@defcom[com "Last Keyboard Macro", bind (C-x e)]
+This command is the keyboard macro most recently defined; invoking it will
+replay the keyboard macro. The prefix argument is used as a repeat count.
+@enddefcom
+
+@defcom[com "Define Keyboard Macro Key", bind (C-x M-(; )]
+@defhvar1[var "Define Keyboard Macro Key Confirm", val {t}]
+This command prompts for a key before going into a mode for defining keyboard
+macros. After defining the macro @hemlock binds it to the key. If the key is
+already bound, @hemlock asks for confirmation before clobbering the binding;
+this prompting can be inhibited by setting @hid[Define Keyboard Macro Key
+Confirm] to @nil.
+@enddefcom
+
+@defcom[com "Keyboard Macro Query", bind (C-x q)]
+This command conditionalizes the execution of a keyboard macro. When invoked
+during the definition of a macro, it does nothing. When the macro replays, it
+prompts the user for a key-event indicating what action to take. The following
+commands are defined:
+@begin[description]
+@binding[Escape]@\
+ Exit all repetitions of this keyboard macro. More than one may have been
+specified using a prefix argument.
+
+@binding[Space, y]@\
+ Proceed with the execution of the keyboard macro.
+
+@binding[Delete, Backspace, n]@\
+ Skip the remainder of the keyboard macro and go on to the next repetition, if
+any.
+
+@binding[!]@\
+ Do all remaining repetitions of the keyboard macro without prompting.
+
+@binding[.]@\
+ Complete this repetition of the macro and then exit without doing any of the
+remaining repetitions.
+
+@binding[C-r]@\
+ Do a recursive edit and then prompt again.
+@end[description]
+@enddefcom
+
+@defcom[com "Name Keyboard Macro"]
+This command prompts for the name of a command and then makes the
+definition for that command the same as @hid[Last Keyboard Macro]'s current
+definition. The command which results is not clobbered when another
+keyboard macro is defined, so it is possible to keep several keyboard
+macros around at once. The resulting command may also be bound to a key
+using @hid[Bind Key], in the same way any other command is.
+@enddefcom
+
+Many keyboard macros are not for customization, but rather for one-shot
+use, a typical example being performing some operation on each line of a file.
+To add "@f[del ]" to the beginning and "@f[.*]" to the end of every line in
+in a buffer, one could do this:
+@begin[programexample]
+C-x ( d e l Space C-e . * C-n C-a C-x ) C-u 9 9 9 C-x e
+@end[programexample]
+First a keyboard macro is defined which performs the desired operation on
+one line, and then the keyboard macro is invoked with a large prefix
+argument. The keyboard macro will not actually execute that many times;
+when the end of the buffer is reached the @binding[C-n] will get an error
+and abort the execution.
+
+
+@section[Binding Keys]
+@index[key bindings]
+@label[binding-keys]
+
+@defcom[com "Bind Key"]
+This command prompts for a command, a key and a kind of binding to make,
+and then makes the specified binding. The following kinds of bindings are
+allowed:
+@begin[description]
+@i[buffer]@\Prompts for a buffer and then makes a key binding which is
+only present when that buffer is the current buffer.
+
+@i[mode]@\Prompts for the name of a mode and then makes a key binding which
+is only in present when that mode is active in the current buffer.
+
+@i[global]@\Makes a global key binding which is in effect when there is
+no applicable mode or buffer key binding. This is the default.
+@end[description]
+@enddefcom
+
+@defcom[com "Delete Key Binding"]
+This command prompts for a key binding the same way that @hid[Bind Key]
+does and makes the specified binding go away.
+@enddefcom
+
+@section[Hemlock Variables]
+
+@label[vars]@index[variables, hemlock]@index[hemlock variables]A number
+of commands use @hemlock variables as flags to control their behavior. Often
+you can get a command to do what you want by setting a variable. Generally the
+default value for a variable is chosen to be the safest value for novice users.
+
+@defcom[com "Set Variable"]
+This command prompts for the name of a @hemlock variable and an expression,
+then sets the current value of the variable to the result of the evaluation of
+the expression.
+@enddefcom
+
+
+@defcom[com "Defhvar"]
+Like @hid[Set Variable], this command prompts for the name of a @hemlock
+variable and an expression. Like @hid[Bind Key], this command prompts for a
+place: mode, buffer or local. The result of evaluating the expression is
+defined to be the value of the named variable in the specified place.
+
+This command is most useful for making mode or buffer local bindings of
+variables. Redefining a variable in a mode or buffer will create a
+customization that takes effect only when in that mode or buffer.
+
+Unlike @hid[Set Variable], the variable name need not be the name of an
+existing variable: new variables may be defined. If the variable is already
+defined in the current environment, @hemlock copies the documentation and hooks
+to the new definition.
+@enddefcom
+
+
+@section[Init Files]
+@index[init files]
+@hemlock customizations are normally put in @hemlock's initialization file,
+"@f[hemlock-init.lisp]", or when compiled "@f[hemlock-init.fasl]". When
+starting up Lisp, use the @f[-hinit] switch to indicate a particular file. The
+contents of the init file must be Lisp code, but there is a fairly
+straightforward correspondence between the basic customization commands and the
+equivalent Lisp code. Rather than describe these functions in depth here, a
+brief example follows:
+@begin[programexample]
+;;; -*- Mode: Lisp; Package: Hemlock -*-
+
+;;; It is necessary to specify that the customizations go in
+;;; the hemlock package.
+(in-package 'hemlock)
+
+;;; Bind @hid[Kill Previous Word] to @binding[M-h].
+(bind-key "Kill Previous Word" '#(#\m-h))
+;;;
+;;; Bind @hid[Extract List] to @binding[C-M-?] when in @hid[Lisp] mode.
+(bind-key "Extract List" '#(#\c-m-?) :mode "Lisp")
+
+;;; Make @binding[C-w] globally unbound.
+(delete-key-binding '#(#\c-w))
+
+;;; Make string searches case-sensitive.
+(setv string-search-ignore-case nil)
+;;;
+;;; Make "Query Replace" replace strings literally.
+(setv case-replace nil)
+@end[programexample]
+For a detailed description of these functions, see the @i[Hemlock Command
+Implementor's Manual].