about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-08-23 10:07:17 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-08-23 10:07:17 +0000
commitf7fa32f091420552d5dbb16ff5f574484508f1de (patch)
tree82be5f077e6cdddad82a015f77a0308d825cd951
parent16060224ac17a8b5a1efb8568643f9a15b14c034 (diff)
downloadzsh-f7fa32f091420552d5dbb16ff5f574484508f1de.tar.gz
zsh-f7fa32f091420552d5dbb16ff5f574484508f1de.tar.xz
zsh-f7fa32f091420552d5dbb16ff5f574484508f1de.zip
zsh-workers/7463
-rw-r--r--Completion/Base/_arguments289
-rw-r--r--Completion/Base/_brace_parameter9
-rw-r--r--Completion/Base/_condition5
-rw-r--r--Completion/Base/_long_options41
-rw-r--r--Completion/Base/_math5
-rw-r--r--Completion/Base/_parameter4
-rw-r--r--Completion/Base/_tilde2
-rw-r--r--Completion/Base/_vars3
-rw-r--r--Completion/Builtins/_vars_eq5
-rw-r--r--Completion/Builtins/_zftp63
-rw-r--r--Completion/Commands/_correct_filename2
-rw-r--r--Completion/Commands/_correct_word2
-rw-r--r--Completion/Commands/_expand_word2
-rw-r--r--Completion/Commands/_history_complete_word2
-rw-r--r--Completion/Commands/_most_recent_file2
-rw-r--r--Completion/Commands/_read_comp2
-rw-r--r--Completion/Core/_parameters61
-rw-r--r--Completion/Core/compinit2
-rw-r--r--Completion/User/_chown8
-rw-r--r--Completion/User/_dir_list4
-rw-r--r--Completion/User/_exec_funcs49
-rw-r--r--Completion/User/_find3
-rw-r--r--Completion/User/_gprof12
-rw-r--r--Completion/User/_rlogin2
-rw-r--r--Completion/User/_su5
-rw-r--r--Completion/User/_tar2
-rw-r--r--Completion/User/_users6
-rw-r--r--Doc/Zsh/compsys.yo23
-rw-r--r--Src/Zle/compctl.c3
-rw-r--r--Util/completion-style-guide44
30 files changed, 415 insertions, 247 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
index 120c50934..86cd1c498 100644
--- a/Completion/Base/_arguments
+++ b/Completion/Base/_arguments
@@ -6,7 +6,7 @@
 setopt localoptions extendedglob
 
 local long args rest ws cur nth def nm expl descr action opt arg tmp
-local single uns ret=1 soptseq soptseq1 sopts prefix
+local single uns ret=1 soptseq soptseq1 sopts prefix line
 
 # Associative arrays used to collect information about the options.
 
@@ -117,182 +117,185 @@ else
   sopts=''
 fi
 
