From f56ba813bb92b1d61be91cb39df620b37a5a0588 Mon Sep 17 00:00:00 2001 From: Sven Wischnowsky Date: Mon, 4 Mar 2002 08:53:41 +0000 Subject: allow different sets of completion definitions selected with option -T to compdef; use this for parameter values and redirections (16755) --- Completion/Base/Completer/_complete | 8 +- Completion/Base/Core/_dispatch | 98 ++++++++++++++++++ Completion/Base/Core/_normal | 123 ++--------------------- Completion/Base/Utility/_contexts | 23 ----- Completion/Base/Utility/_set_command | 31 ++++++ Completion/Unix/Command/_gcc | 24 ++++- Completion/Unix/Command/_su | 2 +- Completion/Unix/Type/_files | 2 +- Completion/Unix/Type/_printers | 2 +- Completion/Unix/Type/_terminals | 2 +- Completion/Unix/Type/_time_zone | 2 +- Completion/X/Type/_x_display | 2 +- Completion/Zsh/Command/_compdef | 1 + Completion/Zsh/Context/_default | 2 +- Completion/Zsh/Context/_in_vared | 2 +- Completion/Zsh/Context/_redirect | 16 ++- Completion/Zsh/Context/_subscript | 2 +- Completion/Zsh/Context/_value | 83 +++++++-------- Completion/compdump | 61 ++++++----- Completion/compinit | 189 +++++++++++++++++++++++++---------- 20 files changed, 397 insertions(+), 278 deletions(-) create mode 100644 Completion/Base/Core/_dispatch delete mode 100644 Completion/Base/Utility/_contexts create mode 100644 Completion/Base/Utility/_set_command (limited to 'Completion') diff --git a/Completion/Base/Completer/_complete b/Completion/Base/Completer/_complete index 16e0f5e9f..23670f7c0 100644 --- a/Completion/Base/Completer/_complete +++ b/Completion/Base/Completer/_complete @@ -95,7 +95,7 @@ fi comp="$_comps[-first-]" if [[ -n "$comp" ]]; then - service="${_services[-first-]:--first-}" + service="${_servicecomps[-first-]:--first-}" ccarray[3]=-first- eval "$comp" && ret=0 if [[ "$_compskip" = all ]]; then @@ -124,7 +124,7 @@ else ccarray[3]="$cname" comp="$_comps[$cname]" - service="${_services[$cname]:-$cname}" + service="${_servicecomps[$cname]:-$cname}" # If not, we use default completion, if any. @@ -134,9 +134,9 @@ else return 1 fi comp="$_comps[-default-]" + service="${_servicecomps[-default-]:--default-}" fi - [[ -n "$comp" ]] && - service="${_services[-default-]:--default-}" && eval "$comp" && ret=0 + [[ -n "$comp" ]] && eval "$comp" && ret=0 fi _compskip= diff --git a/Completion/Base/Core/_dispatch b/Completion/Base/Core/_dispatch new file mode 100644 index 000000000..124aea112 --- /dev/null +++ b/Completion/Base/Core/_dispatch @@ -0,0 +1,98 @@ +#autoload + +local comp pat val name i ret=1 _compskip="$_compskip" +local curcontext="$curcontext" service str comptype noskip def +local __comps __patcomps __postpatcomps __services + +# If we get the option `-s', we don't reset `_compskip'. + +while [[ "$1" = -[sd] ]]; do + if [[ "$1" = -s ]]; then + noskip=yes + else + def=yes + fi + shift +done + +[[ -z "$noskip" ]] && _compskip= + +comptype=$1 + +__comps=_$1 + +(( ${(P)+__comps} )) || return 1 + +__patcomps=_pat$1 +__postpatcomps=_postpat$1 +__services=_service$1 + +shift + +# See if there are any matching pattern completions. + +if [[ "$_compskip" != (all|*patterns*) ]]; then + + for str in "$@"; do + [[ -n "$str" ]] || continue + service="${${(e):-\$${__services}[\$str]}:-$str}" + for i in "${(@e):-\$${__patcomps}[(K)\$str]}"; do + "$i" && ret=0 + if [[ "$_compskip" = *patterns* ]]; then + break + elif [[ "$_compskip" = all ]]; then + _compskip='' + return ret + fi + done + done +fi + +# Now look up the names in the normal completion array. + +ret=1 +for str in "$@"; do + [[ -n "$str" ]] || continue + name="$str" + comp="${(e):-\$${__comps}[\$str]}" + service="${${(e):-\$${__services}[\$str]}:-$str}" + + [[ -z "$comp" ]] || break +done + +# And generate the matches, probably using default completion. + +if [[ -n "$comp" ]]; then + _compskip=patterns + eval "$comp" && ret=0 + [[ "$_compskip" = (all|*patterns*) ]] && return ret +elif [[ "$_compskip" != *default* ]]; then + name=-default- + comp="${(e):-\$${__comps}[-default-]}" +fi + +if [[ "$_compskip" != (all|*patterns*) ]]; then + for str; do + [[ -n "$str" ]] || continue + service="${${(e):-\$${__services}[\$str]}:-$str}" + for i in "${(@e):-\$${__postpatcomps}[(K)\$str]}"; do + _compskip=default + "$i" && ret=0 + if [[ "$_compskip" = *patterns* ]]; then + break + elif [[ "$_compskip" = all ]]; then + _compskip='' + return ret + fi + done + done +fi + +[[ "$name" = -default- && -n "$comp" && + "$_compskip" != (all|*default*) ]] && + service="${${(e):-\$${__services}[-default-]}:--default-}" && + eval "$comp" && ret=0 + +_compskip='' + +return ret diff --git a/Completion/Base/Core/_normal b/Completion/Base/Core/_normal index 9ddfab1cd..028687fd1 100644 --- a/Completion/Base/Core/_normal +++ b/Completion/Base/Core/_normal @@ -1,20 +1,16 @@ #compdef -command-line- -local comp command cmd1 cmd2 pat val name i ret=1 _compskip="$_compskip" -local curcontext="$curcontext" service +local _comp_command1 _comp_command2 skip -# If we get the option `-s', we don't reset `_compskip'. This ensures -# that a value set in the function for the `-first-' context is kept, -# but that we still use pattern functions when we were called form -# another completion function. - -[[ "$1" = -s ]] || _compskip='' +if [[ "$1" = -s ]]; then + skip=(-s) +else + skip=() + _compskip='' +fi -# Completing in command position? If not we set up `cmd1' and `cmd2' as -# two strings we have to search in the completion definition arrays (e.g. -# a path and the last path name component). +# Completing in command position? -command="$words[1]" if [[ CURRENT -eq 1 ]]; then curcontext="${curcontext%:*:*}:-command-:" @@ -22,107 +18,8 @@ if [[ CURRENT -eq 1 ]]; then [[ -n "$comp" ]] && eval "$comp" && ret=0 return ret -else - if (( $+builtins[$command] + $+functions[$command] )); then - cmd1="$command" - curcontext="${curcontext%:*:*}:${cmd1}:" - elif [[ "$command[1]" = '=' ]]; then - eval cmd1\=$command - cmd2="$command[2,-1]" - curcontext="${curcontext%:*:*}:${cmd2}:" - elif [[ "$command" = ..#/* ]]; then - cmd1="${PWD}/$command" - cmd2="${command:t}" - curcontext="${curcontext%:*:*}:${cmd2}:" - elif [[ "$command" = */* ]]; then - cmd1="$command" - cmd2="${command:t}" - curcontext="${curcontext%:*:*}:${cmd2}:" - else - cmd1="$command" - cmd2="$commands[$command]" - curcontext="${curcontext%:*:*}:${cmd1}:" - fi -fi - -# See if there are any matching pattern completions. - -if [[ "$_compskip" != (all|*patterns*) ]]; then - service="${_services[$cmd1]:-$cmd1}" - for i in "${(@)_patcomps[(K)$cmd1]}"; do - "$i" && ret=0 - if [[ "$_compskip" = *patterns* ]]; then - break - elif [[ "$_compskip" = all ]]; then - _compskip='' - return ret - fi - done - if [[ -n "$cmd2" ]]; then - service="${_services[$cmd2]:-$cmd2}" - for i in "${(@)_patcomps[(K)$cmd2]}"; do - "$i" && ret=0 - if [[ "$_compskip" = *patterns* ]]; then - break - elif [[ "$_compskip" = all ]]; then - _compskip='' - return ret - fi - done - fi -fi - -# Now look up the two names in the normal completion array. - -ret=1 -name="$cmd1" -comp="$_comps[$cmd1]" -service="${_services[$cmd1]:-$cmd1}" - -[[ -z "$comp" ]] && - name="$cmd2" comp="$_comps[$cmd2]" service="${_services[$cmd2]:-$cmd2}" - -# And generate the matches, probably using default completion. - -if [[ -n "$comp" ]]; then - _compskip=patterns - eval "$comp" && ret=0 - [[ "$_compskip" = (all|*patterns*) ]] && return ret -elif [[ "$_compskip" != *default* ]]; then - name=-default- - comp="$_comps[-default-]" -fi - -if [[ "$_compskip" != (all|*patterns*) ]]; then - service="${_services[$cmd1]:-$cmd1}" - for i in "${(@)_postpatcomps[(K)$cmd1]}"; do - _compskip=default - "$i" && ret=0 - if [[ "$_compskip" = *patterns* ]]; then - break - elif [[ "$_compskip" = all ]]; then - _compskip='' - return ret - fi - done - if [[ -n "$cmd2" ]]; then - service="${_services[$cmd2]:-$cmd2}" - for i in "${(@)_postpatcomps[(K)$cmd2]}"; do - _compskip=default - "$i" && ret=0 - if [[ "$_compskip" = *patterns* ]]; then - break - elif [[ "$_compskip" = all ]]; then - _compskip='' - return ret - fi - done - fi fi -[[ "$name" = -default- && -n "$comp" && "$_compskip" != (all|*default*) ]] && - service="${_services[-default-]:--default-}" && eval "$comp" && ret=0 - -_compskip='' +_set_command -return ret +_dispatch -d "$skip[@]" comps "$_comp_command1" "$_comp_command2" diff --git a/Completion/Base/Utility/_contexts b/Completion/Base/Utility/_contexts deleted file mode 100644 index f0e5ba874..000000000 --- a/Completion/Base/Utility/_contexts +++ /dev/null @@ -1,23 +0,0 @@ -#autoload - -# This searches $* in the array for normal completions and calls the result. -# It is used to include completions for another command or special context -# into the list generated by the calling function. -# For example the function for `-subscript-' could call this as in -# `_contexts -math-' to get the completions that would be generated for a -# mathematical context. - -local i tmp ret=1 service or - -if [[ $1 = -o ]]; then - or=yes - shift -fi - -for i; do - tmp="$_comps[$i]" - [[ -n "$tmp" ]] && service="${_services[$i]:-$i}" && eval "$tmp" && ret=0 - [[ -n "$or" && ret -eq 0 ]] && return 0 -done - -return ret diff --git a/Completion/Base/Utility/_set_command b/Completion/Base/Utility/_set_command new file mode 100644 index 000000000..daf532686 --- /dev/null +++ b/Completion/Base/Utility/_set_command @@ -0,0 +1,31 @@ +#autoload + +# This sets the parameters _comp_command1 and _comp_command2 in the +# calling function. + +local command + +command="$words[1]" + +[[ -z "$command" ]] && return + +if (( $+builtins[$command] + $+functions[$command] )); then + _comp_command1="$command" + curcontext="${curcontext%:*:*}:${_comp_command1}:" +elif [[ "$command[1]" = '=' ]]; then + eval _comp_command2\=$command + _comp_command1="$command[2,-1]" + curcontext="${curcontext%:*:*}:${_comp_command2}:" +elif [[ "$command" = ..#/* ]]; then + _comp_command1="${PWD}/$command" + _comp_command2="${command:t}" + curcontext="${curcontext%:*:*}:${_comp_command2}:" +elif [[ "$command" = */* ]]; then + _comp_command1="$command" + _comp_command2="${command:t}" + curcontext="${curcontext%:*:*}:${_comp_command2}:" +else + _comp_command1="$command" + _comp_command2="$commands[$command]" + curcontext="${curcontext%:*:*}:${_comp_command1}:" +fi diff --git a/Completion/Unix/Command/_gcc b/Completion/Unix/Command/_gcc index e6c81e408..f297126d1 100644 --- a/Completion/Unix/Command/_gcc +++ b/Completion/Unix/Command/_gcc @@ -1,8 +1,21 @@ -#compdef gcc +#compdef gcc g++ -T values LDFLAGS CFLAGS CPPFLAGS -local curcontext="$curcontext" state line ret=1 expl args +local curcontext="$curcontext" state line ret=1 expl args args2 typeset -A opt_args +if [[ "$comptype" = values ]]; then + compset -q + words=( fake "$words[@]" ) + (( CURRENT++ )) + if ("$service" = LDFLAGS ]]; then + args2=( '-R:runtime path:->rundir' ) + else + args2=() + fi +else + args2=( '*:input file:_files -g \*.\(\[cCmisSoak\]\|cc\|cxx\|ii\|k\[ih\]\)' ) +fi + args=() case $MACHTYPE in m68*) @@ -243,7 +256,7 @@ _arguments -C -M 'L:|-{fW}no-=-{fW} r:|[_-]=* r:|=*' \ -freg-struct-return -fshared-data -fshort-enums \ -fshort-double -fvolatile -fvolatile-global \ -fverbose-asm -fpack-struct \ - '*:input file:_files -g \*.\(\[cCmisSoak\]\|cc\|cxx\|ii\|k\[ih\]\)' && ret=0 + "$args2[@]" && ret=0 case "$state" in @@ -276,6 +289,11 @@ library) _wanted libraries expl library \ compadd - ${^=LD_LIBRARY_PATH:-/usr/lib /usr/local/lib}/lib*.(a|so*)(:t:fr:s/lib//) && ret=0 ;; +rundir) + compset -P '*:' + compset -S ':*' + _files -/ -S/ -r '\n\t\- /:' "$@" + ;; esac return ret diff --git a/Completion/Unix/Command/_su b/Completion/Unix/Command/_su index d8ed17183..a1dd69db8 100644 --- a/Completion/Unix/Command/_su +++ b/Completion/Unix/Command/_su @@ -17,4 +17,4 @@ fi shell="${${(M@)${(@f)$(cfun' \ '*:commands: _command_names' \ - d \ diff --git a/Completion/Zsh/Context/_default b/Completion/Zsh/Context/_default index 8176f392c..81744cdef 100644 --- a/Completion/Zsh/Context/_default +++ b/Completion/Zsh/Context/_default @@ -19,7 +19,7 @@ _files "$@" && return 0 # allow completion to handle file names after any equals sign. if [[ -o magicequalsubst && "$PREFIX" = *\=* ]]; then - compstate[parameter]="${words[1]:t}-${PREFIX%%\=*}" + compstate[parameter]="${PREFIX%%\=*}" compset -P 1 '*=' _value "$@" else diff --git a/Completion/Zsh/Context/_in_vared b/Completion/Zsh/Context/_in_vared index abd24dd95..03f6d404e 100644 --- a/Completion/Zsh/Context/_in_vared +++ b/Completion/Zsh/Context/_in_vared @@ -32,4 +32,4 @@ fi compstate[insert]="${compstate[insert]//tab /}" -_contexts "$also" +_dispatch comps "$also" diff --git a/Completion/Zsh/Context/_redirect b/Completion/Zsh/Context/_redirect index 6e02636da..5e454014b 100644 --- a/Completion/Zsh/Context/_redirect +++ b/Completion/Zsh/Context/_redirect @@ -1,3 +1,17 @@ #compdef -redirect- -_files +# This searches for `:' and `', where +# `' is something like `<' or `2>'. + +local strs _comp_command1 _comp_command2 + +_set_command + +strs=( "$compstate[redirect]" ) + +if [[ -n "$_comp_command1" ]]; then + strs=( "${_comp_command1}:$strs[-1]" "$strs[@]" ) + [[ -n "$_comp_command2" ]] && strs=( "${_comp_command2}:$strs[1]" "$strs[@]" ) +fi + +_dispatch -d redirs "$strs[@]" diff --git a/Completion/Zsh/Context/_subscript b/Completion/Zsh/Context/_subscript index 9ea628fdb..0f1138e1a 100644 --- a/Completion/Zsh/Context/_subscript +++ b/Completion/Zsh/Context/_subscript @@ -113,5 +113,5 @@ elif [[ ${(Pt)${compstate[parameter]}} = array* ]]; then return 1 else - _contexts -math- + _dispatch comps -math- fi diff --git a/Completion/Zsh/Context/_value b/Completion/Zsh/Context/_value index 6ee8f4235..9d0acaa0e 100644 --- a/Completion/Zsh/Context/_value +++ b/Completion/Zsh/Context/_value @@ -1,19 +1,39 @@ -#compdef -value- -array-value- +#compdef -value- -array-value- -T values -default- -_value () { - # You can customize completion for different parameters by writing a - # function `_value:', where is the name of the parameter. - # When completing values of elements of associative arrays, we first - # search for a function `_value:-' and then for - # `_value:', so it's simple to define different functions - # for different keys or one function for a whole association. +# You can customize completion for different parameters by writing +# functions with the tag-line `#compdef -T value '. +# The function searches for the strings `:' +# and `'. If the line contains a command (as in `make foo=') +# the string `::' is also searched for. - if (( $+functions[_value:$compstate[parameter]] )); then - "_value:$compstate[parameter]" "$@" - elif (( $+functions[_value:${compstate[parameter]%%-*}] )); then - "_value:${compstate[parameter]%%-*}" "$@" - elif [[ "$compstate[parameter]" != *-* && - "${(Pt)${compstate[parameter]}}" = assoc* ]]; then +if [[ "$service" != -default- ]]; then + local strs type + + type="${(Pt)compstate[parameter]}" + + if [[ -z "$type" ]]; then + if [[ "$compstate[parameter]" = *-* ]]; then + type=association-value + elif [[ "$compstate[context]" = value ]]; then + type=scalar + else + type=array + fi + fi + + strs=( "${compstate[parameter]}:$type" "$compstate[parameter]" ) + + if [[ "$compstate[context]" != *value && -n "$_comp_command1" ]]; then + strs=( "${_comp_command1}:$^strs[@]" "$strs[@]" ) + [[ -n "$_comp_command2" ]] && + strs=( "${_comp_command2}:${(@)^strs[-2,-1]}" "$strs[@]" ) + fi + + _dispatch -d values "$strs[@]" +else + if [[ "$compstate[parameter]" != *-* && + "$compstate[context]" = *value && + "${(Pt)${compstate[parameter]}}" = assoc* ]]; then if (( CURRENT & 1 )); then _wanted association-keys expl 'association key' \ compadd -k "$compstate[parameter]" @@ -34,37 +54,4 @@ _value () { _default "$@" fi fi -} - -_value:CPPFLAGS () { - compset -q - if compset -P '-I'; then - _files -/ "$@" - else - _default "$@" - fi -} - -_value:LDFLAGS () { - compset -q - if compset -P '-L'; then - _files -/ "$@" - elif compset -P '-R'; then - compset -P '*:' - compset -S ':*' - _files -/ -S/ -r '\n\t\- /:' "$@" - else - _default "$@" - fi -} - -_value:DISPLAY() { _x_display "$@" } - -_value:PRINTER() { _printers "$@" } -_value:LPDEST() { _printers "$@" } - -_value:TERM() { _terminals "$@" } - -_value:TZ() { _time_zone "$@" } - -_value "$@" +fi diff --git a/Completion/compdump b/Completion/compdump index 62840b9fe..194fcf07b 100644 --- a/Completion/compdump +++ b/Completion/compdump @@ -16,7 +16,7 @@ emulate -L zsh setopt extendedglob noshglob -typeset _d_file _d_f _d_bks _d_line _d_als _d_files +typeset _d_file _d_f _d_bks _d_line _d_als _d_files _d_name _d_tmp _d_file=${_comp_dumpfile-${0:h}/compinit.dump}.$HOST.$$ [[ $_d_file = //* ]] && _d_file=${_d_file[2,-1]} @@ -35,33 +35,43 @@ fi print "#files: $#_d_files" > $_d_file -# First dump the arrays _comps, _services and _patcomps. The quoting +# First dump the arrays _comps, _servicecomps and _patcomps. The quoting # hieroglyphics ensure that a single quote inside a variable is itself # correctly quoted. -print "_comps=(" >> $_d_file -for _d_f in ${(ok)_comps}; do - print -r - "${(q)_d_f}" "${(q)_comps[$_d_f]}" -done >> $_d_file -print ")" >> $_d_file - -print "_services=(" >> $_d_file -for _d_f in ${(ok)_services}; do - print -r - "${(q)_d_f}" "${(q)_services[$_d_f]}" -done >> $_d_file -print ")" >> $_d_file - -print "\n_patcomps=(" >> $_d_file -for _d_f in "${(ok@)_patcomps}"; do - print -r - "${(q)_d_f}" "${(q)_patcomps[$_d_f]}" -done >> $_d_file -print ")" >> $_d_file +for _d_name in $_comp_assocs; do + + print "\n\ntypeset -gA _$_d_name _service$_d_name _pat$_d_name _postpat$_d_name" + + _d_tmp="_${_d_name}" + print "\n_${_d_name}=(" + for _d_f in ${(Pok)_d_tmp}; do + print -r - "${(q)_d_f}" "${(q)${(e):-\$${_d_tmp}[$_d_f]}}" + done + print ")" + + _d_tmp="_service${_d_name}" + print "\n_service${_d_name}=(" + for _d_f in ${(Pok)_d_tmp}; do + print -r - "${(q)_d_f}" "${(q)${(e):-\$${_d_tmp}[$_d_f]}}" + done + print ")" + + _d_tmp="_pat${_d_name}" + print "\n_pat${_d_name}=(" + for _d_f in ${(Pok)_d_tmp}; do + print -r - "${(q)_d_f}" "${(q)${(e):-\$${_d_tmp}[$_d_f]}}" + done + print ")" + + _d_tmp="_postpat${_d_name}" + print "\n_postpat${_d_name}=(" + for _d_f in ${(Pok)_d_tmp}; do + print -r - "${(q)_d_f}" "${(q)${(e):-\$${_d_tmp}[$_d_f]}}" + done + print ")" -print "\n_postpatcomps=(" >> $_d_file -for _d_f in "${(ok@)_postpatcomps}"; do - print -r - "${(q)_d_f}" "${(q)_postpatcomps[$_d_f]}" done >> $_d_file -print ")" >> $_d_file print "\n_compautos=(" >> $_d_file for _d_f in "${(ok@)_compautos}"; do @@ -129,6 +139,11 @@ for _i in "${(ok@)_compautos}"; do print "autoload -U $_compautos[$_i] $_i" >> $_d_file done +print >> $_d_file + +print "typeset -gUa _comp_assocs" >> $_d_file +print "_comp_assocs=( ${(q)_comp_assocs} )" >> $_d_file + mv $_d_file ${_d_file%.$HOST.$$} unfunction compdump diff --git a/Completion/compinit b/Completion/compinit index bd879b11c..94f5f7091 100644 --- a/Completion/compinit +++ b/Completion/compinit @@ -11,8 +11,10 @@ # If the first line looks like this, the file is autoloaded as a # function and that function will be called to generate the matches # when completing for one of the commands whose are given. +# The names may also be interspersed with `-T ' options +# specifying for which set of functions this should be added. # -# `#compdef -p ' +# `#compdef -[pP] ' # This defines a function that should be called to generate matches # for commands whose name matches . Note that only one pattern # may be given. @@ -100,13 +102,26 @@ while [[ $# -gt 0 && $1 = -[dDiuC] ]]; do esac done -# The associative array containing the definitions for the commands and +# The name suffixes for the associative arrays containing the functions +# to call. + +typeset -gUa _comp_assocs + +_comp_assocs=(comps) + +# The associative arrays containing the definitions for the commands and # services. -# Definitions for patterns will be stored in the associations `_patcomps' -# and `_postpatcomps'. `_compautos' contains the names and options -# for autoloaded functions that get options. +# Definitions for patterns will be stored in the associations `_pat*' +# and `_postpat*'. +# The assocs for the other function types are created automatically by +# compdef. + +typeset -gA _comps _servicecomps _patcomps _postpatcomps -typeset -gA _comps _services _patcomps _postpatcomps _compautos +# `_compautos' contains the names and options for autoloaded functions +# that get options. + +typeset -gA _compautos # The associative array use to report information about the last # completion to the outside. @@ -176,6 +191,9 @@ comppostfuncs=() # The option `-P' is like `-p', but the function will be called after # trying to find a function defined for the command on the line if no # such function could be found. +# In each of these cases the argument list may also contain `-T assoc' +# options to specify the associactive arrays to which the following +# definitions should be added. # With the `-k' option a function for a special completion keys is # defined and immediately bound to those keys. Here, the extra arguments # are the name of one of the builtin completion widgets and any number @@ -191,7 +209,8 @@ comppostfuncs=() # whose names are given as arguments. If combined with the `-p' option # it deletes the definitions for the patterns given as argument. # The `-d' option may not be combined with the `-k' option, i.e. -# definitions for key function can not be removed. +# definitions for key function can not be removed. But one `-T assoc' +# option may follow the `-d' to say which definitions should be removed. # # Examples: # @@ -213,12 +232,12 @@ comppostfuncs=() # delete the definitions for the command names `bar' and `baz' compdef() { - local opt autol type func delete new i ret=0 cmd svc + local opt autol type func delete new i ret=0 cmd svc assoc=comps # Get the options. - if [[ $#* -eq 0 ]]; then - echo "$0: I needs arguments" + if (( ! $# )); then + echo "$0: I need arguments" return 1 fi @@ -247,8 +266,8 @@ compdef() { done shift OPTIND-1 - if [[ $#* -eq 0 ]]; then - echo "$0: I needs arguments" + if (( ! $# )); then + echo "$0: I need arguments" return 1 fi @@ -257,25 +276,39 @@ compdef() { # and we define which services to use for the commands. if [[ "$1" = *\=* ]]; then - for i; do - if [[ "$i" = *\=* ]]; then - cmd="${i%%\=*}" - svc="${i#*\=}" - func="$_comps[${(k)_services[(R)$svc]:-$svc}]" - (( $+_services[$svc] )) && svc=$_services[$svc] - [[ -z "$func" ]] && - func="${_patcomps[(K)$svc][1]:-${_postpatcomps[(K)$svc][1]}}" - if [[ -n "$func" ]]; then - _comps[$cmd]="$func" - _services[$cmd]="$svc" + while (( $# )); do + if [[ $1 = -T ]]; then + shift + if (( ! $# )); then + echo "$0: missing type" + return 1 + fi + _comp_assocs=( "$_comp_assocs[@]" "$1" ) + typeset -gA _$1 _service$1 _pat$1 _postpat$1 + assoc="$1" + shift + else + if [[ "$1" = *\=* ]]; then + cmd="${1%%\=*}" + svc="${1#*\=}" + func="$_comps[${(e):-\${(k)_service${assoc}[(R)$svc]:-$svc}}]" + [[ -n ${(e):-\$_service${assoc}[$svc]} ]] && + svc=${(e):-\$_service${assoc}[$svc]} + [[ -z "$func" ]] && + func="${${(e):-\$_pat${assoc}[(K)$svc][1]}:-${(e):-\$_postpat${assoc}[(K)$svc][1]}}" + if [[ -n "$func" ]]; then + eval "_${assoc}"'[$cmd]="$func"' + eval "_service${assoc}"'[$cmd]="$svc"' + else + echo "$0: unknown command or service: $svc" + ret=1 + fi else - echo "$0: unknown command or service: $svc" + echo "$0: invalid argument: $1" ret=1 fi - else - echo "$0: invalid argument: $i" - ret=1 - fi + shift + fi done return ret @@ -290,18 +323,40 @@ compdef() { case "$type" in pattern) - if [[ $# -gt 1 ]]; then - echo "$0: only one pattern allowed" - return 1 - fi - _patcomps[$1]="$func" + while (( $# )); do + if [[ $1 = -T ]]; then + shift + if (( ! $# )); then + echo "$0: missing type" + return 1 + fi + _comp_assocs=( "$_comp_assocs[@]" "$1" ) + typeset -gA _$1 _service$1 _pat$1 _postpat$1 + assoc="$1" + shift + else + eval "_pat${assoc}"'[$1]="$func"' + shift + fi + done ;; postpattern) - if [[ $# -gt 1 ]]; then - echo "$0: only one pattern allowed" - return 1 - fi - _postpatcomps[$1]="$func" + while (( $# )); do + if [[ $1 = -T ]]; then + shift + if (( ! $# )); then + echo "$0: missing type" + return 1 + fi + _comp_assocs=( "$_comp_assocs[@]" "$1" ) + typeset -gA _$1 _service$1 _pat$1 _postpat$1 + assoc="$1" + shift + else + eval "_postpat${assoc}"'[$1]="$func"' + shift + fi + done ;; widgetkey) while [[ -n $1 ]]; do @@ -321,7 +376,7 @@ compdef() { fi shift 3 done - ;; + ;; key) if [[ $# -lt 2 ]]; then echo "$0: missing keys" @@ -348,40 +403,66 @@ compdef() { done ;; *) - # For commands store the function name in the `_comps' + # For commands store the function name in the # associative array, command names as keys. - for i; do - if [[ "$i" = *\=* ]]; then - cmd="${i%%\=*}" - svc=yes + while (( $# )); do + if [[ $1 = -T ]]; then + shift + if (( ! $# )); then + echo "$0: missing type" + return 1 + fi + _comp_assocs=( "$_comp_assocs[@]" "$1" ) + typeset -gA _$1 _service$1 _pat$1 _postpat$1 + assoc="$1" + shift else - cmd="$i" - svc= + if [[ "$1" = *\=* ]]; then + cmd="${1%%\=*}" + svc=yes + else + cmd="$1" + svc= + fi + if [[ -z "$new" || -z "${(e):-\$_${assoc}[$1]}" ]]; then + eval "_${assoc}"'[$cmd]="$func"' + [[ -n "$svc" ]] && eval "_service${assoc}"'[$cmd]="${1#*\=}"' + fi + shift fi - if [[ -z "$new" || "${+_comps[$i]}" -eq 0 ]]; then - _comps[$cmd]="$func" - if [[ -n "$svc" ]]; then _services[$cmd]="${i#*\=}"; fi - fi done ;; esac else # Handle the `-d' option, deleting. + + if [[ $1 = -T ]]; then + shift + if (( ! $# )); then + echo "$0: missing type" + return 1 + fi + _comp_assocs=( "$_comp_assocs[@]" "$1" ) + typeset -gA _$1 _service$1 _pat$1 _postpat$1 + assoc="$1" + shift + fi + case "$type" in pattern) - unset "_patcomps[$^@]" + unset "_pat${assoc}[$^@]" ;; postpattern) - unset "_postpatcomps[$^@]" + unset "_postpat${assoc}[$^@]" ;; key) # Oops, cannot do that yet. echo "$0: cannot restore key bindings" - return 1v + return 1 ;; *) - unset "_comps[$^@]" + unset "_${assoc}[$^@]" esac fi } -- cgit 1.4.1