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

PATCH: more fun with _arguments



(... in fact, it's not only `_arguments'):

- change `urls_dir' to `urls_path' and add `colors_path' (in
  `_x_color'), so that you can have your own little color database

- add the utility function `funcall' to `compinit' which is a slightly 
  better version of the hook-calling function I suggested some time
  ago (should we use a different name?)

- changes in _arguments:

  - information about options on the line is made available with the
    association `options', one entry per option, with the value
    containing the arguments to the option, separated by colons

  - the new syntax `->name' for actions can be used to implement these 
    state-machine thingies we were talking about; it sets the global
    paramater `state' (`global' in the sense that it isn't made local
    in `_arguments') to `name' and exits immediatly; also, the `line'
    and `options' parameters are not made local to `_arguments' (so
    they should be local in the calling function when a `->...' is
    used -- this is a bit ugly, because if `options' isn't typeset'ed
    to an association the calling function will get the `options' as a 
    global array (not association)), and finally, the changes to the
    special parameters are not reset when `_arguments' exits

  - option descriptions can contain lists of option names which should 
    not be offered as possible completions if the option described is
    on the line; this is for options that are mutually exclusive, as
    in:

      _arguments '(right)-left' '(left)-right'

    here `-left' or `-right' can be completed, but not both (the `(...)'
    may contain any number of option names separated by white space)
    -- the syntax is probably a bit too ugly, even for my standards.

  - options may also have descriptions for the options themselves,
    which will be shown when options are listed:

      _arguments '-foo[explain what -foo does]'

    (again, the syntax is pretty ugly); these descriptions will only
    be shown if the configuration key `describe_options' is non-empty
    and it doesn't contain the substring `!command', where `command'
    is the name of the command we are completing for

  - ... a similar change to the `option_prefix' key: a `!command' in
    it says that for `command' options will always be listed (if we
    are in a command line position for that)

- the code to create display strings for `compadd -y' has been moved
  into a separate function: `_display'

- as an example for the `->state' thing I have written `_rpm' which
  does all the things from `Rpm'

- finally I've written some more into the `completion-style-guide'

Note that I haven't changed all the functions using `_arguments' to
use these exclusion lists or the option-descriptions. I think at least 
the former should be done sometime.

Bye
 Sven

diff -u od/Zsh/compsys.yo Doc/Zsh/compsys.yo
--- od/Zsh/compsys.yo	Fri Sep  3 21:06:33 1999
+++ Doc/Zsh/compsys.yo	Sun Sep  5 20:38:18 1999
@@ -259,6 +259,15 @@
 tt(-L) option is given, the keys and values are printed as calls to this
 function, usable to be put in a setup script.
 )
+findex(funcall)
+item(tt(funcall) var(return) var(name) [ var(args) ... ])(
+If a function var(name) exists, it is called with the arguments
+var(args). Unless it is the empty string or a single hyphen,
+var(return) is taken as the name of a parameter and the return status
+from the called function is stored in it.
+The return value of tt(funcall) itself is zero if the function
+var(name) exists and was called and non-zero otherwise.
+)
 enditem()
 
 texinode(Control Functions)(Completion Functions)(Initialization)(Completion System)
@@ -735,6 +744,36 @@
 preference to tt(description_format). The latter is used only if the
 former is unset or set to the empty string.
 )
+item(tt(_display))(
+This function generates a display list usable for the `tt(-y)' option
+of tt(compadd) and tt(compgen). For this it takes its second argument
+as an array of possible matches with descriptions. The array may
+either be given as the name of an array parameter or directly as a
+list of words in parentheses.
+
+Each element of the array should contain a match, optionally followed
+by a colon and the description for this match. With this
+tt(_display) builds a string with one match and its description per
+line. Matches witout descriptions are appended at the end and aligned
+in multiple columns. After that, the first argument is taken as a
+parameter name and the string built is stored in it.
+
+Before the building the list, however, this function first uses
+tt(compadd) to remove all strings from the array that don't match the
+string on the line (so that they don't appear in the list). This means 
+that the special parameters tt(PREFIX) and tt(SUFFIX) have to be set
+up correctly before this function is called. This call to tt(compadd)
+also uses the other arguments given to tt(_display), by directly
+giving them to tt(compadd).
+
+Finally, if the array is given as the name of a parameter, this
+paramete will be changed to include only those strings that match the
+string on the line.
+
+The return value of tt(_display) is zero if there was at least one
+matching string and the display string could be built and non-zero
+otherwise.
+)
 item(tt(_multi_parts))(
 This function gets two arguments: a separator character and an
 array.  As usual, the array may be either the
@@ -820,17 +859,6 @@
 are used to store the option settings in effect before the completion
 widget locally sets the options it needs.
 )
-item(tt(_long_options))(
-
-This function is used to complete long options for commands that
-support the `tt(--help)' option as, for example, most of the GNU
-commands do. For this it invokes the command from the line with the
-`tt(--help)' option and then parses the output to find possible option
-names. Note that this means that you should be careful to make sure
-that this function is not called for a command that does not support
-this option.
-
-)
 item(tt(_arguments))(
 This function resides in the tt(Base) subdirectory of the example
 completion system because it is not used by the core system.
@@ -899,8 +927,26 @@
 instead. If the argument may be given as the next string or in same
 string as the option name but separated by it from an equal sign, a
 `tt(=)' should be used instead of the minus or plus sign.
-Finally, if the option may be given more than once, a star
-(`tt(*)') should be added in front of the var(opt-spec).
+
+If the option may be given more than once, a star
+(`tt(*)') has to be added in front of the var(opt-spec) because
+otherwise it is not offered as a possible completion again if it is
+already on the line.
+
+An var(opt-spec) may also contain a list of other option names with
+which the option described is mutually exclusive. Such a list is given 
+in parentheses at the beginning, as in `tt((-two -three)-one:...)'. In 
+this example, the options `tt(-two)' and `tt(-three)' will not be
+offered as possible completions if the option `tt(-one)' is on the
+line.
+
+Finally, the var(opt-spec) may contain a explanation string. This is
+given in brackets at the end, as in `tt(-q[query operation])'. The
+configuration key tt(describe_options) is used to decide if these
+explanation strings should be printed when options are listed. If it
+is set to a non-empty string and it doesn't contain the substring
+`tt(!)var(command)', where `var(command)' is the name of the command
+that is completed for, the descriptions will be shown.
 )
 enditem()
 
@@ -911,7 +957,17 @@
 doubled parentheses, as in `tt(:foo:((a\:bar b\:baz)))' should contain 
 strings consisting of the string to complete followed by a colon
 (which needs to be preceded by a backslash) and a description. The
-matches will be listed together with their descriptions. A string in
+matches will be listed together with their descriptions.
+
+A var(action) of the form `tt(->)var(string)' is used by functions
+that implement a state machine. In this case, the `var(string)' (with
+all leading and trailing spaces and tabs removed) will be stored in
+the global parameter tt(state) and the function returns with a return
+value of one after setting the global `tt(line)' and `tt(options)'
+parameters as described below and without resetting any changes made
+to the special parameters such as tt(PREFIX) and tt(words).
+
+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)
@@ -919,20 +975,25 @@
 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 excluding all options and their 
