about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-05-02 15:19:50 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-05-02 15:19:50 +0000
commit53d36e795b26a945048e7a87a1a91224f8e1663a (patch)
treeaee8b11f48f2af1aceacd4a279f1d4b1de6ebfa6
parent206237c8ec4b7619d9e70a75004cd1ae1066b0a0 (diff)
downloadzsh-53d36e795b26a945048e7a87a1a91224f8e1663a.tar.gz
zsh-53d36e795b26a945048e7a87a1a91224f8e1663a.tar.xz
zsh-53d36e795b26a945048e7a87a1a91224f8e1663a.zip
zsh-3.1.5-pws-17 dot-zsh-199905041932
-rw-r--r--Completion/Builtins/_stat10
-rw-r--r--Completion/Core/.distfiles7
-rw-r--r--Completion/Core/_closequotes11
-rw-r--r--Completion/Core/_menu21
-rw-r--r--Completion/Core/_multi_parts3
-rw-r--r--Completion/Core/_oldlist29
-rw-r--r--Completion/Core/_path_files17
-rw-r--r--Completion/Core/compinstall216
-rw-r--r--Completion/User/_make2
-rw-r--r--Config/version.mk4
-rw-r--r--Doc/Zsh/builtins.yo10
-rw-r--r--Doc/Zsh/compsys.yo47
-rw-r--r--Doc/Zsh/compwid.yo15
-rw-r--r--Doc/Zsh/expn.yo8
-rw-r--r--Doc/Zsh/options.yo2
-rw-r--r--Doc/Zsh/redirect.yo2
-rw-r--r--Src/Modules/example.c39
-rw-r--r--Src/Modules/example.mdd1
-rw-r--r--Src/Modules/zftp.c3
-rw-r--r--Src/Zle/comp.h30
-rw-r--r--Src/Zle/comp1.c8
-rw-r--r--Src/Zle/comp1.export1
-rw-r--r--Src/Zle/compctl.c86
-rw-r--r--Src/Zle/compctl.mdd2
-rw-r--r--Src/Zle/zle_main.c14
-rw-r--r--Src/Zle/zle_misc.c10
-rw-r--r--Src/Zle/zle_refresh.c17
-rw-r--r--Src/Zle/zle_tricky.c306
-rw-r--r--Src/builtin.c14
-rw-r--r--Src/glob.c8
-rw-r--r--Src/mkbltnmlst.sh5
-rw-r--r--Src/mkmakemod.sh3
-rw-r--r--Src/module.c160
-rw-r--r--Src/params.c42
-rw-r--r--Src/prompt.c19
-rw-r--r--Src/zsh.export2
-rw-r--r--Src/zsh.h24
-rw-r--r--Util/zsh-development-guide75
-rw-r--r--patchlist.txt51
39 files changed, 1103 insertions, 221 deletions
diff --git a/Completion/Builtins/_stat b/Completion/Builtins/_stat
new file mode 100644
index 000000000..3cdbb2618
--- /dev/null
+++ b/Completion/Builtins/_stat
@@ -0,0 +1,10 @@
+#compdef stat
+
+if [[ "$words[CURRENT-1]" = -[AH] ]]; then
+  compgen -A
+else
+  [[ "$PREFIX[1]" = + ]] &&
+      compadd - +device +inode +mode +nlink +uid +gid +rdev +size \
+                +atime +mtime +ctime +blksize +block +link
+  _files
+fi
diff --git a/Completion/Core/.distfiles b/Completion/Core/.distfiles
index 6babe9701..9a9e87d7c 100644
--- a/Completion/Core/.distfiles
+++ b/Completion/Core/.distfiles
@@ -1,6 +1,7 @@
 DISTFILES_SRC='
     .distfiles
-    _approximate _compalso _complete _correct _expand _files _list
-    _main_complete _match _multi_parts _normal _options _parameters
-    _path_files _sep_parts _set_options _unset_options compdump compinit
+    _approximate _closequotes _compalso _complete _correct _expand _files
+    _list _main_complete _match _menu _multi_parts _normal _oldlist _options
+    _parameters _path_files _sep_parts _set_options _unset_options
+    compdump compinit compinstall
 '
diff --git a/Completion/Core/_closequotes b/Completion/Core/_closequotes
new file mode 100644
index 000000000..2c4b390e5
--- /dev/null
+++ b/Completion/Core/_closequotes
@@ -0,0 +1,11 @@
+#autoload
+
+# If the current completion is in quotes, add the closing quote.
+# This can clash with some of the more sophisticated forms of completion
+
+if [[ -n $compstate[quote] && $RBUFFER != *${compstate[quote]}* ]]; then
+  compstate[restore]=''
+  ISUFFIX="$ISUFFIX$compstate[quote]"
+fi
+
+return 1
diff --git a/Completion/Core/_menu b/Completion/Core/_menu
new file mode 100644
index 000000000..4cbda4e14
--- /dev/null
+++ b/Completion/Core/_menu
@@ -0,0 +1,21 @@
+#autoload
+
+# This completer is an example showing how menucompletion can be
+# implemented with the new completion system.
+# Use this one before the normal _complete completer, as in:
+#
+#   compconf completer=_menu:_complete
+
+if [[ -n "$compstate[old_list]" ]]; then
+
+  # We have an old list, keep it and insert the next match.
+
+  compstate[old_list]=keep
+  compstate[insert]=$((compstate[old_insert]+1))
+else
+  # No old list, make completion insert the first match.
+
+  compstate[insert]=1
+fi
+
+return 1
diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts
index b49c41e22..392277f94 100644
--- a/Completion/Core/_multi_parts
+++ b/Completion/Core/_multi_parts
@@ -83,8 +83,7 @@ while true; do
   else
     # No exact match, see how many strings match what's on the line.
 
