Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: PATCH: completion



Tanaka Akira wrote:

> 1. The help message may not suited for _long_options.
> 
> For example, help message of "patch" contains: 
>   -p NUM  --strip=NUM  Strip NUM leading components from file names.
> 
> The options are not separeted by ",".

I found the same problem with the output of `gprof' over the weekend
and the patch below fixes that problem.

> I avoid this problem by modifying the help message.
> # http://www.ldl.jaist.ac.jp/~akr/junk/patch-2.5.3-cvsaware-19990820.patch
> 
> But, in general, help messages may not able to modify.  Therefore I
> think it is useful that _arguments can handle options started with
> "--".
> 
> # Also, if _arguments supports options started with "--" directly,
> # opt-spec to specify both "--xxx=yyy" and "--xxx yyy" at once may
> # useful.

I don't agree here -- do you know of any command that accepts a `--'
option which gets its argument in the next word? If so, I think that
command shouldn't do that.

> 2. I would like to refer the parsed arguments in completers.
> 
> I think this is useful in many cases.
> For example, if the completer for port of telnet can refer host
> argument, it can complete ports precisely: "nntp" for news servers,
> "smtp" for mail servers, etc.  If the completer for emacs can check
> whether the argument of -f is batch-byte-compile, we can complete only
> *.el.