-arguments.
+in the description will be shown above the matches.
 
 To include a colon in the var(message) or the var(action), it has to
 be preceded by a backslash.
 
+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 excluding all options
+and their arguments. These are stored in the associative array
+`tt(options)', using the option names as keys and their arguments as
+the values. For options that have more than one argument these are
+given as one string, separated by colons. All colons in the original
+arguments are preceded with backslashes.
+
 Normally the option names are taken as multi-character names and a
 word from the line is considered to contain only one option (or
 none). By giving the tt(-s) option to this function (as the first
 argument), options are considered to be one-character options and the
-string from the line may contain more than one such option letter.
+strings from the line may contain more than one such option letter.
 
 The function can also be made to automatically complete long options
 for commands that support the `tt(--help)' option as, for example,
@@ -986,13 +1047,14 @@
 completion of the second form, one would use `tt(-s "(#--enable-
 --disable-)")'.
 
-Finally, this function uses one configuration key: tt(option_prefix). If
-this is set to a string containing `tt(short)' or `tt(all)' as a
-substring, option names beginning with a single minus sign are added
-as possible matches only if the word on the line begins with a minus
-sign. If the value contains one of the substrings `tt(long)' or
-`tt(all)', option names beginning with two minus signs will be
-added as matches only if the two minus signs are given on the line.
+Finally, this function uses the configuration key tt(option_prefix). If
+it is set to a non-empty string, option names are added as possible
+matches only if the word on the line begins with the prefix character
+of them (i.e. a minus or a plus sign). If the value contains
+`tt(!)var(command)' as a substring, where `var(command)' is the name
+of the command that is completed for, the options are added as
+possible matches even if their prefix character is not given on the
+line.
 
 Example:
 
diff -u -r Completion.old/Base/_arguments Completion/Base/_arguments
--- Completion.old/Base/_arguments	Fri Sep  3 21:06:41 1999
+++ Completion/Base/_arguments	Sun Sep  5 22:14:40 1999
@@ -5,22 +5,22 @@
 
 setopt localoptions extendedglob
 
-local args rest ws cur nth def nm expl descr action opt arg tmp
-local single uns ret=1 soptseq soptseq1 sopts prefix line
-local beg optbeg argbeg nargbeg inopt inrest fromrest
+local args rest ws cur nth def nm expl descr action opt arg tmp xor
+local single uns ret=1 soptseq soptseq1 sopts prefix _line odescr
+local beg optbeg argbeg nargbeg inopt inrest fromrest cmd="$words[1]"
+local matched curopt
 
 # Associative arrays used to collect information about the options.
 
-typeset -A opts dopts odopts
-typeset -A oneshot
+typeset -A opts dopts odopts xors _options
 
 # Fill the cache if we were called with different arguments.
 
 if [[ "$*" != "$_args_cache_descr" ]]; then
   _args_cache_descr="$*"
 
-  unset _args_cache_{opts,dopts,odopts,oneshot}
-  typeset -gA _args_cache_{opts,dopts,odopts,oneshot}
+  unset _args_cache_{opts,dopts,odopts,odescr,xors}
+  typeset -gA _args_cache_{opts,dopts,odopts,xors}
 
   unset _args_cache_{long,longcmd,single,rest,args,sopts,soptseq,soptseq1}
 
@@ -182,10 +182,29 @@
 
   # Now parse the arguments...
 