-    tmp2=( "${(@)matches%%${sep}*}" )
-    compadd -O tmp1 - "$tmp2[@]"
+    compadd -O tmp1 - "${(@)matches%%${sep}*}"
 
     if [[ $#tmp1 -eq 1 ]]; then
 
diff --git a/Completion/Core/_oldlist b/Completion/Core/_oldlist
new file mode 100644
index 000000000..f42197695
--- /dev/null
+++ b/Completion/Core/_oldlist
@@ -0,0 +1,29 @@
+#autoload
+
+# If this is a listing widget and there is already an old list,
+# and either the compconfig key oldlist_list is `always', or it is not `never'
+# and the list is not already shown, then use the existing list for listing
+# (even if it was generated by another widget).
+if [[ -n $compstate[old_list] && $compconfig[oldlist_list] != never &&
+  $WIDGET = *list* &&
+  ( $compconfig[oldlist_list] = always || $compstate[old_list] != shown ) ]]
+then
+  compstate[old_list]=keep
+  return 0
+fi
+
+# If this is a completion widget, and we have a completion inserted already,
+# and the compconfig key oldlist_menu is not never, then we cycle through the
+# existing list (even if it was generated by another widget).
+if [[ -n $compstate[old_insert] && $WIDGET = *complete(|-prefix|-word) &&
+  $compconfig[oldlist_menu] != never ]]; then
+  compstate[old_list]=keep
+  if [[ $WIDGET = *reverse* ]]; then
+    compstate[insert]=$(( compstate[old_insert] - 1 ))
+  else
+    compstate[insert]=$(( compstate[old_insert] + 1 ))
+  fi
+  return 0
+fi
+
+return 1
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index ed799be84..16666909b 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -230,14 +230,15 @@ for prepath in "$prepaths[@]"; do
     if [[ -n "$PREFIX$SUFFIX" ]]; then
       # See which of them match what's on the line.
 
-      compadd -O tmp2 "$ignore[@]" - "${(@)tmp1##*/}"
+      tmp2=("$tmp1[@]")
+      compadd -D tmp1 "$ignore[@]" - "${(@)tmp1##*/}"
 
       # If no file matches, save the expanded path and continue with
       # the outer loop.
 
-      if [[ $#tmp2 -eq 0 ]]; then
- 	if [[ "$tmp1[1]" = */* ]]; then
-	  tmp2=( "${(@)tmp1#${prepath}${realpath}}" )
+      if [[ $#tmp1 -eq 0 ]]; then
+ 	if [[ "$tmp2[1]" = */* ]]; then
+	  tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
 	  if [[ "$tmp2[1]" = */* ]]; then
 	    exppaths=( "$exppaths[@]" ${^tmp2%/*}/${tpre}${tsuf} )
           else
@@ -246,14 +247,6 @@ for prepath in "$prepaths[@]"; do
         fi
         continue 2
       fi
-
-      # Remove all files that weren't matched.
-
-      if [[ "$tmp1[1]" = */* ]]; then
-        tmp1=( "${(@M)tmp1:#*/(${(j:|:)~${(@)tmp2:q}})}" )
-      else
-        tmp1=( "${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}" )
-      fi
     elif (( ! $#tmp1 )); then
       continue 2
     fi
diff --git a/Completion/Core/compinstall b/Completion/Core/compinstall
new file mode 100644
index 000000000..d96121cf2
--- /dev/null
+++ b/Completion/Core/compinstall
@@ -0,0 +1,216 @@
+# This script is to be run by a user to setup the new function based
+# completion system.  The functions themselves are assumed to be already
+# available in some directory; they should have been installed with the
+# the shell (except we haven't written that yet).
+#
+# Run it as a script under zsh and answer the questions.
+# You can run it as `zsh compinstall $FPATH' and it will be able to check
+# your function path for the completion functions.
+#
+# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it),
+# but you can make that unwritable and it will leave the lines in a
+# temporary file instead.
+#
+# You can use this script to modify what compinstall previously
+# added to ~/.zshrc.
+#
+# It is safe to abort with ^C any time you are being prompted for
+# information; your .zshrc will not be altered.
+#
+# To do:
+#  - Maybe this should be sourced, then it can check the user's current
+#    setup better.  But then there is a potentially horrendous option
+#    setting/resetting problem.  (Maybe we need another way of doing that.)
+#  - Should probably offer to set different options for _approximate than
+#    for _complete if both are used.
+#  - Could add code for setting other completers and options.
+#  - Could add keys for context-sensitive help.
+#  - Probably should allow a set of directories to be added to $fpath,
+#    like Core, Base, etc.
+
+# In case a startup script changed options
+emulate zsh
+
+[[ -n $1 ]] && FPATH=$1
+
+for f in $fpath; do
+  if [[ $f != . && -f $f/compinit && -f $f/compdump ]]; then
+    fdir=$f
+    break
+  fi
+done
+
+if [[ -z $fdir ]]; then
+  print "Trying to find where the completion functions are..."
+  if [[ $0 = */* && -f $0:h/compinit && -f $0:h/compdump ]]; then
+    fdir=$0:h
+  else
+    # more guesses?
+    print \
+"Please edit the name of the directory where the completion functions are
+installed.  If they are not installed, you will need to find them in the
+Completion/* directories of the zsh distribution and install them yourself,
+or insult your system manager for incompetence."
+    vared -c fdir
+    while [[ ! -d ${~fdir} || ! -f ${~fdir}/compinit || 
+      ! -f ${~fdir}/compdump ]]; do
+      print "I can't find them in that directory.  Try again or abort."
+      vared fdir
+    done
+  fi
+  eval "fpath=($fdir \$fpath)"
+  fdir=${fdir/#$HOME/\~}
+  lines="fpath=($fdir \$fpath)\n"
+else
+  print "Found completion functions in your fpath, will not alter it."
+fi
+
+files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+if [[ $#files -lt 20 ]]; then
+  print "
+Hmmm, completion functions seem a bit thin on the ground.  There should
+be lots of files with names beginning with an underscore (_).  You should
+look and see what's happened to these.
+[Hit return to continue]"
+  read
+fi
+
+if [[ -w ${~fdir} && ( ! -f ${~fdir}/compinit.dump ||
+  -w ${~fdir}/compinit.dump ) ]]
+then
+  print "
+Using standard dumpfile
+  ${~fdir}/compinit.dump
+to speed up initialisation.
+[Hit return to continue]"
+  read
+else
+  print "
+I will force completion to dump its status, which will speed up the shell's
+start-up considerably.  However, I can't write the file I'd like to, namely
+$fdir/compinit.dump.  Please edit a replacement."
+  dumpfile='~/.compinit.dump'
+  vared dumpfile
+  while ! touch ${~dumpfile} >& /dev/null; do
+    print "Sorry, I can't write that either.  Try again."
+    vared dumpfile
+  done
+  [[ -s $dumpfile ]] || rm -f $dumpfile
+  dumpfile=" $dumpfile"
+fi
+
+fdir=${fdir/#$HOME/\~}
+
+lines="${lines}. $fdir/compinit -d$dumpfile\n"
+
+
+print "
+In addition to completion, zsh can also perform correction of the
+current word, or approximate completion, i.e. completion where the part of
+the word typed so far can be corrected; or it can try correction, then
+approximate completion if that fails.  Would you like:
+  0:  Just ordinary completion
+  C:  Correction
+  A:  Approximate completion
+  B:  Both?
+Please type one of the keys above:"
+while read -k type; do
+  print
+  case $type in
+    0*) completer=_complete
+	break
+	;;
+    [cC]*) completer=_complete:_correct
+	   break
+	   ;;
+    [aA]*) completer=_complete:_approximate
+	   break;
+	   ;;
+    [bB]*) completer=_complete:_correct:_approximate
+	   break
+	   ;;
+    *) print Try again
+       ;;
+  esac
+done
+
+lines="${lines}compconf completer=$completer"
+
+
+if [[ $completer = *(correct|approx)* ]]; then
+  print "
+Correction and approximation will normally allow up to two errors,
+and you will be able to use a numeric prefix (e.g. <Esc>4) to allow
+more.  The standard prompt is \`correct to:'. Do you want to change
+any of this? [n]"
+  if read -q; then
+    print "Number of errors to accept normally (0 is OK):"
+    read accept
+    while [[ $accept != <-> ]]; do
+      read accept"?Please enter a number: "
+    done
+    print \
+"How would you like the numeric prefix to be treated:
+  0:  Not used by correction
+  U:  Used to given the number of errors
+  I:  If present, and not 1, do not perform correction?
+Please type one of the keys above:"
+    while read -k type; do
+      print
+      case $type in
+	0*) break
+	    ;;
+	[uU]*) accept="${accept}n"
+	       break
+	       ;;
+	[Ii]*) accept="${accept}!n"
+	       break
+	       ;;
+	*) print Try again
+	   ;;
+      esac
+    done
+    lines="$lines \\\\
+  correct_accept='$accept'"
+    print "
+Instead of the prompt \`correct to:', you can have no prompt, or a
+prompt of your choosing which can display the number of errors found by
+containing the string \`%e'.  Do you wish to change the correction
+prompt? [n]"
+    if read -q; then
+      cprompt=''
+      print "Edit a new prompt (may be empty):"
+      vared cprompt
+      lines="$lines \\\\
+  correct_prompt='${cprompt//\'/\'\\\'\'}'"
+    fi
+  fi
+fi
+
+lines="$lines\n"
+
+
+startline='# The following lines were added by compinstall'
+endline='# End of lines added by compinstall'
+
+ifile=${ZDOTDIR:-~}/.zshrc
+[[ -f $ifile ]] || touch $ifile
+tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
+
+if [[ ! -w $ifile ]]; then
+  print "\nI can't write to $ifile.  I will leave the lines to add in
+\`$tmpf' and you must add them by hand."
+  print "\n$startline\n$lines\n$endline" >$tmpf
+  return 0
+fi
+
+if grep $endline $ifile >& /dev/null; then
+  print -- "$startline\n$lines$endline" >$tmpf
+  sed -e "/^$endline/r $tmpf
+/^$startline/,/^$endline/d" $ifile >${tmpf}2 && mv ${tmpf}2 $ifile &&
+  print "\nSuccesfully modified old compinstall lines in $ifile."
+  rm -f $tmpf ${tmpf}2
+else
+  print "\n$startline\n$lines\n$endline" >>$ifile &&
+  print "\nSuccessfully appended lines to $ifile."
+fi
diff --git a/Completion/User/_make b/Completion/User/_make
index acaa56b8e..a30ca4b7a 100644
--- a/Completion/User/_make
+++ b/Completion/User/_make
@@ -1,3 +1,3 @@
 #compdef make gmake pmake
 
-compgen -s "\$(awk '/^[a-zA-Z0-9][^\/         ]+:/ {print \$1}' FS=: [mM]akefile /dev/null)"
+compgen -s "\$(awk '/^[a-zA-Z0-9][^\/ 	]+:/ {print \$1}' FS=: [mM]akefile /dev/null)"
diff --git a/Config/version.mk b/Config/version.mk
index a5a52f6c1..be39ecad4 100644
--- a/Config/version.mk
+++ b/Config/version.mk
@@ -27,5 +27,5 @@
 # This must also serve as a shell script, so do not add spaces around the
 # `=' signs.
 
-VERSION=3.1.5-pws-16
-VERSION_DATE='April 25, 1999'
+VERSION=3.1.5-pws-17
+VERSION_DATE='April 30, 1999'
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index ffc9f3cfe..e9bc2ab16 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1175,9 +1175,12 @@ xitem(tt(zmodload) tt(-d) [ tt(-L) ] [ var(name) [ var(dep) ... ] ])
 xitem(tt(zmodload) tt(-du) var(name) [ var(dep) ... ])
 xitem(tt(zmodload) tt(-a) [ tt(-iL) ] [ var(name) [ var(builtin) ... ] ])
 xitem(tt(zmodload) tt(-au) [ tt(-i) ] var(builtin) ...)
-xitem(tt(zmodload) tt(-c) [ tt(-iI) ] [ var(name) [ var(cond) ... ] ])
+xitem(tt(zmodload) tt(-c) [ tt(-iI) ] var(name) [ var(cond) ... ])
 xitem(tt(zmodload) tt(-cu) [ tt(-iI) ] var(cond) ...)
-item(tt(zmodload) tt(-c) [ tt(-IL) ])(
+xitem(tt(zmodload) tt(-c) [ tt(-IL) ])
+xitem(tt(zmodload) tt(-p) [ tt(-i) ] var(name) [ var(parameter) ... ])
+xitem(tt(zmodload) tt(-pu) [ tt(-i) ] var(parameter) ... ])
+item(tt(zmodload) tt(-p) [ tt(-L) ])(
 tt(zmodload) performs operations relating to zsh's loadable modules.
 This feature is not available on all operating systems,
 or on all installations on a particular operating system.
@@ -1253,5 +1256,8 @@ names. Without this option prefix condition names are defined.
 Together with the tt(-u) option definitions for autoloaded conditions
 are removed. If given no condition names all defined names are listed
 (as a series of tt(zmodload) commands if the tt(-L) option is given).
+
+The tt(-p) option is like the tt(-c) option, but makes tt(zmodload)
+work on autoloaded parameters instead of condition codes.
 )
 enditem()
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 159f944c3..cedc4ec8c 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -528,6 +528,53 @@ tt(MENU_COMPLETE) option and does not work with the other
 menucompletion widgets such as tt(reverse-menu-complete), or
 tt(accept-and-menu-complete).
 )
+item(tt(_oldlist))(
+This completer controls how the standard completion widgets behave when
+there is an existing list of completions which may have been generated by a
+special completion (i.e. a separately-bound completion command).  It should
+appear in the list of completers before any of the widgets which generate
+matches.  It understands two configuration keys:
+
+startitem()
+item(tt(oldlist_list))(
+If this is set to tt(always), then standard widgets which perform listing
+will retain the current list of matches, however they were generated.  If
+it is set to tt(never), this will not be done (the behaviour without the
+tt(_oldlist) completer).  If it is unset, or any other value, then the
+existing list of completions will be displayed if it is not already;
+otherwise, the standard completion list will be generated:  this is the
+default behaviour of tt(_oldlist).
+
+For example, suppose you type tt(^Xc) to use the tt(_correct_word)
+widget, which generates a list of corrections for the word under the
+cursor.  Usually, typing tt(^D) would generate a standard list of
+completions for the word on the command line, and show that.  With
+tt(_oldlist), it will instead show the list of corrections already
+generated.
+)
+item(tt(oldlist_menu))(
+Controls how menu completion behaves when a completion has already been
+inserted and the user types a standard completion key type as tt(TAB).
+The default behaviour of tt(_oldlist) is that menu completion always
+continues with the existing list of completions.  If this key is set to
+tt(never), however, a new completion is started if the old list was
+generated by a different completion command (the behaviour without the
+tt(_oldlist) completer).
+For example, suppose you type tt(^Xc) to generate a list of corrections,
+and menu completion is started in one of the usual ways.  Usually, typing
+tt(TAB) at this point would start trying to complete the line as it now
+appears.  With tt(_oldlist), it will instead continue to cycle through the
+list of completions. 
+)
+enditem()
+)
+item(tt(_closequotes))(
+When a completion starts in quotes, this completer will recognise the fact
+and insert a matching closing quote if there is not already one later on
+the line.  It should come earlier in the list of completers than any of the
+completers which generate matches.  It can be confused by some of the more
+sophisticated forms of completion.
+)
 enditem()
 
 texinode(Completion Functions)()(Control Functions)(Completion System)
diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo
index 34f1140b9..79577d13d 100644
--- a/Doc/Zsh/compwid.yo
+++ b/Doc/Zsh/compwid.yo
@@ -140,6 +140,12 @@ with tt(${).
 )
 enditem()
 )
+item(tt(vared))(
+If completion is called while editing a line using the tt(vared)
+builtin, the value of this key is set to the name of the parameter
+given as argument to tt(vared). If tt(vared) is not currently used,
+this key is unset.
+)
 item(tt(parameter))(
 The name of the parameter when completing in a subscript or in the
 value of a parameter assignment.
@@ -340,7 +346,7 @@ xitem([ tt(-W) var(file-prefix) ])
 xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ])
 xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ])
 xitem([ tt(-M) var(match-spec) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ])
-item([ tt(--) ] [ var(words) ... ])(
+item([ tt(-D) var(array) ] [ tt(--) ] [ var(words) ... ])(
 
 This builtin command can be used to add matches directly and control
 all the information the completion code stores with each possible
@@ -518,6 +524,13 @@ on the command line and the string `tt(foo)' as one of the var(words), this
 option stores the string `tt(nofoo)' in the array, whereas the tt(-O)
 option stores the `tt(foo)' originally given.
 )
+item(tt(-D) var(array))(
+As with tt(-O), the var(words) are not added to the set of possible
+completions. Instead, the completion code tests every var(word) if 
+it matches what is on the line. If the var(n)'th var(word) does not
+match, the var(n)'th element of the var(array) is removed. Elements
+for which the corresponding var(word) is matched are retained.
+)
 item(tt(-), tt(--))(
 This flag ends the list of flags and options. All arguments after it
 will be taken as the words to use as matches even if they begin with
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 1dced5b7d..0326e646d 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -361,6 +361,7 @@ the parameter is then substituted.
 item(tt(${)var(name)tt(:?)var(word)tt(}))(
 If var(name) is set and is non-null, then substitute
 its value; otherwise, print var(word) and exit from the shell.
+Interactive shells do not exit.
 If var(word) is omitted, then a standard message is printed.
 )
 item(tt(${)var(name)tt(:PLUS())var(word)tt(}))(
@@ -596,11 +597,12 @@ 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 will be placed
-exactly once directly to the left of the resulting word.
+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.
+As tt(l), but pad the words on the right and insert var(string2)
+on the right.
 )
 item(tt(j:)var(string)tt(:))(
 Join the words of arrays together using var(string) as a separator.
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index c4a8a084e..92de8c2d8 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -670,7 +670,7 @@ tt(trap) and
 tt(unset).
 )
 pindex(PRINT_EIGHT_BIT)
-cindex(exit status, printing)
+cindex(eight bit characters, printing)
 item(tt(PRINT_EIGHT_BIT))(
 Print eight bit characters literally in completion lists, etc.
 This option is not necessary if your system correctly returns the
diff --git a/Doc/Zsh/redirect.yo b/Doc/Zsh/redirect.yo
index 71f03f4cf..b642f1b5f 100644
--- a/Doc/Zsh/redirect.yo
+++ b/Doc/Zsh/redirect.yo
@@ -180,4 +180,4 @@ the command named in the shell variable tt(READNULLCMD) is assumed.
 
 nofill(tt(< file))
 
-prints the contents of tt(file).
+copies the contents of tt(file) to the standard output.
diff --git a/Src/Modules/example.c b/Src/Modules/example.c
index 95545172f..50b8c1626 100644
--- a/Src/Modules/example.c
+++ b/Src/Modules/example.c
@@ -30,22 +30,45 @@
 #include "example.mdh"
 #include "example.pro"
 
+/* parameters */
+
+static long intparam;
+static char *strparam;
+static char **arrparam;
+
+
 /**/
 static int
 bin_example(char *nam, char **args, char *ops, int func)
 {
     unsigned char c;
+    char **oargs = args, **p = arrparam;
+    long i = 0;
 
     printf("Options: ");
     for (c = 32; ++c < 128;)
 	if (ops[c])
 	    putchar(c);
     printf("\nArguments:");
-    for (; *args; args++) {
+    for (; *args; i++, args++) {
 	putchar(' ');
 	fputs(*args, stdout);
     }
     printf("\nName: %s\n", nam);
+    printf("\nInteger Parameter: %ld\n", intparam);
+    printf("String Parameter: %s\n", strparam ? strparam : "");
+    printf("Array Parameter:");
+    if (p)
+	while (*p) printf(" %s", *p++);
+    printf("\n");
+
+    intparam = i;
+    zsfree(strparam);
+    strparam = ztrdup(*oargs ? *oargs : "");
+    freearray(arrparam);
+    PERMALLOC {
+	arrparam = arrdup(oargs);
+    } LASTALLOC;
     return 0;
 }
 
@@ -103,6 +126,12 @@ static struct conddef cotab[] = {
     CONDDEF("ex", CONDF_INFIX, cond_i_ex, 0, 0, 0),
 };
 
+static struct paramdef patab[] = {
+    INTPARAMDEF("exint", &intparam),
+    STRPARAMDEF("exstr", &strparam),
+    ARRPARAMDEF("exarr", &arrparam),
+};
+
 static struct funcwrap wrapper[] = {
     WRAPDEF(ex_wrapper),
 };
@@ -120,8 +149,15 @@ setup_example(Module m)
 int
 boot_example(Module m)
 {
+    intparam = 42;
+    strparam = ztrdup("example");
+    arrparam = (char **) zalloc(3 * sizeof(char *));
+    arrparam[0] = ztrdup("example");
+    arrparam[1] = ztrdup("array");
+    arrparam[2] = NULL;
     return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
 	     addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) |
+	     addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) |
 	     !addwrapper(m, wrapper));
 }
 
@@ -133,6 +169,7 @@ cleanup_example(Module m)
 {
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab));
+    deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab));
     deletewrapper(m, wrapper);
     return 0;
 }
diff --git a/Src/Modules/example.mdd b/Src/Modules/example.mdd
index f2cd50693..5ed55e6f1 100644
--- a/Src/Modules/example.mdd
+++ b/Src/Modules/example.mdd
@@ -2,5 +2,6 @@ autobins="example"
 
 autoinfixconds="ex"
 autoprefixconds="len"
+autoparams="exint exstr exarr"
 
 objects="example.o"
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 126aa061e..651a5c952 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -71,6 +71,9 @@
 #ifdef HAVE_POLL_H
 # include <poll.h>
 #endif
+#if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM)
+# undef HAVE_POLL
+#endif
 
 /* pinch the definition from <netinet/in.h> for deficient headers */
 #ifndef INADDR_NONE
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index c9d6aa859..caeb4d6c3 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -270,6 +270,31 @@ struct cpattern {
 #define CAF_ALT      4
 #define CAF_MATCH    8
 
+/* Data for compadd and addmatches() */
+
+typedef struct cadata *Cadata;
+
+struct cadata {
+    char *ipre;			/* ignored prefix (-i) */
+    char *isuf;			/* ignored suffix (-I) */
+    char *ppre;			/* `path' prefix (-p) */
+    char *psuf;			/* `path' suffix (-s) */
+    char *prpre;		/* expanded `path' prefix (-W) */
+    char *pre;			/* prefix to insert (-P) */
+    char *suf;			/* suffix to insert (-S) */
+    char *group;		/* name of the group (-[JV]) */
+    char *rems;			/* remove suffix on chars... (-r) */
+    char *remf;			/* function to remove suffix (-R) */
+    char *ign;			/* ignored suffixes (-F) */
+    int flags;			/* CMF_* flags (-[fqn]) */
+    int aflags;			/* CAF_* flags (-[QUa]) */
+    Cmatcher match;		/* match spec (parsed from -M) */
+    char *exp;			/* explanation (-X) */
+    char *apar;			/* array to store matches in (-A) */
+    char *opar;			/* array to store originals in (-O) */
+    char *dpar;			/* array to delete non-matches in (-D) */
+};
+
 /* Flags for special parameters. */
 
 #define CP_WORDS      (1 <<  0)
@@ -306,7 +331,8 @@ struct cpattern {
 #define CP_TOEND      (1 << 28)
 #define CP_OLDLIST    (1 << 29)
 #define CP_OLDINS     (1 << 30)
+#define CP_VARED      (1 << 31)
 
-#define CP_NUM              31
+#define CP_NUM              32
 
-#define CP_ALLMASK    ((int) ((((unsigned int) 1) << CP_NUM) - 1))
+#define CP_ALLMASK    ((unsigned int) 0xffffffff)
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index fe21b1dfc..c51aad297 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -52,7 +52,7 @@ void (*comp_setunsetptr) _((int, int));
 /* pointers to functions required by compctl and defined by zle */
 
 /**/
-int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char *, char *, char **));
+int (*addmatchesptr) _((Cadata, char **));
 
 /**/
 char *(*comp_strptr) _((int *, int *, int));
@@ -129,7 +129,8 @@ char **compwords,
      *complastprompt,
      *comptoend,
      *compoldlist,
-     *compoldins;
+     *compoldins,
+     *compvared;
 
 /**/
 Param *comppms;
@@ -445,7 +446,7 @@ setup_comp1(Module m)
 	compquoting = comprestore = complist = compinsert =
 	compexact = compexactstr = comppatmatch = comppatinsert =
 	compforcelist = complastprompt = comptoend = 
-	compoldlist = compoldins = NULL;
+	compoldlist = compoldins = compvared = NULL;
     makecompparamsptr = NULL;
     comp_setunsetptr = NULL;
     return 0;
@@ -497,6 +498,7 @@ finish_comp1(Module m)
     zsfree(comptoend);
     zsfree(compoldlist);
     zsfree(compoldins);
+    zsfree(compvared);
     return 0;
 }
 
diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export
index 4f9fb143d..2dc285d3a 100644
--- a/Src/Zle/comp1.export
+++ b/Src/Zle/comp1.export
@@ -41,6 +41,7 @@ comp_setunsetptr
 comp_strptr
 compsuffix
 comptoend
+compvared
 compwords
 freecmatcher
 freecmlist
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 28c7cb7b7..a06d558e3 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1691,17 +1691,22 @@ bin_compgen(char *name, char **argv, char *ops, int func)
 static int
 bin_compadd(char *name, char **argv, char *ops, int func)
 {
-    char *p, **sp, *e;
-    char *ipre = NULL, *isuf = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
-    char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL;
-    char *ign = NULL, *rf = NULL, *expl = NULL, *apar = NULL, *opar = NULL;
-    int f = 0, a = CAF_MATCH, dm;
+    struct cadata dat;
+    char *p, **sp, *e, *m = NULL;
+    int dm;
     Cmatcher match = NULL;
 
     if (incompfunc != 1) {
 	zerrnam(name, "can only be called from completion function", NULL, 0);
 	return 1;
     }
+    dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre =
+	dat.pre = dat.suf = dat.group = dat.rems = dat.remf =
+	dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL;
+    dat.match = NULL;
+    dat.flags = 0;
+    dat.aflags = CAF_MATCH;
+
     for (; *argv && **argv ==  '-'; argv++) {
 	if (!(*argv)[1]) {
 	    argv++;
@@ -1713,64 +1718,64 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 	    dm = 0;
 	    switch (*p) {
 	    case 'q':
-		f |= CMF_REMOVE;
+		dat.flags |= CMF_REMOVE;
 		break;
 	    case 'Q':
-		a |= CAF_QUOTE;
+		dat.aflags |= CAF_QUOTE;
 		break;
 	    case 'f':
-		f |= CMF_FILE;
+		dat.flags |= CMF_FILE;
 		break;
 	    case 'F':
-		sp = &ign;
+		sp = &(dat.ign);
 		e = "string expected after -%c";
 		break;
 	    case 'n':
-		f |= CMF_NOLIST;
+		dat.flags |= CMF_NOLIST;
 		break;
 	    case 'U':
-		a &= ~CAF_MATCH;
+		dat.aflags &= ~CAF_MATCH;
 		break;
 	    case 'P':
-		sp = &pre;
+		sp = &(dat.pre);
 		e = "string expected after -%c";
 		break;
 	    case 'S':
-		sp = &suf;
+		sp = &(dat.suf);
 		e = "string expected after -%c";
 		break;
 	    case 'J':
-		sp = &group;
+		sp = &(dat.group);
 		e = "group name expected after -%c";
 		break;
 	    case 'V':
-		if (!group)
-		    a |= CAF_NOSORT;
-		sp = &group;
+		if (!dat.group)
+		    dat.aflags |= CAF_NOSORT;
+		sp = &(dat.group);
 		e = "group name expected after -%c";
 		break;
 	    case 'i':
-		sp = &ipre;
+		sp = &(dat.ipre);
 		e = "string expected after -%c";
 		break;
 	    case 'I':
-		sp = &isuf;
+		sp = &(dat.isuf);
 		e = "string expected after -%c";
 		break;
 	    case 'p':
-		sp = &ppre;
+		sp = &(dat.ppre);
 		e = "string expected after -%c";
 		break;
 	    case 's':
-		sp = &psuf;
+		sp = &(dat.psuf);
 		e = "string expected after -%c";
 		break;
 	    case 'W':
-		sp = &prpre;
+		sp = &(dat.prpre);
 		e = "string expected after -%c";
 		break;
 	    case 'a':
-		a |= CAF_ALT;
+		dat.aflags |= CAF_ALT;
 		break;
 	    case 'M':
 		sp = &m;
@@ -1778,25 +1783,29 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 		dm = 1;
 		break;
 	    case 'X':
-		sp = &expl;
+		sp = &(dat.exp);
 		e = "string expected after -%c";
 		break;
 	    case 'r':
-		f |= CMF_REMOVE;
-		sp = &rs;
+		dat.flags |= CMF_REMOVE;
+		sp = &(dat.rems);
 		e = "string expected after -%c";
 		break;
 	    case 'R':
-		f |= CMF_REMOVE;
-		sp = &rf;
+		dat.flags |= CMF_REMOVE;
+		sp = &(dat.remf);
 		e = "function name expected after -%c";
 		break;
 	    case 'A':
-		sp = &apar;
+		sp = &(dat.apar);
 		e = "parameter name expected after -%c";
 		break;
 	    case 'O':
-		sp = &opar;
+		sp = &(dat.opar);
+		e = "parameter name expected after -%c";
+		break;
+	    case 'D':
+		sp = &(dat.dpar);
 		e = "parameter name expected after -%c";
 		break;
 	    case '-':
@@ -1830,12 +1839,11 @@ bin_compadd(char *name, char **argv, char *ops, int func)
     if (!*argv)
 	return 1;
 
-    match = cpcmatcher(match);
-    a = addmatchesptr(ipre, isuf, ppre, psuf, prpre, pre, suf, group,
-		      rs, rf, ign, f, a, match, expl, apar, opar, argv);
+    dat.match = match = cpcmatcher(match);
+    dm = addmatchesptr(&dat, argv);
     freecmatcher(match);
 
-    return a;
+    return dm;
 }
 
 #define CVT_RANGENUM 0
@@ -2165,6 +2173,7 @@ static struct compparam {
     { "to_end", PM_SCALAR, VAL(comptoend), NULL, NULL },
     { "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL },
     { "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL },
+    { "vared", PM_SCALAR, VAL(compvared), NULL, NULL },
     { NULL, 0, NULL, NULL, NULL }
 };
 
@@ -2308,7 +2317,7 @@ compunsetfn(Param pm, int exp)
 
 /**/
 void
-comp_setunset(int set, int unset)
+comp_setunset(unsigned int set, unsigned int unset)
 {
     Param *p;
 
@@ -2334,11 +2343,11 @@ comp_wrapper(List list, FuncWrap w, char *name)
     else {
 	char *orest, *opre, *osuf, *oipre, *oisuf, **owords;
 	long ocur;
-	int unset = 0, m, sm;
+	unsigned int unset = 0, m, sm;
 	Param *pp;
 
 	m = CP_WORDS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | 
-	    CP_IPREFIX | CP_RESTORE;
+	    CP_IPREFIX | CP_ISUFFIX | CP_RESTORE;
 	for (pp = comppms, sm = 1; m; pp++, m >>= 1, sm <<= 1) {
 	    if ((m & 1) && ((*pp)->flags & PM_UNSET))
 		unset |= sm;
@@ -2373,7 +2382,8 @@ comp_wrapper(List list, FuncWrap w, char *name)
 	    } LASTALLOC;
 	    comp_setunset(CP_COMPSTATE |
 			  (~unset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
-				     CP_SUFFIX | CP_IPREFIX | CP_RESTORE)),
+				     CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX |
+				     CP_RESTORE)),
 			  unset);
 	} else
 	    comp_setunset(CP_COMPSTATE | (~unset & CP_RESTORE),
diff --git a/Src/Zle/compctl.mdd b/Src/Zle/compctl.mdd
index 113eef27e..e7b2cfb68 100644
--- a/Src/Zle/compctl.mdd
+++ b/Src/Zle/compctl.mdd
@@ -1,6 +1,6 @@
 moddeps="comp1"
 
-autobins="compctl complist compadd compset"
+autobins="compctl compgen compadd compset"
 
 autoprefixconds="prefix suffix between after"
 
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 4d9c99f87..a5da84b66 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -413,7 +413,6 @@ zleread(char *lp, char *rp, int flags)
 
     baud = getiparam("BAUD");
     costmult = (baud) ? 3840000L / baud : 0;
-    tv.tv_sec = 0;
 #endif
 
     /* ZLE doesn't currently work recursively.  This is needed in case a *
@@ -523,6 +522,7 @@ zleread(char *lp, char *rp, int flags)
 #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,
@@ -656,14 +656,18 @@ handleprefixes(void)
 	initmodifier(&zmod);
 }
 
+/* this exports the argument we are currently vared'iting if != NULL */
+
+/**/
+char *varedarg;
+
 /* vared: edit (literally) a parameter value */
 
 /**/
 static int
 bin_vared(char *name, char **args, char *ops, int func)
 {
-    char *s;
-    char *t;
+    char *s, *t, *ova = varedarg;
     Value v;
     Param pm = 0;
     int create = 0;
@@ -753,7 +757,9 @@ bin_vared(char *name, char **args, char *ops, int func)
     PERMALLOC {
 	pushnode(bufstack, ztrdup(s));
     } LASTALLOC;
+    varedarg = *args;
     t = (char *) zleread(p1, p2, ops['h'] ? ZLRF_HISTORY : 0);
+    varedarg = ova;
     if (!t || errflag) {
 	/* error in editing */
 	errflag = 0;
@@ -927,6 +933,8 @@ setup_zle(Module m)
     /* initialise the keymap system */
     init_keymaps();
 
+    varedarg = NULL;
+
     return 0;
 }
 
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index e7f1744d5..30c31c358 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -611,7 +611,7 @@ Thingy
 executenamedcommand(char *prmt)
 {
     Thingy cmd;
-    int len, l = strlen(prmt);
+    int len, l = strlen(prmt), ols = listshown;
     char *ptr;
     char *okeymap = curkeymapname;
 
@@ -629,6 +629,10 @@ executenamedcommand(char *prmt)
 	if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
 	    statusline = NULL;
 	    selectkeymap(okeymap, 1);
+	    if ((listshown = ols))
+		showinglist = -2;
+	    else
+		clearlist = 1;
 	    return NULL;
 	}
 	if(cmd == Th(z_clearscreen)) {
@@ -669,6 +673,10 @@ executenamedcommand(char *prmt)
 		    unrefthingy(r);
 		    statusline = NULL;
 		    selectkeymap(okeymap, 1);
+		    if ((listshown = ols))
+			showinglist = -2;
+		    else
+			clearlist = 1;
 		    return r;
 		}
 		unrefthingy(r);
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 6b0239961..2377b70fa 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -96,6 +96,7 @@ static int more_start,		/* more text before start of screen?	    */
     olnct,			/* previous number of lines		    */
     ovln,			/* previous video cursor position line	    */
     lpromptw, rpromptw,		/* prompt widths on screen                  */
+    lpromptwof,			/* left prompt width with real end position */
     lprompth,			/* lines taken up by the prompt		    */
     rprompth,			/* right prompt height                      */
     vcs, vln,			/* video cursor position column & line	    */
@@ -141,8 +142,14 @@ resetvideo(void)
 	    *obuf[ln] = '\0';
     }
 
-    countprompt(lpromptbuf, &lpromptw, &lprompth);
-    countprompt(rpromptbuf, &rpromptw, &rprompth);
+    countprompt(lpromptbuf, &lpromptwof, &lprompth, 1);
+    countprompt(rpromptbuf, &rpromptw, &rprompth, 0);
+    if (lpromptwof != winw)
+	lpromptw = lpromptwof;
+    else {
+	lpromptw = 0;
+	lprompth++;
+    }
 
     if (lpromptw) {
     	memset(nbuf[0], ' ', lpromptw);
@@ -271,7 +278,7 @@ zrefresh(void)
 	    clearflag = 0;
 	    resetneeded = 1;
 	}
-	listshown = 0;
+	listshown = showinglist = 0;
     }
     clearlist = 0;
 
@@ -327,7 +334,7 @@ zrefresh(void)
             vcs = 0;
         else if (!clearflag && lpromptbuf[0]) {
             zputs(lpromptbuf, shout);
-	    if (lpromptw == 0 && lprompth == 1)
+	    if (lpromptwof == winw)
 		zputs("\n", shout);	/* works with both hasam and !hasam */
 	}
 	if (clearflag) {
@@ -947,7 +954,7 @@ tc_rightcurs(int cl)
 		zputc('\r', shout);
 	    tc_upcurs(lprompth - 1);
 	    zputs(lpromptbuf, shout);
-	    if (lpromptw == 0 && lprompth == 1)
+	    if (lpromptwof == winw)
 		zputs("\n", shout);	/* works with both hasam and !hasam */
 	}
 	i = lpromptw;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 92b167cfe..8db571d0b 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -87,6 +87,10 @@ static int usemenu, useglob, useexact, useline, uselist;
 
 static int oldlist, oldins;
 
+/* Non-zero if we have to redisplay the list of matches. */
+
+static int showagain = 0;
+
 /* The match and group number to insert when starting menucompletion.   */
 
 static int insmnum, insgnum, insgroup;
@@ -555,7 +559,7 @@ acceptandmenucomplete(void)
 /* These are flags saying if we are completing in the command *
  * position, in a redirection, or in a parameter expansion.   */
 
-static int lincmd, linredir, ispar, linwhat;
+static int lincmd, linredir, ispar, linwhat, linarr;
 
 /* The string for the redirection operator. */
 
@@ -758,10 +762,14 @@ docomplete(int lst)
     char *s, *ol;
     int olst = lst, chl = 0, ne = noerrs, ocs;
 
+    if (showagain && validlist)
+	showinglist = -2;
+    showagain = 0;
+
     /* If we are doing a menu-completion... */
 
-    if (menucmp && lst != COMP_LIST_EXPAND && compwidget &&
-	compwidget == lastcompwidget) {
+    if (menucmp && lst != COMP_LIST_EXPAND && 
+	(!compwidget || compwidget == lastcompwidget)) {
 	do_menucmp(lst);
 	return;
     }
@@ -872,7 +880,7 @@ docomplete(int lst)
 	    }
 	    if (lst == COMP_EXPAND_COMPLETE)
 		do {
-		    /* check if there is a parameter expresiion. */
+		    /* Check if there is a parameter expression. */
 		    for (; *q && *q != String; q++);
 		    if (*q == String && q[1] != Inpar && q[1] != Inbrack) {
 			if (*++q == Inbrace) {
@@ -1128,7 +1136,7 @@ unmetafy_line(void)
 static char *
 get_comp_string(void)
 {
-    int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, inarr, ia, parct;
+    int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, ia, parct;
     char *s = NULL, *linptr, *tmp, *p, *tt = NULL;
 
     zsfree(brbeg);
@@ -1192,7 +1200,7 @@ get_comp_string(void)
 	inpush(dupstrspace((char *) linptr), 0, NULL);
 	strinbeg();
 	stophist = 2;
-	i = tt0 = cp = rd = ins = oins = inarr = parct = ia = 0;
+	i = tt0 = cp = rd = ins = oins = linarr = parct = ia = 0;
 
 	/* This loop is possibly the wrong way to do this.  It goes through *
 	 * the previously massaged command line using the lexer.  It stores *
@@ -1211,11 +1219,11 @@ get_comp_string(void)
 	    linredir = (inredir && !ins);
 	    oins = ins;
 	    /* Get the next token. */
-	    if (inarr)
+	    if (linarr)
 		incmdpos = 0;
 	    ctxtlex();
 	    if (tok == ENVARRAY) {
-		inarr = 1;
+		linarr = 1;
 		zsfree(varname);
 		varname = ztrdup(tokstr);
 	    } else if (tok == INPAR)
@@ -1224,7 +1232,7 @@ get_comp_string(void)
 		if (parct)
 		    parct--;
 		else
-		    inarr = 0;
+		    linarr = 0;
 	    }
 	    if (inredir)
 		rdstr = tokstrings[tok];
@@ -1267,7 +1275,7 @@ get_comp_string(void)
 		clwpos = i;
 		cp = lincmd;
 		rd = linredir;
-		ia = inarr;
+		ia = linarr;
 		if (inwhat == IN_NOTHING && incond)
 		    inwhat = IN_COND;
 	    } else if (linredir)
@@ -1515,12 +1523,53 @@ get_comp_string(void)
 	     */
 	    for (i = 0, p = s; *p; p++, i++) {
 		/* careful, ${... is not a brace expansion...
-		 * in fact, if it's got a substitution in it's too
-		 * hard for us anyway.  sorry.
+		 * we try to get braces after a parameter expansion right,
+		 * but this may fail sometimes. sorry.
 		 */
 		if (*p == String || *p == Qstring) {
-		    tt = NULL;
-		    break;
+		    if (p[1] == Inbrace || p[1] == Inpar || p[1] == Inbrack) {
+			char *tp = p + 1;
+			if (skipparens(*tp, (*tp == Inbrace ? Outbrace :
+					     (*tp == Inpar ? Outpar : Outbrack)),
+				       &tp)) {
+			    tt = NULL;
+			    break;
+			}
+			i += tp - p;
+			p = tp;
+		    } else {
+			char *tp = p + 1;
+
+			for (; *tp == '^' || *tp == Hat ||
+				 *tp == '=' || *tp == Equals ||
+				 *tp == '~' || *tp == Tilde ||
+				 *tp == '#' || *tp == Pound || *tp == '+';
+			     tp++);
+			if (*tp == Quest || *tp == Star || *tp == String ||
+			    *tp == Qstring || *tp == '?' || *tp == '*' ||
+			    *tp == '$' || *tp == '-' || *tp == '!' ||
+			    *tp == '@')
+			    p++, i++;
+			else {
+			    if (idigit(*tp))
+				while (idigit(*tp))
+				    tp++;
+			    else if (iident(*tp))
+				while (iident(*tp))
+				    tp++;
+			    else {
+				tt = NULL;
+				break;
+			    }
+			    if (*tp == Inbrace) {
+				tt = NULL;
+				break;
+			    }
+			    tp--;
+			    i += tp - p;
+			    p = tp;
+			}
+		    }
 		} else if (*p == Inbrace) {
 		    if (tt) {
 			/* too many inbraces */
@@ -3472,14 +3521,10 @@ set_param(char *name, LinkList l)
 
 /**/
 int
-addmatches(char *ipre, char *isuf,
-	   char *ppre, char *psuf, char *prpre, char *pre,
-	   char *suf, char *group, char *rems, char *remf, char *ign,
-	   int flags, int aflags, Cmatcher match, char *exp, 
-	   char *apar, char *opar, char **argv)
+addmatches(Cadata dat, char **argv)
 {
     char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
-    char **aign = NULL;
+    char **aign = NULL, **dparr;
     int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
     int oisalt = 0, isalt, isexact, doadd;
     Cline lc = NULL;
@@ -3487,45 +3532,52 @@ addmatches(char *ipre, char *isuf,
     struct cmlist mst;
     Cmlist oms = mstack;
     Comp cp = NULL;
-    LinkList aparl = NULL, oparl = NULL;
+    LinkList aparl = NULL, oparl = NULL, dparl = NULL;
 
     /* Switch back to the heap that was used when the completion widget
      * was invoked. */
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
-	    doadd = (!apar && !opar);
-	    if (apar)
+	    doadd = (!dat->apar && !dat->opar && !dat->dpar);
+	    if (dat->apar)
 		aparl = newlinklist();
-	    if (opar)
+	    if (dat->opar)
 		oparl = newlinklist();
-	    if (exp) {
+	    if (dat->dpar) {
+		if (*(dat->dpar) == '(')
+		    dparr = NULL;
+		else if ((dparr = get_user_var(dat->dpar)) && !*dparr)
+		    dparr = NULL;
+		dparl = newlinklist();
+	    }
+	    if (dat->exp) {
 		expl = (Cexpl) zhalloc(sizeof(struct cexpl));
 		expl->count = expl->fcount = 0;
-		expl->str = dupstring(exp);
+		expl->str = dupstring(dat->exp);
 	    } else
 		expl = NULL;
 
 	    /* Store the matcher in our stack of matchers. */
-	    if (match) {
+	    if (dat->match) {
 		mst.next = mstack;
-		mst.matcher = match;
+		mst.matcher = dat->match;
 		mstack = &mst;
 
 		if (!mnum)
-		    add_bmatchers(match);
+		    add_bmatchers(dat->match);
 
-		addlinknode(matchers, match);
-		match->refc++;
+		addlinknode(matchers, dat->match);
+		dat->match->refc++;
 	    }
 	    if (mnum && (mstack || bmatchers))
 		update_bmatchers();
 
 	    /* Get the suffixes to ignore. */
-	    if (ign)
-		aign = get_user_var(ign);
+	    if (dat->ign)
+		aign = get_user_var(dat->ign);
 	    /* Get the contents of the completion variables if we have
 	     * to perform matching. */
-	    if (aflags & CAF_MATCH) {
+	    if (dat->aflags & CAF_MATCH) {
 		lipre = dupstring(compiprefix);
 		lisuf = dupstring(compisuffix);
 		lpre = dupstring(compprefix);
@@ -3533,8 +3585,8 @@ addmatches(char *ipre, char *isuf,
 		llpl = strlen(lpre);
 		llsl = strlen(lsuf);
 		/* Test if there is an existing -P prefix. */
-		if (pre && *pre) {
-		    pl = pfxlen(pre, lpre);
+		if (dat->pre && *dat->pre) {
+		    pl = pfxlen(dat->pre, lpre);
 		    llpl -= pl;
 		    lpre += pl;
 		}
@@ -3557,79 +3609,76 @@ addmatches(char *ipre, char *isuf,
 		}
 	    }
 	    /* Now duplicate the strings we have from the command line. */
-	    if (ipre)
-		ipre = (lipre ? dyncat(lipre, ipre) : dupstring(ipre));
+	    if (dat->ipre)
+		dat->ipre = (lipre ? dyncat(lipre, dat->ipre) :
+			     dupstring(dat->ipre));
 	    else if (lipre)
-		ipre = lipre;
-	    if (isuf)
-		isuf = (lisuf ? dyncat(lisuf, isuf) : dupstring(isuf));
+		dat->ipre = lipre;
+	    if (dat->isuf)
+		dat->isuf = (lisuf ? dyncat(lisuf, dat->isuf) :
+			     dupstring(dat->isuf));
 	    else if (lisuf)
-		isuf = lisuf;
-	    if (ppre) {
-		ppre = dupstring(ppre);
-		lpl = strlen(ppre);
+		dat->isuf = lisuf;
+	    if (dat->ppre) {
+		dat->ppre = dupstring(dat->ppre);
+		lpl = strlen(dat->ppre);
 	    } else
 		lpl = 0;
-	    if (psuf) {
-		psuf = dupstring(psuf);
-		lsl = strlen(psuf);
+	    if (dat->psuf) {
+		dat->psuf = dupstring(dat->psuf);
+		lsl = strlen(dat->psuf);
 	    } else
 		lsl = 0;
-	    if (aflags & CAF_MATCH) {
-		s = ppre ? ppre : "";
-		if (llpl <= lpl && strpfx(lpre, s)) {
-		    llpl = 0;
+	    if (dat->aflags & CAF_MATCH) {
+		s = dat->ppre ? dat->ppre : "";
+		if (llpl <= lpl && strpfx(lpre, s))
 		    lpre = "";
-		} else if (llpl > lpl && strpfx(s, lpre)) {
-		    llpl -= lpl;
+		else if (llpl > lpl && strpfx(s, lpre))
 		    lpre += lpl;
-		} else
+		else
 		    *argv = NULL;
-		s = psuf ? psuf : "";
-		if (llsl <= lsl && strsfx(lsuf, s)) {
-		    llsl = 0;
+		s = dat->psuf ? dat->psuf : "";
+		if (llsl <= lsl && strsfx(lsuf, s))
 		    lsuf = "";
-		} else if (llsl > lsl && strsfx(s, lsuf)) {
+		else if (llsl > lsl && strsfx(s, lsuf))
 		    lsuf[llsl - lsl] = '\0';
-		    llsl -= lsl;
-		} else
+		else
 		    *argv = NULL;
 	    }
 	    if (*argv) {
-		if (pre)
-		    pre = dupstring(pre);
-		if (suf)
-		    suf = dupstring(suf);
-		if (!prpre && (prpre = ppre)) {
-		    singsub(&prpre);
-		    untokenize(prpre);
+		if (dat->pre)
+		    dat->pre = dupstring(dat->pre);
+		if (dat->suf)
+		    dat->suf = dupstring(dat->suf);
+		if (!dat->prpre && (dat->prpre = dat->ppre)) {
+		    singsub(&(dat->prpre));
+		    untokenize(dat->prpre);
 		} else
-		    prpre = dupstring(prpre);
+		    dat->prpre = dupstring(dat->prpre);
 		/* Select the group in which to store the matches. */
-		if (group) {
+		if (dat->group) {
 		    endcmgroup(NULL);
-		    begcmgroup(group, (aflags & CAF_NOSORT));
-		    if (aflags & CAF_NOSORT)
+		    begcmgroup(dat->group, (dat->aflags & CAF_NOSORT));
+		    if (dat->aflags & CAF_NOSORT)
 			mgroup->flags |= CGF_NOSORT;
 		} else {
 		    endcmgroup(NULL);
 		    begcmgroup("default", 0);
 		}
 		/* Select the set of matches. */
-		oisalt = (aflags & CAF_ALT);
+		oisalt = (dat->aflags & CAF_ALT);
 
-		if (remf) {
-		    remf = dupstring(remf);
-		    rems = NULL;
-		} else if (rems)
-		    rems = dupstring(rems);
+		if (dat->remf) {
+		    dat->remf = dupstring(dat->remf);
+		    dat->rems = NULL;
+		} else if (dat->rems)
+		    dat->rems = dupstring(dat->rems);
 
 		/* Probably quote the prefix and suffix for testing. */
-		if (!cp && (aflags & CAF_MATCH) && !(aflags & CAF_QUOTE)) {
+		if (!cp && (dat->aflags & CAF_MATCH) &&
+		    !(dat->aflags & CAF_QUOTE)) {
 		    lpre = quotename(lpre, NULL);
 		    lsuf = quotename(lsuf, NULL);
-		    llpl = strlen(lpre);
-		    llsl = strlen(lsuf);
 		}
 	    }
 	    /* Walk through the matches given. */
@@ -3638,7 +3687,7 @@ addmatches(char *ipre, char *isuf,
 		bpl = brpl;
 		bsl = brsl;
 		isalt = oisalt;
-		if ((!psuf || !*psuf) && aign) {
+		if ((!dat->psuf || !*(dat->psuf)) && aign) {
 		    /* Do the suffix-test. If the match has one of the
 		     * suffixes from ign, we put it in the alternate set. */
 		    char **pt = aign;
@@ -3649,39 +3698,52 @@ addmatches(char *ipre, char *isuf,
 			    && !strcmp(*pt, s + sl - filell))
 			    isalt = 1;
 
-		    if (isalt && !doadd)
+		    if (isalt && !doadd) {
+			if (dparr && !*++dparr)
+			    dparr = NULL;
 			continue;
+		    }
 		}
-		if (!(aflags & CAF_MATCH)) {
+		if (!(dat->aflags & CAF_MATCH)) {
 		    ms = dupstring(s);
 		    lc = bld_parts(ms, sl, -1, NULL);
 		    isexact = 0;
 		} else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc,
-					     !(aflags & CAF_QUOTE),
-					     &bpl, &bsl, &isexact)))
+					     !(dat->aflags & CAF_QUOTE),
+					     &bpl, &bsl, &isexact))) {
+		    if (dparr && !*++dparr)
+			dparr = NULL;
 		    continue;
-
+		}
 		if (doadd) {
-		    cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, 
-					prpre, ppre, psuf, suf, bpl, bsl,
-					flags, isexact);
-		    cm->rems = rems;
-		    cm->remf = remf;
+		    cm = add_match_data(isalt, ms, lc, dat->ipre, dat->ipre,
+					dat->isuf, dat->pre, dat->prpre,
+					dat->ppre, dat->psuf, dat->suf,
+					bpl, bsl, dat->flags, isexact);
+		    cm->rems = dat->rems;
+		    cm->remf = dat->remf;
 		} else {
-		    if (apar)
+		    if (dat->apar)
 			addlinknode(aparl, ms);
-		    if (opar)
+		    if (dat->opar)
 			addlinknode(oparl, s);
+		    if (dat->dpar && dparr) {
+			addlinknode(dparl, *dparr);
+			if (!*++dparr)
+			    dparr = NULL;
+		    }
 		    free_cline(lc);
 		}
 	    }
 	    compnmatches = mnum;
-	    if (exp)
+	    if (dat->exp)
 		addexpl();
-	    if (apar)
-		set_param(apar, aparl);
-	    if (opar)
-		set_param(opar, oparl);
+	    if (dat->apar)
+		set_param(dat->apar, aparl);
+	    if (dat->opar)
+		set_param(dat->opar, oparl);
+	    if (dat->dpar)
+		set_param(dat->dpar, dparl);
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
 
@@ -4128,6 +4190,7 @@ docompletion(char *s, int lst, int incmd)
 				(unset(ALWAYSLASTPROMPT) && zmult != 1)) ?
 				"yes" : "");
 	movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1);
+	showinglist = 0;
 
 	/* Make sure we have the completion list and compctl. */
 	if (makecomplist(s, incmd, lst)) {
@@ -4217,14 +4280,22 @@ callcompfunc(char *s, char *fn)
 
     if ((list = getshfunc(fn)) != &dummy_list) {
 	char **p, *tmp;
-	int set, aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
+	int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
+	unsigned int set;
 	Param *ocpms = comppms;
 
 	comppms = (Param *) zalloc(CP_NUM * sizeof(Param));
 
-	set = -1 & ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING |
-		     CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS |
-		     (useglob ? 0 : CP_PATMATCH));
+	set = CP_ALLMASK &
+	    ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING |
+	      CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS |
+	      (useglob ? 0 : CP_PATMATCH));
+	zsfree(compvared);
+	if (varedarg) {
+	    compvared = ztrdup(varedarg);
+	    set |= CP_VARED;
+	} else
+	    compvared = ztrdup("");
 	if (!*complastprompt)
 	    set &= ~CP_LASTPROMPT;
 	zsfree(compcontext);
@@ -4257,7 +4328,7 @@ callcompfunc(char *s, char *fn)
 	} else
 	    switch (linwhat) {
 	    case IN_ENV:
-		compcontext = "array_value";
+		compcontext = (linarr ? "array_value" : "value");
 		compparameter = varname;
 		set |= CP_PARAMETER;
 		if (!clwpos) {
@@ -4551,6 +4622,7 @@ makecomplist(char *s, int incmd, int lst)
 	insmnum = insgnum = 1;
 	insgroup = oldlist = oldins = 0;
 	begcmgroup("default", 0);
+	menucmp = 0;
 
 	ccused = newlinklist();
 	ccstack = newlinklist();
@@ -6717,11 +6789,13 @@ unambig_data(int *cp)
     return scache;
 }
 
-/* Insert the given match. This returns the number of characters inserted.*/
+/* Insert the given match. This returns the number of characters inserted.
+ * scs is used to return the position where a automatically created suffix
+ * has to be inserted. */
 
 /**/
 static int
-instmatch(Cmatch m)
+instmatch(Cmatch m, int *scs)
 {
     int l, r = 0, ocs, a = cs;
 
@@ -6771,6 +6845,7 @@ instmatch(Cmatch m)
     } else
 	brscs = -1;
     /* -S suffix */
+    *scs = cs;
     if (m->suf) {
 	inststrlen(m->suf, 1, (l = strlen(m->suf)));
 	r += l;
@@ -6842,13 +6917,13 @@ do_ambiguous(void)
 
 	/* If REC_EXACT and AUTO_MENU are set and what we inserted is an  *
 	 * exact match, we want menu completion the next time round       *
-	 * so we set fromcomp,to ensure that the word on the line is not  *
+	 * so we set fromcomp, to ensure that the word on the line is not *
 	 * taken as an exact match. Also we remember if we just moved the *
 	 * cursor into the word.                                          */
 	fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) |
 		    ((atend && cs != lastend) ? FC_INWORD : 0));
 
-	/* Probably move the cursor to then end. */
+	/* Probably move the cursor to the end. */
 	if (movetoend == 3)
 	    cs = lastend;
 
@@ -6907,7 +6982,7 @@ ztat(char *nam, struct stat *buf, int ls)
 static void
 do_single(Cmatch m)
 {
-    int l, sr = 0;
+    int l, sr = 0, scs;
     int havesuff = 0;
     char *str = m->str, *ppre = m->ppre, *psuf = m->psuf, *prpre = m->prpre;
 
@@ -6937,7 +7012,7 @@ do_single(Cmatch m)
     foredel(l);
 
     /* And then we insert the new string. */
-    menulen = instmatch(m);
+    menulen = instmatch(m, &scs);
     menuend = cs;
     cs = menupos + menulen;
 
@@ -6956,6 +7031,7 @@ do_single(Cmatch m)
     } else {
 	/* There is no user-specified suffix, *
 	 * so generate one automagically.     */
+	cs = scs;
 	if (m->ripre && (m->flags & CMF_PARBR)) {
 	    /*{{*/
 	    /* Completing a parameter in braces.  Add a removable `}' suffix. */
@@ -7006,6 +7082,8 @@ do_single(Cmatch m)
 		}
 	    }
 	}
+	if (!menuinsc)
+	    cs = menupos + menulen;
     }
     /* If completing in a brace expansion... */
     if (brbeg) {
@@ -7018,7 +7096,7 @@ do_single(Cmatch m)
 	} else if (!menucmp) {
 	    /*{{*/
 	    /* Otherwise, add a `,' suffix, and let `}' remove it. */
-	    cs = menuend;
+	    cs = scs;
 	    havesuff = 1;
 	    inststrlen(",", 1, 1);
 	    menuinsc++;
@@ -7492,7 +7570,12 @@ listlist(LinkList l)
     struct cmgroup dg;
     Cmgroup am = amatches;
     int vl = validlist, sm = smatches;
+    char *oclp = complastprompt;
+
+    if (listshown)
+	showagain = 1;
 
+    complastprompt = ((zmult == 1) == !!isset(ALWAYSLASTPROMPT) ? "yes" : NULL);
     smatches = 1;
     validlist = 1;
     amatches = &dg;
@@ -7503,6 +7586,7 @@ listlist(LinkList l)
     amatches = am;
     validlist = vl;
     smatches = sm;
+    complastprompt = oclp;
 }
 
 /* Expand the history references. */
diff --git a/Src/builtin.c b/Src/builtin.c
index c042537f4..9ffcad1b3 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -120,7 +120,7 @@ static struct builtin builtins[] =
     BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"),
 
 #ifdef DYNAMIC
-    BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicI", NULL),
+    BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicIp", NULL),
 #endif
 };
 
@@ -1485,7 +1485,7 @@ typeset_single(char *cname, char *pname, Param pm, int func,
     int usepm, tc, keeplocal = 0;
 
     /* use the existing pm? */
-    usepm = pm && !(pm->flags & PM_UNSET);
+    usepm = pm && !(pm->flags & (PM_UNSET | PM_AUTOLOAD));
 
     /* Always use an existing pm if special at current locallevel */
     if (pm && (pm->flags & PM_SPECIAL) && pm->level == locallevel)
@@ -1793,7 +1793,9 @@ bin_typeset(char *name, char **argv, char *ops, int func)
 	    continue;
 	}
 	if (!typeset_single(name, asg->name,
-			    (Param)paramtab->getnode(paramtab, asg->name),
+			    (Param) (paramtab == realparamtab ?
+				     gethashnode2(paramtab, asg->name) :
+				     paramtab->getnode(paramtab, asg->name)),
 			    func, on, off, roff, asg->value, NULL))
 	    returnval = 1;
     }
@@ -1945,7 +1947,7 @@ bin_unset(char *name, char **argv, char *ops, int func)
 			next = (Param) pm->next;
 			if ((!(pm->flags & PM_RESTRICTED) ||
 			    unset(RESTRICTED)) && domatch(pm->nam, com, 0)) {
-			    unsetparam(pm->nam);
+			    unsetparam_pm(pm, 0, 1);
 			    match++;
 			}
 		    }
@@ -1974,7 +1976,9 @@ bin_unset(char *name, char **argv, char *ops, int func)
 	    }
 	    *ss = 0;
 	}
-	pm = (Param) paramtab->getnode(paramtab, s);
+	pm = (Param) (paramtab == realparamtab ?
+		      gethashnode2(paramtab, s) :
+		      paramtab->getnode(paramtab, s));
 	if (!pm)
 	    returnval = 1;
 	else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
diff --git a/Src/glob.c b/Src/glob.c
index 47ca1d659..79a86bbef 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -3379,16 +3379,14 @@ tokenize(char *s)
 	    *t = Inang;
 	    *s = Outang;
 	    break;
-	case '^':
-	case '#':
-	case '~':
-	    if (unset(EXTENDEDGLOB))
-		break;
 	case '(':
 	case '|':
 	case ')':
 	    if (isset(SHGLOB))
 		break;
+	case '^':
+	case '#':
+	case '~':
 	case '[':
 	case ']':
 	case '*':
diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh
index b58d1e1dd..c174cbac6 100644
--- a/Src/mkbltnmlst.sh
+++ b/Src/mkbltnmlst.sh
@@ -24,7 +24,7 @@ for x_mod in $x_mods; do
 	*" $x_mod "*) ;;
 	*)  echo "/* non-linked-in known module \`$x_mod' */"
 	    eval "loc=\$loc_$x_mod"
-	    unset moddeps autobins autoinfixconds autoprefixconds
+	    unset moddeps autobins autoinfixconds autoprefixconds autoparams
 	    . $srcdir/../$loc/${x_mod}.mdd
 	    for bin in $autobins; do
 		echo "    add_autobin(\"$bin\", \"$x_mod\");"
@@ -35,6 +35,9 @@ for x_mod in $x_mods; do
 	    for cond in $autoprefixconds; do
 		echo "    add_autocond(\"$cond\", 0, \"$x_mod\");"
 	    done
+	    for param in $autoparams; do
+		echo "    add_autoparam(\"$param\", \"$x_mod\");"
+	    done
 	    for dep in $moddeps; do
 		case $bin_mods in
 		    *" $dep "*)
diff --git a/Src/mkmakemod.sh b/Src/mkmakemod.sh
index 2f79acbc3..cd92c7f07 100644
--- a/Src/mkmakemod.sh
+++ b/Src/mkmakemod.sh
@@ -24,6 +24,7 @@
 #   autoinfixconds  infix condition codes defined by the module, for
 #                   autoloading (without the leading `-')
 #   autoprefixconds like autoinfixconds, but for prefix condition codes
+#   autoparams      parameters defined by the module, for autoloading
 #   objects         .o files making up this module (*must* be defined)
 #   proto           .pro files for this module (default generated from $objects)
 #   headers         extra headers for this module (default none)
@@ -170,7 +171,7 @@ if $first_stage; then
     for module in $here_modules; do
 
 	unset moddeps nozshdep alwayslink hasexport
-	unset autobins autoinfixconds autoprefixconds
+	unset autobins autoinfixconds autoprefixconds autoparams
 	unset objects proto headers hdrdeps otherincs
 	. $top_srcdir/$the_subdir/${module}.mdd
 	test -n "${moddeps+set}" || moddeps=
diff --git a/Src/module.c b/Src/module.c
index ff386c630..09f1fd5db 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -539,18 +539,24 @@ load_module(char const *name)
 	m = zcalloc(sizeof(*m));
 	m->nam = ztrdup(name);
 	m->handle = handle;
+	m->flags |= MOD_SETUP;
+	PERMALLOC {
+	    node = addlinknode(modules, m);
+	} LASTALLOC;
 	if (setup_module(m) || init_module(m)) {
 	    finish_module(m);
+	    remnode(modules, node);
 	    zsfree(m->nam);
 	    zfree(m, sizeof(*m));
+	    m->flags &= ~MOD_SETUP;
 	    return NULL;
 	}
-	PERMALLOC {
-	    addlinknode(modules, m);
-	} LASTALLOC;
+	m->flags &= ~MOD_SETUP;
 	return m;
     } 
     m = (Module) getdata(node);
+    if (m->flags & MOD_SETUP)
+	return m;
     if (m->flags & MOD_UNLOAD)
 	m->flags &= ~MOD_UNLOAD;
     else if (m->handle)
@@ -570,17 +576,22 @@ load_module(char const *name)
     if (!m->handle) {
 	if (!(m->handle = do_load_module(name)))
 	    return NULL;
+	m->flags |= MOD_SETUP;
 	if (setup_module(m)) {
 	    finish_module(m->handle);
 	    m->handle = NULL;
+	    m->flags &= ~MOD_SETUP;
 	    return NULL;
 	}
     }
+    m->flags |= MOD_SETUP;
     if (init_module(m)) {
 	finish_module(m->handle);
 	m->handle = NULL;
+	m->flags &= ~MOD_SETUP;
 	return NULL;
     }
+    m->flags &= ~MOD_SETUP;
     return m;
 }
 
@@ -690,6 +701,8 @@ bin_zmodload(char *nam, char **args, char *ops, int func)
 	return bin_zmodload_auto(nam, args, ops);
     else if (ops['c'] || ops['C'])
 	return bin_zmodload_cond(nam, args, ops);
+    else if (ops['p'])
+	return bin_zmodload_param(nam, args, ops);
     else
 	return bin_zmodload_load(nam, args, ops);
 }