(I think you mean completion functions, the term `completer' refers to 
those top-level thingies like `_complete'.)

Yes, another one of the things I hacked at the weekend. The patch
makes the non-options from the line available in the `line' array
(there may be a better name) in everything that gets called or
evaluated from `_arguments' (or `_long_options' if that was called
from `_arguments').

> 3. "xterm -e" style.
> 
> Some options take arguments up to end of command line.
> 
> If _arguments supports this style of options, it is also useful for
> _cvs, I suppose. Because first non-option argument for cvs command
> behaves like that.

Yes, again, I thought about this when I wrote `_arguments' but
couldn't think of a syntax and then simply forgot to write it. I think 
I'll send a patch for this some time...

> Also, I found the problem about associative array with rcexpandparam.
> 
> Z(2):akr@is27e1u11% zsh -f
> is27e1u11% typeset -A arr 
> is27e1u11% arr[a]=
> is27e1u11% print -lr - "A${(@)^arr[(I)b]}B"
> AB
> 
> This should be empty.  Because of this problem, completions for
> single-letter option doesn't work well.

No, it shouldn't -- there is one string resulting from the expansion,
even it is the empty string.

What exactly doesn't work with single-letter option because of this?
(I'm a bit too lazy to search ;-) I guess that this can be avoided by
adding a ${...:#} somewhere.


Other things the patch contains:

- a fixlet for `compadd' it didn't skip over arguments of the second
  to nth occurrence of an option that was given more than once
- first attempt for auto-param-slash
- it changes the `Commands/*' files to not contain the `-n' option -- 
  this is made implicit in `compinit' in the same way this is implicit
  for normal `compdef's
- actions in `_arguments' and `_long_options' can be made evaluated
  with the new syntax `{string}'
- `_arguments' lists short options in a better readable form
- it cleans up some functions to make use of helper functions like
  `_hosts' and `_users'
- the file `Util/completion-style-guide' contains the beginnings of a
  style guide for completion functions; for now this is just a simple
  list of things to do or not to do

Bye
 Sven

diff -u os/Zle/compctl.c Src/Zle/compctl.c
--- os/Zle/compctl.c	Fri Aug 20 15:18:19 1999
+++ Src/Zle/compctl.c	Mon Aug 23 10:23:09 1999
@@ -1850,8 +1850,9 @@
 			*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 -u od/Zsh/compsys.yo Doc/Zsh/compsys.yo
--- od/Zsh/compsys.yo	Fri Aug 20 15:18:10 1999
+++ Doc/Zsh/compsys.yo	Mon Aug 23 10:23:09 1999
@@ -846,7 +846,7 @@
 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 @@
 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 -u -r oc/Base/_arguments Completion/Base/_arguments
--- oc/Base/_arguments	Mon Aug 23 10:12:47 1999
+++ Completion/Base/_arguments	Mon Aug 23 10:38:49 1999
@@ -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 @@
   sopts=''
 fi
 
-if [[ $#long -ne 0 && "$PREFIX" = --* ]]; then
+# Parse the command line...
 
-   # If the current words starts with `--' and we should use long
-   # options, just call...
+ws=( "${(@)words[2,-1]}" )
+cur=$(( CURRENT-2 ))
+nth=1
+liine=( "$words[1]" )
 
-  _long_options "$long[@]"
-else
+# ...until the current word is reached.
 
-  # Otherwise parse the command line...
+while [[ cur -gt 0 ]]; do
 
-  ws=( "${(@)words[2,-1]}" )
-  cur=$(( CURRENT-2 ))
-  nth=1
+  # `def' holds the description for the option we are currently after.
+  # Check if the next argument for the option is optional.
+
+  if [[ "$def" = :* ]]; then
+    opt=yes
+  else
+    opt=''
+  fi
+  arg=''
 
-  # ...until the current word is reached.
+  # Remove one description/action pair from `def' if that isn't empty.
 
-  while [[ cur -gt 0 ]]; do
+  if [[ -n "$def" ]]; then
+    if [[ "$def" = ?*:*:* ]]; then
+      def="${def#?*:*:}"
+    else
+      def=''
+    fi
+  else
 
-    # `def' holds the description for the option we are currently after.
-    # Check if the next argument for the option is optional.
+    # 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 [[ "$def" = :* ]]; then
+    if [[ $#long -eq 0 || "$ws[1]" != --* ]]; then
       opt=yes
+      arg=yes
     else
-      opt=''
+      def=''
     fi
-    arg=''
+  fi
 
-    # Remove one description/action pair from `def' if that isn't empty.
+  if [[ -n "$opt" ]]; then
 
-    if [[ -n "$def" ]]; then
-      if [[ "$def" = ?*:*:* ]]; then
-        def="${def#?*:*:}"
-      else
-        def=''
-      fi
-    else
+    # `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 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 [[ $#long -eq 0 || "$ws[1]" != --* ]]; then
-        opt=yes
-	arg=yes
-      else
-        def=''
+    if (( $+opts[$ws[1]] )); then
+
+      # Options that may only be given once are removed from the
+      # associative array so that we don't offer them again.
+
+      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
-    fi
 
-    if [[ -n "$opt" ]]; 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.
 
-      # `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" && $#dopts -ne 0 ]]; then
 
-      if (( $+opts[$ws[1]] )); then
+	# First we get the option names.
 
-        # Options that may only be given once are removed from the
-        # associative array so that we don't offer them again.
+	tmp=( "${(@k)dopts}" )
 
-        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=''
+	# Then we loop over them and see if the current word begins
+	# with one of the option names.
+
+	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
-        fi
+	  shift 1 tmp
+	done
+
+	if (( $#tmp )); 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.
-
-        if [[ -n "$opt" && $#dopts -ne 0 ]]; then
-
-	  # First we get the option names.
-
-	  tmp=( "${(@k)dopts}" )
-
-	  # Then we loop over them and see if the current word begins
-	  # with one of the option names.
-
-	  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.
-
-	    opt=''
-	    def="$dopts[$tmp[1]]"
-	    [[ -n "$oneshot[$tmp[1]]" ]] && unset "dopts[$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
-        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
+      fi
 
-	  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
+      [[ -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 @@
         _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 @@
       # 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 -u -r oc/Base/_brace_parameter Completion/Base/_brace_parameter
--- oc/Base/_brace_parameter	Mon Aug 23 10:12:47 1999
+++ Completion/Base/_brace_parameter	Mon Aug 23 10:23:10 1999
@@ -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 @@
 
 [[ n -gt 0 ]] && suf=''
 
-_parameters -Qs "${q[1,-n-1]}" -S "$suf" -r '-:?#%+=[/}'
+_parameters "$suf[@]" -Qs "${q[1,-n-1]}" -r '-:?#%+=[/}'
diff -u -r oc/Base/_condition Completion/Base/_condition
--- oc/Base/_condition	Mon Aug 23 10:12:47 1999
+++ Completion/Base/_condition	Mon Aug 23 10:23:10 1999
@@ -7,11 +7,10 @@
 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 -u -r oc/Base/_long_options Completion/Base/_long_options
--- oc/Base/_long_options	Mon Aug 23 10:12:47 1999
+++ Completion/Base/_long_options	Mon Aug 23 10:44:58 1999
@@ -112,8 +112,9 @@
   # 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 @@
 
       _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 @@
 
     _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 @@
 
 anum=1
 for name in "$_lo_cache_names[@]"; do
-  action="$_lo_cache_actions[anum]"
-
   _description expl option
 
   if [[ "$name" = *_optarg_* ]]; then
diff -u -r oc/Base/_math Completion/Base/_math
--- oc/Base/_math	Mon Aug 23 10:12:47 1999
+++ Completion/Base/_math	Mon Aug 23 10:23:11 1999
@@ -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 @@
   SUFFIX="${SUFFIX%%[^a-zA-Z0-9_]*}"
 fi
 
-_description expl parameter
-compgen "$expl[@]" -v
+_parameters
diff -u -r oc/Base/_parameter Completion/Base/_parameter
--- oc/Base/_parameter	Mon Aug 23 10:12:47 1999
+++ Completion/Base/_parameter	Mon Aug 23 10:23:11 1999
@@ -1,7 +1,7 @@
 #compdef -parameter-
 
 if [[ "$compstate[insert]" = *menu* ]]; then
-  _parameters
+  _parameters -s ''
 else
-  _parameters -S ' ' -r '['
+  _parameters -s ' '
 fi
diff -u -r oc/Base/_tilde Completion/Base/_tilde
--- oc/Base/_tilde	Mon Aug 23 10:12:47 1999
+++ Completion/Base/_tilde	Mon Aug 23 10:23:11 1999
@@ -41,7 +41,7 @@
   if (( $# )); then
     d=( "$@" )
   else
-    _description d user
+    _description d 'user or named directory'
   fi
 fi
 
diff -u -r oc/Base/_vars Completion/Base/_vars
--- oc/Base/_vars	Mon Aug 23 10:12:47 1999
+++ Completion/Base/_vars	Mon Aug 23 10:23:11 1999
@@ -20,6 +20,5 @@
     compadd "$expl[@]" $addclose - ${(kP)var}
   fi
 else
-  _description expl parameter
-  compgen "$expl[@]" -v
+  _parameter
 fi
diff -u -r oc/Builtins/_vars_eq Completion/Builtins/_vars_eq
--- oc/Builtins/_vars_eq	Mon Aug 23 10:12:49 1999
+++ Completion/Builtins/_vars_eq	Mon Aug 23 10:23:11 1999
@@ -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 -u -r oc/Builtins/_zftp Completion/Builtins/_zftp
--- oc/Builtins/_zftp	Mon Aug 23 10:12:49 1999
+++ Completion/Builtins/_zftp	Mon Aug 23 10:23:12 1999
@@ -23,47 +23,46 @@
 
 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 -u -r oc/Commands/_correct_filename Completion/Commands/_correct_filename
--- oc/Commands/_correct_filename	Mon Aug 23 10:12:49 1999
+++ Completion/Commands/_correct_filename	Mon Aug 23 10:23:12 1999
@@ -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 -u -r oc/Commands/_correct_word Completion/Commands/_correct_word
--- oc/Commands/_correct_word	Mon Aug 23 10:12:49 1999
+++ Completion/Commands/_correct_word	Mon Aug 23 10:23:12 1999
@@ -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 -u -r oc/Commands/_expand_word Completion/Commands/_expand_word
--- oc/Commands/_expand_word	Mon Aug 23 10:12:50 1999
+++ Completion/Commands/_expand_word	Mon Aug 23 10:23:12 1999
@@ -1,4 +1,4 @@
-#compdef -kn complete-word \C-xe
+#compdef -k complete-word \C-xe
 
 # Simple completion front-end implementing expansion.
 #
diff -u -r oc/Commands/_history_complete_word Completion/Commands/_history_complete_word
--- oc/Commands/_history_complete_word	Mon Aug 23 10:12:50 1999
+++ Completion/Commands/_history_complete_word	Mon Aug 23 10:23:12 1999
@@ -1,4 +1,4 @@
-#compdef -kn complete-word \e/
+#compdef -k complete-word \e/
 
 local expl
 
diff -u -r oc/Commands/_most_recent_file Completion/Commands/_most_recent_file
--- oc/Commands/_most_recent_file	Mon Aug 23 10:12:50 1999
+++ Completion/Commands/_most_recent_file	Mon Aug 23 10:23:12 1999
@@ -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 -u -r oc/Commands/_read_comp Completion/Commands/_read_comp
--- oc/Commands/_read_comp	Mon Aug 23 10:12:50 1999
+++ Completion/Commands/_read_comp	Mon Aug 23 10:23:13 1999
@@ -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 -u -r oc/Core/_parameters Completion/Core/_parameters
--- oc/Core/_parameters	Mon Aug 23 10:12:51 1999
+++ Completion/Core/_parameters	Mon Aug 23 11:03:48 1999
@@ -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 -u -r oc/Core/compinit Completion/Core/compinit
--- oc/Core/compinit	Mon Aug 23 10:12:51 1999
+++ Completion/Core/compinit	Mon Aug 23 10:23:13 1999
@@ -379,7 +379,7 @@
       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 -u -r oc/User/_chown Completion/User/_chown
--- oc/User/_chown	Mon Aug 23 10:12:58 1999
+++ Completion/User/_chown	Mon Aug 23 10:23:13 1999
@@ -4,14 +4,10 @@
   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 -u -r oc/User/_dir_list Completion/User/_dir_list
--- oc/User/_dir_list	Mon Aug 23 11:28:33 1999
+++ Completion/User/_dir_list	Mon Aug 23 10:23:14 1999
@@ -0,0 +1,4 @@
+#autoload
+
+compset -P '*:'
+_files -S: -r ': \t\t\-' -/
diff -u -r oc/User/_exec_funcs Completion/User/_exec_funcs
--- oc/User/_exec_funcs	Mon Aug 23 11:28:33 1999
+++ Completion/User/_exec_funcs	Mon Aug 23 10:23:14 1999
@@ -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 -u -r oc/User/_find Completion/User/_find
--- oc/User/_find	Mon Aug 23 10:12:58 1999
+++ Completion/User/_find	Mon Aug 23 10:23:14 1999
@@ -27,6 +27,5 @@
 elif [[ "$prev" = -group ]]; then
   _groups
 elif [[ "$prev" = -user ]]; then
-  _description expl user
-  compgen "$expl[@]" -u
+  _users
 fi
diff -u -r oc/User/_gprof Completion/User/_gprof
--- oc/User/_gprof	Mon Aug 23 11:28:33 1999
+++ Completion/User/_gprof	Mon Aug 23 11:29:44 1999
@@ -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 -u -r oc/User/_rlogin Completion/User/_rlogin
--- oc/User/_rlogin	Mon Aug 23 10:12:59 1999
+++ Completion/User/_rlogin	Mon Aug 23 10:23:14 1999
@@ -15,5 +15,5 @@
 elif [[ CURRENT -eq 3 ]]; then
   compadd - -l
 else
-  compgen "$expl[@]" -S @ -u
+  _users -S @
 fi
diff -u -r oc/User/_su Completion/User/_su
--- oc/User/_su	Mon Aug 23 10:12:59 1999
+++ Completion/User/_su	Mon Aug 23 10:23:15 1999
@@ -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 -u -r oc/User/_tar Completion/User/_tar
--- oc/User/_tar	Mon Aug 23 10:12:59 1999
+++ Completion/User/_tar	Mon Aug 23 10:23:15 1999
@@ -72,7 +72,7 @@
 
   # ...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 -u -r oc/User/_users Completion/User/_users
--- oc/User/_users	Mon Aug 23 11:30:03 1999
+++ Completion/User/_users	Mon Aug 23 10:23:15 1999
@@ -0,0 +1,6 @@
+#autoload
+
+local expl
+
+_description expl user
+compgen "$@" "$expl[@]" -u
--- Util/completion-style-guide.old	Mon Aug 23 11:27:28 1999
+++ Util/completion-style-guide	Mon Aug 23 11:25:15 1999
@@ -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).

--
Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx



Messages sorted by: Reverse Date, Date, Thread, Author