about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2005-04-01 10:47:51 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2005-04-01 10:47:51 +0000
commit96df9db2e7296ec37db2afcd3e5ba3eb890697f4 (patch)
treeb02ba30a7055de16b7b4e8e271f95c61fec381f0
parente43b2acd67a7b06d4653ff910af1b4b51aedcdfe (diff)
downloadzsh-96df9db2e7296ec37db2afcd3e5ba3eb890697f4.tar.gz
zsh-96df9db2e7296ec37db2afcd3e5ba3eb890697f4.tar.xz
zsh-96df9db2e7296ec37db2afcd3e5ba3eb890697f4.zip
21078: exit status on parse error
21042: execute-named-command limitation
users/8609: parameter flag documentation
20978: EOFs in recursive edit
20886: SIGTTOU -> TTOU in configure
-rw-r--r--ChangeLog20
-rw-r--r--Doc/Zsh/expn.yo900
-rw-r--r--Doc/Zsh/zle.yo790
-rw-r--r--Src/Zle/zle_main.c856
-rw-r--r--configure.ac4
5 files changed, 1976 insertions, 594 deletions
diff --git a/ChangeLog b/ChangeLog
index 470e10c3a..f2ede269e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,11 +20,27 @@
 	* 21045: Src/Zle/compcore.c, Src/Zle/complete.c: more places
 	where completion didn't handled Meta characters.
 
+2005-03-21  Peter Stephenson  <pws@csr.com>
+
+	* 21042: Src/Zle/zle_main.c, Doc/Zsh/zle.yo: test for and
+	document limitation that execute-named-comand and
+	execute-last-named-command can't be redefined or called by name.
+
+2005-03-18  Peter Stephenson  <pws@csr.com>
+
+	* zsh-users/8609: Doc/Zsh/expn.yo: document order of (u), (o)
+	and (O) parameter expansion flags.
+
 2005-03-16  Peter Stephenson  <pws@csr.com>
 
 	* 20983: Test/D02glob.ztst, Src/glob.c: fixed string segments
 	in globbed paths could be copied wrongly, resulting in failed globs.
 
+2005-03-15  Peter Stephenson  <pws@csr.com>
+
+	* 20978: Src/zle_main.c: don't propagate EOFs from recursive
+	edit.
+
 2005-03-10  Peter Stephenson  <pws@csr.com>
 
 	* 20959 (variant of 20958): Src/params.c, Src/Module/parameter.c,
@@ -58,6 +74,10 @@
 	a single-character Makefile variable if it is a digit.  Avoids
 	an infinite recursion from a Makefile referencing $1.
 
+2005-02-28  Philippe Troin  <phil@fifi.org>
+
+	* 20886: configure.ac: Use TTOU with trap rather than SIGTTOU.
+
 2005-02-25  Oliver Kiddle  <opk@zsh.org>
 
 	* 20867: Completion/Unix/Command/_ant: handle imported files
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index ee554e6c1..eac35f6a9 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1,36 +1,44 @@
-texinode(Expansion)(Parameters)(Restricted Shell)(Top)
+texinode(Expansion)(Parameters)(Prompt Expansion)(Top)
 chapter(Expansion)
 cindex(expansion)