@@ -888,6 +901,66 @@ bin_zmodload_cond(char *nam, char **args, char *ops)
     }
 }
 
+static void
+printautoparams(HashNode hn, int lon)
+{
+    Param pm = (Param) hn;
+
+    if (pm->flags & PM_AUTOLOAD) {
+	if (lon)
+	    printf("zmodload -p %s %s\n", pm->u.str, pm->nam);
+	else
+	    printf("%s (%s)\n", pm->nam, pm->u.str);
+    }
+}
+
+/**/
+static int
+bin_zmodload_param(char *nam, char **args, char *ops)
+{
+    int ret = 0;
+
+    if (ops['u']) {
+	/* remove autoloaded parameters */
+	for (; *args; args++) {
+	    Param pm = (Param) gethashnode2(paramtab, *args);
+
+	    if (!pm) {
+		if (!ops['i']) {
+		    zwarnnam(nam, "%s: no such parameter", *args, 0);
+		    ret = 1;
+		}
+	    } else if (!(pm->flags & PM_AUTOLOAD)) {
+		zwarnnam(nam, "%s: parameter is already defined", *args, 0);
+		ret = 1;
+	    } else
+		unsetparam_pm(pm, 0, 1);
+	}
+	return ret;
+    } else if (!*args) {
+	scanhashtable(paramtab, 1, 0, 0, printautoparams, ops['L']);
+	return 0;
+    } else {
+	/* add autoloaded parameters */
+	char *modnam;
+
+	modnam = *args++;
+	if(isset(RESTRICTED) && strchr(modnam, '/')) {
+	    zwarnnam(nam, "%s: restricted", modnam, 0);
+	    return 1;
+	}
+	do {
+	    char *pnam = *args ? *args++ : modnam;
+	    if (strchr(pnam, '/')) {
+		zwarnnam(nam, "%s: `/' is illegal in a parameter", pnam, 0);
+		ret = 1;
+	    } else
+		add_autoparam(pnam, modnam);
+	} while(*args);
+	return ret;
+    }
+}
+
 /**/
 int
 unload_module(Module m, LinkNode node)
