From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9116 invoked from network); 23 Aug 1999 09:32:29 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 23 Aug 1999 09:32:29 -0000 Received: (qmail 10758 invoked by alias); 23 Aug 1999 09:32:18 -0000 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 7463 Received: (qmail 10750 invoked from network); 23 Aug 1999 09:32:17 -0000 Date: Mon, 23 Aug 1999 11:32:16 +0200 (MET DST) Message-Id: <199908230932.LAA02718@beta.informatik.hu-berlin.de> From: Sven Wischnowsky To: zsh-workers@sunsite.auc.dk In-reply-to: Tanaka Akira's message of 21 Aug 1999 08:22:55 +0900 Subject: 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@informatik.hu-berlin.de