+  odescr=()
   args=()
   nth=1
   while (( $# )); do
 
+    descr=''
+    xor=''
+
+    # Get the names of other values that are mutually exclusive with
+    # this one.
+
+    if [[ "$1" = \(*\)* ]]; then
+      xor="${${1[2,-1]}%%\)*}"
+      1="${1#*\)}"
+    fi
+
+    # Get a description, if any.
+
+    if [[ "$1" = *\[*\](|:*) ]]; then
+      descr="${${1#*\[}%%\]*}"
+      1="${1/\[$descr\]}"
+    fi
+
     # Description for both the `-foo' and `+foo' form?
 
     if [[ "$1" = (\*|)(-+|+-)* ]]; then
@@ -196,12 +215,10 @@
       if [[ "$1" = \** ]]; then
         tmp="${1[4,-1]%%:*}"
         [[ "$tmp" = *[-+] ]] && tmp="$tmp[1,-2]"
-        unset "_args_cache_oneshot[-$tmp]" "_args_cache_oneshot[+$tmp]"
       else
         tmp="${1[3,-1]%%:*}"
         [[ "$tmp" = *[-+] ]] && tmp="$tmp[1,-2]"
-        _args_cache_oneshot[-$tmp]=yes
-        _args_cache_oneshot[+$tmp]=yes
+        xor="$xor -$tmp +$tmp"
       fi
 
       # If the option name ends in a `-', the first argument comes
@@ -222,6 +239,12 @@
         _args_cache_opts[-$tmp]=''
         _args_cache_opts[+$tmp]=''
       fi
+
+      _args_cache_odescr=( "$_args_cache_odescr[@]" {-,+}"${tmp}:$descr" )
+      if [[ -n "$xor" ]]; then
+        _args_cache_xors[-$tmp]="${${xor##[ 	]#}%%[ 	]#}"
+        _args_cache_xors[+$tmp]="${${xor##[ 	]#}%%[ 	]#}"
+      fi
     elif [[ "$1" = (\*|)[-+]* ]]; then
 
       # With a `*' at the beginning, the option may appear more than
@@ -230,11 +253,10 @@
       if [[ "$1" = \** ]]; then
         tmp="${1[2,-1]%%:*}"
         [[ "$tmp" = *[-+] ]] && tmp="$tmp[1,-2]"
-        unset "_args_cache_oneshot[$tmp]"
       else
         tmp="${1%%:*}"
         [[ "$tmp" = *[-+] ]] && tmp="$tmp[1,-2]"
-        _args_cache_oneshot[$tmp]=yes
+	xor="$xor ${tmp%\=}"
       fi
 
       # If the option name ends in a `-', the first argument comes
@@ -251,6 +273,9 @@
       else
         _args_cache_opts[$tmp]=''
       fi
+      _args_cache_odescr=( "$_args_cache_odescr[@]" "${tmp%[-+=]}:$descr" )
+      [[ -n "$xor" ]] && 
+          _args_cache_xors[${tmp%\=}]="${${xor##[ 	]#}%%[ 	]#}"
     elif [[ "$1" = \*::* ]]; then
 
       # This is `*:...', describing `all other arguments', with argument 
@@ -306,7 +331,8 @@
 opts=( "${(@kv)_args_cache_opts}" )
 dopts=( "${(@kv)_args_cache_dopts}" )
 odopts=( "${(@kv)_args_cache_odopts}" )
-oneshot=( "${(@kv)_args_cache_oneshot}" )
+odescr=( "$_args_cache_odescr[@]" )
+xors=( "${(@kv)_args_cache_xors}" )
 single="$_args_cache_single"
 
 # Parse the command line...
@@ -314,7 +340,7 @@
 ws=( "${(@)words[2,-1]}" )
 cur=$(( CURRENT-2 ))
 nth=1
-line=( "$words[1]" )
+_line=( "$words[1]" )
 beg=2
 argbeg=1
 optbeg=1
@@ -324,6 +350,14 @@
 
 while [[ cur -gt 0 ]]; do
 
+  if [[ -n "$def" && -n "$curopt" ]]; then
+    if [[ -n "$_options[$curopt]" ]]; then
+      _options[$curopt]="$_options[$curopt]:${ws[1]//:/\\:}"
+    else
+      _options[$curopt]="${ws[1]//:/\\:}"
+    fi
+  fi
+
   # `def' holds the description for the option we are currently after.
   # Check if the next argument for the option is optional.
 
@@ -339,6 +373,7 @@
 
   if [[ "$def" = \**[^\\]:* && "$ws[1]" = ${~${(M)def#*[^\\]:}[2,-2]} ]]; then
     def=''
+    curopt=''
     shift 1 ws
     (( cur-- ))
     (( beg++ ))
@@ -353,6 +388,7 @@
       argbeg="$beg"
     else
       def=''
+      curopt=''
     fi
   elif [[ -z "$def" ]]; then
 
@@ -360,6 +396,7 @@
 
     opt=yes
     arg=yes
+    curopt=''
   fi
 
   if [[ -n "$opt" ]]; then
@@ -374,16 +411,23 @@
       # associative array so that we don't offer them again.
 
       def="$opts[$ws[1]]"
+      curopt="$ws[1]"
+      _options[$curopt]=''
       optbeg="$beg"
       argbeg="$beg"
       inopt=yes
-      [[ -n "$oneshot[$ws[1]]" ]] && unset "opts[$ws[1]]"
+      if [[ -n "$xors[$ws[1]]" ]]; then
+        odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$ws[1]]}}):*}" )
+        unset {{,d,od}opts,xors}\[${^=xors[$ws[1]]}\]
+      fi
     else
       uns=''
       if [[ -n "$sopts" && "$ws[1]" = [-+]${~soptseq}[$sopts] ]]; then
 	tmp="${ws[1][1]}${ws[1][-1]}"
 	if (( $+opts[$tmp] )); then
 	  def="$opts[$tmp]"
+          curopt="$tmp"
+          _options[$curopt]=''
 	  optbeg="$beg"
 	  argbeg="$beg"
           inopt=yes
@@ -425,10 +469,15 @@
 
 	  opt=''
 	  def="$dopts[$tmp[1]]"
+          curopt="$tmp[1]"
+	  _options[$curopt]="${ws[1]#${tmp[1]}}"
 	  optbeg="$beg"
 	  argbeg="$beg"
 	  inopt=yes
-	  [[ -n "$oneshot[$tmp[1]]" ]] && unset "dopts[$tmp[1]]"
+	  if [[ -n "$xors[$tmp[1]]" ]]; then
+            odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$tmp[1]]}}):*}" )
+            unset {{,d,od}opts,xors}\[${^=xors[$tmp[1]]}\]
+          fi
 	  if [[ "$def" = [^*]*[^\\]:*[^\\]:* ]]; then
             def="${def#?*[^\\]:*[^\\]:}"
           else