@@ -1114,6 +1187,71 @@ addconddefs(char const *nam, Conddef c, int size)
     return hadf ? hads : 1;
 }
 
+/* This adds the given parameter definition. The return value is zero on *
+ * success and 1 on failure. */
+
+/**/
+int
+addparamdef(Paramdef d)
+{
+    Param pm;
+
+    if ((pm = (Param) gethashnode2(paramtab, d->name)))
+	unsetparam_pm(pm, 0, 1);
+
+    if (!(pm = createparam(d->name, d->flags)) &&
+	!(pm = (Param) paramtab->getnode(paramtab, d->name)))
+	return 1;
+
+    pm->level = 0;
+    pm->u.data = d->var;
+    pm->sets.ifn = (void (*)(Param, long)) d->set;
+    pm->gets.ifn = (long (*)(Param)) d->get;
+    pm->unsetfn = (void (*)(Param, int)) d->unset;
+
+    return 0;
+}
+
+/* This adds multiple parameter definitions. This is like addbuiltins(). */
+
+/**/
+int
+addparamdefs(char const *nam, Paramdef d, int size)
+{
+    int hads = 0, hadf = 0;
+
+    while (size--) {
+	if (addparamdef(d)) {
+	    zwarnnam(nam, "error when adding parameter `%s'", d->name, 0);
+	    hadf = 1;
+	} else
+	    hads = 2;
+	d++;
+    }
+    return hadf ? hads : 1;
+}
+
+/* Delete parameters defined. No error checking yet. */
+
+/**/
+int
+deleteparamdef(Paramdef d)
+{
+    unsetparam(d->name);
+    return 0;
+}
+
+/**/
+int
+deleteparamdefs(char const *nam, Paramdef d, int size)
+{
+    while (size--) {
+	deleteparamdef(d);
+	d++;
+    }
+    return 1;
+}
+
 #ifdef DYNAMIC
 
 /* This adds a definition for autoloading a module for a condition. */