-sect(Description)
-The types of expansions performed are
-
-startlist()
-list(em(History Expansion))
-list(em(Alias Expansion))
-list(em(Process Substitution))
-list(em(Parameter Expansion))
-list(em(Command Substitution))
-list(em(Arithmetic Expansion))
-list(em(Brace Expansion))
-list(em(Filename Expansion))
-list(em(Filename Generation))
-endlist()
-
-Expansion is done in the above specified order in five steps.  The
-first is em(history expansion), which is only performed in
-interactive shells.  The next step is em(alias expansion), which is
-done right before the command line is parsed.  They are followed by
-em(process substitution), em(parameter expansion), em(command
-substitution), em(arithmetic expansion) and em(brace expansion)
-which are performed in one step in left-to-right fashion.  After
-these expansions, all unquoted occurrences of the characters `tt(\)',
-`tt(')' and `tt(")' are removed, and the result is subjected to
-em(filename expansion) followed by em(filename generation).
+ifnztexi(sect(Description))
+The following types of expansions are performed in the indicated order in
+five steps:
 
-If the tt(SH_FILE_EXPANSION) option is set, the order of expansion is modified
-for compatibility with bf(sh) and bf(ksh).  em(Filename expansion)
-is performed immediately after em(alias expansion),
+startitem()
+item(em(History Expansion))(
+This is performed only in interactive shells.
+)
+item(em(Alias Expansion))(
+Aliases are expanded immediately before the command line is parsed as
+explained
+ifzman(under Aliasing in zmanref(zshmisc))\
+ifnzman(in noderef(Aliasing))\
+.
+)
+xitem(em(Process Substitution))
+xitem(em(Parameter Expansion))
+xitem(em(Command Substitution))
+xitem(em(Arithmetic Expansion))
+item(em(Brace Expansion))(
+These five are performed in one step in left-to-right fashion.  After
+these expansions, all unquoted occurrences of the characters `tt(\)',
+`tt(')' and `tt(")' are removed.
+)
+item(em(Filename Expansion))(
+If the tt(SH_FILE_EXPANSION) option is set, the order of expansion is
+modified for compatibility with bf(sh) and bf(ksh).  In that case
+em(filename expansion) is performed immediately after em(alias expansion),
 preceding the set of five expansions mentioned above.
+)
+cindex(globbing)
+item(em(Filename Generation))(
+This expansion, commonly referred to as bf(globbing), is always done last.
+)
+enditem()
+
+The following sections explain the types of expansion in detail.
+
 startmenu()
 menu(History Expansion)
 menu(Process Substitution)
@@ -49,36 +57,93 @@ cindex(expansion, history)
 History expansion allows you to use words from previous command
 lines in the command line you are typing.  This simplifies spelling
 corrections and the repetition of complicated commands or arguments.
-Command lines are saved in the history list, the size of which
-is controlled by the tt(HISTSIZE)
 vindex(HISTSIZE, use of)
-parameter.  The most recent command is retained in any case.
-A history expansion begins with the first character of the
-tt(histchars) parameter which is `tt(!)'
-by default and may occur anywhere on the command line; history
-expansions do not nest.  The `tt(!)' can be escaped with `tt(\)'
-or can be enclosed between a pair of single quotes (tt('')) to suppress
-its special meaning. Double quotes will em(not) work for this.
-
-Input lines containing history expansions are echoed on the
-terminal after being expanded, but before any other
-expansions take place or the command gets executed.
+Immediately before execution, each command is saved in the history list,
+the size of which is controlled by the tt(HISTSIZE) parameter.  The one
+most recent command is always retained in any case.  Each saved command in
+the history list is called a history em(event) and is assigned a number,
+beginning with 1 (one) when the shell starts up.  The history number that
+you may see in your prompt (see
+ifzman(Prompt Expansion in zmanref(zshmisc))\
+ifnzman(noderef(Prompt Expansion))\
+) is the number that is to be assigned to the em(next) command.
+
 startmenu()
+menu(Overview)
 menu(Event Designators)
 menu(Word Designators)
 menu(Modifiers)
 endmenu()
-texinode(Event Designators)(Word Designators)()(History Expansion)
+texinode(Overview)(Event Designators)()(History Expansion)
+subsect(Overview)
+vindex(histchars, use of)
+A history expansion begins with the first character of the tt(histchars)
+parameter, which is `tt(!)' by default, and may occur anywhere on the
+command line; history expansions do not nest.  The `tt(!)' can be escaped
+with `tt(\)' or can be enclosed between a pair of single quotes (tt(''))
+to suppress its special meaning.  Double quotes will em(not) work for
+this.  Following this history character is an optional event designator
+(ifzman(see )noderef(Event Designators)) and then an optional word
+designator (noderef(Word Designators)); if neither of these designators is
+present, no history expansion occurs.
+
+Input lines containing history expansions are echoed after being expanded,
+but before any other expansions take place and before the command is
+executed.  It is this expanded form that is recorded as the history event
+for later references.
+
+By default, a history reference with no event designator refers to the
+same event as any preceding history reference on that command line; if it
+is the only history reference in a command, it refers to the previous
+command.
+pindex(CSH_JUNKIE_HISTORY, use of)
+However, if the option tt(CSH_JUNKIE_HISTORY) is set, then every history
+reference with no event specification em(always) refers to the previous
+command.
+
+For example, `tt(!)' is the event designator for the previous command, so
+`tt(!!:1)' always refers to the first word of the previous command, and
+`tt(!!$)' always refers to the last word of the previous command.  With
+tt(CSH_JUNKIE_HISTORY) set, then `tt(!:1)' and `tt(!$)' function in the
+same manner as `tt(!!:1)' and `tt(!!$)', respectively.  Conversely, if
+tt(CSH_JUNKIE_HISTORY) is unset, then `tt(!:1)' and `tt(!$)' refer to the
+first and last words, respectively, of the same event referenced by the
+nearest other history reference preceding them on the current command
+line, or to the previous command if there is no preceding reference.
+
+The character sequence `tt(^)var(foo)tt(^)var(bar)' (where `tt(^)' is
+actually the second character of the tt(histchars) parameter)
+repeats the last command, replacing the string var(foo) with var(bar).
+More precisely, the sequence `tt(^)var(foo)tt(^)var(bar)tt(^)' is
+synonymous with `tt(!!:s)tt(^)var(foo)tt(^)var(bar)tt(^)', hence other
+modifiers (see noderef(Modifiers)) may follow the final `tt(^)'.
+
+If the shell encounters the character sequence `tt(!")'
+in the input, the history mechanism is temporarily disabled until
+the current list (see
+ifzman(zmanref(zshmisc))\
+ifnzman(noderef(Shell Grammar))\
+) is fully parsed.  The `tt(!")' is removed from the input, and any
+subsequent `tt(!)' characters have no special significance.
+
+findex(fc, use of)
+A less convenient but more comprehensible form of command history support
+is provided by the tt(fc) builtin.
+texinode(Event Designators)(Word Designators)(Overview)(History Expansion)
 subsect(Event Designators)
 cindex(history event designators)
 cindex(event designators, history)
-An event designator is a reference to a command-line entry in
-the history list.
+An event designator is a reference to a command-line entry in the history
+list.  In the list below, remember that the initial tt(`!') in each item
+may be changed to another character by setting the tt(histchars)
+parameter.
 
 startitem()
 item(tt(!))(
 Start a history expansion, except when followed by a blank, newline,
-`tt(=)' or `tt(LPAR())'.
+`tt(=)' or `tt(LPAR())'.  If followed immediately by a word designator
+(ifzman(see )noderef(Word Designators)), this forms a history reference
+with no event designator (ifzman(see )noderef(Overview)).
 )
 item(tt(!!))(
 Refer to the previous command.
@@ -95,7 +160,9 @@ item(tt(!)var(str))(
 Refer to the most recent command starting with var(str).
 )
 item(tt(!?)var(str)[tt(?)])(
-Refer to the most recent command containing var(str).
+Refer to the most recent command containing var(str).  The trailing
+`tt(?)' is necessary if this reference is to be followed by a modifier or
+followed by any text that is not to be considered part of var(str).
 )
 item(tt(!#))(
 Refer to the current command line typed in so far.  The line is
@@ -110,10 +177,10 @@ texinode(Word Designators)(Modifiers)(Event Designators)(History Expansion)
 subsect(Word Designators)
 cindex(history word designators)
 cindex(word designators, history)
-A word designator indicates which word or words of a given command line will
-be included in a history reference.  A `tt(:)'
+A word designator indicates which word or words of a given command line are
+to be included in a history reference.  A `tt(:)' usually
 separates the event specification from the word designator.
-It can be omitted if the word designator begins with a
+It may be omitted only if the word designator begins with a
 `tt(^)', `tt($)', `tt(*)', `tt(-)' or `tt(%)'.
 Word designators include:
 
@@ -129,14 +196,17 @@ sitem(var(x)tt(*))(Abbreviates `var(x)tt(-$)'.)
 sitem(var(x)tt(-))(Like `var(x)tt(*)' but omitting word tt($).)
 endsitem()
 
-Note that a `tt(%)' word designator will only work when used as
-`tt(!%)', `tt(!:%)' or `tt(!?)var(str)tt(?:%)',
-and only when used after a tt(!?) expansion.  Anything else will result
+Note that a `tt(%)' word designator works only when used in one of
+`tt(!%)', `tt(!:%)' or `tt(!?)var(str)tt(?:%)', and only when used after a
+tt(!?) expansion (possibly in an earlier command).  Anything else results
 in an error, although the error may not be the most obvious one.
 texinode(Modifiers)()(Word Designators)(History Expansion)
 subsect(Modifiers)
-cindex(modifiers, history)
+cindex(modifiers)
+cindex(colon modifiers)
 cindex(history modifiers)
+cindex(globbing modifiers)
+cindex(parameter modifiers)
 After the optional word designator, you can add
 a sequence of one or more of the following modifiers,
 each preceded by a `tt(:)'.  These modifiers also work on the result
@@ -145,16 +215,19 @@ noted.
 
 startitem()
 item(tt(h))(
-Remove a trailing pathname component, leaving the head.
+Remove a trailing pathname component, leaving the head.  This works
+like `tt(dirname)'.
 )
 item(tt(r))(
-Remove a trailing suffix of the form `tt(.)var(xxx)', leaving the basename.
+Remove a filename extension of the form `tt(.)var(xxx)', leaving
+the root name.
 )
 item(tt(e))(
-Remove all but the suffix.
+Remove all but the extension.
 )
 item(tt(t))(
-Remove all leading pathname components, leaving the tail.
+Remove all leading pathname components, leaving the tail.  This works
+like `tt(basename)'.
 )
 item(tt(p))(
 Print the new command but do not execute it.  Only works with history
@@ -162,15 +235,16 @@ expansion.
 )
 item(tt(q))(
 Quote the substituted words, escaping further substitutions.  Works
-with history expansion and parameter expansion, though in the second
-case it is only useful if the resulting text is to be re-evaluated
-such as by tt(eval).
+with history expansion and parameter expansion, though for parameters
+it is only useful if the resulting text is to be re-evaluated such as
+by tt(eval).
 )
 item(tt(Q))(
 Remove one level of quotes from the substituted words.
 )
 item(tt(x))(
-Like tt(q), but break into words at each blank.
+Like tt(q), but break into words at whitespace.  Does not work with
+parameter expansion.
 )
 item(tt(l))(
 Convert the words to all lowercase.
@@ -178,30 +252,6 @@ Convert the words to all lowercase.
 item(tt(u))(
 Convert the words to all uppercase.
 )
-item(tt(f))(
-(This and the following
-tt(F), tt(w) and tt(W) modifier only work with parameter expansion and
-filename generation.)
-Repeats the immediately (without a colon) following modifier until the
-resulting word doesn't change any more.
-)
-item(tt(F:)var(expr)tt(:))(
-Like tt(f), but repeats only var(n) times if the expression
-var(expr) evaluates to var(n).  Any character can be used instead of
-the `tt(:)'; if `tt(LPAR())', `tt([)', or `tt({)'
-is used as the opening delimiter,
-the closing delimiter should be 'tt(RPAR())', `tt(])', or `tt(})',
-respectively.
-)
-item(tt(w))(
-Makes the immediately following modifier work on each word in the
-string.
-)
-item(tt(W:)var(sep)tt(:))(
-Like tt(w) but words are considered to be the parts of the string
-that are separated by var(sep). Any character can be used instead of
-the `tt(:)'; opening parentheses are handled specially, see above.
-)
 item(tt(s/)var(l)tt(/)var(r)[tt(/)])(
 Substitute var(r) for var(l) as described below.
 Unless preceded immediately by a tt(g), with no colon between,
@@ -230,43 +280,33 @@ the rightmost `tt(?)' in a context scan can similarly be omitted.
 Note the same record of the last var(l) and var(r) is maintained
 across all forms of expansion.
 
-By default, a history reference with no event specification refers to the same
-line as the previous history reference on that command line, unless it is the
-first history reference in a command.  In that case, a history reference
-with no event specification always refers to the previous command.  However,
-if the option tt(CSH_JUNKIE_HISTORY) is set,
-pindex(CSH_JUNKIE_HISTORY, use of)
-then history reference with no
-event specification will em(always) refer to the previous command.
-
-For example, `tt(!!:1)'
-will always refer to the first word of the previous command, and `tt(!!$)'
-will always refer to the last word of the previous command.  And with
-tt(CSH_JUNKIE_HISTORY) set, then `tt(!:1)' and `tt(!$)'
-will function in the same manner as `tt(!!:1)' and `tt(!!$)',
-respectively.  However, if tt(CSH_JUNKIE_HISTORY) is unset, then
-`tt(!:1)' and `tt(!$)'
-will refer to the first and last words respectively, of the last command
-referenced on the current command line.  However, if they are the first history
-reference on the command line, then they refer to the previous command.
+The following tt(f), tt(F), tt(w) and tt(W) modifiers work only with
+parameter expansion and filename generation.  They are listed here to
+provide a single point of reference for all modifiers.
 
-The character sequence `tt(^)var(foo)tt(^)var(bar)' (where `tt(^)' is
-actually the second charcter of the tt(histchars) parameter)
-repeats the last command, replacing the string var(foo) with var(bar).
-More precisely, the sequence `tt(^)var(foo)tt(^)var(bar)tt(^)' is
-synonymous with `tt(!!:s)tt(^)var(foo)tt(^)var(bar)tt(^)', hence other
-modifiers may follow the final `tt(^)'.
-
-If the shell encounters the character sequence `tt(!")'
-in the input, the history mechanism is temporarily disabled until
-the current list is fully parsed.  The `tt(!")'
-is removed from the input, and any subsequent `tt(!)'
-characters have no special significance.
-
-A less convenient but more comprehensible
-form of command history support
-is provided by the tt(fc) builtin.
-findex(fc, use of)
+startitem()
+item(tt(f))(
+Repeats the immediately (without a colon) following modifier until the
+resulting word doesn't change any more.
+)
+item(tt(F:)var(expr)tt(:))(
+Like tt(f), but repeats only var(n) times if the expression
+var(expr) evaluates to var(n).  Any character can be used instead of
+the `tt(:)'; if `tt(LPAR())', `tt([)', or `tt({)'
+is used as the opening delimiter,
+the closing delimiter should be 'tt(RPAR())', `tt(])', or `tt(})',
+respectively.
+)
+item(tt(w))(
+Makes the immediately following modifier work on each word in the
+string.
+)
+item(tt(W:)var(sep)tt(:))(
+Like tt(w) but words are considered to be the parts of the string
+that are separated by var(sep). Any character can be used instead of
+the `tt(:)'; opening parentheses are handled specially, see above.
+)
+enditem()
 texinode(Process Substitution)(Parameter Expansion)(History Expansion)(Expansion)
 sect(Process Substitution)
 cindex(process substitution)
@@ -276,38 +316,71 @@ Each command argument of the form
 `tt(>LPAR())var(list)tt(RPAR())' or
 `tt(=LPAR())var(list)tt(RPAR())'
 is subject to process substitution.
-In the case of the tt(<) or tt(>) forms, the shell will run process
-var(list) asynchronously, connected to a named pipe (FIFO).
-The name of this pipe will become the argument to the command.
-If the form with tt(>)
-is selected then writing on this file will provide input for var(list).
-If tt(<) is used, then the file passed as an argument will
-be a named pipe connected to the output of the var(list) process.
-For example,
-
-nofill(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() |
+In the case of the tt(<) or tt(>) forms, the shell runs process
+var(list) asynchronously.  If the system supports the tt(/dev/fd)
+mechanism, the command argument is the name of the device file
+corresponding to a file descriptor; otherwise, if the system supports named
+pipes (FIFOs), the command argument will be a named pipe.  If the form with
+tt(>) is selected then writing on this special file will provide input for
+var(list).  If tt(<) is used, then the file passed as an argument will
+be connected to the output of the var(list) process.  For example,
+
+example(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() |
 tee >LPAR())var(process1)tt(RPAR() >LPAR())var(process2)tt(RPAR() >/dev/null))
 
 cuts fields 1 and 3 from the files var(file1) and var(file2) respectively,
 pastes the results together, and sends it to the processes
 var(process1) and var(process2).
-Note that the file, which is passed as an argument to the command,
-is a system pipe, so programs that expect to lseek (see manref(lseek)(2))
-on the file will not work.
+
+If tt(=LPAR())var(...)tt(RPAR()) is used instead of
+tt(<LPAR())var(...)tt(RPAR()),
+then the file passed as an argument will be the name
+of a temporary file containing the output of the var(list)
+process.  This may be used instead of the tt(<)
+form for a program that expects to lseek (see manref(lseek)(2))
+on the input file.
+
+The tt(=) form is useful as both the tt(/dev/fd) and the named pipe
+implementation of tt(<LPAR())var(...)tt(RPAR()) have drawbacks.  In 
+the former case, some programmes may automatically close the file
+descriptor in question before examining the file on the command line,
+particularly if this is necessary for security reasons such as when the
+programme is running setuid.  In the second case, if the
+programme does not actually open the file, the subshell attempting to read
+from or write to the pipe will (in a typical implementation, different
+operating systems may have different behaviour) block for ever and have to
+be killed explicitly.  In both cases, the shell actually supplies the
+information using a pipe, so that programmes that expect to lseek
+(see manref(lseek)(2)) on the file will not work.
+
 Also note that the previous example can be more compactly and
 efficiently written (provided the tt(MULTIOS) option is set) as:
 
-nofill(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() > >LPAR())var(process1)tt(RPAR() > >LPAR())var(process2)tt(RPAR()))
+example(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR()) ifzman(\ 
+)tt(> >LPAR())var(process1)tt(RPAR() > >LPAR())var(process2)tt(RPAR()))
 
 The shell uses pipes instead of FIFOs to implement the latter
 two process substitutions in the above example.
 
-If tt(=) is used,
-then the file passed as an argument will be the name
-of a temporary file containing the output of the var(list)
-process.  This may be used instead of the tt(<)
-form for a program that expects to lseek (see manref(lseek)(2))
-on the input file.
+There is an additional problem with tt(>LPAR())var(process)tt(RPAR()); when
+this is attached to an external command, the parent shell does not wait
+for var(process) to finish and hence an immediately following command
+cannot rely on the results being complete.  The problem and solution are
+the same as described in the section em(MULTIOS) in
+ifzman(zmanref(zshmisc))\
+ifnzman(noderef(Redirection)).  Hence in a simplified
+version of the example above:
+
+example(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR()) tt(> >LPAR())var(process)tt(RPAR()))
+
+(note that no tt(MULTIOS) are involved), var(process) will be run
+asynchronously.  The workaround is:
+
+example(tt({ paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() }) tt(> >LPAR())var(process)tt(RPAR()))
+
+The extra processes here are
+spawned from the parent shell which will wait for their completion.
+
 texinode(Parameter Expansion)(Command Substitution)(Process Substitution)(Expansion)
 sect(Parameter Expansion)
 cindex(parameter expansion)
@@ -323,12 +396,17 @@ noderef(Parameters)
 for a description of parameters, including arrays, associative arrays,
 and subscript notation to access individual array elements.
 
+Note in particular the fact that words of unquoted parameters are not
+automatically split on whitespace unless the option tt(SH_WORD_SPLIT) is
+set; see references to this option below for more details.  This is an
+important difference from other shells.
+
 In the expansions discussed below that require a pattern, the form of
 the pattern is the same as that used for filename generation;
 see noderef(Filename Generation).  Note that these patterns, along with
 the replacement text of any substitutions, are themselves subject to
 parameter expansion, command substitution, and arithmetic expansion.
-In addition to the following operations, the file modifiers described in
+In addition to the following operations, the colon modifiers described in
 noderef(Modifiers) in noderef(History Expansion) can be
 applied:  for example, tt(${i:s/foo/bar/}) performs string
 substitution on the expansion of parameter tt($i).
@@ -422,13 +500,21 @@ item(tt(${)var(name)tt(//)var(pattern)tt(/)var(repl)tt(}))(
 Replace the longest possible match of var(pattern) in the expansion of
 parameter var(name) by string var(repl).  The first form
 replaces just the first occurrence, the second form all occurrences.
+Both var(pattern) and var(repl) are subject to double-quoted substitution,
+so that expressions like tt(${name/$opat/$npat}) will work, but note the
+usual rule that pattern characters in tt($opat) are not treated specially
+unless either the option tt(GLOB_SUBST) is set, or tt($opat) is instead
+substituted as tt(${~opat}).
+
 The var(pattern) may begin with a `tt(#)', in which case the
 var(pattern) must match at the start of the string, or `tt(%)', in
 which case it must match at the end of the string.  The var(repl) may
 be an empty string, in which case the final `tt(/)' may also be omitted.
-To quote the final `tt(/)' in other cases it should be preceded by two
-backslashes (i.e., a quoted backslash); this is not necessary if the
-`tt(/)' occurs inside a substituted parameter.
+To quote the final `tt(/)' in other cases it should be preceded by a
+single backslash; this is not necessary if the
+`tt(/)' occurs inside a substituted parameter.  Note also that the `tt(#)'
+and `tt(%)' are not active if they occur inside a substituted parameter,
+even at the start.
 
 The first `tt(/)' may be preceded by a `tt(:)', in which case the match
 will only succeed if it matches the entire word.  Note also the
@@ -456,7 +542,7 @@ Note that `tt(^)', `tt(=)', and `tt(~)', below, must appear
 to the left of `tt(#)' when these forms are combined.
 )
 item(tt(${^)var(spec)tt(}))(
-pindex(RC_EXPAND_PARAM, use of)
+pindex(RC_EXPAND_PARAM, toggle)
 cindex(array expansion style, rc)
 cindex(rc, array expansion style)
 Turn on the tt(RC_EXPAND_PARAM) option for the
@@ -477,9 +563,9 @@ tt($var[)var(N)tt(]) may themselves be split into different list
 elements.
 )
 item(tt(${=)var(spec)tt(}))(
-pindex(SH_WORD_SPLIT, use of)
-cindex(field splitting, sh style)
-cindex(sh, field splitting style)
+pindex(SH_WORD_SPLIT, toggle)
+cindex(field splitting, sh style, parameter)
+cindex(sh, field splitting style, parameter)
 Perform word splitting using the rules for tt(SH_WORD_SPLIT) during the
 evaluation of var(spec), but regardless of whether the parameter appears in
 double quotes; if the `tt(=)' is doubled, turn it off.
@@ -493,7 +579,7 @@ of var(spec) em(before) the assignment to var(name) is performed.
 This affects the result of array assignments with the tt(A) flag.
 )
 item(tt(${~)var(spec)tt(}))(
-pindex(GLOB_SUBST)
+pindex(GLOB_SUBST, toggle)
 Turn on the tt(GLOB_SUBST) option for the evaluation of
 var(spec); if the `tt(~)' is doubled, turn it off.  When this option is
 set, the string resulting from the expansion will be interpreted as a
@@ -511,11 +597,15 @@ possible to perform nested operations:  tt(${${foo#head}%tail})
 substitutes the value of tt($foo) with both `tt(head)' and `tt(tail)'
 deleted.  The form with tt($LPAR())...tt(RPAR()) is often useful in
 combination with the flags described next; see the examples below.
+Each var(name) or nested tt(${)...tt(}) in a parameter expansion may
+also be followed by a subscript expression as described in
+ifzman(em(Array Parameters) in zmanref(zshparam))\
+ifnzman(noderef(Array Parameters)).
 
-Note that double quotes may appear around nested substitutions, in which
+Note that double quotes may appear around nested expressions, in which
 case only the part inside is treated as quoted; for example,
 tt(${(f)"$(foo)"}) quotes the result of tt($(foo)), but the flag `tt((f))'
-(see below) is applied using the rules for unquoted substitutions.  Note
+(see below) is applied using the rules for unquoted expansions.  Note
 further that quotes are themselves nested in this context; for example, in
 tt("${(@f)"$(foo)"}"), there are two sets of quotes, one surrounding the
 whole expression, the other (redundant) surrounding the tt($(foo)) as
@@ -527,95 +617,65 @@ cindex(flags, parameter expansion)
 cindex(substitution, parameter, flags)
 If the opening brace is directly followed by an opening parenthesis,
 the string up to the matching closing parenthesis will be taken as a
-list of flags.  Where arguments are valid, any character, or the
-matching pairs `tt(LPAR())...tt(RPAR())', `tt({)...tt(})',
-`tt([)...tt(])', or `tt(<)...tt(>)',  may be used
-in place of the colon as delimiters.  The following flags are supported:
+list of flags.  In cases where repeating a flag is meaningful, the
+repetitions need not be consecutive; for example, `(tt(q%q%q))'
+means the same thing as the more readable `(tt(%%qqq))'.  The
+following flags are supported:
 
 startitem()
-item(tt(A))(
-Create an array parameter with tt(${)...tt(=)...tt(}),
-tt(${)...tt(:=)...tt(}) or tt(${)...tt(::=)...tt(}).
-If this flag is repeated (as in tt(AA)), create an associative
-array parameter.  Assignment is made before sorting or padding.
-The var(name) part may be a subscripted range for ordinary
-arrays; the var(word) part em(must) be converted to an array, for
-example by using tt(${(AA)=)var(name)tt(=)...tt(}) to activate word
-splitting, when creating an associative array.
+item(tt(%))(
+Expand all tt(%) escapes in the resulting words in the same way as in in
+prompts (see noderef(Prompt Expansion)). If this flag is given twice,
+full prompt expansion is done on the resulting words, depending on the
+setting of the tt(PROMPT_PERCENT), tt(PROMPT_SUBST) and tt(PROMPT_BANG)
+options.
 )
 item(tt(@))(
 In double quotes, array elements are put into separate words.
-E.g., tt("${(@)foo}") is equivalent to tt("${foo[@]}") and
-tt("${(@)foo[1,2]}") is the same as tt("$foo[1]" "$foo[2]").
-)
-item(tt(e))(
-Perform em(parameter expansion), em(command substitution) and
-em(arithmetic expansion) on the result. Such expansions can be
-nested but too deep recursion may have unpredictable effects.
-)
-item(tt(P))(
-This forces the value of the parameter var(name) to be interpreted as a
-further parameter name, whose value will be used where appropriate. If used
-with a nested parameter or command substitution, the result of that will be
-taken as a parameter name in the same way.  For example, if you have
-`tt(foo=bar)' and `tt(bar=baz)', the strings tt(${(P)foo}),
-tt(${(P)${foo}}), and tt(${(P)$(echo bar)}) will be expanded to `tt(baz)'.
-)
-item(tt(o))(
-Sort the resulting words in ascending order.
+E.g., `tt("${(@)foo}")' is equivalent to `tt("${foo[@]}")' and
+`tt("${(@)foo[1,2]}")' is the same as `tt("$foo[1]" "$foo[2]")'.
+This is distinct from em(field splitting) by the the tt(f), tt(s)
+or tt(z) flags, which still applies within each array element.
 )
-item(tt(O))(
-Sort the resulting words in descending order.
-)
-item(tt(i))(
-With tt(o) or tt(O), sort case-independently.
+item(tt(A))(
+Create an array parameter with `tt(${)...tt(=)...tt(})',
+`tt(${)...tt(:=)...tt(})' or `tt(${)...tt(::=)...tt(})'.
+If this flag is repeated (as in `tt(AA)'), create an associative
+array parameter.  Assignment is made before sorting or padding.
+The var(name) part may be a subscripted range for ordinary
+arrays; the var(word) part em(must) be converted to an array, for
+example by using `tt(${(AA)=)var(name)tt(=)...tt(})' to activate
+field splitting, when creating an associative array.
 )
-item(tt(L))(
-Convert all letters in the result to lower case.
+item(tt(a))(
+With tt(o) or tt(O), sort in array index order. Note that `tt(oa)' is
+therefore equivalent to the default but `tt(Oa)' is useful for
+obtaining an array's elements in reverse order.
 )
-item(tt(U))(
-Convert all letters in the result to upper case.
+item(tt(c))(
+With tt(${#)var(name)tt(}), count the total number of characters in an array,
+as if the elements were concatenated with spaces between them.
 )
 item(tt(C))(
 Capitalize the resulting words.  `Words' in this case refers to sequences
 of alphanumeric characters separated by non-alphanumerics, em(not) to words
 that result from field splitting.
 )
-item(tt(V))(
-Make any special characters in the resulting words visible.
-)
-item(tt(q))(
-Quote the resulting words with backslashes. If this flag is given
-twice, the resulting words are quoted in single quotes and if it is
-given three times, the words are quoted in double quotes. If it is
-given four times, the words are quoted in single quotes preceded a tt($).
-)
-item(tt(Q))(
-Remove one level of quotes from the resulting words.
-)
-item(tt(%))(
-Expand all tt(%) escapes in the resulting words in the same way as in
-prompts (see noderef(Prompt Expansion)). If this flag is given twice,
-full prompt expansion is done on the resulting words, depending on the 
-setting of the tt(PROMPT_PERCENT), tt(PROMPT_SUBST) and
-tt(PROMPT_BANG) options.
-)
-item(tt(X))(
-With this flag parsing errors occuring with the tt(Q) flag or the
-pattern matching forms such as `tt(${)var(name)tt(#)var(pattern)tt(})' 
-are reported. Without the flag they are silently ignored.
+item(tt(e))(
+Perform em(parameter expansion), em(command substitution) and
+em(arithmetic expansion) on the result. Such expansions can be
+nested but too deep recursion may have unpredictable effects.
 )
-item(tt(c))(
-With tt(${#)var(name)tt(}), count the total number of characters in an array,
-as if the elements were concatenated with spaces between them.
+item(tt(f))(
+Split the result of the expansion to lines. This is a shorthand
+for `tt(ps:\n:)'.
 )
-item(tt(w))(
-With tt(${#)var(name)tt(}), count words in arrays or strings; the tt(s)
-flag may be used to set a word delimiter.
+item(tt(F))(
+Join the words of arrays together using newline as a separator.
+This is a shorthand for `tt(pj:\n:)'.
 )
-item(tt(W))(
-Similar to tt(w) with the difference that empty words between
-repeated delimiters are also counted.
+item(tt(i))(
+With tt(o) or tt(O), sort case-independently.
 )
 item(tt(k))(
 If var(name) refers to an associative array, substitute the em(keys)
@@ -624,54 +684,42 @@ subscripts (including ordinary arrays), force indices or keys to be
 substituted even if the subscript form refers to values.  However,
 this flag may not be combined with subscript ranges.
 )
-item(tt(v))(
-Used with tt(k), substitute (as two consecutive words) both the key
-and the value of each associative array element.  Used with subscripts,
-force values to be substituted even if the subscript form refers to
-indices or keys.
-)
-item(tt(p))(
-Recognize the same escape sequences as the tt(print) builtin
-in string arguments to any of the flags described below.
+item(tt(L))(
+Convert all letters in the result to lower case.
 )
-item(tt(l:)var(expr)tt(::)var(string1)tt(::)var(string2)tt(:))(
-Pad the resulting words on the left.  Each word will be truncated if
-required and placed in a field var(expr) characters wide.  The space
-to the left will be filled with var(string1) (concatenated as often
-as needed) or spaces if var(string1) is not given.  If both
-var(string1) and var(string2) are given, this string is inserted
-once directly to the left of each word, before padding.
+item(tt(n))(
+With tt(o) or tt(O), sort numerically.
 )
-item(tt(r:)var(expr)tt(::)var(string1)tt(::)var(string2)tt(:))(
-As tt(l), but pad the words on the right and insert var(string2)
-on the right.
+item(tt(o))(
+Sort the resulting words in ascending order.
 )
-item(tt(j:)var(string)tt(:))(
-Join the words of arrays together using var(string) as a separator.
-pindex(SH_WORD_SPLIT, use of)
-Note that this occurs before field splitting by the tt(SH_WORD_SPLIT)
-option.
+item(tt(O))(
+Sort the resulting words in descending order.
 )
-item(tt(F))(
-Join the words of arrays together using newline as a separator.
-This is a shorthand for `tt(pj:\n:)'.
+item(tt(P))(
+This forces the value of the parameter var(name) to be interpreted as a
+further parameter name, whose value will be used where appropriate. If
+used with a nested parameter or command substitution, the result of that
+will be taken as a parameter name in the same way.  For example, if you
+have `tt(foo=bar)' and `tt(bar=baz)', the strings tt(${(P)foo}),
+tt(${(P)${foo}}), and tt(${(P)$(echo bar)}) will be expanded to `tt(baz)'.
 )
-item(tt(s:)var(string)tt(:))(
-Force field splitting (see the option tt(SH_WORD_SPLIT)) at the
-separator var(string).  Splitting only occurs in places where an
-array value is valid.
+item(tt(q))(
+Quote the resulting words with backslashes. If this flag is given
+twice, the resulting words are quoted in single quotes and if it is
+given three times, the words are quoted in double quotes. If it is
+given four times, the words are quoted in single quotes preceded by a tt($).
 )
-item(tt(f))(
-Split the result of the expansion to lines. This is a shorthand
-for `tt(ps:\n:)'.
+item(tt(Q))(
+Remove one level of quotes from the resulting words.
 )
 item(tt(t))(
 Use a string describing the type of the parameter where the value
 of the parameter would usually appear. This string consists of keywords
 separated by hyphens (`tt(-)'). The first keyword in the string describes
 the main type, it can be one of `tt(scalar)', `tt(array)', `tt(integer)',
-or `tt(association)'. The other keywords describe the type in more
-detail:
+`tt(float)' or `tt(association)'. The other keywords describe the type in
+more detail:
 
 startitem()
 item(tt(local))(
@@ -714,6 +762,80 @@ for special parameters defined by the shell
 )
 enditem()
 )
+item(tt(u))(
+Expand only the first occurrence of each unique word.
+)
+item(tt(U))(
+Convert all letters in the result to upper case.
+)
+item(tt(v))(
+Used with tt(k), substitute (as two consecutive words) both the key
+and the value of each associative array element.  Used with subscripts,
+force values to be substituted even if the subscript form refers to
+indices or keys.
+)
+item(tt(V))(
+Make any special characters in the resulting words visible.
+)
+item(tt(w))(
+With tt(${#)var(name)tt(}), count words in arrays or strings; the tt(s)
+flag may be used to set a word delimiter.
+)
+item(tt(W))(
+Similar to tt(w) with the difference that empty words between
+repeated delimiters are also counted.
+)
+item(tt(X))(
+With this flag parsing errors occurring with the tt(Q) and tt(e) flags or the
+pattern matching forms such as `tt(${)var(name)tt(#)var(pattern)tt(})' 
+are reported. Without the flag they are silently ignored.
+)
+item(tt(z))(
+Split the result of the expansion into words using shell parsing to
+find the words, i.e. taking into account any quoting in the value.
+
+Note that this is done very late, as for the `tt((s))' flag. So to
+access single words in the result, one has to use nested expansions as 
+in `tt(${${(z)foo}[2]})'. Likewise, to remove the quotes in the
+resulting words one would do: `tt(${(Q)${(z)foo}})'.
+)
+enditem()
+
+The following flags (except tt(p)) are followed by one or more arguments
+as shown.  Any character, or the matching pairs `tt(LPAR())...tt(RPAR())',
+`tt({)...tt(})', `tt([)...tt(])', or `tt(<)...tt(>)', may be used in place
+of a colon as delimiters, but note that when a flag takes more than one
+argument, a matched pair of delimiters must surround each argument.
+
+startitem()
+item(tt(p))(
+Recognize the same escape sequences as the tt(print) builtin
+in string arguments to any of the flags described below.
+)
+item(tt(j:)var(string)tt(:))(
+Join the words of arrays together using var(string) as a separator.
+pindex(SH_WORD_SPLIT, use of)
+Note that this occurs before field splitting by the tt(SH_WORD_SPLIT)
+option.
+)
+item(tt(l:)var(expr)tt(::)var(string1)tt(::)var(string2)tt(:))(
+Pad the resulting words on the left.  Each word will be truncated if
+required and placed in a field var(expr) characters wide.  The space
+to the left will be filled with var(string1) (concatenated as often
+as needed) or spaces if var(string1) is not given.  If both
+var(string1) and var(string2) are given, this string is inserted
+once directly to the left of each word, before padding.
+)
+item(tt(r:)var(expr)tt(::)var(string1)tt(::)var(string2)tt(:))(
+As tt(l), but pad the words on the right and insert var(string2)
+on the right.
+)
+item(tt(s:)var(string)tt(:))(
+Force field splitting (see the option tt(SH_WORD_SPLIT)) at the
+separator var(string).  Note that a var(string) of two or more
+characters means all must all match in sequence; this differs from
+the treatment of two or more characters in the tt(IFS) parameter.
+)
 enditem()
 
 The following flags are meaningful with the tt(${)...tt(#)...tt(}) or
@@ -725,24 +847,34 @@ item(tt(S))(
 Search substrings as well as beginnings or ends; with tt(#) start
 from the beginning and with tt(%) start from the end of the string.
 With substitution via tt(${)...tt(/)...tt(}) or
-tt(${)...tt(//)...tt(}), specifies that the shortest instead of the
-longest match should be replaced.
+tt(${)...tt(//)...tt(}), specifies non-greedy matching, i.e. that the
+shortest instead of the longest match should be replaced.
 )
 item(tt(I:)var(expr)tt(:))(
 Search the var(expr)th match (where var(expr) evaluates to a number).
 This only applies when searching for substrings, either with the tt(S)
 flag, or with tt(${)...tt(/)...tt(}) (only the var(expr)th match is
 substituted) or tt(${)...tt(//)...tt(}) (all matches from the
-var(expr)th on are substituted).  The var(expr)th match is counted
-such that there is either one or zero matches from each starting
-position in the string, although for global substitution matches
-overlapping previous replacements are ignored.
-)
-item(tt(M))(
-Include the matched portion in the result.
-)
-item(tt(R))(
-Include the unmatched portion in the result (the em(R)est).
+var(expr)th on are substituted).  The default is to take the first match.
+
+The var(expr)th match is counted such that there is either one or zero
+matches from each starting position in the string, although for global
+substitution matches overlapping previous replacements are ignored.  With
+the tt(${)...tt(%)...tt(}) and tt(${)...tt(%%)...tt(}) forms, the starting
+position for the match moves backwards from the end as the index increases,
+while with the other forms it moves forward from the start.
+
+Hence with the string
+example(which switch is the right switch for Ipswich?)
+substitutions of the form
+tt(${)LPAR()tt(SI:)var(N)tt(:)RPAR()tt(string#w*ch}) as var(N) increases
+from 1 will match and remove `tt(which)', `tt(witch)', `tt(witch)' and
+`tt(wich)'; the form using `tt(##)' will match and remove `tt(which switch
+is the right switch for Ipswich)', `tt(witch is the right switch for
+Ipswich)', `tt(witch for Ipswich)' and `tt(wich)'. The form using `tt(%)'
+will remove the same matches as for `tt(#)', but in reverse order, and the
+form using `tt(%%)' will remove the same matches as for `tt(##)' in reverse
+order.
 )
 item(tt(B))(
 Include the index of the beginning of the match in the result.
@@ -750,9 +882,15 @@ Include the index of the beginning of the match in the result.
 item(tt(E))(
 Include the index of the end of the match in the result.
 )
+item(tt(M))(
+Include the matched portion in the result.
+)
 item(tt(N))(
 Include the length of the match in the result.
 )
+item(tt(R))(
+Include the unmatched portion in the result (the em(R)est).
+)
 enditem()
 
 subsect(Rules)
@@ -824,7 +962,7 @@ Note that the `tt((F))' flag implicitly supplies a string for joining in this
 manner.
 )
 item(tt(8.) em(Forced Splitting))(
-If one of the `tt((s))' or `tt((f))' flags are present, or the `tt(=)'
+If one of the `tt((s))', `tt((f))' or `tt((z))' flags are present, or the `tt(=)'
 specifier was present (e.g. tt(${=)var(var)tt(})), the word is split on
 occurrences of the specified string, or (for tt(=) with neither of the two
 flags present) any of the characters in tt($IFS).
@@ -833,17 +971,34 @@ item(tt(9.) em(Shell Word Splitting))(
 If no `tt((s))', `tt((f))' or `tt(=)' was given, but the word is not
 quoted and the option tt(SH_WORD_SPLIT) is set, the word is split on
 occurrences of any of the characters in tt($IFS).  Note this step, too,
-take place at all levels of a nested substitution.
+takes place at all levels of a nested substitution.
 )
-item(tt(10.) em(Re-Evaluation))(
+item(tt(10.) em(Uniqueness))(
+If the result is an array and the `tt((u))' flag was present, duplicate
+elements are removed from the array.
+)
+item(tt(11.) em(Ordering))(
+If the result is still an array and one of the `tt((o))' or `tt((O))' flags
+was present, the array is reordered.
+)
+item(tt(12.) em(Re-Evaluation))(
 Any `tt((e))' flag is applied to the value, forcing it to be re-examined
 for new parameter substitutions, but also for command and arithmetic
 substitutions.
 )
-item(tt(11.) em(Padding))(
+item(tt(13.) em(Padding))(
 Any padding of the value by the `tt(LPAR()l.)var(fill)tt(.RPAR())' or
 `tt(LPAR()r.)var(fill)tt(.RPAR())' flags is applied.
 )
+item(tt(14.) em(Semantic Joining))(
+In contexts where expansion semantics requires a single word to
+result, all words are rejoined with the first character of tt(IFS)
+between.  So in `tt(${LPAR()P)tt(RPAR()${LPAR()f)tt(RPAR()lines}})'
+the value of tt(${lines}) is split at newlines, but then must be
+joined again before the tt(P) flag can be applied.
+
+If a single word is not required, this rule is skipped.
+)
 enditem()
 
 subsect(Examples)
@@ -867,7 +1022,7 @@ that this is a scalar, so that (despite the `tt((@))' flag) the subscript
 picks the first character. 
 )
 item(tt("${${(@)foo}[1]}"))(
-The produces the result `tt(bar)'.  In this case, the inner substitution
+This produces the result `tt(bar)'.  In this case, the inner substitution
 tt("${(@)foo}") produces the array `tt(LPAR()bar baz)tt(RPAR())'.  The outer
 substitution tt("${...[1]}") detects that this is an array and picks the
 first word.  This is similar to the simple case tt("${foo[1]}").
@@ -1006,11 +1161,9 @@ tt($OLDPWD) are never abbreviated in this fashion.
 If a word begins with an unquoted `tt(=)'
 and the tt(EQUALS) option is set,
 the remainder of the word is taken as the
-name of a command or alias.  If a command
+name of a command.  If a command
 exists by that name, the word is replaced
 by the full pathname of the command.
-If an alias exists by that name, the word
-is replaced with the text of the alias.
 
 Filename expansion is performed on the right hand side of a parameter
 assignment, including those appearing after commands of the
@@ -1028,7 +1181,6 @@ first `tt(=)' also inhibits this.
 texinode(Filename Generation)()(Filename Expansion)(Expansion)
 sect(Filename Generation)
 cindex(filename generation)
-cindex(globbing)
 If a word contains an unquoted instance of one of the characters
 `tt(*)', `tt(LPAR())', `tt(|)', `tt(<)', `tt([)', or `tt(?)', it is regarded
 as a pattern for filename generation, unless the tt(GLOB) option is unset.
@@ -1068,9 +1220,11 @@ Matches any of the enclosed characters.  Ranges of characters
 can be specified by separating two characters by a `tt(-)'.
 A `tt(-)' or `tt(])' may be matched by including it as the
 first character in the list.
+cindex(character classes)
 There are also several named classes of characters, in the form
 `tt([:)var(name)tt(:])' with the following meanings:  `tt([:alnum:])'
 alphanumeric, `tt([:alpha:])' alphabetic,
+`tt([:ascii:])' 7-bit,
 `tt([:blank:])' space or tab,
 `tt([:cntrl:])' control character, `tt([:digit:])' decimal
 digit, `tt([:graph:])' printable character except whitespace,
@@ -1096,6 +1250,14 @@ Matches any number in the range var(x) to var(y), inclusive.
 Either of the numbers may be omitted to make the range open-ended;
 hence `tt(<->)' matches any number.  To match individual digits, the
 tt([)...tt(]) form is more efficient.
+
+Be careful when using other wildcards adjacent to patterns of this form;
+for example, tt(<0-9>*) will actually match any number whatsoever at the
+start of the string, since the `tt(<0-9>)' will match the first digit, and
+the `tt(*)' will match any others.  This is a trap for the unwary, but is
+in fact an inevitable consequence of the rule that the longest possible
+match always succeeds.  Expressions such as `tt(<0-9>[^[:digit:]]*)' can be
+used instead.
 )
 item(tt(LPAR())...tt(RPAR()))(
 Matches the enclosed pattern.  This is used for grouping.
@@ -1186,7 +1348,7 @@ The precedence of the operators given above is (highest) `tt(^)', `tt(/)',
 `tt(~)', `tt(|)' (lowest); the
 remaining operators are simply treated from left to right as part of a
 string, with `tt(#)' and `tt(##)' applying to the shortest possible
-preceeding unit (i.e. a character, `tt(?)', `tt([)...tt(])',
+preceding unit (i.e. a character, `tt(?)', `tt([)...tt(])',
 `tt(<)...tt(>)', or a parenthesised expression).  As mentioned
 above, a `tt(/)' used as a directory separator may not appear inside
 parentheses, while a `tt(|)' must do so; in patterns used in other contexts
@@ -1298,6 +1460,42 @@ item(tt(a)var(num))(
 Approximate matching: var(num) errors are allowed in the string matched by
 the pattern.  The rules for this are described in the next subsection.
 )
+item(tt(s), tt(e))(
+Unlike the other flags, these have only a local effect, and each must
+appear on its own:  `tt((#s))' and `tt((#e))' are the only valid forms.
+The `tt((#s))' flag succeeds only at the start of the test string, and the
+`tt((#e))' flag succeeds only at the end of the test string; they
+correspond to `tt(^)' and `tt($)' in standard regular expressions.  They
+are useful for matching path segments in patterns other than those in
+filename generation (where path segments are in any case treated
+separately).  For example, `tt(*((#s)|/)test((#e)|/)*)' matches a path
+segment `tt(test)' in any of the following strings: tt(test),
+tt(test/at/start), tt(at/end/test), tt(in/test/middle).
+
+Another use is in parameter substitution; for example
+`tt(${array/(#s)A*Z(#e)})' will remove only elements of an array which
+match the complete pattern `tt(A*Z)'.  There are other ways of performing
+many operations of this type, however the combination of the substitution
+operations `tt(/)' and `tt(//)' with the `tt((#s))' and `tt((#e))' flags
+provides a single simple and memorable method.
+
+Note that assertions of the form `tt((^(#s)))' also work, i.e. match
+anywhere except at the start of the string, although this actually means
+`anything except a zero-length portion at the start of the string'; you
+need to use `tt((""~(#s)))' to match a zero-length portion of the string
+not at the start.
+)
+item(tt(q))(
+A `tt(q)' and everything up to the closing parenthesis of the globbing
+flags are ignored by the pattern matching code.  This is intended to
+support the use of glob qualifiers, see below.  The result is that
+the pattern `tt((#b)(*).c(#q.))' can be used both for globbing and for
+matching against a string.  In the former case, the `tt((#q.))' will be
+treated as a glob qualifier and the `tt((#b))' will not be useful, while in
+the latter case the `tt((#b))' is useful for backreferences and the
+`tt((#q.))' will be ignored.  Note that colon modifiers in the glob
+qualifiers are also not applied in ordinary pattern matching.
+)
 enditem()
 
 For example, the test string tt(fooxx) can be matched by the pattern
@@ -1374,6 +1572,13 @@ crucial one for establishing whether to use approximation; for example,
 tt((#a1)abc(#a0)xyz) will not match tt(abcdxyz), because the error occurs
 at the `tt(x)', where approximation is turned off.
 
+Entire path segments may be matched approximately, so that
+`tt((#a1)/foo/d/is/available/at/the/bar)' allows one error in any path
+segment.  This is much less efficient than without the tt((#a1)), however,
+since every directory in the path must be scanned for a possible
+approximate match.  It is best to place the tt((#a1)) after any path
+segments which are known to be correct.
+
 subsect(Recursive Globbing)
 A pathname component of the form `tt(LPAR())var(foo)tt(/RPAR()#)'
 matches a path consisting of zero or more directories
@@ -1391,10 +1596,11 @@ or
 example(ls **/bar)
 
 does a recursive directory search for files named `tt(bar)' (potentially
-including the file `tt(bar)' in the current directory), not following
-symbolic links.  To follow links, use `tt(***/)'.  Neither of these can be
-combined with other forms of globbing within the same filename segment; in
-that case, the `tt(*)' operators revert to their usual effect.
+including the file `tt(bar)' in the current directory).  This form does not
+follow symbolic links; the alternative form `tt(***/)' does, but is
+otherwise identical.  Neither of these can be combined with other forms of
+globbing within the same path segment; in that case, the `tt(*)'
+operators revert to their usual effect.
 subsect(Glob Qualifiers)
 cindex(globbing, qualifiers)
 cindex(qualifiers, globbing)
@@ -1409,7 +1615,22 @@ containing no `tt(|)' or `tt(LPAR())' characters (or `tt(~)' if it is special)
 is taken as a set of
 glob qualifiers.  A glob subexpression that would normally be taken as glob
 qualifiers, for example `tt((^x))', can be forced to be treated as part of
-the glob pattern by doubling the parentheses, for example `tt(((^x)))'.
+the glob pattern by doubling the parentheses, in this case producing
+`tt(((^x)))'.
+
+If the option tt(EXTENDED_GLOB) is set, a different syntax for glob
+qualifiers is available, namely `tt((#qx))' where tt(x) is any of the same
+glob qualifiers used in the other format.  The qualifiers must still appear
+at the end of the pattern.  However, with this syntax multiple glob
+qualifiers may be chained together.  They are treated as a logical AND of
+the individual sets of flags.  Also, as the syntax is unambiguous, the
+expression will be treated as glob qualifiers just as long any parentheses
+contained within it are balanced; appearance of `tt(|)', `tt(LPAR())' or
+`tt(~)' does not negate the effect.  Note that qualifiers will be
+recognised in this form even if a bare glob qualifier exists at the end of
+the pattern, for example `tt(*(#q*)(.))' will recognise executable regular
+files if both options are set; however, mixed syntax should probably be
+avoided for the sake of clarity.
 
 A qualifier may be any one of the following:
 
@@ -1417,6 +1638,12 @@ startitem()
 item(tt(/))(
 directories
 )
+item(tt(F))(
+`full' (i.e. non-empty) directories.  Note that the
+opposite sense tt(LPAR()^F)tt(RPAR()) expands to empty directories
+and all non-directories.  Use tt(LPAR()/^F)tt(RPAR()) for
+empty directories
+)
 item(tt(.))(
 plain files
 )
@@ -1494,11 +1721,11 @@ If the qualifier `tt(f)' is followed by any other character anything
 up to the next matching character (`tt([)', `tt({)', and `tt(<)' match 
 `tt(])', `tt(})', and `tt(>)' respectively, any other character
 matches itself) is taken as a list of comma-separated
-var(sub-spec)s. Each var(sub-spec) may be either a octal number as
+var(sub-spec)s. Each var(sub-spec) may be either an octal number as
 described above or a list of any of the characters `tt(u)', `tt(g)',
 `tt(o)', and `tt(a)', followed by a `tt(=)', a `tt(PLUS())', or a
 `tt(-)', followed by a list of any of the characters `tt(r)', `tt(w)', 
-`tt(x)', `tt(s)', and `tt(t)', or a octal digit. The first list of
+`tt(x)', `tt(s)', and `tt(t)', or an octal digit. The first list of
 characters specify which access rights are to be checked. If a `tt(u)'
 is given, those for the owner of the file are used, if a `tt(g)' is
 given, those of the group are checked, a `tt(o)' means to test those
@@ -1520,30 +1747,50 @@ the owner and the other members of the group have at least write
 permission, and for which other users don't have read or execute
 permission.
 )
-item(tt(e)var(string))(
-The var(string) will be executed and the return value determines if the
-filename should be included in the list (if it is zero) or not (if it
-is non-zero). The first character after the `tt(e)' will be used as a
-separator and anything up to the next matching separator will be taken 
-as the var(string) (`tt([)', `tt({)', and `tt(<)' match `tt(])',
-`tt(})', and `tt(>)' respectively, any other character matches
-itself). Note that expansions have to be quoted in the var(string) to
-prevent them from being expanded before globbing is done.
-
-During the execution of var(string) the parameter tt(REPLY) is set to
-the filename currently being tested. It may also be set to any string
-to make this string be inserted into the list instead of the original
-filename. Also, the parameter tt(reply) may be set to an array or a
-string and if it is, these strings will be inserted instead of the
-value of the tt(REPLY) parameter. For security reasons, tt(reply)
-will be unset by the shell before the var(string) is executed.
+xitem(tt(e)var(string))
+item(tt(PLUS())var(cmd))(
+The var(string) will be executed as shell code.  The filename will be
+included in the list if and only if the code returns a zero status (usually
+the status of the last command).  The first character after the `tt(e)'
+will be used as a separator and anything up to the next matching separator
+will be taken  as the var(string); `tt([)', `tt({)', and `tt(<)' match
+`tt(])', `tt(})', and `tt(>)', respectively, while any other character
+matches itself. Note that expansions must be quoted in the var(string)
+to prevent them from being expanded before globbing is done.
+
+vindex(REPLY, use of)
+vindex(reply, use of)
+During the execution of var(string) the filename currently being tested is
+available in the parameter tt(REPLY); the parameter may be altered to
+a string to be inserted into the list instead of the original
+filename.  In addition, the parameter tt(reply) may be set to an array or a
+string, which overrides the value of tt(REPLY).  If set to an array, the
+latter is inserted into the command line word by word.
+
+For example, suppose a directory contains a single file `tt(lonely)'.  Then
+the expression `tt(*(e:'reply=(${REPLY}{1,2})':))' will cause the words
+`tt(lonely1 lonely2)' to be inserted into the command line.  Note the
+quotation marks.
+
+The form tt(PLUS())var(cmd) has the same effect, but no delimiters appear
+around var(cmd).  Instead, var(cmd) is taken as the longest sequence of
+characters following the tt(PLUS()) that are alphanumeric or underscore.
+Typically var(cmd) will be the name of a shell function that contains the
+appropriate test.  For example,
+
+example(nt() { [[ $REPLY -nt $NTREF ]] }
+NTREF=reffile
+ls -l *(+nt))
+
+lists all files in the directory that have been modified more recently than
+tt(reffile).
 )
 item(tt(d)var(dev))(
 files on the device var(dev)
 )
 item(tt(l)[tt(-)|tt(PLUS())]var(ct))(
 files having a link count less than var(ct) (tt(-)), greater than
-var(ct) (tt(PLUS())), or is equal to var(ct)
+var(ct) (tt(PLUS())), or equal to var(ct)
 )
 item(tt(U))(
 files owned by the effective user ID
@@ -1618,19 +1865,24 @@ pindex(NUMERIC_GLOB_SORT, setting in pattern)
 )
 item(tt(o)var(c))(
 specifies how the names of the files should be sorted. If var(c) is
-tt(n) they are sorted by name (the default), if it is tt(L) they
-are sorted depending on the size (length) of the files, if tt(l) 
-they are sorted by the number of links, and if tt(a), tt(m), and tt(c)
+tt(n) they are sorted by name (the default); if it is tt(L) they
+are sorted depending on the size (length) of the files; if tt(l) 
+they are sorted by the number of links; if tt(a), tt(m), or tt(c)
 they are sorted by the time of the last access, modification, or
-inode change respectively. Note that tt(a), tt(m), and tt(c) compare
-the age against the current time, hence the first name in the list is the 
-the youngest file. Also note that the modifiers tt(^) and tt(-) are 
-used, so `tt(*(^-oL))' gives a list of all files sorted by file size in 
-descending order, following any symbolic links.
+inode change respectively; if tt(d), files in subdirectories appear before
+those in the current directory at each level of the search --- this is best
+combined with other criteria, for example `tt(odon)' to sort on names for
+files within the same directory.  Note that tt(a), tt(m), and tt(c) compare
+the age against the current time, hence the first name in the list is the
+youngest file. Also note that the modifiers tt(^) and tt(-) are used,
+so `tt(*(^-oL))' gives a list of all files sorted by file size in descending
+order, following any symbolic links.
 )
 item(tt(O)var(c))(
 like `tt(o)', but sorts in descending order; i.e. `tt(*(^oc))' is the
-same as `tt(*(Oc))' and `tt(*(^Oc))' is the same as `tt(*(oc))'
+same as `tt(*(Oc))' and `tt(*(^Oc))' is the same as `tt(*(oc))'; `tt(Od)'
+puts files in the current directory before those in subdirectories at each
+level of the search.
 )
 item(tt([)var(beg)[tt(,)var(end)]tt(]))(
 specifies which of the matched filenames should be included in the
@@ -1644,7 +1896,11 @@ enditem()
 
 More than one of these lists can be combined, separated by commas. The
 whole list matches if at least one of the sublists matches (they are
-`or'ed, the qualifiers in the sublists are `and'ed).
+`or'ed, the qualifiers in the sublists are `and'ed).  Some qualifiers,
+however, affect all matches generated, independent of the sublist in
+which they are given.  These are the qualifiers `tt(M)', `tt(T)',
+`tt(N)', `tt(D)', `tt(n)', `tt(o)', `tt(O)' and the subscripts given
+in brackets (`tt([...])').
 
 If a `tt(:)' appears in a qualifier list, the remainder of the expression in
 parenthesis is interpreted as a modifier (see noderef(Modifiers)
@@ -1679,3 +1935,11 @@ example(ls *.*~(lex|parse).[ch](^D^l1))
 lists all files having a link count of one whose names contain a dot
 (but not those starting with a dot, since tt(GLOB_DOTS) is explicitly
 switched off) except for tt(lex.c), tt(lex.h), tt(parse.c) and tt(parse.h).
+
+example(print b*.pro(#q:s/pro/shmo/)(#q.:s/builtin/shmiltin/))
+
+demonstrates how colon modifiers and other qualifiers may be chained
+together.  The ordinary qualifier `tt(.)' is applied first, then the colon
+modifiers in order from left to right.  So if tt(EXTENDED_GLOB) is set and
+the base pattern matches the regular file tt(builtin.pro), the shell will
+print `tt(shmiltin.shmo)'.
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 820774173..048cba576 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -2,6 +2,7 @@ texinode(Zsh Line Editor)(Completion Widgets)(Shell Builtin Commands)(Top)
 chapter(Zsh Line Editor)
 cindex(line editor)
 cindex(editor, line)
+cindex(ZLE)
 sect(Description)
 pindex(ZLE, use of)
 If the tt(ZLE) option is set (which it is by default in interactive shells)
@@ -19,6 +20,22 @@ cindex(editor ksh style)
 This mode
 is similar to bf(ksh), and uses no termcap sequences.  If tt(TERM) is
 "emacs", the tt(ZLE) option will be unset by default.
+
+vindex(BAUD, use of)
+vindex(COLUMNS, use of)
+vindex(LINES, use of)
+The parameters tt(BAUD), tt(COLUMNS), and tt(LINES) are also used by the
+line editor.
+ifzman(See em(Parameters Used By The Shell) in zmanref(zshparam))\
+ifnzman(noderef(Parameters Used By The Shell)).
+
+startmenu()
+menu(Keymaps)
+menu(Zle Builtins)
+menu(Zle Widgets)
+endmenu()
+
+texinode(Keymaps)(Zle Builtins)()(Zsh Line Editor)
 sect(Keymaps)
 cindex(keymaps)
 cindex(key bindings)
@@ -77,6 +94,465 @@ and the command reading process starts again using these fake keystrokes.
 This input can itself invoke further replacement strings, but in order to
 detect loops the process will be stopped if there are twenty such replacements
 without a real command being read.
+
+texinode(Zle Builtins)(Zle Widgets)(Keymaps)(Zsh Line Editor)
+sect(Zle Builtins)
+cindex(zle, builtin commands)
+The ZLE module contains three related builtin commands. The tt(bindkey)
+command manipulates keymaps and key bindings; the tt(vared) command invokes
+ZLE on the value of a shell parameter; and the tt(zle) command manipulates
+editing widgets and allows command line access to ZLE commands from within
+shell functions.
+
+startitem()
+findex(bindkey)
+cindex(keys, rebinding)
+cindex(rebinding keys)
+cindex(keys, binding)
+cindex(binding keys)
+cindex(keymaps)
+xitem(tt(bindkey) [ var(options) ] tt(-l))
+xitem(tt(bindkey) [ var(options) ] tt(-d))
+xitem(tt(bindkey) [ var(options) ] tt(-D) var(keymap) ...)
+xitem(tt(bindkey) [ var(options) ] tt(-A) var(old-keymap new-keymap))
+xitem(tt(bindkey) [ var(options) ] tt(-N) var(new-keymap) [ var(old-keymap) ])
+xitem(tt(bindkey) [ var(options) ] tt(-m))
+xitem(tt(bindkey) [ var(options) ] tt(-r) var(in-string) ...)
+xitem(tt(bindkey) [ var(options) ] tt(-s) var(in-string out-string) ...)
+xitem(tt(bindkey) [ var(options) ] var(in-string command) ...)
+item(tt(bindkey) [ var(options) ] [ var(in-string) ])(
+tt(bindkey)'s options can be divided into three categories: keymap selection,
+operation selection, and others.  The keymap selection options are:
+
+startitem()
+item(tt(-e))(
+Selects keymap `tt(emacs)', and also links it to `tt(main)'.
+)
+item(tt(-v))(
+Selects keymap `tt(viins)', and also links it to `tt(main)'.
+)
+item(tt(-a))(
+Selects keymap `tt(vicmd)'.
+)
+item(tt(-M) var(keymap))(
+The var(keymap) specifies a keymap name.
+)
+enditem()
+
+If a keymap selection is required and none of the options above are used, the
+`tt(main)' keymap is used.  Some operations do not permit a keymap to be
+selected, namely:
+
+startitem()
+item(tt(-l))(
+List all existing keymap names.  If the tt(-L)
+option is also used, list in the form of tt(bindkey)
+commands to create the keymaps.
+)
+item(tt(-d))(
+Delete all existing keymaps and reset to the default state.
+)
+item(tt(-D) var(keymap) ...)(
+Delete the named var(keymap)s.
+)
+item(tt(-A) var(old-keymap new-keymap))(
+Make the var(new-keymap) name an alias for var(old-keymap), so that
+both names refer to the same keymap.  The names have equal standing;
+if either is deleted, the other remains.  If there is already a keymap
+with the var(new-keymap) name, it is deleted.
+)
+item(tt(-N) var(new-keymap) [ var(old-keymap) ])(
+Create a new keymap, named var(new-keymap).  If a keymap already has that
+name, it is deleted.  If an var(old-keymap) name is given, the new keymap
+is initialized to be a duplicate of it, otherwise the new keymap will
+be empty.
+)
+enditem()
+
+To use a newly created keymap, it should be linked to tt(main).  Hence
+the sequence of commands to create and use a new keymap `tt(mymap)'
+initialized from the tt(emacs) keymap (which remains unchanged) is:
+
+example(bindkey -N mymap emacs
+bindkey -A mymap main)
+
+Note that while `tt(bindkey -A) var(newmap) tt(main)' will work when
+var(newmap) is tt(emacs) or tt(viins), it will not work for tt(vicmd), as
+switching from vi insert to command mode becomes impossible.
+
+The following operations act on the `tt(main)' keymap if no keymap
+selection option was given:
+
+startitem()
+item(tt(-m))(
+Add the built-in set of meta-key bindings to the selected keymap.
+Only keys that are unbound or bound to tt(self-insert) are affected.
+)
+item(tt(-r) var(in-string) ...)(
+Unbind the specified var(in-string)s in the selected keymap.
+This is exactly equivalent to binding the strings to tt(undefined-key).
+
+When tt(-R) is also used, interpret the var(in-string)s as ranges.
+
+When tt(-p) is also used, the var(in-string)s specify prefixes.  Any
+binding that has the given var(in-string) as a prefix, not including the
+binding for the var(in-string) itself, if any, will be removed.  For
+example,
+
+example(bindkey -rpM viins '^[')
+
+will remove all bindings in the vi-insert keymap beginning with an escape
+character (probably cursor keys), but leave the binding for the escape
+character itself (probably tt(vi-cmd-mode)).  This is incompatible with the
+option tt(-R).
+)
+item(tt(-s) var(in-string out-string) ...)(
+Bind each var(in-string) to each var(out-string).
+When var(in-string) is typed, var(out-string) will be
+pushed back and treated as input to the line editor.
+When tt(-R) is also used, interpret the var(in-string)s as ranges.
+)
+item(var(in-string command) ...)(
+Bind each var(in-string) to each var(command).
+When tt(-R) is used, interpret the var(in-string)s as ranges.
+)
+item([ var(in-string) ])(
+List key bindings.  If an var(in-string) is specified, the binding of
+that string in the selected keymap is displayed.  Otherwise, all key
+bindings in the selected keymap are displayed.  (As a special case,
+if the tt(-e) or tt(-v) option is used alone, the keymap is em(not)
+displayed - the implicit linking of keymaps is the only thing that
+happens.)
+
+When the option tt(-p) is used, the var(in-string) must be present.
+The listing shows all bindings which have the given key sequence as a
+prefix, not including any bindings for the key sequence itself.
+
+When the tt(-L) option is used, the list is in the form of tt(bindkey)
+commands to create the key bindings.
+)
+enditem()
+
+When the tt(-R) option is used as noted above, a valid range consists of
+two characters, with an optional `tt(-)' between them.  All characters
+between the two specified, inclusive, are bound as specified.
+
+For either var(in-string) or var(out-string), the following
+escape sequences are recognised:
+
+startsitem()
+sitem(tt(\a))(bell character)
+sitem(tt(\b))(backspace)
+sitem(tt(\e), tt(\E))(escape)
+sitem(tt(\f))(form feed)
+sitem(tt(\n))(linefeed (newline))
+sitem(tt(\r))(carriage return)
+sitem(tt(\t))(horizontal tab)
+sitem(tt(\v))(vertical tab)
+sitem(tt(\)var(NNN))(character code in octal)
+sitem(tt(\x)var(NN))(character code in hexadecimal)
+sitem(tt(\M)[tt(-)]var(X))(character with meta bit set)
+sitem(tt(\C)[tt(-)]var(X))(control character)
+sitem(tt(^)var(X))(control character)
+endsitem()
+
+In all other cases, `tt(\)' escapes the following character.  Delete is
+written as `tt(^?)'.  Note that `tt(\M^?)' and `tt(^\M?)' are not the same,
+and that (unlike emacs), the bindings `tt(\M-)var(X)' and `tt(\e)var(X)'
+are entirely distinct, although they are initialized to the same bindings
+by `tt(bindkey -m)'.
+)
+findex(vared)
+cindex(parameters, editing)
+cindex(editing parameters)
+xitem(tt(vared) [ tt(-Aache) ] [ tt(-p) var(prompt) ] [ tt(-r) var(rprompt) ])
+item(  [ -M var(main-keymap) ] [ -m var(vicmd-keymap) ] var(name))(
+The value of the parameter var(name) is loaded into the edit
+buffer, and the line editor is invoked.  When the editor exits,
+var(name) is set to the string value returned by the editor.
+When the tt(-c) flag is given, the parameter is created if it doesn't
+already exist.  The tt(-a) flag may be given with tt(-c) to create
+an array parameter, or the tt(-A) flag to create an associative array.
+If the type of an existing parameter does not match the type to be
+created, the parameter is unset and recreated.
+
+If an array or array slice is being edited, separator characters as defined
+in tt($IFS) will be shown quoted with a backslash, as will backslashes
+themselves.  Conversely, when the edited text is split into an array, a
+backslash quotes an immediately following separator character or backslash;
+no other special handling of backslashes, or any handling of quotes, is
+performed.
+
+Individual elements of existing array or associative array parameters
+may be edited by using subscript syntax on var(name).  New elements are
+created automatically, even without tt(-c).
+
+If the tt(-p) flag is given, the following string will be taken as
+the prompt to display at the left.  If the tt(-r) flag is given,
+the following string gives the prompt to display at the right.  If the
+tt(-h) flag is specified, the history can be accessed from ZLE. If the
+tt(-e) flag is given, typing tt(^D) (Control-D) on an empty line
+causes tt(vared) to exit immediately with a non-zero return value.
+
+The tt(-M) option gives a keymap to link to the tt(main) keymap during
+editing, and the tt(-m) option gives a keymap to link to the tt(vicmd)
+keymap during editing.  For vi-style editing, this allows a pair of keymaps
+to override tt(viins) and tt(vicmd).  For emacs-style editing, only tt(-M)
+is normally needed but the tt(-m) option may still be used.  On exit, the
+previous keymaps will be restored.
+)
+findex(zle)
+cindex(widgets, rebinding)
+cindex(rebinding widgets)
+cindex(widgets, binding)
+cindex(binding widgets)
+cindex(widgets, invoking)
+cindex(invoking widgets)
+cindex(widgets, calling)
+cindex(calling widgets)
+cindex(widgets, defining)
+cindex(defining widgets)
+xitem(tt(zle))
+xitem(tt(zle) tt(-l) [ tt(-L) | tt(-a) ] [ var(string) ... ])
+xitem(tt(zle) tt(-D) var(widget) ...)
+xitem(tt(zle) tt(-A) var(old-widget) var(new-widget))
+xitem(tt(zle) tt(-N) var(widget) [ var(function) ])
+xitem(tt(zle) tt(-C) var(widget) var(completion-widget) var(function))
+xitem(tt(zle) tt(-R) [ tt(-c) ] [ var(display-string) ] [ var(string) ... ])
+xitem(tt(zle) tt(-M) var(string))
+xitem(tt(zle) tt(-U) var(string))
+xitem(tt(zle) tt(-K) var(keymap))
+xitem(tt(zle) tt(-F) [ tt(-L) ] [ var(fd) [ var(handler) ] ])
+xitem(tt(zle) tt(-I))
+item(tt(zle) var(widget) tt([ -n) var(num) tt(]) tt([ -N ]) var(args) ...)(
+The tt(zle) builtin performs a number of different actions concerning
+ZLE.
+
+With no options and no arguments, only the return status will be
+set.  It is zero if ZLE is currently active and widgets could be
+invoked using this builtin command and non-zero otherwise.
+Note that even if non-zero status is returned, zle may still be active as
+part of the completion system; this does not allow direct calls to ZLE
+widgets.
+
+Otherwise, which operation it performs depends on its options:
+
+startitem()
+item(tt(-l) [ tt(-L) | tt(-a) ])(
+List all existing user-defined widgets.  If the tt(-L)
+option is used, list in the form of tt(zle)
+commands to create the widgets.
+
+When combined with the tt(-a) option, all widget names are listed,
+including the builtin ones. In this case the tt(-L) option is ignored.
+
+If at least one var(string) is given, nothing will be printed but the
+return status will be zero if all var(string)s are names of existing
+widgets (or of user-defined widgets if the tt(-a) flag is not given)
+and non-zero if at least one var(string) is not a name of an defined
+widget.
+)
+item(tt(-D) var(widget) ...)(
+Delete the named var(widget)s.
+)
+item(tt(-A) var(old-widget) var(new-widget))(
+Make the var(new-widget) name an alias for var(old-widget), so that
+both names refer to the same widget.  The names have equal standing;
+if either is deleted, the other remains.  If there is already a widget
+with the var(new-widget) name, it is deleted.
+)
+item(tt(-N) var(widget) [ var(function) ])(
+Create a user-defined widget.  If there is already a widget with the
+specified name, it is overwritten.  When the new
+widget is invoked from within the editor, the specified shell var(function)
+is called.  If no function name is specified, it defaults to
+the same name as the widget.  For further information, see the section
+em(Widgets) in
+ifzman(zmanref(zshzle))\
+ifnzman(noderef(Zsh Line Editor))\
+.
+)
+cindex(completion widgets, creating)
+item(tt(-C) var(widget) var(completion-widget) var(function))(
+Create a user-defined completion widget named var(widget). The 
+completion widget will behave like the built-in completion-widget
+whose name is given as var(completion-widget). To generate the
+completions, the shell function var(function) will be called.
+For further information, see
+ifzman(zmanref(zshcompwid))\
+ifnzman(noderef(Completion Widgets))\
+.
+)
+item(tt(-R) [ tt(-c) ] [ var(display-string) ] [ var(string) ... ])(
+Redisplay the command line; this is to be called from within a user-defined
+widget to allow changes to become visible.  If a var(display-string) is
+given and not empty, this is shown in the status line (immediately
+below the line being edited).
+
+If the optional var(string)s are given they are listed below the
+prompt in the same way as completion lists are printed. If no
+var(string)s are given but the tt(-c) option is used such a list is
+cleared.
+
+Note that this option is only useful for widgets that do not exit
+immediately after using it because the strings displayed will be erased 
+immediately after return from the widget.
+
+This command can safely be called outside user defined widgets; if zle is
+active, the display will be refreshed, while if zle is not active, the
+command has no effect.  In this case there will usually be no other
+arguments.
+
+The status is zero if zle was active, else one.
+)
+item(tt(-M) var(string))(
+As with the tt(-R) option, the var(string) will be displayed below the 
+command line; unlike the tt(-R) option, the string will not be put into
+the status line but will instead be printed normally below the
+prompt.  This means that the var(string) will still be displayed after
+the widget returns (until it is overwritten by subsequent commands).
+)
+item(tt(-U) var(string))(
+This pushes the characters in the var(string) onto the input stack of
+ZLE.  After the widget currently executed finishes ZLE will behave as
+if the characters in the var(string) were typed by the user.
+
+As ZLE uses a stack, if this option is used repeatedly
+the last string pushed onto the stack will be processed first.  However,
+the characters in each var(string) will be processed in the order in which
+they appear in the string.
+)
+item(tt(-K) var(keymap))(
+Selects the keymap named var(keymap).  An error message will be displayed if
+there is no such keymap.
+
+This keymap selection affects the interpretation of following keystrokes
+within this invocation of ZLE.  Any following invocation (e.g., the next
+command line) will start as usual with the `tt(main)' keymap selected.
+)
+item(tt(-F) [ tt(-L) ] [ var(fd) [ var(handler) ] ])(
+Only available if your system supports one of the `poll' or `select' system
+calls; most modern systems do.
+
+Installs var(handler) (the name of a shell function) to handle input from
+file descriptor var(fd).  When zle is attempting to read data, it will
+examine both the terminal and the list of handled var(fd)'s.  If data
+becomes available on a handled var(fd), zle will call var(handler) with
+the fd which is ready for reading as the only argument.  If the handler
+produces output to the terminal, it should call `tt(zle -I)' before doing
+so (see below).  The handler should not attempt to read from the terminal.
+Note that zle makes no attempt to check whether this fd is actually
+readable when installing the handler.  The user must make their own
+arrangements for handling the file descriptor when zle is not active.
+
+Any number of handlers for any number of readable file descriptors may be
+installed.  Installing a handler for an var(fd) which is already handled
+causes the existing handler to be replaced.
+
+If no var(handler) is given, but an var(fd) is present, any handler for
+that var(fd) is removed.  If there is none, an error message is printed
+and status 1 is returned.
+
+If no arguments are given, or the tt(-L) option is supplied, a list of
+handlers is printed in a form which can be stored for later execution.
+
+An var(fd) (but not a var(handler)) may optionally be given with the tt(-L)
+option; in this case, the function will list the handler if any, else
+silently return status 1.
+
+Note that this feature should be used with care.  Activity on one of the
+var(fd)'s which is not properly handled can cause the terminal to become
+unusable.
+
+Here is a simple example of using this feature.  A connection to a remote
+TCP port is created using the ztcp command; see 
+ifzman(the description of the tt(zsh/net/tcp) module in zmanref(zshmodules))\
+ifnzman(noderef(The zsh/net/tcp Module)).  Then a handler is installed
+which simply prints out any data which arrives on this connection.  Note
+that `select' will indicate that the file descriptor needs handling
+if the remote side has closed the connection; we handle that by testing
+for a failed read.
+example(if ztcp pwspc 2811; then
+  tcpfd=$REPLY
+  handler() {
+    zle -I
+    local line
+    if ! read -r line <&$1; then
+      # select marks this fd if we reach EOF,
+      # so handle this specially.
+      print "[Read on fd $1 failed, removing.]" >&2
+      zle -F $1
+      return 1
+    fi
+    print -r - $line
+  }
+  zle -F $tcpfd handler
+fi)
+)
+item(tt(-I))(
+Unusually, this option is most useful outside ordinary widget functions,
+though it may be used within if normal output to the terminal is required.
+It invalidates the current zle display in preparation for output; typically
+this will be from a trap function.  It has no effect if zle is not
+active.  When a trap exits, the shell checks to see if the display needs
+restoring, hence the following will print output in such a way as not to
+disturb the line being edited:
+
+example(TRAPUSR1() {
+    # Invalidate zle display
+  [[ -o zle ]] && zle -I
+    # Show output
+  print Hello
+})
+
+In general, the trap function may need to test whether zle is active before
+using this method (as shown in the example), since the tt(zsh/zle) module
+may not even be loaded; if it is not, the command can be skipped.
+
+It is possible to call `tt(zle -I)' several times before control is
+returned to the editor; the display will only be invalidated the first time
+to minimise disruption.
+
+Note that there are normally better ways of manipulating the display from
+within zle widgets; see, for example, `tt(zle -R)' above.
+
+The returned status is zero if zle was invalidated, even though
+this may have been by a previous call to `tt(zle -I)' or by a system
+notification.  To test if a zle widget may be called at this point, execute
+tt(zle) with no arguments and examine the return status.
+)
+item(var(widget) tt([ -n) var(num) tt(]) tt([ -N ]) var(args) ...)(
+Invoke the specified widget.  This can only be done when ZLE is
+active; normally this will be within a user-defined widget.
+
+With the options tt(-n) and tt(-N), the current numerical argument will be
+saved and then restored after the call to tt(widget); `tt(-n) var(num)'
+sets the numerical argument temporarily to var(num), while `tt(-N)' sets it
+to the default, i.e. as if there were none.
+
+Any further arguments will be passed to the widget.  If it is a shell
+function, these are passed down as positional parameters; for builtin
+widgets it is up to the widget in question what it does with them.
+Currently arguments are only handled by the incremental-search commands,
+the tt(history-search-forward) and tt(-backward) and the corresponding
+functions prefixed by tt(vi-), and by tt(universal-argument).  No error is
+flagged if the command does not use the arguments, or only uses some of
+them.
+
+The return status reflects the success or failure of the operation carried
+out by the widget, or if it is a user-defined widget the return status of
+the shell function.  
+
+A non-zero return status causes the shell to beep when the widget exits,
+unless the tt(BEEP) options was unset or the widget was called via the
+tt(zle) command.  Thus if a user defined widget requires an immediate beep,
+it should call the tt(beep) widget directly.
+)
+enditem()
+)
+enditem()
+
+texinode(Zle Widgets)()(Zle Builtins)(Zsh Line Editor)
 sect(Widgets)
 cindex(widgets)
 All actions in the editor are performed by `widgets'.  A widget's job is
@@ -103,8 +579,10 @@ cindex(widgets, user-defined)
 User-defined widgets, being implemented as shell functions,
 can execute any normal shell command.  They can also run other widgets
 (whether built-in or user-defined) using the tt(zle) builtin command.
-They can use tt(read -k) or tt(read -q) to read characters from standard
-input.  Finally, they can examine and edit the ZLE buffer being edited by
+The standard input of the function is closed to prevent external commands
+from unintentionally blocking ZLE by reading from the terminal, but
+tt(read -k) or tt(read -q) can be used to read characters.  Finally,
+they can examine and edit the ZLE buffer being edited by
 reading and setting the special parameters described below.
 
 cindex(parameters, editor)
@@ -125,6 +603,31 @@ The entire contents of the edit buffer.  If it is written to, the
 cursor remains at the same offset, unless that would put it outside the
 buffer.
 )
+vindex(BUFFERLINES)
+item(tt(BUFFERLINES) (integer))(
+The number of screen lines needed for the edit buffer currently
+displayed on screen (i.e. without any changes to the preceding
+parameters done after the last redisplay); read-only.
+)
+vindex(CONTEXT)
+item(tt(CONTEXT) (scalar))(
+The context in which zle was called to read a line; read-only.  One of
+the values:
+startitem()
+item(start)(
+The start of a command line (at prompt tt(PS1)).
+)
+item(cont)(
+A continuation to a command line (at prompt tt(PS2)).
+)
+item(select)(
+In a tt(select) loop.
+)
+item(vared)(
+Editing a variable in tt(vared).
+)
+enditem()
+)
 vindex(CURSOR)
 item(tt(CURSOR) (integer))(
 The offset of the cursor, within the edit buffer.  This is in the range
@@ -132,9 +635,50 @@ The offset of the cursor, within the edit buffer.  This is in the range
 Attempts to move the cursor outside the buffer will result in the
 cursor being moved to the appropriate end of the buffer.
 )
-vindex(MARK)
-item(tt(MARK) (integer))(
-Like tt(CURSOR), but for the mark.
+vindex(CUTBUFFER)
+item(tt(CUTBUFFER) (scalar))(
+The last item to be cut using one of the `tt(kill-)' commands; the
+string which the next yank would insert in the line.
+)
+vindex(HISTNO)
+item(tt(HISTNO) (integer))(
+The current history number.  Setting this has the same effect as
+moving up or down in the history to the corresponding history line.
+An attempt to set it is ignored if the line is not stored in the
+history.  Note this is not the same as the parameter tt(HISTCMD),
+which always gives the number of the history line being added to the main
+shell's history.  tt(HISTNO) refers to the line being retrieved within
+zle.
+)
+vindex(KEYMAP)
+item(tt(KEYMAP) (scalar))(
+The name of the currently selected keymap; read-only.
+)
+vindex(KEYS)
+item(tt(KEYS) (scalar))(
+The keys typed to invoke this widget, as a literal string; read-only.
+)
+vindex(killring)
+item(tt(killring) (array))(
+The array of previously killed items, with the most recently killed first.
+This gives the items that would be retrieved by a tt(yank-pop) in the
+same order.
+
+The default size for the kill ring is eight, however the length may be
+changed by normal array operations.  Any empty string in the kill ring is
+ignored by the tt(yank-pop) command, hence the size of the array
+effectively sets the maximum length of the kill ring, while the number of
+non-zero strings gives the current length, both as seen by the user at the
+command line.
+)
+
+vindex(LASTSEARCH)
+item(tt(LASTSEARCH) (scalar))(
+The last search string used by an interactive search ; read-only.
+)
+vindex(LASTWIDGET)
+item(tt(LASTWIDGET) (scalar))(
+The name of the last widget that was executed; read-only.
 )
 vindex(LBUFFER)
 item(tt(LBUFFER) (scalar))(
@@ -142,17 +686,24 @@ The part of the buffer that lies to the left of the cursor position.
 If it is assigned to, only that part of the buffer is replaced, and the
 cursor remains between the new tt($LBUFFER) and the old tt($RBUFFER).
 )
-vindex(RBUFFER)
-item(tt(RBUFFER) (scalar))(
-The part of the buffer that lies to the right of the cursor position.
-If it is assigned to, only that part of the buffer is replaced, and the
-cursor remains between the old tt($LBUFFER) and the new tt($RBUFFER).
+vindex(MARK)
+item(tt(MARK) (integer))(
+Like tt(CURSOR), but for the mark.
 )
-vindex(BUFFERLINES)
-item(tt(BUFFERLINES))(
-The number of screen lines needed for the edit buffer currently
-displayed on screen (i.e. without any changes to the preceding
-parameters done after the last redisplay).
+vindex(NUMERIC)
+item(tt(NUMERIC) (integer))(
+The numeric argument. If no numeric argument was given, this parameter
+is unset. When this is set inside a widget function, builtin widgets
+called with the tt(zle) builtin command will use the value
+assigned. If it is unset inside a widget function, builtin widgets
+called behave as if no numeric argument was given.
+)
+vindex(PENDING)
+item(tt(PENDING) (integer))(
+The number of bytes pending for input, i.e. the number of bytes which have
+already been typed and can immediately be read. On systems where the shell
+is not able to get this information, this parameter will always have a
+value of zero.  Read-only.
 )
 vindex(PREBUFFER)
 item(tt(PREBUFFER) (scalar))(
@@ -160,37 +711,85 @@ In a multi-line input at the secondary prompt, this read-only parameter
 contains the contents of the lines before the one the cursor is
 currently in.
 )
-vindex(WIDGET)
-item(tt(WIDGET) (scalar))(
-The name of the widget currently being executed.
+vindex(PREDISPLAY)
+item(tt(PREDISPLAY) (scalar))(
+Text to be displayed before the start of the editable text buffer.  This
+does not have to be a complete line; to display a complete line, a newline
+must be appended explicitly.    The text is reset on each new invocation
+(but not recursive invocation) of zle.
 )
-vindex(LASTWIDGET)
-item(tt(LASTWIDGET) (scalar))(
-The name of the last widget that was executed.
+vindex(POSTDISPLAY)
+item(tt(POSTDISPLAY) (scalar))(
+Text to be displayed after the end of the editable text buffer.  This
+does not have to be a complete line; to display a complete line, a newline
+must be prepended explicitly.  The text is reset on each new invocation
+(but not recursive invocation) of zle.
 )
-vindex(KEYS)
-item(tt(KEYS) (scalar))(
-The keys typed to invoke this widget, as a literal string.
+vindex(RBUFFER)
+item(tt(RBUFFER) (scalar))(
+The part of the buffer that lies to the right of the cursor position.
+If it is assigned to, only that part of the buffer is replaced, and the
+cursor remains between the old tt($LBUFFER) and the new tt($RBUFFER).
 )
-vindex(NUMERIC)
-item(tt(NUMERIC) (integer))(
-The numeric argument. If no numeric argument was given, this parameter
-is unset. When this is set inside a widget function, builtin widgets
-called with the tt(zle) builtin command will use the value
-assigned. If it is unset inside a widget function, builtin widgets
-called behave as if no numeric argument was given.
+vindex(WIDGET)
+item(tt(WIDGET) (scalar))(
+The name of the widget currently being executed; read-only.
+)
+vindex(WIDGETFUNC)
+item(tt(WIDGETFUNC) (scalar))(
+The name of the shell function that implements a widget defined with
+either tt(zle -N) or tt(zle -C).  In the former case, this is the second
+argument to the tt(zle -N) command that defined the widget, or
+the first argument if there was no second argument.  In the latter case
+this is the the third argument to the tt(zle -C) command that defined the
+widget.  Read-only.
+)
+vindex(WIDGETSTYLE)
+item(tt(WIDGETSTYLE) (scalar))(
+Describes the implementation behind the completion widget currently being
+executed; the second argument that followed tt(zle -C) when the widget was
+defined.  This is the name of a builtin completion widget.  For widgets
+defined with tt(zle -N) this is set to the empty string.  Read-only.
 )
-vindex(HISTNO)
-item(tt(HISTNO) (integer))(
-The current history number.
+enditem()
+
+subsect(Special Widget)
+
+There is one user-defined widget which is special to the shell.
+If it does not exist, no special action is taken.  The environment
+provided is identical to that for any other editing widget.
+
+startitem()
+tindex(zle-line-init)
+item(tt(zle-line-init))(
+Executed every time the line editor is started to read a new line
+of input.  The following example puts the line editor into vi command
+mode when it starts up.
+
+example(zle-line-init() { zle -K vicmd; }
+zle -N zle-line-init)
+
+(The command inside the function sets the keymap directly; it is
+equivalent to tt(zle vi-cmd-mode).)
 )
 enditem()
+
 sect(Standard Widgets)
 cindex(widgets, standard)
 The following is a list of all the standard widgets,
 and their default bindings in emacs mode,
 vi command mode and vi insert mode
 (the `tt(emacs)', `tt(vicmd)' and `tt(viins)' keymaps, respectively).
+
+Note that cursor keys are bound to movement keys in all three keymaps;
+the shell assumes that the cursor keys send the key sequences reported
+by the terminal-handling library (termcap or terminfo).  The key sequences
+shown in the list are those based on the VT100, common on many modern
+terminals, but in fact these are not necessarily bound.  In the case of the
+tt(viins) keymap, the initial escape character of the sequences serves also
+to return to the tt(vicmd) keymap: whether this happens is determined by
+the tt(KEYTIMEOUT) parameter, see ifzman(zmanref(zshparam))\
+ifnzman(noderef(Parameters)).
 startmenu()
 menu(Movement)
 menu(History Control)
@@ -199,7 +798,7 @@ menu(Arguments)
 menu(Completion)
 menu(Miscellaneous)
 endmenu()
-texinode(Movement)(History Control)()(Zsh Line Editor)
+texinode(Movement)(History Control)()(Zle Widgets)
 subsect(Movement)
 startitem()
 tindex(vi-backward-blank-word)
@@ -212,7 +811,7 @@ item(tt(backward-char) (^B ESC-[D) (unbound) (unbound))(
 Move backward one character.
 )
 tindex(vi-backward-char)
-item(tt(vi-backward-char) (unbound) (^H h ^?) (unbound))(
+item(tt(vi-backward-char) (unbound) (^H h ^?) (ESC-[D))(
 Move backward one character, without changing lines.
 )
 tindex(backward-word)
@@ -263,7 +862,7 @@ item(tt(forward-char) (^F ESC-[C) (unbound) (unbound))(
 Move forward one character.
 )
 tindex(vi-forward-char)
-item(tt(vi-forward-char) (unbound) (space l) (unbound))(
+item(tt(vi-forward-char) (unbound) (space l) (ESC-[C))(
 Move forward one character.
 )
 tindex(vi-find-next-char)
@@ -329,7 +928,7 @@ item(tt(vi-rev-repeat-find) (unbound) (,) (unbound))(
 Repeat the last tt(vi-find) command in the opposite direction.
 )
 enditem()
-texinode(History Control)(Modifying Text)(Movement)(Zsh Line Editor)
+texinode(History Control)(Modifying Text)(Movement)(Zle Widgets)
 subsect(History Control)
 startitem()
 tindex(beginning-of-buffer-or-history)
@@ -347,7 +946,7 @@ item(tt(beginning-of-history))(
 Move to the first event in the history list.
 )
 tindex(down-line-or-history)
-item(tt(down-line-or-history) (^N ESC-[B) (j) (unbound))(
+item(tt(down-line-or-history) (^N ESC-[B) (j) (ESC-[B))(
 Move down a line in the buffer, or if already at the bottom line,
 move to the next event in the history list.
 )
@@ -526,6 +1125,37 @@ left (zero inserts the previous command word).  Repeating this command
 replaces the word just inserted with the last word from the
 history event prior to the one just used; numeric arguments can be used in
 the same way to pick a word from that event.
+
+When called from a shell function invoked from a user-defined widget, the
+command can take one to three arguments.  The first argument specifies a
+history offset which applies to successive calls to this widget: if is -1,
+the default behaviour is used, while if it is 1, successive calls will move
+forwards through the history.  The value 0 can be used to indicate that the
+history line examined by the previous execution of the command will be
+reexamined.  Note that negative numbers should be preceded with a
+`tt(-)tt(-)' argument to avoid confusing them with options.
+
+If two arguments are given, the second specifies the word on the command
+line in normal array index notation (as a more natural alternative to the
+prefix argument).  Hence 1 is the first word, and -1 (the default) is the
+last word.
+
+If a third argument is given, its value is ignored, but it is used to
+signify that the history offset is relative to the current history line,
+rather than the one remembered after the previous invocations of
+tt(insert-last-word).
+
+For example, the default behaviour of the command corresponds to
+
+example(zle insert-last-word -- -1 -1)
+
+while the command
+
+example(zle insert-last-word -- -1 1 -)
+
+always copies the first word of the line in the history immediately before
+the line being edited.  This has the side effect that later invocations of
+the widget will be relative to that line.
 )
 tindex(vi-repeat-search)
 item(tt(vi-repeat-search) (unbound) (n) (unbound))(
@@ -536,7 +1166,7 @@ item(tt(vi-rev-repeat-search) (unbound) (N) (unbound))(
 Repeat the last vi history search, but in reverse.
 )
 tindex(up-line-or-history)
-item(tt(up-line-or-history) (^P ESC-[A) (k) (unbound))(
+item(tt(up-line-or-history) (^P ESC-[A) (k) (ESC-[A))(
 Move up a line in the buffer, or if already at the top line,
 move to the previous event in the history list.
 )
@@ -567,7 +1197,7 @@ line up to the cursor.
 This leaves the cursor in its original position.
 )
 enditem()
-texinode(Modifying Text)(Arguments)(History Control)(Zsh Line Editor)
+texinode(Modifying Text)(Arguments)(History Control)(Zle Widgets)
 subsect(Modifying Text)
 startitem()
 tindex(vi-add-eol)
@@ -630,7 +1260,13 @@ Copy the area from the cursor to the mark to the kill buffer.
 )
 tindex(copy-prev-word)
 item(tt(copy-prev-word) (ESC-^_) (unbound) (unbound))(
-Duplicate the word behind the cursor.
+Duplicate the word to the left of the cursor.
+)
+tindex(copy-prev-shell-word)
+item(tt(copy-prev-shell-word))(
+Like tt(copy-prev-word), but the word is found by using shell parsing, 
+whereas tt(copy-prev-word) looks for blanks. This makes a difference
+when the word is quoted and contains spaces.
 )
 tindex(vi-delete)
 item(tt(vi-delete) (unbound) (d) (unbound))(
@@ -845,7 +1481,7 @@ into the kill buffer.
 Arguably, this is what Y should do in vi, but it isn't what it actually does.
 )
 enditem()
-texinode(Arguments)(Completion)(Modifying Text)(Zsh Line Editor)
+texinode(Arguments)(Completion)(Modifying Text)(Zle Widgets)
 subsect(Arguments)
 startitem()
 tindex(digit-argument)
@@ -858,7 +1494,7 @@ Inside a widget function, a call to this function treats the last key of
 the key sequence which called the widget as the digit.
 )
 tindex(neg-argument)
-item(tt(neg-argument) (ESC--) (unbound) (unbound))(
+item(tt(neg-argument) (ESC-DASH()) (unbound) (unbound))(
 Changes the sign of the following argument.
 )
 tindex(universal-argument)
@@ -876,7 +1512,7 @@ universal-argument) var(num)', the numerical argument will be set to
 var(num); this is equivalent to `tt(NUMERIC=)var(num)'.
 )
 enditem()
-texinode(Completion)(Miscellaneous)(Arguments)(Zsh Line Editor)
+texinode(Completion)(Miscellaneous)(Arguments)(Zle Widgets)
 subsect(Completion)
 startitem()
 tindex(accept-and-menu-complete)
@@ -951,7 +1587,7 @@ When a previous completion displayed a list below the prompt, this
 widget can be used to move the prompt below the list.
 )
 enditem()
-texinode(Miscellaneous)()(Completion)(Zsh Line Editor)
+texinode(Miscellaneous)()(Completion)(Zle Widgets)
 subsect(Miscellaneous)
 startitem()
 tindex(accept-and-hold)
@@ -1034,10 +1670,14 @@ possibilities if the tt(AUTO_LIST) option is set.
 Any other character that is not bound to tt(self-insert) or
 tt(self-insert-unmeta) will beep and be ignored.
 The bindings of the current insert mode will be used.
+
+Currently this command may not be redefined or called by name.
 )
 tindex(execute-last-named-cmd)
 item(tt(execute-last-named-cmd) (ESC-z) (unbound) (unbound))(
 Redo the last function executed with tt(execute-named-cmd).
+
+Currently this command may not be redefined or called by name.
 )
 tindex(get-line)
 item(tt(get-line) (ESC-G ESC-g) (unbound) (unbound))(
@@ -1085,10 +1725,66 @@ At a secondary (tt(PS2)) prompt, move the entire current multiline
 construct into the editor buffer.
 The latter is equivalent to tt(push-input) followed by tt(get-line).
 )
+tindex(recursive-edit)
+item(tt(recursive-edit))(
+Only useful from a user-defined widget.  At this point in the function,
+the editor regains control until one of the standard widgets which would
+normally cause zle to exit (typically an tt(accept-line) caused by
+hitting the return key) is executed.  Instead, control returns to the
+user-defined widget.  The status returned is non-zero if the return was
+caused by an error, but the function still continues executing and hence
+may tidy up.  This makes it safe for the user-defined widget to alter
+the command line or key bindings temporarily.
+
+
+The following widget, tt(caps-lock), serves as an example.
+example(self-insert-ucase() {
+  LBUFFER+=${(U)KEYS[-1]}
+}
+
+integer stat
+
+zle -N self-insert self-insert-ucase
+zle -A caps-lock save-caps-lock
+zle -A accept-line caps-lock
+
+zle recursive-edit
+stat=$?
+
+zle -A .self-insert self-insert
+zle -A save-caps-lock caps-lock
+zle -D save-caps-lock
+
+(( stat )) && zle send-break
+
+return $stat
+)
+This causes typed letters to be inserted capitalised until either
+tt(accept-line) (i.e. typically the return key) is typed or the
+tt(caps-lock) widget is invoked again; the later is handled by saving
+the old definition of tt(caps-lock) as tt(save-caps-lock) and then
+rebinding it to invoke tt(accept-line).  Note that an error from the
+recursive edit is detected as a non-zero return status and propagated by
+using the tt(send-break) widget.
+)
 tindex(redisplay)
 item(tt(redisplay) (unbound) (^R) (^R))(
 Redisplays the edit buffer.
 )
+tindex(reset-prompt)
+item(tt(reset-prompt) (unbound) (unbound) (unbound))(
+Force the prompts on both the left and right of the screen to be
+re-expanded, then redisplay the edit buffer.  This
+reflects changes both to the prompt variables themselves and changes
+in the expansion of the values (for example, changes in time or
+directory, or changes to the value of variables referred to by the
+prompt).
+
+Otherwise, the prompt is only expanded each time zle starts, and
+when the display as been interrupted by output from another part of the
+shell (such as a job notification) which causes the command line to be
+reprinted.
+)
 tindex(send-break)
 item(tt(send-break) (^G ESC-^G) (unbound) (unbound))(
 Abort the current editor function, e.g. tt(execute-named-command), or the
@@ -1099,7 +1795,7 @@ tindex(run-help)
 item(tt(run-help) (ESC-H ESC-h) (unbound) (unbound))(
 Push the buffer onto the buffer stack, and execute the
 command `tt(run-help) var(cmd)', where var(cmd) is the current
-command.  tt(run-help) is normally aliased to var(man).
+command.  tt(run-help) is normally aliased to tt(man).
 )
 tindex(vi-set-buffer)
 item(tt(vi-set-buffer) (unbound) (") (unbound))(
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index aa5086597..41b837ea9 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -30,6 +30,13 @@
 #include "zle.mdh"
 #include "zle_main.pro"
 
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#endif
+#if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM)
+# undef HAVE_POLL
+#endif
+
 /* != 0 if in a shell function called from completion, such that read -[cl]  *
  * will work (i.e., the line is metafied, and the above word arrays are OK). */
 
@@ -51,6 +58,11 @@ mod_export int hascompmod;
 /**/
 int zlereadflags;
 
+/* ZLCON_* flags passed to zleread() */
+
+/**/
+int zlecontext;
+
 /* != 0 if we're done editing */
 
 /**/
@@ -64,7 +76,7 @@ int mark;
 /* last character pressed */
 
 /**/
-int c;
+mod_export int lastchar;
 
 /* the bindings for the previous and for this key */
 
@@ -76,13 +88,17 @@ mod_export Thingy lbindk, bindk;
 /**/
 int insmode;
 
-static int eofchar, eofsent;
+/**/
+mod_export int eofchar;
+
+static int eofsent;
 static long keytimeout;
 
-#ifdef HAVE_SELECT
+#if defined(HAVE_SELECT) || defined(HAVE_POLL)
 /* Terminal baud rate */
 
 static int baud;
+static long costmult;
 #endif
 
 /* flags associated with last command */
@@ -96,9 +112,9 @@ mod_export Widget compwidget;
 /* the status line, and its length */
 
 /**/
-char *statusline;
+mod_export char *statusline;
 /**/
-int statusll;
+mod_export int statusll;
 
 /* The current history line and cursor position for the top line *
  * on the buffer stack.                                          */
@@ -134,10 +150,23 @@ int kungetct;
 /**/
 mod_export char *zlenoargs[1] = { NULL };
 
+static char **raw_lp, **raw_rp;
+
 #ifdef FIONREAD
 static int delayzsetterm;
 #endif
 
+/*
+ * File descriptors we are watching as well as the terminal fd. 
+ * These are all for reading; we don't watch for writes or exceptions.
+ */
+/**/
+int nwatch;		/* Number of fd's we are watching */
+/**/
+int *watch_fds;		/* The list of fds, not terminated! */
+/**/
+char **watch_funcs;	/* The corresponding functions to call, normal array */
+
 /* set up terminal */
 
 /**/
@@ -313,6 +342,7 @@ breakread(int fd, char *buf, int n)
 
     FD_ZERO(&f);
     FD_SET(fd, &f);
+
     return (select(fd + 1, (SELECT_ARG_2_T) & f, NULL, NULL, NULL) == -1 ?
 	    EOF : read(fd, buf, n));
 }
@@ -320,82 +350,269 @@ breakread(int fd, char *buf, int n)
 # define read    breakread
 #endif
 
-/**/
-mod_export int
-getkey(int keytmout)
+static int
+raw_getkey(int keytmout, char *cptr)
 {
-    char cc;
-    unsigned int ret;
     long exp100ths;
-    int die = 0, r, icnt = 0;
-    int old_errno = errno, obreaks = breaks;
-
-#ifdef HAVE_SELECT
-    fd_set foofd;
-
-#else
-# ifdef HAS_TIO
+    int ret;
+#if defined(HAS_TIO) && \
+  (defined(sun) || (!defined(HAVE_POLL) && !defined(HAVE_SELECT)))
     struct ttyinfo ti;
-
+#endif
+#ifndef HAVE_POLL
+# ifdef HAVE_SELECT
+    fd_set foofd;
 # endif
 #endif
 
-    if (kungetct)
-	ret = STOUC(kungetbuf[--kungetct]);
-    else {
-#ifdef FIONREAD
-	if (delayzsetterm) {
-	    int val;
-	    ioctl(SHTTY, FIONREAD, (char *)&val);
-	    if (!val)
-		zsetterm();
-	}
-#endif
-	if (keytmout
+    /*
+     * Handle timeouts and watched fd's.  We only do one at once;
+     * key timeouts take precedence.  This saves tricky timing
+     * problems with the key timeout.
+     */
+    if ((nwatch || keytmout)
 #ifdef FIONREAD
-	    && ! delayzsetterm
+	&& ! delayzsetterm
 #endif
-	    ) {
-	    if (keytimeout > 500)
-		exp100ths = 500;
-	    else if (keytimeout > 0)
-		exp100ths = keytimeout;
+	) {
+	if (!keytmout || keytimeout <= 0)
+	    exp100ths = 0;
+	else if (keytimeout > 500)
+	    exp100ths = 500;
+	else
+	    exp100ths = keytimeout;
+#if defined(HAVE_SELECT) || defined(HAVE_POLL)
+	if (!keytmout || exp100ths) {
+	    int i, errtry = 0, selret;
+# ifdef HAVE_POLL
+	    int poll_timeout;
+	    int nfds;
+	    struct pollfd *fds;
+# else
+	    int fdmax;
+	    struct timeval *tvptr;
+	    struct timeval expire_tv;
+# endif
+# if defined(HAS_TIO) && defined(sun)
+	    /*
+	     * Yes, I know this is complicated.  Yes, I know we
+	     * already have three bits of code to poll the terminal
+	     * down below.  No, I don't want to do this either.
+	     * However, it turns out on certain OSes, specifically
+	     * Solaris, that you can't poll typeahead for love nor
+	     * money without actually trying to read it.  But
+	     * if we are trying to select (and we need to if we
+	     * are watching other fd's) we won't pick that up.
+	     * So we just try and read it without blocking in
+	     * the time-honoured (i.e. absurdly baroque) termios
+	     * fashion.
+	     */
+	    gettyinfo(&ti);
+	    ti.tio.c_cc[VMIN] = 0;
+	    settyinfo(&ti);
+	    ret = read(SHTTY, cptr, 1);
+	    ti.tio.c_cc[VMIN] = 1;
+	    settyinfo(&ti);
+	    if (ret > 0)
+		return 1;
+# endif
+# ifdef HAVE_POLL
+	    nfds = keytmout ? 1 : 1 + nwatch;
+	    /* First pollfd is SHTTY, following are the nwatch fds */
+	    fds = zalloc(sizeof(struct pollfd) * nfds);
+	    if (exp100ths)
+		poll_timeout = exp100ths * 10;
 	    else
-		exp100ths = 0;
-#ifdef HAVE_SELECT
+		poll_timeout = -1;
+
+	    fds[0].fd = SHTTY;
+	    /*
+	     * POLLIN, POLLIN, POLLIN,
+	     * Keep those fd's POLLIN...
+	     */
+	    fds[0].events = POLLIN;
+	    if (!keytmout) {
+		for (i = 0; i < nwatch; i++) {
+		    fds[i+1].fd = watch_fds[i];
+		    fds[i+1].events = POLLIN;
+		}
+	    }
+# else
+	    fdmax = SHTTY;
+	    tvptr = NULL;
 	    if (exp100ths) {
-		struct timeval expire_tv;
-
 		expire_tv.tv_sec = exp100ths / 100;
 		expire_tv.tv_usec = (exp100ths % 100) * 10000L;
+		tvptr = &expire_tv;
+	    }
+# endif
+	    do {
+# ifdef HAVE_POLL
+		selret = poll(fds, errtry ? 1 : nfds, poll_timeout);
+# else
 		FD_ZERO(&foofd);
 		FD_SET(SHTTY, &foofd);
-		if (select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
-			   NULL, NULL, &expire_tv) <= 0)
-		    return EOF;
-	    }
+		if (!keytmout && !errtry) {
+		    for (i = 0; i < nwatch; i++) {
+			int fd = watch_fds[i];
+			FD_SET(fd, &foofd);
+			if (fd > fdmax)
+			    fdmax = fd;
+		    }
+		}
+		selret = select(fdmax+1, (SELECT_ARG_2_T) & foofd,
+				NULL, NULL, tvptr);
+# endif
+		/*
+		 * Make sure a user interrupt gets passed on straight away.
+		 */
+		if (selret < 0 && errflag)
+		    break;
+		/*
+		 * Try to avoid errors on our special fd's from
+		 * messing up reads from the terminal.  Try first
+		 * with all fds, then try unsetting the special ones.
+		 */
+		if (selret < 0 && !keytmout && !errtry) {
+		    errtry = 1;
+		    continue;
+		}
+		if (selret == 0) {
+		    /* Special value -2 signals nothing ready */
+		    selret = -2;
+		}
+		if (selret < 0)
+		    break;
+		if (!keytmout && nwatch) {
+		    /*
+		     * Copy the details of the watch fds in case the
+		     * user decides to delete one from inside the
+		     * handler function.
+		     */
+		    int lnwatch = nwatch;
+		    int *lwatch_fds = zalloc(lnwatch*sizeof(int));
+		    char **lwatch_funcs = zarrdup(watch_funcs);
+		    memcpy(lwatch_fds, watch_fds, lnwatch*sizeof(int));
+		    for (i = 0; i < lnwatch; i++) {
+			if (
+# ifdef HAVE_POLL
+			    (fds[i+1].revents & POLLIN)
+# else
+			    FD_ISSET(lwatch_fds[i], &foofd)
+# endif
+			    ) {
+			    /* Handle the fd. */
+			    LinkList funcargs = znewlinklist();
+			    zaddlinknode(funcargs, ztrdup(lwatch_funcs[i]));
+			    {
+				char buf[BDIGBUFSIZE];
+				convbase(buf, lwatch_fds[i], 10);
+				zaddlinknode(funcargs, ztrdup(buf));
+			    }
+# ifdef HAVE_POLL
+#  ifdef POLLERR
+			    if (fds[i+1].revents & POLLERR)
+				zaddlinknode(funcargs, ztrdup("err"));
+#  endif
+#  ifdef POLLHUP
+			    if (fds[i+1].revents & POLLHUP)
+				zaddlinknode(funcargs, ztrdup("hup"));
+#  endif
+#  ifdef POLLNVAL
+			    if (fds[i+1].revents & POLLNVAL)
+				zaddlinknode(funcargs, ztrdup("nval"));
+#  endif
+# endif
+
+
+			    callhookfunc(lwatch_funcs[i], funcargs);
+			    if (errflag) {
+				/* No sensible way of handling errors here */
+				errflag = 0;
+				/*
+				 * Paranoia: don't run the hooks again this
+				 * time.
+				 */
+				errtry = 1;
+			    }
+			    freelinklist(funcargs, freestr);
+			}
+		    }
+		    /* Function may have invalidated the display. */
+		    if (resetneeded)
+			zrefresh();
+		    zfree(lwatch_fds, lnwatch*sizeof(int));
+		    freearray(lwatch_funcs);
+		}
+	    } while (!
+# ifdef HAVE_POLL
+		     (fds[0].revents & POLLIN)
+# else
+		     FD_ISSET(SHTTY, &foofd)
+# endif
+		);
+# ifdef HAVE_POLL
+	    zfree(fds, sizeof(struct pollfd) * nfds);
+# endif
+	    if (selret < 0)
+		return selret;
+	}
 #else
 # ifdef HAS_TIO
-	    ti = shttyinfo;
-	    ti.tio.c_lflag &= ~ICANON;
-	    ti.tio.c_cc[VMIN] = 0;
-	    ti.tio.c_cc[VTIME] = exp100ths / 10;
+	ti = shttyinfo;
+	ti.tio.c_lflag &= ~ICANON;
+	ti.tio.c_cc[VMIN] = 0;
+	ti.tio.c_cc[VTIME] = exp100ths / 10;
 #  ifdef HAVE_TERMIOS_H
-	    tcsetattr(SHTTY, TCSANOW, &ti.tio);
+	tcsetattr(SHTTY, TCSANOW, &ti.tio);
 #  else
-	    ioctl(SHTTY, TCSETA, &ti.tio);
+	ioctl(SHTTY, TCSETA, &ti.tio);
 #  endif
-	    r = read(SHTTY, &cc, 1);
+	ret = read(SHTTY, cptr, 1);
 #  ifdef HAVE_TERMIOS_H
-	    tcsetattr(SHTTY, TCSANOW, &shttyinfo.tio);
+	tcsetattr(SHTTY, TCSANOW, &shttyinfo.tio);
 #  else
-	    ioctl(SHTTY, TCSETA, &shttyinfo.tio);
+	ioctl(SHTTY, TCSETA, &shttyinfo.tio);
 #  endif
-	    return (r <= 0) ? EOF : cc;
+	return (ret <= 0) ? ret : *cptr;
 # endif
 #endif
+    }
+
+    ret = read(SHTTY, cptr, 1);
+
+    return ret;
+}
+
+/**/
+mod_export int
+getkey(int keytmout)
+{
+    char cc;
+    unsigned int ret;
+    int die = 0, r, icnt = 0;
+    int old_errno = errno, obreaks = breaks;
+
+    if (kungetct)
+	ret = STOUC(kungetbuf[--kungetct]);
+    else {
+#ifdef FIONREAD
+	if (delayzsetterm) {
+	    int val;
+	    ioctl(SHTTY, FIONREAD, (char *)&val);
+	    if (!val)
+		zsetterm();
 	}
-	while ((r = read(SHTTY, &cc, 1)) != 1) {
+#endif
+	for (;;) {
+	    int q = queue_signal_level();
+	    dont_queue_signals();
+	    r = raw_getkey(keytmout, &cc);
+	    restore_queue_signals(q);
+	    if (r == -2)	/* timeout */
+		return EOF;
+	    if (r == 1)
+		break;
 	    if (r == 0) {
 		/* The test for IGNOREEOF was added to make zsh ignore ^Ds
 		   that were typed while commands are running.  Unfortuantely
@@ -407,7 +624,7 @@ getkey(int keytmout)
 		   an infinite loop.  The simple way around this was to add
 		   the counter (icnt) so that this happens 20 times and than
 		   the shell gives up (yes, this is a bit dirty...). */
-		if (isset(IGNOREEOF) && icnt++ < 20)
+		if ((zlereadflags & ZLRF_IGNOREEOF) && icnt++ < 20)
 		    continue;
 		stopmsg = 1;
 		zexit(1, 0);
@@ -452,21 +669,101 @@ getkey(int keytmout)
     return ret;
 }
 
+/**/
+void
+zlecore(void)
+{
+#if !defined(HAVE_POLL) && defined(HAVE_SELECT)
+    struct timeval tv;
+    fd_set foofd;
+
+    FD_ZERO(&foofd);
+#endif
+
+    /*
+     * A widget function may decide to exit the shell.
+     * We never exit directly from functions, to allow
+     * the shell to tidy up, so we have to test for
+     * that explicitly.
+     */
+    while (!done && !errflag && !exit_pending) {
+
+	statusline = NULL;
+	vilinerange = 0;
+	reselectkeymap();
+	selectlocalmap(NULL);
+	bindk = getkeycmd();
+	if (bindk) {
+	    if (!ll && isfirstln && !(zlereadflags & ZLRF_IGNOREEOF) &&
+		lastchar == eofchar) {
+		/*
+		 * Slight hack: this relies on getkeycmd returning
+		 * a value for the EOF character.  However,
+		 * undefined-key is fine.  That's necessary because
+		 * otherwise we can't distinguish this case from
+		 * a ^C.
+		 */
+		eofsent = 1;
+		break;
+	    }
+	    if (execzlefunc(bindk, zlenoargs)) {
+		handlefeep(zlenoargs);
+		if (eofsent)
+		    break;
+	    }
+	    handleprefixes();
+	    /* for vi mode, make sure the cursor isn't somewhere illegal */
+	    if (invicmdmode() && cs > findbol() &&
+		(cs == ll || line[cs] == '\n'))
+		cs--;
+	    if (undoing)
+		handleundo();
+	} else {
+	    errflag = 1;
+	    break;
+	}
+#ifdef HAVE_POLL
+	if (baud && !(lastcmd & ZLE_MENUCMP)) {
+	    struct pollfd pfd;
+	    int to = cost * costmult / 1000; /* milliseconds */
+
+	    if (to > 500)
+		to = 500;
+	    pfd.fd = SHTTY;
+	    pfd.events = POLLIN;
+	    if (!kungetct && poll(&pfd, 1, to) <= 0)
+		zrefresh();
+	} else
+#else
+# ifdef HAVE_SELECT
+	if (baud && !(lastcmd & ZLE_MENUCMP)) {
+	    FD_SET(SHTTY, &foofd);
+	    tv.tv_sec = 0;
+	    if ((tv.tv_usec = cost * costmult) > 500000)
+		tv.tv_usec = 500000;
+	    if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
+				    NULL, NULL, &tv) <= 0)
+		zrefresh();
+	} else
+# endif
+#endif
+	    if (!kungetct)
+		zrefresh();
+    }
+}
+
 /* Read a line.  It is returned metafied. */
 
 /**/
 unsigned char *
-zleread(char *lp, char *rp, int flags)
+zleread(char **lp, char **rp, int flags, int context)
 {
     unsigned char *s;
     int old_errno = errno;
     int tmout = getiparam("TMOUT");
+    Thingy initthingy;
 
-#ifdef HAVE_SELECT
-    long costmult;
-    struct timeval tv;
-    fd_set foofd;
-
+#if defined(HAVE_POLL) || defined(HAVE_SELECT)
     baud = getiparam("BAUD");
     costmult = (baud) ? 3840000L / baud : 0;
 #endif
@@ -478,7 +775,8 @@ zleread(char *lp, char *rp, int flags)
 	char *pptbuf;
 	int pptlen;
 
-	pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen);
+	pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL),
+			  &pptlen);
 	write(2, (WRITE_ARG_2_T)pptbuf, pptlen);
 	free(pptbuf);
 	return (unsigned char *)shingetline();
@@ -504,18 +802,20 @@ zleread(char *lp, char *rp, int flags)
     insmode = unset(OVERSTRIKE);
     eofsent = 0;
     resetneeded = 0;
-    lpromptbuf = promptexpand(lp, 1, NULL, NULL);
+    raw_lp = lp;
+    lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL);
     pmpt_attr = txtchange;
-    rpromptbuf = promptexpand(rp, 1, NULL, NULL);
+    raw_rp = rp;
+    rpromptbuf = promptexpand(rp ? *rp : NULL, 1, NULL, NULL);
     rpmpt_attr = txtchange;
+    free_prepostdisplay();
 
     zlereadflags = flags;
+    zlecontext = context;
     histline = curhist;
-#ifdef HAVE_SELECT
-    FD_ZERO(&foofd);
-#endif
     undoing = 1;
     line = (unsigned char *)zalloc((linesz = 256) + 2);
+    *line = '\0';
     virangeflag = lastcmd = done = cs = ll = mark = 0;
     vichgflag = 0;
     viinsbegin = 0;
@@ -548,52 +848,26 @@ zleread(char *lp, char *rp, int flags)
     lastcol = -1;
     initmodifier(&zmod);
     prefixflag = 0;
+
     zrefresh();
-    while (!done && !errflag) {
 
-	statusline = NULL;
-	vilinerange = 0;
-	reselectkeymap();
-	selectlocalmap(NULL);
-	bindk = getkeycmd();
-	if (!ll && isfirstln && c == eofchar) {
-	    eofsent = 1;
-	    break;
-	}
-	if (bindk) {
-	    if (execzlefunc(bindk, zlenoargs))
-		handlefeep(zlenoargs);
-	    handleprefixes();
-	    /* for vi mode, make sure the cursor isn't somewhere illegal */
-	    if (invicmdmode() && cs > findbol() &&
-		(cs == ll || line[cs] == '\n'))
-		cs--;
-	    if (undoing)
-		handleundo();
-	} else {
-	    errflag = 1;
-	    break;
-	}
-#ifdef HAVE_SELECT
-	if (baud && !(lastcmd & ZLE_MENUCMP)) {
-	    FD_SET(SHTTY, &foofd);
-	    tv.tv_sec = 0;
-	    if ((tv.tv_usec = cost * costmult) > 500000)
-		tv.tv_usec = 500000;
-	    if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
-				    NULL, NULL, &tv) <= 0)
-		zrefresh();
-	} else
-#endif
-	    if (!kungetct)
-		zrefresh();
+    if ((initthingy = rthingy_nocreate("zle-line-init"))) {
+	char *args[2];
+	args[0] = initthingy->nam;
+	args[1] = NULL;
+	execzlefunc(initthingy, args);
+	unrefthingy(initthingy);
+	errflag = retflag = 0;
     }
+
+    zlecore();
+
     statusline = NULL;
     invalidatelist();
     trashzle();
     free(lpromptbuf);
     free(rpromptbuf);
-    zleactive = zlereadflags = lastlistlen = 0;
+    zleactive = zlereadflags = lastlistlen = zlecontext = 0;
     alarm(0);
 
     freeundo();
@@ -630,26 +904,49 @@ execzlefunc(Thingy func, char **args)
     } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) {
 	int wflags = w->flags;
 
-	if(!(wflags & ZLE_KEEPSUFFIX))
-	    removesuffix();
-	if(!(wflags & ZLE_MENUCMP)) {
-	    fixsuffix();
-	    invalidatelist();
+	/*
+	 * The rule is that "zle -N" widgets suppress EOF warnings.  When
+	 * a "zle -N" widget invokes "zle another-widget" we pass through
+	 * this code again, but with actual arguments rather than with the
+	 * zlenoargs placeholder.
+	 */
+	if (keybuf[0] == eofchar && !keybuf[1] && args == zlenoargs &&
+	    !ll && isfirstln && (zlereadflags & ZLRF_IGNOREEOF)) {
+	    showmsg((!islogin) ? "zsh: use 'exit' to exit." :
+		    "zsh: use 'logout' to logout.");
+	    eofsent = 1;
+	    ret = 1;
+	} else {
+	    if(!(wflags & ZLE_KEEPSUFFIX))
+		removesuffix();
+	    if(!(wflags & ZLE_MENUCMP)) {
+		fixsuffix();
+		invalidatelist();
+	    }
+	    if (wflags & ZLE_LINEMOVE)
+		vilinerange = 1;
+	    if(!(wflags & ZLE_LASTCOL))
+		lastcol = -1;
+	    if (wflags & WIDGET_NCOMP) {
+		int atcurhist = histline == curhist;
+		compwidget = w;
+		ret = completecall(args);
+		if (atcurhist)
+		    histline = curhist;
+	    } else if (!w->u.fn) {
+		handlefeep(zlenoargs);
+	    } else {
+		queue_signals();
+		ret = w->u.fn(args);
+		unqueue_signals();
+	    }
+	    if (!(wflags & ZLE_NOTCOMMAND))
+		lastcmd = wflags;
 	}
-	if (wflags & ZLE_LINEMOVE)
-	    vilinerange = 1;
-	if(!(wflags & ZLE_LASTCOL))
-	    lastcol = -1;
-	if (wflags & WIDGET_NCOMP) {
-	    compwidget = w;
-	    ret = completecall(args);
-	} else
-	    ret = w->u.fn(args);
-	if (!(wflags & ZLE_NOTCOMMAND))
-	    lastcmd = wflags;
 	r = 1;
     } else {
-	Eprog prog = getshfunc(w->u.fnnam);
+	Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, w->u.fnnam);
+	Eprog prog = (shf ? shf->funcdef : &dummy_eprog);
 
 	if(prog == &dummy_eprog) {
 	    /* the shell function doesn't exist */
@@ -661,7 +958,8 @@ execzlefunc(Thingy func, char **args)
 	    zsfree(msg);
 	    ret = 1;
 	} else {
-	    int osc = sfcontext, osi = movefd(0), olv = lastval;
+	    int osc = sfcontext, osi = movefd(0);
+	    int oxt = isset(XTRACE);
 	    LinkList largs = NULL;
 
 	    if (*args) {
@@ -673,9 +971,9 @@ execzlefunc(Thingy func, char **args)
 	    startparamscope();
 	    makezleparams(0);
 	    sfcontext = SFC_WIDGET;
-	    doshfunc(w->u.fnnam, prog, largs, 0, 0);
-	    ret = lastval;
-	    lastval = olv;
+	    opts[XTRACE] = 0;
+	    ret = doshfunc(w->u.fnnam, prog, largs, shf->flags, 1);
+	    opts[XTRACE] = oxt;
 	    sfcontext = osc;
 	    endparamscope();
 	    lastcmd = 0;
@@ -720,6 +1018,45 @@ handleprefixes(void)
 	initmodifier(&zmod);
 }
 
+/**/
+static int
+savekeymap(char *cmdname, char *oldname, char *newname, Keymap *savemapptr)
+{
+    Keymap km = openkeymap(newname);
+
+    if (km) {
+	*savemapptr = openkeymap(oldname);
+	/* I love special cases */
+	if (*savemapptr == km)
+	    *savemapptr = NULL;
+	else {
+	    /* make sure this doesn't get deleted. */
+	    if (*savemapptr)
+		refkeymap(*savemapptr);
+	    linkkeymap(km, oldname, 0);
+	}
+	return 0;
+    } else {
+	zwarnnam(cmdname, "no such keymap: %s", newname, 0);
+	return 1;
+    }
+}
+
+/**/
+static void
+restorekeymap(char *cmdname, char *oldname, char *newname, Keymap savemap)
+{
+    if (savemap) {
+	linkkeymap(savemap, oldname, 0);
+	/* we incremented the reference count above */
+	unrefkeymap(savemap);
+    } else if (newname) {
+	/* urr... can this happen? */
+	zwarnnam(cmdname,
+		 "keymap %s was not defined, not restored", oldname, 0);
+    }
+}
+
 /* this exports the argument we are currently vared'iting if != NULL */
 
 /**/
@@ -729,98 +1066,108 @@ mod_export char *varedarg;
 
 /**/
 static int
-bin_vared(char *name, char **args, char *ops, int func)
+bin_vared(char *name, char **args, Options ops, UNUSED(int func))
 {
     char *s, *t, *ova = varedarg;
     struct value vbuf;
     Value v;
     Param pm = 0;
-    int create = 0, ifl;
+    int ifl;
     int type = PM_SCALAR, obreaks = breaks, haso = 0;
-    char *p1 = NULL, *p2 = NULL;
+    char *p1, *p2, *main_keymapname, *vicmd_keymapname;
+    Keymap main_keymapsave = NULL, vicmd_keymapsave = NULL;
     FILE *oshout = NULL;
 
+    if ((interact && unset(USEZLE)) || !strcmp(term, "emacs")) {
+	zwarnnam(name, "ZLE not enabled", NULL, 0);
+	return 1;
+    }
     if (zleactive) {
 	zwarnnam(name, "ZLE cannot be used recursively (yet)", NULL, 0);
 	return 1;
     }
 
-    /* all options are handled as arguments */
-    while (*args && **args == '-') {
-	while (*++(*args))
-	    switch (**args) {
-	    case 'c':
-		/* -c option -- allow creation of the parameter if it doesn't
-		yet exist */
-		create = 1;
-		break;
-	    case 'a':
-		type = PM_ARRAY;
-		break;
-	    case 'A':
-		type = PM_HASHED;
-		break;
-	    case 'p':
-		/* -p option -- set main prompt string */
-		if ((*args)[1])
-		    p1 = *args + 1, *args = "" - 1;
-		else if (args[1])
-		    p1 = *(++args), *args = "" - 1;
-		else {
-		    zwarnnam(name, "prompt string expected after -%c", NULL,
-			     **args);
-		    return 1;
-		}
-		break;
-	    case 'r':
-		/* -r option -- set right prompt string */
-		if ((*args)[1])
-		    p2 = *args + 1, *args = "" - 1;
-		else if (args[1])
-		    p2 = *(++args), *args = "" - 1;
-		else {
-		    zwarnnam(name, "prompt string expected after -%c", NULL,
-			     **args);
-		    return 1;
-		}
-		break;
-	    case 'h':
-		/* -h option -- enable history */
-		ops['h'] = 1;
-		break;
-	    case 'e':
-		/* -e option -- enable EOF */
-		ops['e'] = 1;
-		break;
-	    default:
-		/* unrecognised option character */
-		zwarnnam(name, "unknown option: %s", *args, 0);
-		return 1;
-	    }
-	args++;
+    if (OPT_ISSET(ops,'A'))
+    {
+	if (OPT_ISSET(ops, 'a'))
+	{
+	    zwarnnam(name, "specify only one of -a and -A", NULL, 0);
+	    return 1;
+	}
+	type = PM_HASHED;
     }
-    if (type && !create) {
+    else if (OPT_ISSET(ops,'a'))
+	type = PM_ARRAY;
+    p1 = OPT_ARG_SAFE(ops,'p');
+    p2 = OPT_ARG_SAFE(ops,'r');
+    main_keymapname = OPT_ARG_SAFE(ops,'M');
+    vicmd_keymapname = OPT_ARG_SAFE(ops,'m');
+
+    if (type != PM_SCALAR && !OPT_ISSET(ops,'c')) {
 	zwarnnam(name, "-%s ignored", type == PM_ARRAY ? "a" : "A", 0);
     }
 
-    /* check we have a parameter name */
-    if (!*args) {
-	zwarnnam(name, "missing variable", NULL, 0);
-	return 1;
-    }
     /* handle non-existent parameter */
     s = args[0];
-    v = fetchvalue(&vbuf, &s, (!create || type == PM_SCALAR),
+    queue_signals();
+    v = fetchvalue(&vbuf, &s, (!OPT_ISSET(ops,'c') || type == PM_SCALAR),
 		   SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY);
-    if (!v && !create) {
+    if (!v && !OPT_ISSET(ops,'c')) {
+	unqueue_signals();
 	zwarnnam(name, "no such variable: %s", args[0], 0);
 	return 1;
     } else if (v) {
-	s = getstrvalue(v);
-	pm = v->pm;
+	if (v->isarr) {
+	    /* Array: check for separators and quote them. */
+	    char **arr = getarrvalue(v), **aptr, **tmparr, **tptr;
+	    tptr = tmparr = (char **)zhalloc(sizeof(char *)*(arrlen(arr)+1));
+	    for (aptr = arr; *aptr; aptr++) {
+		int sepcount = 0;
+		/*
+		 * See if this word contains a separator character
+		 * or backslash
+		 */
+		for (t = *aptr; *t; t++) {
+		    if (*t == Meta) {
+			if (isep(t[1] ^ 32))
+			    sepcount++;
+			t++;
+		    } else if (isep(*t) || *t == '\\')
+			sepcount++;
+		}
+		if (sepcount) {
+		    /* Yes, so allocate enough space to quote it. */
+		    char *newstr, *nptr;
+		    newstr = zhalloc(strlen(*aptr)+sepcount+1);
+		    /* Go through string quoting separators */
+		    for (t = *aptr, nptr = newstr; *t; ) {
+			if (*t == Meta) {
+			    if (isep(t[1] ^ 32))
+				*nptr++ = '\\';
+			    *nptr++ = *t++;
+			} else if (isep(*t) || *t == '\\')
+			    *nptr++ = '\\';
+			*nptr++ = *t++;
+		    }
+		    *nptr = '\0';
+		    /* Stick this into the array of words to join up */
+		    *tptr++ = newstr;
+		} else
+		    *tptr++ = *aptr; /* No, keep original array element */
+	    }
+	    *tptr = NULL;
+	    s = sepjoin(tmparr, NULL, 0);
+	} else {
+	    s = ztrdup(getstrvalue(v));
+	}
+	unqueue_signals();
     } else if (*s) {
+	unqueue_signals();
 	zwarnnam(name, "invalid parameter name: %s", args[0], 0);
 	return 1;
+    } else {
+	unqueue_signals();
+	s = ztrdup(s);
     }
 
     if (SHTTY == -1) {
@@ -835,22 +1182,32 @@ bin_vared(char *name, char **args, char *ops, int func)
 	haso = 1;
     }
     /* edit the parameter value */
-    zpushnode(bufstack, ztrdup(s));
+    zpushnode(bufstack, s);
+
+    if (main_keymapname &&
+	savekeymap(name, "main", main_keymapname, &main_keymapsave))
+	main_keymapname = NULL;
+    if (vicmd_keymapname &&
+	savekeymap(name, "vicmd", vicmd_keymapname, &vicmd_keymapsave))
+	vicmd_keymapname = NULL;
 
     varedarg = *args;
     ifl = isfirstln;
-    if (ops['e'])
-	isfirstln = 1;
-    if (ops['h'])
-	hbegin(1);
-    t = (char *) zleread(p1, p2, ops['h'] ? ZLRF_HISTORY : 0);
-    if (ops['h'])
-	hend();
+    if (OPT_ISSET(ops,'h'))
+	hbegin(2);
+    isfirstln = OPT_ISSET(ops,'e');
+    t = (char *) zleread(&p1, &p2, OPT_ISSET(ops,'h') ? ZLRF_HISTORY : 0,
+			 ZLCON_VARED);
+    if (OPT_ISSET(ops,'h'))
+	hend(NULL);
     isfirstln = ifl;
     varedarg = ova;
+
+    restorekeymap(name, "main", main_keymapname, main_keymapsave);
+    restorekeymap(name, "vicmd", vicmd_keymapname, vicmd_keymapsave);
+
     if (haso) {
-	close(SHTTY);
-	fclose(shout);
+	fclose(shout);	/* close(SHTTY) */
 	shout = oshout;
 	SHTTY = -1;
     }
@@ -864,30 +1221,34 @@ bin_vared(char *name, char **args, char *ops, int func)
     if (t[strlen(t) - 1] == '\n')
 	t[strlen(t) - 1] = '\0';
     /* final assignment of parameter value */
-    if (create && (!pm || (type && PM_TYPE(pm->flags) != type))) {
-	if (pm)
-	    unsetparam(args[0]);
+    if (OPT_ISSET(ops,'c')) {
+	unsetparam(args[0]);
 	createparam(args[0], type);
-	pm = 0;
     }
-    if (!pm)
-	pm = (Param) paramtab->getnode(paramtab, args[0]);
+    queue_signals();
+    pm = (Param) paramtab->getnode(paramtab, args[0]);
     if (pm && (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) {
 	char **a;
 
-	a = spacesplit(t, 1, 0);
+	/*
+	 * Use spacesplit with fourth argument 1: identify quoted separators,
+	 * and unquote.  This duplicates the string, so we still need to free.
+	 */
+	a = spacesplit(t, 1, 0, 1);
+	zsfree(t);
 	if (PM_TYPE(pm->flags) == PM_ARRAY)
 	    setaparam(args[0], a);
 	else
 	    sethparam(args[0], a);
     } else
 	setsparam(args[0], t);
+    unqueue_signals();
     return 0;
 }
 
 /**/
 int
-describekeybriefly(char **args)
+describekeybriefly(UNUSED(char **args))
 {
     char *seq, *str, *msg, *is;
     Thingy func;
@@ -925,7 +1286,7 @@ struct findfunc {
 
 /**/
 static void
-scanfindfunc(char *seq, Thingy func, char *str, void *magic)
+scanfindfunc(char *seq, Thingy func, UNUSED(char *str), void *magic)
 {
     struct findfunc *ff = magic;
 
@@ -944,7 +1305,7 @@ scanfindfunc(char *seq, Thingy func, char *str, void *magic)
 
 /**/
 int
-whereis(char **args)
+whereis(UNUSED(char **args))
 {
     struct findfunc ff;
 
@@ -963,6 +1324,39 @@ whereis(char **args)
 }
 
 /**/
+int
+recursiveedit(UNUSED(char **args))
+{
+    int locerror;
+
+    zrefresh();
+    zlecore();
+
+    locerror = errflag;
+    errflag = done = eofsent = 0;
+
+    return locerror;
+}
+
+/**/
+void
+reexpandprompt(void)
+{
+    free(lpromptbuf);
+    lpromptbuf = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL);
+    free(rpromptbuf);
+    rpromptbuf = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL);
+}
+
+/**/
+int
+resetprompt(UNUSED(char **args))
+{
+    reexpandprompt();
+    return redisplay(NULL);
+}
+
+/**/
 mod_export void
 trashzle(void)
 {
@@ -974,6 +1368,7 @@ trashzle(void)
 	 * extra `inlist' check]).                                          */
 	int sl = showinglist;
 	showinglist = 0;
+	trashedzle = 1;
 	zrefresh();
 	showinglist = sl;
 	moveto(nlnct, 0);
@@ -996,7 +1391,7 @@ trashzle(void)
  * active. */
 
 static int
-zlebeforetrap(Hookdef dummy, void *dat)
+zlebeforetrap(UNUSED(Hookdef dummy), UNUSED(void *dat))
 {
     if (zleactive) {
 	startparamscope();
@@ -1006,7 +1401,7 @@ zlebeforetrap(Hookdef dummy, void *dat)
 }
 
 static int
-zleaftertrap(Hookdef dummy, void *dat)
+zleaftertrap(UNUSED(Hookdef dummy), UNUSED(void *dat))
 {
     if (zleactive)
 	endparamscope();
@@ -1015,9 +1410,9 @@ zleaftertrap(Hookdef dummy, void *dat)
 }
 
 static struct builtin bintab[] = {
-    BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaMldDANmrsLR", NULL),
-    BUILTIN("vared",   0, bin_vared,   1,  7, 0, NULL,             NULL),
-    BUILTIN("zle",     0, bin_zle,     0, -1, 0, "lDANCLmMgGcRaU", NULL),
+    BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaM:ldDANmrsLRp", NULL),
+    BUILTIN("vared",   0, bin_vared,   1,  1, 0, "aAcehM:m:p:r:", NULL),
+    BUILTIN("zle",     0, bin_zle,     0, -1, 0, "aAcCDFgGIKlLmMNRU", NULL),
 };
 
 /* The order of the entries in this table has to match the *HOOK
@@ -1036,14 +1431,14 @@ mod_export struct hookdef zlehooks[] = {
 
 /**/
 int
-setup_(Module m)
+setup_(UNUSED(Module m))
 {
     /* Set up editor entry points */
     trashzleptr = trashzle;
-    gotwordptr = gotword;
     refreshptr = zrefresh;
     spaceinlineptr = spaceinline;
     zlereadptr = zleread;
+    zlesetkeymapptr = zlesetkeymap;
 
     getkeyptr = getkey;
 
@@ -1054,6 +1449,8 @@ setup_(Module m)
     /* miscellaneous initialisations */
     stackhist = stackcs = -1;
     kungetbuf = (char *) zalloc(kungetsz = 32);
+    comprecursive = 0;
+    rdstrs = NULL;
 
     /* initialise the keymap system */
     init_keymaps();
@@ -1061,8 +1458,9 @@ setup_(Module m)
     varedarg = NULL;
 
     incompfunc = incompctlfunc = hascompmod = 0;
+    hascompwidgets = 0;
 
-    clwords = (char **) zcalloc((clwsize = 16) * sizeof(char *));
+    clwords = (char **) zshcalloc((clwsize = 16) * sizeof(char *));
 
     return 0;
 }
@@ -1096,7 +1494,7 @@ cleanup_(Module m)
 
 /**/
 int
-finish_(Module m)
+finish_(UNUSED(Module m))
 {
     int i;
 
@@ -1108,19 +1506,23 @@ finish_(Module m)
     zfree(vichgbuf, vichgbufsz);
     zfree(kungetbuf, kungetsz);
     free_isrch_spots();
-
+    if (rdstrs)
+        freelinklist(rdstrs, freestr);
     zfree(cutbuf.buf, cutbuf.len);
-    for(i = KRINGCT; i--; )
-	zfree(kring[i].buf, kring[i].len);
+    if (kring) {
+	for(i = kringsize; i--; )
+	    zfree(kring[i].buf, kring[i].len);
+	zfree(kring, kringsize * sizeof(struct cutbuffer));
+    }
     for(i = 35; i--; )
 	zfree(vibuf[i].buf, vibuf[i].len);
 
     /* editor entry points */
     trashzleptr = noop_function;
-    gotwordptr = noop_function;
     refreshptr = noop_function;
     spaceinlineptr = noop_function_int;
     zlereadptr = fallback_zleread;
+    zlesetkeymapptr= noop_function_int;
 
     getkeyptr = NULL;
 
diff --git a/configure.ac b/configure.ac
index f79a5592d..dcc0acf96 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1862,7 +1862,7 @@ esac],[zsh_working_tcsetpgrp=check])
 if test "x$ac_cv_func_tcsetpgrp" = xyes; then
 case "x$zsh_working_tcsetpgrp" in
   xcheck)
-    trap "" SIGTTOU > /dev/null 2>&1 || :
+    ( trap "" SIGTTOU > /dev/null 2>&1 ) && trap "" SIGTTOU > /dev/null 2>&1 
     AC_CACHE_CHECK(if tcsetpgrp() actually works,
     zsh_cv_sys_tcsetpgrp,
     [AC_TRY_RUN([
@@ -1893,7 +1893,7 @@ esac
 Try running configure with --with-tcsetpgrp or --without-tcsetpgrp]);;
       *)      AC_MSG_ERROR([unexpected return status]);;
     esac
-    trap - SIGTTOU > /dev/null 2>&1 || :
+    ( trap - SIGTTOU > /dev/null 2>&1 ) && trap - SIGTTOU > /dev/null 2>&1 
     ;;
   xyes) :;;
   xno)  AC_DEFINE(BROKEN_TCSETPGRP);;