@@ -453,11 +502,28 @@
 	if (( $#tmp )); then
 	  opt=''
 	  def="$odopts[$tmp[1]]"
-          [[ -z "$def" ]] && def="$odopts[$tmp[1]=]"
+	  curopt="$tmp[1]"
+          if [[ -z "$def" ]]; then
+	    def="$odopts[$tmp[1]=]"
+	    if [[ "$ws[1]" = ${tmp[1]}?* ]]; then
+	      _options[$curopt]="${ws[1]#${tmp[1]}=}"
+            else
+	      _options[$curopt]=''
+	    fi
+          else
+	    if [[ "$ws[1]" = ${tmp[1]}?* ]]; then
+	      _options[$curopt]="${ws[1]#${tmp[1]}}"
+            else
+	      _options[$curopt]=''
+	    fi
+	  fi
 	  optbeg="$beg"
 	  argbeg="$beg"
 	  inopt=yes
-	  [[ -n "$oneshot[$tmp[1]]" ]] && unset "odopts[$tmp[1]]"
+	  if [[ -n "$xors[$tmp[1]]" ]]; then
+            odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$tmp[1]]}}):*}" )
+            unset {{,d,od}opts,xors}\[${^=xors[$tmp[1]]}\]
+          fi
 
 	  # For options whose first argument *may* come after the
 	  # option, we skip over the first description only if there
@@ -481,7 +547,7 @@
           uns="${ws[1][2,-1]}"
 
       if [[ -n "$uns" ]]; then