@@ -1188,4 +1326,20 @@ deleteconddefs(char const *nam, Conddef c, int size)
     return hadf ? hads : 1;
 }
 
+/* This adds a definition for autoloading a module for a parameter. */
+
+/**/
+void
+add_autoparam(char *nam, char *module)
+{
+    Param pm;
+
+    if ((pm = (Param) gethashnode2(paramtab, nam)))
+	unsetparam_pm(pm, 0, 1);
+
+    pm = setsparam(ztrdup(nam), ztrdup(module));
+
+    pm->flags |= PM_AUTOLOAD;
+}
+
 #endif
diff --git a/Src/params.c b/Src/params.c
index dbc6ce8d8..d60f91990 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -255,7 +255,11 @@ static Param argvparam;
 /* hash table containing the parameters */
  
 /**/
-HashTable paramtab;
+HashTable paramtab, realparamtab;
+
+#ifndef DYNAMIC
+#define getparamnode gethashnode2
+#endif /* DYNAMIC */
 
 /**/
 HashTable
@@ -267,8 +271,8 @@ newparamtable(int size, char const *name)
     ht->emptytable  = emptyhashtable;
     ht->filltable   = NULL;
     ht->addnode     = addhashnode;
-    ht->getnode     = gethashnode2;
-    ht->getnode2    = gethashnode2;
+    ht->getnode     = getparamnode;
+    ht->getnode2    = getparamnode;
     ht->removenode  = removehashnode;
     ht->disablenode = NULL;
     ht->enablenode  = NULL;