-if [[ $#long -ne 0 && "$PREFIX" = --* ]]; then
-
-   # If the current words starts with `--' and we should use long
-   # options, just call...
+# Parse the command line...
 
-  _long_options "$long[@]"
-else
+ws=( "${(@)words[2,-1]}" )
+cur=$(( CURRENT-2 ))
+nth=1
+liine=( "$words[1]" )
 
-  # Otherwise parse the command line...
+# ...until the current word is reached.
 
-  ws=( "${(@)words[2,-1]}" )
-  cur=$(( CURRENT-2 ))
-  nth=1
+while [[ cur -gt 0 ]]; do
 
-  # ...until the current word is reached.
+  # `def' holds the description for the option we are currently after.
+  # Check if the next argument for the option is optional.
 
-  while [[ cur -gt 0 ]]; do
+  if [[ "$def" = :* ]]; then
+    opt=yes
+  else
+    opt=''
+  fi
+  arg=''
 
-    # `def' holds the description for the option we are currently after.
-    # Check if the next argument for the option is optional.
+  # Remove one description/action pair from `def' if that isn't empty.
 
-    if [[ "$def" = :* ]]; then
-      opt=yes
+  if [[ -n "$def" ]]; then
+    if [[ "$def" = ?*:*:* ]]; then
+      def="${def#?*:*:}"
     else
-      opt=''
+      def=''
     fi
-    arg=''
+  else
 
-    # Remove one description/action pair from `def' if that isn't empty.
+    # If it is empty, and the word starts with `--' and we should
+    # complete long options, just ignore this word, otherwise make sure
+    # we test for options below and handle normal arguments.
 
-    if [[ -n "$def" ]]; then
-      if [[ "$def" = ?*:*:* ]]; then
-        def="${def#?*:*:}"
-      else
-        def=''
-      fi
+    if [[ $#long -eq 0 || "$ws[1]" != --* ]]; then
+      opt=yes
+      arg=yes
     else
+      def=''
+    fi
+  fi
 
-      # If it is empty, and the word starts with `--' and we should
-      # complete long options, just ignore this word, otherwise make sure
-      # we test for options below and handle normal arguments.
+  if [[ -n "$opt" ]]; then
 
-      if [[ $#long -eq 0 || "$ws[1]" != --* ]]; then
-        opt=yes
-	arg=yes
-      else
-        def=''
-      fi
-    fi
+    # `opt' was set above if we have to test if the word is an option.
+    # We first test for the simple options -- those without arguments or
+    # those whose arguments have to be given as separate words.
 
-    if [[ -n "$opt" ]]; then
+    if (( $+opts[$ws[1]] )); then
 
-      # `opt' was set above if we have to test if the word is an option.
-      # We first test for the simple options -- those without arguments or
-      # those whose arguments have to be given as separate words.
+      # Options that may only be given once are removed from the
+      # associative array so that we don't offer them again.
 
-      if (( $+opts[$ws[1]] )); then
+      def="$opts[$ws[1]]"
+      [[ -n "$oneshot[$ws[1]]" ]] && unset "opts[$ws[1]]"
+    else
+      uns=''
+      if [[ -n "$sopts" && "$ws[1]" = [-+]${~soptseq}[$sopts] ]]; then
+	tmp="${ws[1][1]}${ws[1][-1]}"
+	if (( $+opts[$tmp] )); then
+	  def="$opts[$tmp]"
+	  uns="${ws[1][2,-1]}"
+	  opt=''
+	fi
+      fi
 
-        # Options that may only be given once are removed from the
-        # associative array so that we don't offer them again.
+      # If the word is none of the simple options, test for those
+      # whose first argument has to or may come directly after the
+      # option. This is done in two loops looking very much alike.
 
-        def="$opts[$ws[1]]"
-        [[ -n "$oneshot[$ws[1]]" ]] && unset "opts[$ws[1]]"
-      else
-        uns=''
-        if [[ -n "$sopts" && "$ws[1]" = [-+]${~soptseq}[$sopts] ]]; then
-	  tmp="${ws[1][1]}${ws[1][-1]}"
-	  if (( $+opts[$tmp] )); then
-	    def="$opts[$tmp]"
-	    uns="${ws[1][2,-1]}"
-	    opt=''
-	  fi
-        fi
+      if [[ -n "$opt" && $#dopts -ne 0 ]]; then
 
-        # If the word is none of the simple options, test for those
-        # whose first argument has to or may come directly after the
-        # option. This is done in two loops looking very much alike.
+	# First we get the option names.
 
-        if [[ -n "$opt" && $#dopts -ne 0 ]]; then
+	tmp=( "${(@k)dopts}" )
 
-	  # First we get the option names.
+	# Then we loop over them and see if the current word begins
+	# with one of the option names.
 
-	  tmp=( "${(@k)dopts}" )
+	while (( $#tmp )); do
+          if [[ -n "$sopts" && $tmp[1] = [-+]? ]]; then
+	    if [[ "$ws[1]" = ${tmp[1][1]}${~soptseq}${tmp[1][2]}* ]]; then
+	      uns="${ws[1][2,-1]%%${tmp[1][2]}*}${tmp[1][2]}"
+	      break;
+	    fi
+	  elif [[ "$ws[1]" = ${tmp[1]}* ]]; then
+            break
+	  fi
+	  shift 1 tmp
+	done
 
-	  # Then we loop over them and see if the current word begins
-	  # with one of the option names.
+	if (( $#tmp )); then
 
-	  while (( $#tmp )); do
-            if [[ -n "$sopts" && $tmp[1] = [-+]? ]]; then
-	      if [[ "$ws[1]" = ${tmp[1][1]}${~soptseq}${tmp[1][2]}* ]]; then
-	        uns="${ws[1][2,-1]%%${tmp[1][2]}*}${tmp[1][2]}"
-		break;
-	      fi
-	    elif [[ "$ws[1]" = ${tmp[1]}* ]]; then
-              break
+	  # It does. So use the description for it, but only from
+	  # the second argument on, because we are searching the
+	  # description for the next command line argument.
+
+	  opt=''
+	  def="$dopts[$tmp[1]]"
+	  [[ -n "$oneshot[$tmp[1]]" ]] && unset "dopts[$tmp[1]]"
+	  if [[ "$def" = ?*:*:* ]]; then
+            def="${def#?*:*:}"
+          else
+            def=''
+	  fi
+        fi
+      fi
+      if [[ -n "$opt" && $#odopts -ne 0 ]]; then
+	tmp=( "${(@k)odopts}" )
+	while (( $#tmp )); do
+          if [[ -n "$sopts" && $tmp[1] = [-+]? ]]; then
+	    if [[ "$ws[1]" = ${tmp[1][1]}${~soptseq}${tmp[1][2]}* ]]; then
+	      uns="${ws[1][2,-1]%%${tmp[1][2]}*}${tmp[1][2]}"
+	      break;
 	    fi
-	    shift 1 tmp
-	  done
+	  elif [[ "$ws[1]" = ${tmp[1]}* ]]; then
+	    break
+	  fi
+	  shift 1 tmp
+	done
 
-	  if (( $#tmp )); then
+	if (( $#tmp )); then
+	  opt=''
+	  def="$odopts[$tmp[1]]"
+	  [[ -n "$oneshot[$tmp[1]]" ]] && unset "odopts[$tmp[1]]"
 
-	    # It does. So use the description for it, but only from
-	    # the second argument on, because we are searching the
-	    # description for the next command line argument.
+	  # For options whose first argument *may* come after the
+	  # option, we skip over the first description only if there
+	  # is something after the option name on the line.
 
-	    opt=''
-	    def="$dopts[$tmp[1]]"
-	    [[ -n "$oneshot[$tmp[1]]" ]] && unset "dopts[$tmp[1]]"
+	  if [[ ( -z "$sopts" && "$ws[1]" != "$tmp[1]" ) ||
+                ( -n "$sopts" && ( ( $tmp[1] = [-+]? && "$ws[1]" != "${tmp[1][1]}"${~soptseq}"${tmp[1][2]}" ) ||
+		  		   ( $tmp[1] != [-+]? && "$ws[1]" != "$tmp[1]" ) ) ) ]]; then
 	    if [[ "$def" = ?*:*:* ]]; then
               def="${def#?*:*:}"
             else
               def=''
-	    fi
-          fi
-        fi
-        if [[ -n "$opt" && $#odopts -ne 0 ]]; then
-	  tmp=( "${(@k)odopts}" )
-	  while (( $#tmp )); do
-            if [[ -n "$sopts" && $tmp[1] = [-+]? ]]; then
-	      if [[ "$ws[1]" = ${tmp[1][1]}${~soptseq}${tmp[1][2]}* ]]; then
-	        uns="${ws[1][2,-1]%%${tmp[1][2]}*}${tmp[1][2]}"
-		break;
-	      fi
-	    elif [[ "$ws[1]" = ${tmp[1]}* ]]; then
-	      break
-	    fi
-	    shift 1 tmp
-	  done
-
-	  if (( $#tmp )); then
-	    opt=''
-	    def="$odopts[$tmp[1]]"
-	    [[ -n "$oneshot[$tmp[1]]" ]] && unset "odopts[$tmp[1]]"
-
-	    # For options whose first argument *may* come after the
-	    # option, we skip over the first description only if there
-	    # is something after the option name on the line.
-
-	    if [[ ( -z "$sopts" && "$ws[1]" != "$tmp[1]" ) ||
-                  ( -n "$sopts" && ( ( $tmp[1] = [-+]? && "$ws[1]" != "${tmp[1][1]}"${~soptseq}"${tmp[1][2]}" ) ||
-		  		     ( $tmp[1] != [-+]? && "$ws[1]" != "$tmp[1]" ) ) ) ]]; then
-	      if [[ "$def" = ?*:*:* ]]; then
-                def="${def#?*:*:}"
-              else
-                def=''
-              fi
-	    fi
-          fi
+            fi
+	  fi
         fi
+      fi
 
-        [[ -n "$sopts" && -n "$opt" && "$ws[1]" = [-+]${~soptseq} ]] && \
-            uns="${ws[1][2,-1]}"
+      [[ -n "$sopts" && -n "$opt" && "$ws[1]" = [-+]${~soptseq} ]] && \
+          uns="${ws[1][2,-1]}"
 
-	if [[ -n "$uns" ]]; then
-	  uns="${(j::)${(@k)oneshot[(I)${ws[1][1]}[$uns]]#[-+]}}"
-	  unset "opts[${(@)^opts[(I)${ws[1][1]}[$uns]]}]" \
-	        "dopts[${(@)^dopts[(I)${ws[1][1]}[$uns]]}]" \
-	        "odopts[${(@)^odopts[(I)${ws[1][1]}[$uns]]}]"
-	fi
+      if [[ -n "$uns" ]]; then
+	uns="${(j::)${(@k)oneshot[(I)${ws[1][1]}[$uns]]#[-+]}}"
+	unset "opts[${(@)^opts[(I)${ws[1][1]}[$uns]]}]" \
+	      "dopts[${(@)^dopts[(I)${ws[1][1]}[$uns]]}]" \
+	      "odopts[${(@)^odopts[(I)${ws[1][1]}[$uns]]}]"
+      fi
 
-	# If we didn't find a matching option description and we were
-	# told to use normal argument descriptions, just increase
-	# our counter `nth'.
+      # If we didn't find a matching option description and we were
+      # told to use normal argument descriptions, just increase
+      # our counter `nth'.
 
-        if [[ -n "$opt" && -n "$arg" ]]; then
-          def=''
-	  (( nth++ ))
-        fi
+      if [[ -n "$opt" && -n "$arg" ]]; then
+        def=''
+	line=( "$line[@]" "$ws[1]" )
+	(( nth++ ))
       fi
     fi
+  fi
 
-    shift 1 ws
-    (( cur-- ))
-  done
+  shift 1 ws
+  (( cur-- ))
+done
+
+# Now generate the matches.
+
+if [[ $#long -ne 0 && "$PREFIX" = --* ]]; then
 
-  # Now generate the matches.
+  # If the current words starts with `--' and we should use long
+  # options, just call...
+
+  _long_options "$long[@]"
+
+else
 
   nm="$compstate[nmatches]"
 
@@ -379,9 +382,11 @@ else
         _description expl option
 	if [[ -n "$sopts" && -n "$PREFIX" && "$PREFIX" = [-+]${~soptseq}[$sopts] ]]; then
 	  if [[ "$PREFIX" = [-+]${~soptseq1} ]]; then
-	    compadd "$expl[@]" -Q - "${PREFIX}${(@k)^opts[(I)${PREFIX[1]}?]#?}" \
-				    "${PREFIX}${(@k)^dopts[(I)${PREFIX[1]}?]#?}" \
-				    "${PREFIX}${(@k)^odopts[(I)${PREFIX[1]}?]#?}" && ret=0
+	    compadd "$expl[@]" -Q \
+                    -y "( ${(k)opts} ${(k)dopts} ${(k)odopts} )" - \
+                    "${PREFIX}${(@k)^opts[(I)${PREFIX[1]}?]#?}" \
+		    "${PREFIX}${(@k)^dopts[(I)${PREFIX[1]}?]#?}" \
+		    "${PREFIX}${(@k)^odopts[(I)${PREFIX[1]}?]#?}" && ret=0
 	  else
 	    # The last option takes an argument in next word.
 	    compadd "$expl[@]" -Q - "${PREFIX}" && ret=0
@@ -418,11 +423,17 @@ else
       # An empty action means that we should just display a message.
       _message "$descr"
       return ret
-    elif [[ "$action[1]" = \( ]]; then
+    elif [[ "$action[1]" = \(*\) ]]; then
 
       # Anything inside `(...)' is added directly.
 
       compadd "$expl[@]" - ${=action[2,-2]}
+    elif [[ "$action" = \{*\} ]]; then
+
+      # A string in braces is evaluated.
+
+      eval "$action[2,-2]"
+
     elif [[ "$action" = \ * ]]; then
 
       # If the action starts with a space, we just call it.
diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter
index 767743281..4a91dde73 100644
--- a/Completion/Base/_brace_parameter
+++ b/Completion/Base/_brace_parameter
@@ -2,16 +2,17 @@
 
 setopt localoptions extendedglob
 
-local lp ls n q suf=''
+local lp ls n q
 
 if [[ "$SUFFIX" = *\}* ]]; then
   ISUFFIX="${SUFFIX#*\}}$ISUFFIX"
   SUFFIX="${SUFFIX%%\}*}"
+  suf=()
 elif [[ "$LBUFFER" = *\$\{[^}]#\$\{[^}]#$PREFIX ||
         "$compstate[insert]" = *menu* ]]; then
-  suf='}'
+  suf=(-b '')
 else
-  suf='} '
+  suf=(-b ' ')
 fi
 
 lp="$LBUFFER[1,-${#PREFIX}-1]"
@@ -21,4 +22,4 @@ q=${(M)lp%%\"#}
 
 [[ n -gt 0 ]] && suf=''
 
-_parameters -Qs "${q[1,-n-1]}" -S "$suf" -r '-:?#%+=[/}'
+_parameters "$suf[@]" -Qs "${q[1,-n-1]}" -r '-:?#%+=[/}'
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
index afac03195..84c9fea20 100644
--- a/Completion/Base/_condition
+++ b/Completion/Base/_condition
@@ -7,11 +7,10 @@ if [[ "$prev" = -o ]]; then
 elif [[ "$prev" = -([no]t|ef) ]]; then
   _files
 else
-  local ret=1 expl
+  local ret=1
 
   _files && ret=0
-  _description expl parameter
-  compgen "$expl[@]" -v && ret=0
+  _parameters && ret=0
 
   return ret
 fi
diff --git a/Completion/Base/_long_options b/Completion/Base/_long_options
index 0080a48b6..716ff8884 100644
--- a/Completion/Base/_long_options
+++ b/Completion/Base/_long_options
@@ -112,8 +112,9 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
   # those hyphens and anything from the space or comma after the
   # option up to the end. 
 
-  opts=("--${(@)^${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$("$words[1]" --help)}:#[ 	]#-*}//,/
-}}:#[ 	]#--*}#*--}%%[, ]*}")
+  opts=("--${(@)^${(@)${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$("$words[1]" --help 2>&1)//\[--/
+--}:#[ 	]#-*}//,/
+}}:#[ 	]#--*}#*--}%%[, ]*}:#}")
 
   # Now remove all ignored options ...
 
@@ -256,15 +257,15 @@ if [[ "$str" = *\=* ]]; then
 
       _description expl "$descr"
 
-      if [[ "$action[1]" = (\[|\() ]]; then
+      if [[ "$action[1]" = (\[*\]|\(*\)) ]]; then
         compadd "$expl[@]" - ${=action[2,-2]}
-      elif (( $#action )); then
-        if [[ "$action" = \ * ]]; then
-          ${(e)=~action}
-        else
-	  action=($=action)
-	  ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
-        fi
+      elif [[ "$action" = \{*\} ]]; then
+        eval "$action[2,-2]"
+      elif [[ "$action" = \ * ]]; then
+        ${(e)=~action}
+      elif [[ -n "$action" ]]; then
+	action=($=action)
+	${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
       else
         _message "$descr"
       fi
@@ -308,15 +309,15 @@ if [[ "$str" = *\=* ]]; then
 
     _description expl "$partd"
 
-    if (( $#parta )); then
-      if [[ "$parta[1]" = (\[|\() ]]; then
-        compadd "$expl[@]" - ${=parta[2,-2]}
-      elif [[ "$parta" = \ * ]]; then
-        ${(e)=~parta}
-      else
-	action=($=parta)
-	${(e)~parta[1]} "$expl[@]" ${(e)~action[2,-1]}
-      fi
+    if [[ "$parta[1]" = (\[*\]|\(*\)) ]]; then
+      compadd "$expl[@]" - ${=parta[2,-2]}
+    elif [[ "$parta" = \{*\} ]]; then
+      eval "$parta[2,-2]"
+    elif [[ "$parta" = \ * ]]; then
+      ${(e)=~parta}
+    elif [[ -n "$parta" ]]; then
+      action=($=parta)
+      ${(e)~action[1]} "$expl[@]" ${(e)~action[2,-1]}
     else
       compadd -S '' - "$PREFIX"
     fi
@@ -346,8 +347,6 @@ fi
 
 anum=1
 for name in "$_lo_cache_names[@]"; do
-  action="$_lo_cache_actions[anum]"
-
   _description expl option
 
   if [[ "$name" = *_optarg_* ]]; then
diff --git a/Completion/Base/_math b/Completion/Base/_math
index 82b97fe4a..b9743d6b4 100644
--- a/Completion/Base/_math
+++ b/Completion/Base/_math
@@ -1,7 +1,5 @@
 #compdef -math-
 
-local expl
-
 if [[ "$PREFIX" = *[^a-zA-Z0-9_]* ]]; then
   IPREFIX="$IPREFIX${PREFIX%%[a-zA-Z0-9_]#}"
   PREFIX="${PREFIX##*[^a-zA-Z0-9_]}"
@@ -11,5 +9,4 @@ if [[ "$SUFFIX" = *[^a-zA-Z0-9_]* ]]; then
   SUFFIX="${SUFFIX%%[^a-zA-Z0-9_]*}"
 fi
 
-_description expl parameter
-compgen "$expl[@]" -v
+_parameters
diff --git a/Completion/Base/_parameter b/Completion/Base/_parameter
index 5f6f56db2..aa9e3ce01 100644
--- a/Completion/Base/_parameter
+++ b/Completion/Base/_parameter
@@ -1,7 +1,7 @@
 #compdef -parameter-
 
 if [[ "$compstate[insert]" = *menu* ]]; then
-  _parameters
+  _parameters -s ''
 else
-  _parameters -S ' ' -r '['
+  _parameters -s ' '
 fi
diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde
index f249d4ffa..cab371216 100644
--- a/Completion/Base/_tilde
+++ b/Completion/Base/_tilde
@@ -41,7 +41,7 @@ else
   if (( $# )); then
     d=( "$@" )
   else
-    _description d user
+    _description d 'user or named directory'
   fi
 fi
 
diff --git a/Completion/Base/_vars b/Completion/Base/_vars
index 5a06488a5..a81a49f48 100644
--- a/Completion/Base/_vars
+++ b/Completion/Base/_vars
@@ -20,6 +20,5 @@ if [[ $PREFIX = *\[* ]]; then
     compadd "$expl[@]" $addclose - ${(kP)var}
   fi
 else
-  _description expl parameter
-  compgen "$expl[@]" -v
+  _parameter
 fi
diff --git a/Completion/Builtins/_vars_eq b/Completion/Builtins/_vars_eq
index 16a55595e..d2cac8741 100644
--- a/Completion/Builtins/_vars_eq
+++ b/Completion/Builtins/_vars_eq
@@ -1,6 +1,3 @@
 #compdef declare export integer local readonly typeset
 
-local expl
-
-_description expl parameter
-compgen "$expl[@]" -v -q -S '='
+_parameters -q -S '='
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index e6f7ea683..7b3ee0f97 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -23,47 +23,46 @@ fi
 
 case $subcom in
   *(cd|ls|dir))
-   # complete remote directories; we could be smarter about hiding prefixes
-   zfcd_match $PREFIX $SUFFIX
-   _description expl 'remote directory'
-   (( $#reply )) && compadd "$expl[@]" -S/ -q - $reply
-   ;;
+    # complete remote directories; we could be smarter about hiding prefixes
+    zfcd_match $PREFIX $SUFFIX
+    _description expl 'remote directory'
+    (( $#reply )) && compadd "$expl[@]" -S/ -q - $reply
+    ;;
 
   *(get(|at)|gcp|delete|remote))
-   # complete remote files
-   zfget_match $PREFIX $SUFFIX
-   _description expl 'remote file'
-   (( $#reply )) && compadd "$expl[@]" -F fignore - $reply
-   ;;
+    # complete remote files
+    zfget_match $PREFIX $SUFFIX
+    _description expl 'remote file'
+    (( $#reply )) && compadd "$expl[@]" -F fignore - $reply
+    ;;
 
   *(put(|at)|pcp))
-   # complete local files
-   _files
-   ;;
+    # complete local files
+    _files
+    ;;
 
   *(open|anon|params))
-  # complete hosts:  should do cleverer stuff with user names
-  _description expl host
-  compgen "$expl[@]" -k hosts
-  ;;
+    # complete hosts:  should do cleverer stuff with user names
+    _hosts
+    ;;
 
   *(goto|mark))
-  # complete bookmarks.  First decide if ncftp mode is go.
-  _description expl bookmark
-  if [[ $words[2] = -*n* ]]; then
-    if [[ -f ~/.ncftp/bookmarks ]]; then
-      compadd "$expl[@]" - $(awk -F, 'NR > 2 { print $1 }' ~/.ncftp/bookmarks)
+    # complete bookmarks.  First decide if ncftp mode is go.
+    _description expl bookmark
+    if [[ $words[2] = -*n* ]]; then
+      if [[ -f ~/.ncftp/bookmarks ]]; then
+        compadd "$expl[@]" - $(awk -F, 'NR > 2 { print $1 }' ~/.ncftp/bookmarks)
+      fi
+    else
+      if [[ -f ${ZFTP_BMFILE:=${ZDOTDIR:-$HOME}/.zfbkmarks} ]]; then
+        compadd "$expl[@]" - $(awk '{print $1}' $ZFTP_BMFILE)
+      fi
     fi
-  else
-    if [[ -f ${ZFTP_BMFILE:=${ZDOTDIR:-$HOME}/.zfbkmarks} ]]; then
-      compadd "$expl[@]" - $(awk '{print $1}' $ZFTP_BMFILE)
-    fi
-  fi
-  ;;
+    ;;
 
   *)
-  # dunno... try ordinary completion after all.
-  unset _compskip
-  return 1
-  ;;
+    # dunno... try ordinary completion after all.
+    unset _compskip
+    return 1
+    ;;
 esac
diff --git a/Completion/Commands/_correct_filename b/Completion/Commands/_correct_filename
index e9415a81f..7431a4831 100644
--- a/Completion/Commands/_correct_filename
+++ b/Completion/Commands/_correct_filename
@@ -1,4 +1,4 @@
-#compdef -kn complete-word \C-xC
+#compdef -k complete-word \C-xC
 
 # Function to correct a filename.  Can be used as a completion widget,
 # or as a function in its own right, in which case it will print the
diff --git a/Completion/Commands/_correct_word b/Completion/Commands/_correct_word
index 4376de092..d0abcd4fe 100644
--- a/Completion/Commands/_correct_word
+++ b/Completion/Commands/_correct_word
@@ -1,4 +1,4 @@
-#compdef -kn complete-word \C-xc
+#compdef -k complete-word \C-xc
 
 # Simple completion front-end implementing spelling correction.
 # The maximum number of errors is set quite high, and
diff --git a/Completion/Commands/_expand_word b/Completion/Commands/_expand_word
index 481d5e6a0..570f06987 100644
--- a/Completion/Commands/_expand_word
+++ b/Completion/Commands/_expand_word
@@ -1,4 +1,4 @@
-#compdef -kn complete-word \C-xe
+#compdef -k complete-word \C-xe
 
 # Simple completion front-end implementing expansion.
 #
diff --git a/Completion/Commands/_history_complete_word b/Completion/Commands/_history_complete_word
index fb1c502c8..b55966062 100644
--- a/Completion/Commands/_history_complete_word
+++ b/Completion/Commands/_history_complete_word
@@ -1,4 +1,4 @@
-#compdef -kn complete-word \e/
+#compdef -k complete-word \e/
 
 local expl
 
diff --git a/Completion/Commands/_most_recent_file b/Completion/Commands/_most_recent_file
index f8d2bd80c..868da8993 100644
--- a/Completion/Commands/_most_recent_file
+++ b/Completion/Commands/_most_recent_file
@@ -1,4 +1,4 @@
-#compdef -kn complete-word \C-xm
+#compdef -k complete-word \C-xm
 
 # Complete the most recent file matching the pattern on the line so
 # far: globbing is active, i.e. *.txt will be expanded to the most recent
diff --git a/Completion/Commands/_read_comp b/Completion/Commands/_read_comp
index 0a4f549f1..a32879b56 100644
--- a/Completion/Commands/_read_comp
+++ b/Completion/Commands/_read_comp
@@ -1,4 +1,4 @@
-#compdef -kn complete-word \C-x\C-r
+#compdef -k complete-word \C-x\C-r
 
 # This allows an on-the-fly choice of completions.  On typing the key
 # sequence given above, you will be prompted for a string of arguments.  If
diff --git a/Completion/Core/_parameters b/Completion/Core/_parameters
index 824d8dbc9..a6336424c 100644
--- a/Completion/Core/_parameters
+++ b/Completion/Core/_parameters
@@ -1,16 +1,67 @@
 #autoload
 
 # This should be used to complete parameter names if you need some of the
-# extra options of compadd. It completes only non-local parameters. All
-# arguments are given to compadd.
+# extra options of compadd. It completes only non-local parameters.
+# If the first argument is `-s' or `-b' auto_param_slash will be tested
+# and slashes will be added to parameters containing a directory. `-s' is
+# for parameter expansions without braces and `-b' is for expansions with
+# braces. A `-' as the first argument is ignored and in all cases all
+# other arguments will be given to `compadd'.
 
-local expl
+
+setopt localoptions extendedglob
+
+local pars expl slash suf
+
+if [[ "$1" = -s ]]; then
+  slash=normal
+  suf="$2"
+  shift 2
+elif [[ "$1" = -b ]]; then
+  slash=brace
+  suf="$2"
+  shift 2
+elif [[ "$1" = - ]]; then
+  shift
+fi
 
 _description expl parameter
 
 if zmodload -e parameter; then
   setopt localoptions extendedglob
-  compadd "$expl[@]" "$@" - ${(k)parameters[(R)^*local*]}
+  pars=( ${(k)parameters[(R)^*local*]} )
+else
+  pars=( ${${${(f)"$(typeset +)"}:#*local *}##* } )
+fi
+
+if [[ -n "$slash" && -o autoparamslash ]]; then
+  local i dirs nodirs ret=1
+
+  dirs=()
+  nodirs=()
+  for i in $pars; do
+    if [[ -d "${(P)i}" ]]; then
+      dirs=( $dirs $i )
+    else
+      nodirs=( $nodirs $i )
+    fi
+  done
+
+  if [[ "$slash" = normal ]]; then
+    compadd -S "/${suf%% #}" -r ' [/:' "$expl[@]" "$@" - $dirs && ret=0
+    compadd -S "$suf" -r ' [:' "$expl[@]" "$@" - $nodirs && ret=0
+  elif [[ "$slash" = brace ]]; then
+    compadd -S "}/${suf%% #}" -r '-:?#%+=[/}' "$expl[@]" "$@" - $dirs && ret=0
+    compadd -S "}$suf" -r '-:?#%+=[/}' "$expl[@]" "$@" - $nodirs && ret=0
+  fi
+
+  return ret
 else
-  compadd "$expl[@]" "$@" - ${${${(f)"$(typeset +)"}:#*local *}##* }
+  if [[ "$slash" = normal ]]; then
+    compadd -S "$suf" -r ' [:' "$expl[@]" "$@" - $pars
+  elif [[ "$slash" = brace ]]; then
+    compadd -S "}$suf" -r '-:?#%+=[/}' "$expl[@]" "$@" - $pars
+  else
+    compadd "$expl[@]" "$@" - $pars
+  fi
 fi
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index f160e7dcf..04438327c 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -379,7 +379,7 @@ if [[ -z "$_i_done" ]]; then
       case $_i_tag in
       (\#compdef)
 	if [[ $_i_line[1] = -[pPk](n|) ]]; then
-	  compdef ${_i_line[1]}a "${_i_file:t}" "${(@)_i_line[2,-1]}"
+	  compdef ${_i_line[1]}na "${_i_file:t}" "${(@)_i_line[2,-1]}"
 	else
 	  compdef -na "${_i_file:t}" "${_i_line[@]}"
 	fi
diff --git a/Completion/User/_chown b/Completion/User/_chown
index c75dbc4b3..3a14d3f89 100644
--- a/Completion/User/_chown
+++ b/Completion/User/_chown
@@ -4,14 +4,10 @@ if [[ CURRENT -eq 2 || CURRENT -eq 3 && $words[CURRENT-1] = -* ]]; then
   if [[ $words[1] = chgrp ]] || compset -P '*[:.]'; then
     _groups
   else
-    local expl
-
-    _description expl user
-
     if [[ $OSTYPE = (solaris*|hpux*) ]]; then
-      compgen "$expl[@]" -u -S ':' -q
+      _users -S ':' -q
     else
-      compgen "$expl[@]" -u -S '.' -q
+      _users -S '.' -q
     fi
   fi
 else
diff --git a/Completion/User/_dir_list b/Completion/User/_dir_list
new file mode 100644
index 000000000..8e3615dac
--- /dev/null
+++ b/Completion/User/_dir_list
@@ -0,0 +1,4 @@
+#autoload
+
+compset -P '*:'
+_files -S: -r ': \t\t\-' -/
diff --git a/Completion/User/_exec_funcs b/Completion/User/_exec_funcs
new file mode 100644
index 000000000..2fd64b230
--- /dev/null
+++ b/Completion/User/_exec_funcs
@@ -0,0 +1,49 @@
+#autoload
+
+# This should be called from `_arguments' or otherwise the calling
+# function has to set up an array named `line' that contains the
+# name of the executable as its seconf element or it has to supply
+# that name as an argument.
+# One option is recognized: `-p' means that we are completing a pair
+# of names separated by a slash.
+
+local cmd pair expl
+
+if [[ "$1" = -p ]]; then
+  pair=yes
+  shift
+fi
+
+if (( $# )); then
+  cmd="$1"
+elif [[ $#line -gt 1 ]]; then
+  cmd="$line[2]"
+else
+  return 1
+fi
+
+if [[ -n "$cmd" ]]; then
+  if [[ "$cmd" = /* ]]; then
+    tmp="$cmd"
+  else
+    tmp="$PWD/$cmd"
+  fi
+
+  if [[ "$tmp" != "$_es_command" ]]; then
+    _es_command="$tmp"
+    _es_funcs=( "${(@)${(@M)${(@f)$(nm $cmd)}:#[^ ]# [tT] ([^_]|_[^_])*}##* }" )
+  fi
+  
+  if [[ -n "$pair" ]]; then
+    if compset -P '*/'; then
+      _description expl 'call arc to function'
+    else
+      _description expl 'call arc from function'
+    fi
+  else
+    _description expl function
+  fi
+  compadd -M 'r:|_=* r:|=*' - "$_es_funcs[@]"
+else
+  return 1
+fi
diff --git a/Completion/User/_find b/Completion/User/_find
index 20e8f4ff7..3ccb14c32 100644
--- a/Completion/User/_find
+++ b/Completion/User/_find
@@ -27,6 +27,5 @@ elif [[ "$prev" = -fstype ]]; then
 elif [[ "$prev" = -group ]]; then
   _groups
 elif [[ "$prev" = -user ]]; then
-  _description expl user
-  compgen "$expl[@]" -u
+  _users
 fi
diff --git a/Completion/User/_gprof b/Completion/User/_gprof
new file mode 100644
index 000000000..0a1d621be
--- /dev/null
+++ b/Completion/User/_gprof
@@ -0,0 +1,12 @@
+#compdef gprof
+
+_arguments -s -{a,b,c,D,h,i,l,L,s,T,v,w,x,y,z} \
+           -{A,C,e,E,f,F,J,n,N,O,p,P,q,Q,Z}:'function name: _exec_funcs' \
+	   '-I:directory:_dir_list' \
+	   '-d-:debug level:' '-k:function names: _exec_funcs -p' \
+	   '-m:minimum execution count:' \
+	   ':executable:_files -g *(*)' \
+	   ':profile file:_files -g gmon.*' \
+	   -- -s '(#--[no-] --)' \
+           '*=name*:function name: _exec_funcs' \
+	   '*=dirs*:directory:_dir_list'
diff --git a/Completion/User/_rlogin b/Completion/User/_rlogin
index 8756ec42d..e61890702 100644
--- a/Completion/User/_rlogin
+++ b/Completion/User/_rlogin
@@ -15,5 +15,5 @@ if [[ CURRENT -eq 2 ]];
 elif [[ CURRENT -eq 3 ]]; then
   compadd - -l
 else
-  compgen "$expl[@]" -S @ -u
+  _users -S @
 fi
diff --git a/Completion/User/_su b/Completion/User/_su
index 7b9744cd9..df1b89f97 100644
--- a/Completion/User/_su
+++ b/Completion/User/_su
@@ -1,13 +1,12 @@
 #compdef su
 
-local shell comp name usr base expl
+local shell comp name usr base
 
 [[ $words[2] != - ]]
 (( base=$?+2 ))
 
 if [[ CURRENT -eq base ]]; then
-  _description expl user
-  compgen "$expl[@]" -u && return
+  _users && return
   usr=root
 elif [[ CURRENT -ge base+1 ]]; then
   usr=$words[base]
diff --git a/Completion/User/_tar b/Completion/User/_tar
index 02551759a..8135bf006 100644
--- a/Completion/User/_tar
+++ b/Completion/User/_tar
@@ -72,7 +72,7 @@ if [[ "$PREFIX" = --* ]]; then
 
   # ...long options after `--'.
 
-  _long_options '--owner*:user:_tilde' \
+  _long_options '--owner*:user:_users' \
                 '*=(PROG|COMMAND)*:program:_command_names' \
 		'*=ARCHIVE*:archive: _tar_archive' \
 		'*=NAME*:file:_files' \
diff --git a/Completion/User/_users b/Completion/User/_users
new file mode 100644
index 000000000..fc1e87e52
--- /dev/null
+++ b/Completion/User/_users
@@ -0,0 +1,6 @@
+#autoload
+
+local expl
+
+_description expl user
+compgen "$@" "$expl[@]" -u
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 9db538a12..1181aa571 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -846,7 +846,7 @@ possible values for an optional argument, a list in parentheses
 gives words to complete for mandatory arguments. If the action does
 not start with a bracket or parentheses, it should be the name of a
 command (probably with arguments) that should be invoked to complete 
-after the equal sign. E.g.:
+after the equal sign or a string in braces that will be evaluated. E.g.:
 
 example(_long_options '*\*'     '(yes no)' \ 
               '*=FILE*' '_files' \ 
@@ -930,14 +930,19 @@ enditem()
 In each of the cases above, the var(action) says how the possible
 completions should be generated. In cases where only one of a fixed
 set of strings can be completed, these string can directly be given as 
-a list in parentheses, as in `tt(:foo:(foo bar baz))'. If the
-var(action) does not begin with an opening parentheses, it will be
-split into separate words and executed. If the var(action) starts with 
-a space, this list of words will be invoked unchanged, otherwise it
-will be invoked with some extra string placed after the first word
-which can be given as arguments to the tt(compadd) and tt(compgen)
-builtins and which make sure that the var(message) given in the
-description will be shown above the matches.
+a list in parentheses, as in `tt(:foo:(foo bar baz))'. A string in
+braces will be evaluated to generate the matches and if the
+var(action) does not begin with an opening parentheses or brace, it
+will be split into separate words and executed. If the var(action)
+starts with a space, this list of words will be invoked unchanged,
+otherwise it will be invoked with some extra string placed after the
+first word which can be given as arguments to the tt(compadd) and
+tt(compgen) builtins and which make sure that the var(message) given
+in the description will be shown above the matches. During the
+evaluation or execution of the action the array `tt(line)' will be set 
+to the command name and normal arguments from the command line,
+i.e. to the words from the command line xcluding all options and their 
+arguments.
 
 Normally the option names are taken as multi-character names and a
 word from the line is considered to contain only one option (or
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 31daff24c..92e0b4e25 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1850,8 +1850,9 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 			*sp = p + 1;
 		    p = "" - 1;
 		} else if (argv[1]) {
+		    argv++;
 		    if (!*sp)
-			*sp = *++argv;
+			*sp = *argv;
 		    p = "" - 1;
 		} else {
 		    zerrnam(name, e, NULL, *p);
diff --git a/Util/completion-style-guide b/Util/completion-style-guide
new file mode 100644
index 000000000..307954760
--- /dev/null
+++ b/Util/completion-style-guide
@@ -0,0 +1,44 @@
+For now this is just a list of things one should or shouldn't do.
+
+1)  Use the functions `_files' and `_path_files' instead of `compgen'
+    with the `-f', `-/', or `-g' options.
+2)  *Never* use `compgen' with the `-s' option. This can always be done 
+    by a call to `compadd' which is faster.
+3)  Using `compgen' with the `-k' option should only be done if a) the
+    array is already existent or b) it is very large (several hundred
+    or thousend elements). In other cases using `compadd' is faster.
+4)  Supply match specifications to `compadd' and `compgen' if there are 
+    sensible ones.
+5)  Use `_description' when adding matches with `compadd' or
+    `compgen'. Use `_message' in places where no matches can be
+    generated. If you want to add different types of matches, add them
+    with multiple calls to `compadd' or `compgen', supplying different
+    descriptions.
+6)  Use helper functions that do option completion for you (like
+    `_arguments' and `_long_options') -- it will make your life much
+    easier.
+7)  Use helper functions like `_users' and `_groups' instead of direct
+    calls to `compgen -u' or some ad hoc mechanisms to generate such
+    information. This ensures that user can change the way these things 
+    will be completed everywhere by just using their own implementations 
+    for these functions.
+8)  Make sure that the return value of your functions is correct: zero
+    if matches where added and non-zero if no matches were found.
+    In some cases you'll need to test the value of `$compstate[nmatches]'
+    for this. This should always be done by first saving the old value
+    (`local nm="$compstate[nmatches]"') and later comparing this with
+    the current value after all matches have been added (e.g. by
+    writing `[[ nmm -ne compstate[nmatches] ]]' at the end of your
+    function). This guarantees that your functions will be re-usable
+    because calling functions may rely on the correct return value.
+9)  In places where different behaviors may be useful, add a
+    configuration key to allow users to select the behavior they
+    prefer. Names for configuration keys should look like `prefix_name',
+    where `prefix' is the (probably abbreviated) name of your function
+    and `name' describes what can be configured.
+    When testing the values of configuration keys, the empty string
+    should result in the same behavior as if the key were unset. This
+    can be achieved by the test `[[ -n "$compconfig[prefix_name]" ]]'.
+10) When writing helper functions that generate matches, the arguments
+    of these should be given unchanged to `compadd' or `compgen' (if
+    they are not used by the helper function itself).