-	uns="${(j::)${(@k)oneshot[(I)${ws[1][1]}[$uns]]#[-+]}}"
+        uns="${(@j::)${(v)=xors[(I)${ws[1][1]}[$uns]]}#[-+]}"
 	tmp=(
 	  "opts[${(@)^opts[(I)${ws[1][1]}[$uns]]}]"
 	  "dopts[${(@)^dopts[(I)${ws[1][1]}[$uns]]}]"
@@ -496,7 +562,7 @@
 
       if [[ -n "$opt" && -n "$arg" ]]; then
         def=''
-	line=( "$line[@]" "$ws[1]" )
+	_line=( "$_line[@]" "$ws[1]" )
 	[[ -n "$inopt" ]] && nargbeg=$(( beg - 1 ))
 	inopt=''
         if [[ -z "$args[nth]" && "$rest" = \*::* ]]; then
@@ -593,7 +659,7 @@
       uns="${PREFIX[2,-1]}"
 
   if [[ -n "$uns" ]]; then
-    uns="${(j::)${(@k)oneshot[(I)${ws[1][1]}[$uns]]#[-+]}}"
+    uns="${(@j::)${(v)=xors[(I)${ws[1][1]}[$uns]]}#[-+]}"
     tmp=(
       "opts[${(@)^opts[(I)${pre[1]}[$uns]]}]"
       "dopts[${(@)^dopts[(I)${pre[1]}[$uns]]}]"
@@ -657,67 +723,134 @@
 
     _description expl "$descr"
 
-    if [[ "$action" = \ # ]]; then
+    if [[ "$action" = -\>* ]]; then
+      line=( "$_line[@]" )
+      options=( "${(@kv)_options}" )
+      state="${${action[3,-1]##[ 	]#}%%[ 	]#}"
+      compstate[restore]=''
+      return 1
+    else
+      if [[ "${(t)line}" != *local* ]]; then
+        local line
+	typeset -A options
+      fi
 
-      # An empty action means that we should just display a message.
+      line=( "$_line[@]" )
+      options=( "${(@kv)_options}" )
 
-      _message "$descr"
-      break
+      if [[ "$action" = \ # ]]; then
 
-    elif [[ "$action" = \(\(*\)\) ]]; then
+        # An empty action means that we should just display a message.
 
-      # ((...)) contains literal strings with descriptions.
-
-      eval ws\=\( "${action[3,-3]}" \)
-
-      compadd -D ws - "${(@)ws%%:*}"
-
-      if (( $#ws )); then
-        beg=1
-        for nth in "$ws[@]"; do
-          tmp="${#nth%%:*}"
-	  [[ tmp -gt beg ]] && beg="$tmp"
-        done
-        tmp=''
-        for nth in "$ws[@]"; do
-          tmp="$tmp
-${(r:beg:: :)nth%%:*} -- ${nth#*:}"
-        done
-        tmp="$tmp[2,-1]"
-        compadd "$expl[@]" -y tmp - "${(@)ws%%:*}"
-      else
+        [[ -n "$matched" ]] && compadd -n -Q -S '' -s "$SUFFIX" - "$PREFIX"
         _message "$descr"
-      fi
-    elif [[ "$action" = \(*\) ]]; then
+        break
 
-      # Anything inside `(...)' is added directly.
+      elif [[ "$action" = \(\(*\)\) ]]; then
 
-      compadd "$expl[@]" - ${=action[2,-2]}
-    elif [[ "$action" = \{*\} ]]; then
+        # ((...)) contains literal strings with descriptions.
 
-      # A string in braces is evaluated.
+        eval ws\=\( "${action[3,-3]}" \)
 
-      eval "$action[2,-2]"
+	if _display tmp ws -M 'r:|[_-]=* r:|=*'; then
+          compadd "$expl[@]" -y tmp - "${(@)ws%%:*}"
+        else
+          [[ -n "$matched" ]] && compadd -Q -S -s "$SUFFIX" - "$PREFIX"
+          _message "$descr"
+        fi
+      elif [[ "$action" = \(*\) ]]; then
 
-    elif [[ "$action" = \ * ]]; then
+        # Anything inside `(...)' is added directly.
 
-      # If the action starts with a space, we just call it.
+        compadd "$expl[@]" - ${=action[2,-2]}
+      elif [[ "$action" = \{*\} ]]; then
 
-      ${(e)=~action}
-    else
+        # A string in braces is evaluated.
+
+        eval "$action[2,-2]"
 
-      # Otherwise we call it with the description-arguments built above.
+      elif [[ "$action" = \ * ]]; then
 
-      action=( $=action )
-      ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
+        # If the action starts with a space, we just call it.
+
+        ${(e)=~action}
+      else
+
+        # Otherwise we call it with the description-arguments built above.
+
+        action=( $=action )
+        ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
+      fi
     fi
   fi
 
-  if [[ nm -eq compstate[nmatches] && $#_args_cache_long -ne 0 &&
-        "$PREFIX" = --*=* ]]; then
+  # Probably add the option names.
+
+  if [[ -n "$opt" &&
+        ( nm -eq compstate[nmatches] ||
+          -z "$compconfig[option_prefix]" || 
+          "$compconfig[option_prefix]" = *\!${cmd}* ||
+          "$PREFIX" = [-+]* ) ]]; then
+    _description expl option
+    if [[ -n "$sopts" && -n "$PREFIX" &&
+      "$PREFIX" = [-+]${~soptseq}[$sopts] ]]; then
+      if [[ "$PREFIX" = [-+]${~soptseq1} ]]; then
+        if [[ -n "$compconfig[describe_options]" &&
+              "$compconfig[describe_options]" != *\!${cmd}* ]]; then
+          _display tmp odescr
+        else
+          tmp="( ${(j: :)${(@)${(@M)${=:-${(k)opts} ${(k)dopts} ${(k)odopts}}:#[-+]?(|=)}#?}%=} )"
+        fi
+        compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -y tmp - \
+                "${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 the next word.
+
+        compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' - "${PREFIX}" && ret=0
+      fi
+    else
+      tmp=''
+      if [[ -n "$compconfig[describe_options]" &&
+            "$compconfig[describe_options]" != *\!${cmd}* ]]; then
+        if _display tmp odescr; then
+          if (( $#dopts )); then
+            compadd -n "$expl[@]" -QS '' -M 'r:|[_-]=* r:|=*' -y tmp - \
+                    "${(@k)dopts}" && ret=0
+            compadd -n -J option -Q -M 'r:|[_-]=* r:|=*' - \
+                    "${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
+            compadd -n -J option -QqS= -M 'r:|[_-]=* r:|=*' - \
+                    "${(@k)odopts[(I)*=]%=}" && ret=0
+          elif (( ${(@k)#odopts[(I)*=]} )); then
+            compadd -n "$expl[@]" -QqS= -M 'r:|[_-]=* r:|=*' -y tmp - \
+                    "${(@k)odopts[(I)*=]%=}" && ret=0
+            compadd -n -J option -Q -M 'r:|[_-]=* r:|=*' - \
+                    "${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
+          else
+            compadd -n "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -y tmp - \
+                    "${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
+          fi
+        fi
+      fi
+      if [[ -z "$tmp" ]]; then
+        compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' - \
+                "${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
+        compadd "$expl[@]" -QqS= -M 'r:|[_-]=* r:|=*' - \
+                "${(@k)odopts[(I)*=]%=}" && ret=0
+        compadd "$expl[@]" -QS '' -M 'r:|[_-]=* r:|=*' - \
+                "${(@k)dopts}" && ret=0
+      fi
+    fi
+  fi
+
+  if [[ nm -eq compstate[nmatches] && 
+        ( -z "$single" ||
+          ( $#_args_cache_long -ne 0 && "$PREFIX" = --*=* ) ) ]]; then
     local suffix
 
-    tmp=( "${(@Mk)odopts:#--[^:]#\=}" )
+    tmp=( "${(@Mk)odopts:#[^:]#\=}" )
     prefix="${PREFIX#*\=}"
     suffix="$SUFFIX"
     PREFIX="${PREFIX%%\=*}"
@@ -729,39 +862,13 @@
       PREFIX="$prefix"
       SUFFIX="$suffix"
       IPREFIX="$tmp[1]"
+      matched=yes
       continue
     fi
   fi
+
   break
 done
-
-# Probably add the option names.
-
-if [[ -n "$opt" &&
-      ( nm -eq compstate[nmatches] ||
-        -z "$compconfig[option_prefix]" || "$PREFIX" = [-+]* ) ]]; then
-  _description expl option
-  if [[ -n "$sopts" && -n "$PREFIX" &&
-    "$PREFIX" = [-+]${~soptseq}[$sopts] ]]; then
-    if [[ "$PREFIX" = [-+]${~soptseq1} ]]; then
-      compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' \
-              -y "( ${(j: :)${(@)${(@M)${=:-${(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 the next word.
-
-      compadd "$expl[@]" -Q  -M 'r:|[_-]=* r:|=*' - "${PREFIX}" && ret=0
-    fi
-  else
-    compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' - \
-            "${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
-    compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -qS= - \
-            "${(@k)odopts[(I)*=]%=}" && ret=0
-    compadd "$expl[@]" -QS '' -M 'r:|[_-]=* r:|=*' - "${(@k)dopts}" && ret=0
-  fi
-fi
 
 # Set the return value.
 
diff -u -r Completion.old/Core/_display Completion/Core/_display
--- Completion.old/Core/_display	Mon Sep  6 09:48:57 1999
+++ Completion/Core/_display	Sun Sep  5 22:59:03 1999
@@ -0,0 +1,76 @@
+#autoload
+
+# This builds a display-list for the `-y' option of `compadd' and
+# `compgen' out of the arguments it gets. The first argument is
+# taken as the name of a parameter and the string built is stored
+# into it.
+# The second argument is the name of an array whose elements each
+# contains a string to complete, optionally followed by a colon
+# and a description. The display list created will contain one
+# line per string with the description after it, all nicely
+# aligned. Strings without descriptions are put at the end in a
+# column-oriented fashion.
+# All arguments after the second one are given as arguments to
+# `compadd'.
+# This function will also do the matching required to find out
+# which strings will be included in the list. All elements that
+# don't match will be removed from the array. This means that the
+# special parameters `PREFI' and `SUFFIX' have to be set up 
+# correctly before this function is called.
+
+local _param="$1" _arr _len _i _tmp _simple
+
+# Remove all descriptions not matched by the string on the line.
+
+if [[ "${2[1]}" = \( ]]; then
+  _arr=( ${(o)=2[2,-2]} )
+else
+  _arr=( "${(@Po)2}" )
+fi
+
+compadd -D _arr "${(@)argv[3,-1]}" - "${(@)_arr%%:*}"
+
+[[ "${2[1]}" != \( ]] && eval "${2}=( \"\$_arr[@]\" )"
+
+if (( $#_arr )); then
+
+  # There are strings left, first get the length of the longest of
+  # them (to be able to align them) and collect all strings without
+  # descriptions.
+
+  _simple=()
+  _len=1
+  for _i in "$_arr[@]";  do
+    _tmp="${#_i%%:*}"
+    if [[ "$_i" = *:?* ]]; then
+      [[ _tmp -gt _len ]] && _len="$_tmp"
+    else
+      _simple=( "$_simple[@]" "${_i%:}" )
+    fi
+  done
+
+  # Now we build the list in `_tmp', adding one line per string.
+
+  _tmp=''
+  for _i in "$_arr[@]"; do
+    [[ "$_i" = *:?* ]] && _tmp="$_tmp
+${(r:_len:: :)_i%%:*} -- ${_i#*:}"
+  done
+
+  # If there were strings without descriptions, we just add them by
+  # calling `print -c'.
+
+  (( $#_simple )) && _tmp="${_tmp}
+$(print -c - $_simple)"
+
+  eval "${_param}=${(q)_tmp[2,-1]}"
+
+  return 0
+else
+
+  # None of the strings matches what's on the line, signal this by
+  # setting the parameter to an empty string and by the return value.
+
+  eval "${_param}=''"
+  return 1
+fi
diff -u -r Completion.old/Core/compinit Completion/Core/compinit
--- Completion.old/Core/compinit	Fri Sep  3 21:06:41 1999
+++ Completion/Core/compinit	Fri Sep  3 22:09:50 1999
@@ -320,6 +320,34 @@
   fi
 }
 
+# Utility function to call a function if it exists.
+#
+# Usage: call <return> <name> [ <args> ... ]
+#
+# If a function named <name> is defined (or defined to be autoloaded),
+# it is called. If <return> is given not the string `-' or empty, it is
+# taken as the name of a parameter and the return status of the function
+# called is stored in this parameter. All other arguments are given
+# to the function called.
+# The return value of this function is zero if the function was
+# called and non-zero otherwise.
+
+funcall() {
+  local _name _ret
+
+  [[ "$1" != (|-) ]] && _name="$1"
+
+  shift
+
+  if builtin functions "$1"; then
+    "$@"
+    _ret="$?"
+    [[ -n "$_name" ]] && eval "${_name}=${_ret}"
+    return 0
+  fi
+  return 1
+}
+
 # Now we automatically make the definition files autoloaded.
 
 typeset -U _i_files
diff -u -r Completion.old/Linux/_rpm Completion/Linux/_rpm
--- Completion.old/Linux/_rpm	Mon Sep  6 09:48:57 1999
+++ Completion/Linux/_rpm	Sun Sep  5 21:23:22 1999
@@ -0,0 +1,215 @@
+#compdef rpm
+
+# This uses `_arguments' in a state-machine kind of way. These states
+# have names and before executing the default action for such a state
+# we try to call a function with the name `_rpm_<state>'. If such a
+# function exists, we return with it's return status immediatly. This
+# allows users to override the default completions by simply defining
+# these functions.
+# The states (and possible values for the `<state>' above) are:
+#
+#  query
+#    complete for `rpm -q' query
+#  verify
+#    complete for `rpm --verify'
+#  install
+#    complete for `rpm -i' or `rpm --install'
+#  upgrade
+#    complete for `rpm -U' or `rpm --upgrade'
+#  uninstall
+#    complete for `rpm -e' or `rpm --erase'
+#  build_b
+#    complete for `rpm -bx' (the stage `x' is already completed)
+#  build_t
+#    complete for `rpm -tx' (the stage `x' is already completed)
+#  sigcheck
+#    complete for `rpm --sigcheck'
+#  rebuild
+#    complete for `rpm --rebuild'
+#  package
+#    complete a RPM package name
+#  package_file
+#    complete a RPM package file name
+#  package_or_file
+#    the previous two together
+#  tags
+#    complete a tag name
+#  capability
+#    complete a capability
+#  relocate
+#    complete a `old=new' pair of paths
+
+local ret=1 tmp expl
+
+# Used by `_arguments', made local here.
+
+local state lstate line
+tyeset -A options
+
+state=''
+
+# Do simple completions or get the first state.
+
+_arguments \
+  '--rcfile:resource file:_files' \
+  '--ftpproxy:FTP proxy server:_hosts' \
+  '--ftpport:FTP port number:' \
+  '-q:*:query:->query' \
+  -{V,v,vv,y,-{setperms,setugids,querytags,initdb,showrc}} \
+  '-pipe:*:pipe command:_command_names -e' \
+  '--verify:*:verify:->verify' \
+  -{i,-install}':*:install:->install' \
+  -{U,-upgrade}':*:upgrade:->upgrade' \
+  -{e,-erase}':*:uninstall:->uninstall' \
+  -'b+:build stage:((p\:execute\ \%prep\ stage l\:do\ a\ list\ check c\:execute\ build\ stage i\:execute\ install\ stage b\:build\ a\ binary\ package a\:build\ binary\ and\ source\ packages)):*:build:->build_b' \
+  -'t+:build stage:((p\:execute\ \%prep\ stage l\:do\ a\ list\ check c\:execute\ build\ stage i\:execute\ install\ stage b\:build\ a\ binary\ package a\:build\ binary\ and\ source\ packages)):*:build:->build_t' \
+  --{rebuild,rmsource,recompile,resign,addsign}':*:RPM package:->package' \
+  -{K,-checksig}':*:sigcheck:->sigcheck' \
+  '--rebuilddb:*:rebuild:->rebuild' && ret=0
+
+# As long as we have a state name...
+
+while [[ -n "$state" ]]; do
+
+  # First try to call a user-defined function.
+
+  funcall ret _rpm_$state && return ret
+
+  # Copy the state and reset `state', to simplify the test above.
+
+  lstate="$state"
+  state=''
+  tmp=()
+
+  # Dispatch...
+
+  case "$lstate" in
+  query)
+    _arguments \
+      -{v,vv} \
+      '--rcfile:resource file:_files' \
+      '--ftpproxy:FTP proxy server:_hosts' \
+      '--ftpport:FTP port number:' \
+      '--root:RPM root directory:_files -/' \
+      '--dbpath:RPM database path:_files -/' \
+      '--queryformat:RPM query format:->tags' \
+      '-f:file:_files' \
+      '-p:RPM package file:->package_file' \
+      '--triggeredby:RPM package:->package' \
+      '--whatprovides:RPM capability:->capability' \
+      '--whatrequires:RPM capability:->capability' \
+      '*:RPM package:->package_or_file' && ret=0
+    ;;
+  verify)
+    _arguments \
+      -{v,vv} \
+      '--rcfile:resource file:_files' \
+      '--ftpproxy:FTP proxy server:_hosts' \
+      '--ftpport:FTP port number:' \
+      --no{deps,md5,files} \
+      '--root:RPM root directory:_files -/' \
+      '--dbpath:RPM database path:_files -/' \
+      '*:RPM package:->package' && ret=0
+    ;;
+  upgrade)
+    tmp=( --oldpackage )
+    ;&
+  install)
+    _arguments "$tmp[@]" \
+      -{v,vv} \
+      '--rcfile:resource file:_files' \
+      '--ftpproxy:FTP proxy server:_hosts' \
+      '--ftpport:FTP port number:' \
+      -{-{badreloc,excludedocs,force,hash,allfiles,ignorearch,ignoreos,includedocs,justdb,nodeps,noorder,noscripts,notriggers,percent,replacefiles,replacepkgs,test},h} \
+      '--relocate:relocate:->relocate' \
+      '--prefix:package prefix directory:_files -/' \
+      '--root:RPM root directory:_files -/' \
+      '--dbpath:RPM database path:_files -/' \
+      '*:pkg file:->package_file' && ret=0
+    ;;
+  uninstall)
+    _arguments \
+      -{v,vv} \
+      '--rcfile:resource file:_files' \
+      '--ftpproxy:FTP proxy server:_hosts' \
+      '--ftpport:FTP port number:' \
+      --{allmatches,justdb,nodeps,noorder,noscripts,notriggers} \
+      '--root:RPM root directory:_files -/' \
+      '--dbpath:RPM database path:_files -/' \
+      '*:RPM package:->package' && ret=0
+    ;;
+  build_b)
+    tmp=( '*:RPM package:->package' )
+    ;&
+  build_t)
+    (( $#tmp )) || tmp=( '*:tar file:_files -g \*.\(\#i\)tar\(.\*\|\)' )
+
+    _arguments \
+      -{v,vv} \
+      '--rcfile:resource file:_files' \
+      '--ftpproxy:FTP proxy server:_hosts' \
+      '--ftpport:FTP port number:' \
+      --{short-circuit,clean,rmsource,sign,test} \
+      '--buildroot:build root directory:_files -/' \
+      '--buildarch:architecture for which to build:' \
+      '--buildos:ositecture for which to build:' \
+      '--timecheck:time check (seconds):' "$tmp[1]" && ret=0
+    ;;
+  sigcheck)
+    _arguments \
+      -{v,vv} \
+      '--rcfile:resource file:_files' \
+      '--ftpproxy:FTP proxy server:_hosts' \
+      '--ftpport:FTP port number:' \
+      --no{pgp,md5} \
+      '*:RPM package file:->package_or_file' && ret=0
+    ;;
+  rebuild)
+    _arguments \
+      -{v,vv} \
+      '--rcfile:resource file:_files' \
+      '--ftpproxy:FTP proxy server:_hosts' \
+      '--ftpport:FTP port number:' \
+      '--root:RPM root directory:_files -/' \
+      '--dbpath:RPM database path:_files -/' \
+      '*:RPM source package file:->package_file' && ret=0
+    ;;
+  package_or_file)
+    state=package_file
+    ;&
+  package)
+    _description expl 'RPM package'
+    compadd "$expl[@]" -M 'r:|-=* r:|=*' - $(rpm -qa) && ret=0
+    ;;
+  package_file)
+    if compset -P ftp:; then
+      _hosts -S/ && ret=0
+    else
+      _files -g '*.(#i)rpm' && ret=0
+    fi
+    ;;
+  tags)
+    if compset -P '*\{'; then
+      _description expl 'RPM tag'
+      compadd "$expl[@]" -M 'm:{a-z}={A-Z}' -S '}' - \
+              "${(@)${(@f)$(rpm --querytags)}#RPMTAG_}" && ret=0
+    else
+      _message 'RPM format'
+    fi
+    ;;
+  capability)
+    _message 'RPM capability'
+    ;;
+  relocate)
+    if compset -P '*\='; then
+      _description expl 'new path'
+    else
+      _description expl 'old path'
+    fi
+
+    _files "$expl[@]" -/ && ret=0
+    ;;
+  esac
+done
+
+return ret
diff -u -r Completion.old/User/_urls Completion/User/_urls
--- Completion.old/User/_urls	Fri Sep  3 21:06:45 1999
+++ Completion/User/_urls	Fri Sep  3 21:07:31 1999
@@ -6,7 +6,7 @@
 #
 # Configuration key used:
 #
-#  urls_dir
+#  urls_path
 #    The path to a directory containing a URL database, such as:
 #
 #      % cd ~/.zsh/urls
@@ -32,8 +32,8 @@
   _files "$@" && return
 fi
 
-if [[ -z "$compconfig[urls_dir]" ]]; then
-  compconfig[urls_dir]=${ZDOTDIR:-$HOME}/.zsh/urls
+if [[ -z "$compconfig[urls_path]" ]]; then
+  compconfig[urls_path]=${ZDOTDIR:-$HOME}/.zsh/urls
 fi
 
 ipre="$IPREFIX"
@@ -52,12 +52,12 @@
 esac
 
 if [[ "$scheme" = bookmark &&
-      -f "$compconfig[urls_dir]/$scheme/$PREFIX$SUFFIX" &&
-      -s "$compconfig[urls_dir]/$scheme/$PREFIX$SUFFIX" ]]; then
-  compadd "$@" -QU -- "$ipre$(<"$compconfig[urls_dir]/$scheme/$PREFIX$SUFFIX")"
+      -f "$compconfig[urls_path]/$scheme/$PREFIX$SUFFIX" &&
+      -s "$compconfig[urls_path]/$scheme/$PREFIX$SUFFIX" ]]; then
+  compadd "$@" -QU -- "$ipre$(<"$compconfig[urls_path]/$scheme/$PREFIX$SUFFIX")"
 else
-  dirs=($compconfig[urls_dir]/$scheme/$PREFIX*$SUFFIX(/:t))
-  files=($compconfig[urls_dir]/$scheme/$PREFIX*$SUFFIX(.:t))
+  dirs=($compconfig[urls_path]/$scheme/$PREFIX*$SUFFIX(/:t))
+  files=($compconfig[urls_path]/$scheme/$PREFIX*$SUFFIX(.:t))
   compset -P '*/'
   compadd "$@" -Q -S '/' - $dirs
   if [[ "$scheme" = bookmark ]]; then
diff -u -r Completion.old/X/_x_color Completion/X/_x_color
--- Completion.old/X/_x_color	Fri Sep  3 21:06:45 1999
+++ Completion/X/_x_color	Fri Sep  3 21:13:57 1999
@@ -1,5 +1,13 @@
 #autoload
 
+# This tries to automatically find the rgb.txt color database. If this
+# in an unusual place on your system or you want a personal database,
+# you can use the configuration key:
+#
+#  colors_path
+#    Path to a file containing the names of colors you want to
+#    complete. In the form of a X11 rgb.txt file.
+
 local expl
 
 if (( ! $+_color_cache )); then
@@ -7,16 +15,18 @@
 
   # Cache of color names doesn't exist yet, create it.
 
-  file=( /usr/{lib,{{X11R6,openwin},local{,/X11{,R6}}}/lib}/X11/rgb.txt(N) )
-
-  if (( $#file )); then
-    _color_cache=( "${(@)${(@f)$(< $file[1])}[2,-1]##*		}" )
+  if [[ -n "$compconfig[colors_path]" ]]; then
+    _color_cache=( "${(@)${(@f)$(< $compconfig[colors_path])}[2,-1]##*		}" )
   else
+    file=( /usr/{lib,{{X11R6,openwin},local{,/X11{,R6}}}/lib}/X11/rgb.txt(N) )
 
-    # Stupid default value.
-
-    _color_cache=(white black gray red blue green)
+    (( $#file )) &&
+        _color_cache=( "${(@)${(@f)$(< $file[1])}[2,-1]##*		}" )
   fi
+
+  # Stupid default value.
+
+  (( $#_color_cache )) || _color_cache=(white black gray red blue green)
 fi
 
 _description expl 'color specification'
--- Etc/completion-style-guide.old	Sun Sep  5 13:39:30 1999
+++ Etc/completion-style-guide	Sun Sep  5 13:54:54 1999
@@ -15,11 +15,11 @@
     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
+    `_arguments' and `_values') -- 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 
+    information. This ensures that users 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
@@ -28,7 +28,7 @@
     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
+    writing `[[ nm -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
@@ -42,3 +42,36 @@
 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).
+11) When option names are generated as possible matches, add them *with*
+    the `-', `+', or `--' at the beginning. This is the style used 
+    throughout the completion system from the distribution and makes it
+    easier to distinguish options from other matches in completion lists.
+    Also, when adding options as matches, put them in a sorted group
+    named `option'. The best way to do this is by using the `_description'
+    helper function as in:
+
+      local expl
+      _description expl option
+      compadd "$expl[@]" - <option-names ...>
+
+    Also, before adding options as possible matches, test the
+    `option_prefix' configuration key. If it set and it doesn't contain
+    the sub-string `!cmd' (where `cmd' is the name of the command that
+    is completed for) options should only be added if the prefix character
+    (`-' or `+') is on the line or if no other useful matches could be 
+    generated. This can be achieved by first generating these other matches
+    (if any) and then using a test like:
+
+      if [[ nm -eq "$compstate[nmatches]" ||
+            -z "$compconfig[option_prefix]" ||
+            "$compconfig[option_prefix]" = *\!${words[1]}* ||
+            "$PREFIX" = [-+]* ]]; then
+        # Add options...
+      fi
+
+    Finally, it is good style to display descriptions for options that
+    aren't self-explanatory. See the `_display' function and it's use
+    in `_arguments'.
+
+    All this should make it look like a really good idea to just use the
+    supplied `_arguments' function to complete options.

--
Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx



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