@@ -278,6 +282,25 @@ newparamtable(int size, char const *name)
     return ht;
 }
 
+#ifdef DYNAMIC
+/**/
+static HashNode
+getparamnode(HashTable ht, char *nam)
+{
+    HashNode hn = gethashnode2(ht, nam);
+    Param pm = (Param) hn;
+
+    if (pm && pm->u.str && (pm->flags & PM_AUTOLOAD)) {
+	char *mn = dupstring(pm->u.str);
+
+	if (!load_module(mn))
+	    return NULL;
+	hn = gethashnode2(ht, nam);
+    }
+    return hn;
+}
+#endif /* DYNAMIC */
+
 /* Copy a parameter hash table */
 
 static HashTable outtable;
@@ -402,7 +425,7 @@ createparamtable(void)
     char buf[50], *str, *iname;
     int num_env;
 
-    paramtab = newparamtable(151, "paramtab");
+    paramtab = realparamtab = newparamtable(151, "paramtab");
 
     /* Add the special parameters to the hash table */
     for (ip = special_params; ip->nam; ip++)
@@ -542,7 +565,9 @@ createparam(char *name, int flags)
     Param pm, oldpm;
 
     if (name != nulstring) {
-	oldpm = (Param) paramtab->getnode(paramtab, name);
+	oldpm = (Param) (paramtab == realparamtab ?
+			 gethashnode2(paramtab, name) :
+			 paramtab->getnode(paramtab, name));
 
 	if (oldpm && oldpm->level == locallevel) {
 	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
@@ -2703,6 +2728,8 @@ printparamnode(HashNode hn, int printflags)
 
     /* Print the attributes of the parameter */
     if (printflags & PRINT_TYPE) {
+	if (p->flags & PM_AUTOLOAD)
+	    printf("undefined ");
 	if (p->flags & PM_INTEGER)
 	    printf("integer ");
 	else if (p->flags & PM_ARRAY)
@@ -2736,6 +2763,11 @@ printparamnode(HashNode hn, int printflags)
     }
 
     quotedzputs(p->nam, stdout);
+
+    if (p->flags & PM_AUTOLOAD) {
+	putchar('\n');
+	return;
+    }
     if (printflags & PRINT_KV_PAIR)
 	putchar(' ');
     else
diff --git a/Src/prompt.c b/Src/prompt.c
index 69823a5e3..ad7cdbc31 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -232,7 +232,7 @@ putpromptchar(int doprint, int endchar)
 		    break;
 		case 'l':
 		    *bp = '\0';
-		    countprompt(bufline, &t0, 0);
+		    countprompt(bufline, &t0, 0, 0);
 		    if (t0 >= arg)
 			test = 1;
 		    break;
@@ -678,11 +678,15 @@ putstr(int d)
 
 /**/
 void
-countprompt(char *str, int *wp, int *hp)
+countprompt(char *str, int *wp, int *hp, int overf)
 {
     int w = 0, h = 1;
     int s = 1;
     for(; *str; str++) {
+	if(w >= columns) {
+	    w = 0;
+	    h++;
+	}
 	if(*str == Meta)
 	    str++;
 	if(*str == Inpar)
@@ -694,12 +698,15 @@ countprompt(char *str, int *wp, int *hp)
 	else if(s) {
 	    if(*str == '\t')
 		w = (w | 7) + 1;
-	    else if(*str == '\n')
-		w = columns;
-	    else
+	    else if(*str == '\n') {
+		w = 0;
+		h++;
+	    } else
 		w++;
 	}
-	if(w >= columns) {
+    }
+    if(w >= columns) {
+	if (!overf || w > columns) {
 	    w = 0;
 	    h++;
 	}
diff --git a/Src/zsh.export b/Src/zsh.export
index dcee683f6..7f994bf29 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -4,6 +4,7 @@ addbuiltins
 addconddefs
 addedx
 addhashnode
+addparamdefs
 addwrapper
 arrvargetfn
 arrvarsetfn
@@ -40,6 +41,7 @@ current_limits
 deletebuiltins
 deleteconddefs
 deletehashtable
+deleteparamdefs
 deletewrapper
 domatch
 doshfunc
diff --git a/Src/zsh.h b/Src/zsh.h
index c3c853dfd..1eefc51c1 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -231,6 +231,7 @@ typedef struct hashtable *HashTable;
 typedef struct reswd     *Reswd;
 typedef struct alias     *Alias;
 typedef struct param     *Param;
+typedef struct paramdef  *Paramdef;
 typedef struct cmdnam    *Cmdnam;
 typedef struct shfunc    *Shfunc;
 typedef struct funcwrap  *FuncWrap;
@@ -850,6 +851,7 @@ struct module {
 
 #define MOD_BUSY    (1<<0)
 #define MOD_UNLOAD  (1<<1)
+#define MOD_SETUP   (1<<2)
 
 /* node used in parameter hash table (paramtab) */
 
@@ -923,6 +925,7 @@ struct param {
 #define PM_RESTRICTED	(1<<15) /* cannot be changed in restricted mode       */
 #define PM_UNSET	(1<<16)	/* has null value                             */
 #define PM_REMOVABLE	(1<<17)	/* special can be removed from paramtab */
+#define PM_AUTOLOAD     (1<<18) /* autoloaded from module */
 
 /* Flags for extracting elements of arrays and associative arrays */
 #define SCANPM_WANTVALS   (1<<0)
@@ -955,6 +958,27 @@ struct param {
 #define PF_ASSIGN	0x02	/* argument handled like the RHS of foo=bar */
 #define PF_SINGLE	0x04	/* single word substitution */
 
+struct paramdef {
+    char *name;
+    int flags;
+    void *var;
+    void *set;
+    void *get;
+    void *unset;
+};
+
+#define PARAMDEF(name, flags, var, set, get, unset) \
+    { name, flags, (void *) var, (void *) set, (void *) get, (void *) unset }
+#define INTPARAMDEF(name, var) \
+    { name, PM_INTEGER, (void *) var, (void *) intvarsetfn, \
+      (void *) intvargetfn, (void *) stdunsetfn }
+#define STRPARAMDEF(name, var) \
+    { name, PM_SCALAR, (void *) var, (void *) strvarsetfn, \
+      (void *) strvargetfn, (void *) stdunsetfn }
+#define ARRPARAMDEF(name, var) \
+    { name, PM_ARRAY, (void *) var, (void *) arrvarsetfn, \
+      (void *) arrvargetfn, (void *) stdunsetfn }
+
 /* node for named directory hash table (nameddirtab) */
 
 struct nameddir {
diff --git a/Util/zsh-development-guide b/Util/zsh-development-guide
index f779b17b3..3775f43b7 100644
--- a/Util/zsh-development-guide
+++ b/Util/zsh-development-guide
@@ -127,6 +127,7 @@ variables:
   - autoinfixconds  infix condition codes defined by the module, for
                     autoloading (without the leading `-')
   - autoprefixconds like autoinfixconds, but for prefix condition codes
+  - autoparams      parameters defined by the module, for autoloading
   - objects         .o files making up this module (*must* be defined)
   - proto           .pro files for this module (default generated from $objects)
   - headers         extra headers for this module (default none)
@@ -137,7 +138,7 @@ Be sure to put the values in quotes. For further enlightenment have a
 look at the `mkmakemod.sh' script in the Src directory of the
 distribution.
 
-Modules have to define four functions which will automatically called
+Modules have to define four functions which will be called automatically
 by the zsh core. The first one, named `setup_foo' for a module named
 `foo', should set up any data needed in the module, at least any data
 other modules may be interested in. The second one, named `boot_foo',
@@ -323,6 +324,78 @@ almost exactly the same as for builtins, using the functions
 Arguments and return values are the same as for the functions for
 builtins.
 
+For defining parameters, a module can call `createparam()' directly or 
+use a table to describe them, e.g.:
+
+  static struct paramdef patab[] = {
+    PARAMDEF("foo", PM_INTEGER, NULL, get_foo, set_foo, unset_foo),
+    INTPARAMDEF("exint", &intparam),
+    STRPARAMDEF("exstr", &strparam),
+    ARRPARAMDEF("exarr", &arrparam),
+  };
+
+There are four macros used:
+
+  - PARAMDEF() gets as arguments:
+    - the name of the parameter
+    - the parameter flags to set for it (from the PM_* flags defined
+      in zsh.h)
+    - optionally a pointer to a variable holding the value of the
+      parameter
+    - three functions that will be used to get the value of the
+      parameter, store a value in the parameter, and unset the
+      parameter
+  - the other macros provide simple ways to define the most common
+    types of parameters; they get the name of the parameter and a
+    pointer to a variable holding the value as arguments; they are
+    used to define integer-, scalar-, and array-parameters, so the
+    variables whose addresses are given should be of type `long',
+    `char *', and `char **', respectively
+
+For a description of how to write functions for getting or setting the 
+value of parameters, or how to write a function to unset a parameter,
+see the description of the following functions in the `params.c' file:
+
+  - `intvargetfn()' and `intvarsetfn()' for integer parameters
+  - `strvargetfn()' and `strvarsetfn()' for scalar parameters
+  - `arrvargetfn()' and `arrvarsetfn()' for array parameters
+  - `stdunsetfn()' for unsetting parameters
+
+Note that if one defines parameters using the last two macros (for
+scalars and arrays), the variable holding the value should be
+initialized to either `NULL' or to a a piece of memory created with
+`zalloc()'. But this memory should *not* be freed in the
+finish-function of the module because that will be taken care of by
+the `deleteparamdefs()' function described below.
+
+To register the parameters in the zsh core, the function
+`addparamdefs()' is called as in:
+
+  /**/
+  int
+  boot_example(Module m)
+  {
+    int ret;
+
+    ret = addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab))
+    ...
+  }
+
+The arguments and the return value are as for the functions used to
+add builtins and condition codes and like these, it should be called
+in the boot-function of the module. To remove the parameters defined,
+the function `deleteparamdefs()' should be called, again with the same 
+arguments and the same return value as for the functions to remove
+builtins and condition codes:
+
+  /**/
+  int
+  cleanup_example(Module m)
+  {
+    deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab));
+    ...
+  }
+
 Finally, modules can define wrapper functions. These functions are
 called whenever a shell function is to be executed.
 
diff --git a/patchlist.txt b/patchlist.txt
index 9a07210b6..faeade93b 100644
--- a/patchlist.txt
+++ b/patchlist.txt
@@ -940,7 +940,7 @@ pws: 6053: compwid.yo
 
 Sven: 6056: compwid.yo
 
-Sven: 6058: small changes
+Sven: 6058: small changes in _path_files, compinit and documentation
 
 Sven: 6060: don't invalidatelist() in zle_main.c before calling completion
 functions
@@ -967,3 +967,52 @@ Tanaka Akira: 6085: _make can hang when no [mM]akefile
 Tanaka Akira: 6092: _find, bad glob pattern
 
 pws: 6101: multi-line prompt ending in '\n' got another newline
+
+  pws-17
+
+Geoff: 6104: multi-line prompt fix (6101 backed off)
+
+Sven: 6105: _make patch whitespace
+
+Bart: 6106: short documentation fixes in expn.yo, options.yo, redirect.yo
+
+Sven: 6109: completion in parameter assignment should set context `value'
+
+Sven: 6113: compadd -D, nuke element in an array for each failed match
+
+Sven: 6117: position of ignored suffix in inserted match
+
+pws: 6118: _closequote and _oldlist completers
+
+Sven: 6119: don't insert word separator before ignored suffix
+
+Sven: 6121: try harder with braces after a parameter expansion
+
+Sven: 6124: menu completion wasn't consistent between tabs
+
+Sven: 6128: completion after an expansion; list after a non-completion list
+
+Sven: 6129: comments for struct cadata
+
+Ville Herva: 6131, see 6126: reset tv.tv_sec before select for Linux
+
+Sven: 6132: compctl.mdd
+
+Sven: 6133: autoloaded parameters
+
+Sven: 6150: alwayslastprompt sometimes failed in M-x
+
+Sven: 6152: compstate[vared]
+
+Sven: 6153: realparamtab to smooth access to autoloaded parameters
+
+Bart: 6162: autoloadable parameter code links without dynamic loading
+
+pws: 6165: globsubst'd foo='~/bin' depended on extendedglob being set
+
+Sven: 6167: show unloaded parameters as undefined
+
+Bart: 6171 as rewritten in 6174: old RedHat Linux doesn't have normall
+definitions for poll.
+
+pws: 6180: Completion/Core/compinstall