diff options
Diffstat (limited to 'Completion')
73 files changed, 3647 insertions, 2211 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments index 5170acb84..bf263d6e9 100644 --- a/Completion/Base/_arguments +++ b/Completion/Base/_arguments @@ -3,386 +3,345 @@ # Complete the arguments of the current command according to the # descriptions given as arguments to this function. -local long args rest ws cur nth def nm expl descr action opt arg tmp +local long cmd="$words[1]" descr mesg subopts opt usecc autod +local oldcontext="$curcontext" hasopts -# Associative arrays used to collect information about the options. +long=$argv[(I)--] +if (( long )); then + local name tmp tmpargv -typeset -A opts mopts dopts dmopts odopts odmopts - -# See if we support long options, too. + if [[ long -eq 1 ]]; then + tmpargv=() + else + tmpargv=( "${(@)argv[1,long-1]}" ) + fi -nth=$argv[(I)--] -if (( nth )); then - long=( "${(@)argv[nth+1,-1]}" ) - argv=("${(@)argv[1,nth-1]}") -else - long=() -fi + name=${~words[1]} + [[ "$name" != /* ]] && tmp="$PWD/$name" -# Now parse the arguments... + name="_args_cache_${name}" + name="${name//[^a-zA-Z0-9_]/_}" -args=() -nth=1 -while (( $# )); do + if (( ! ${(P)+name} )); then + local iopts sopts pattern tmpo cur cache + typeset -U lopts - # This describes a one-shot option. + cache=() - if [[ "$1" = [-+]* ]]; then - if [[ "$1" = *:* ]]; then + # We have to build a new long-option cache, get the `-i' and + # `-s' options. - # If the option name ends in a `-', the first argument comes - # directly after the option, if it ends in a `+', the first - # argument *may* come directly after the option, otherwise it - # is in the next word. + set -- "${(@)argv[long+1,-1]}" - if [[ "$1" = [^:]##-:* ]]; then - dopts[${${1%%:*}[1,-2]}]="${1#*:}" - elif [[ "$1" = [^:]##+:* ]]; then - odopts[${${1%%:*}[1,-2]}]="${1#*:}" + iopts=() + sopts=() + while [[ "$1" = -[is]* ]]; do + if [[ "$1" = -??* ]]; then + tmp="${1[3,-1]}" + cur=1 else - opts[${1%%:*}]="${1#*:}" + tmp="$2" + cur=2 fi - else - opts[$1]='' - fi - elif [[ "$1" = \*[-+]* ]]; then - - # The same for options that may appear more than once. - - if [[ "$1" = *:* ]]; then - if [[ "$1" = [^:]##-:* ]]; then - dmopts[${${1[2,-1]%%:*}[1,-2]}]="${1#*:}" - elif [[ "$1" = [^:]##+:* ]]; then - odmopts[${${1[2,-1]%%:*}[1,-2]}]="${1#*:}" + if [[ "$tmp[1]" = '(' ]]; then + tmp=( ${=tmp[2,-2]} ) else - mopts[${1[2,-1]%%:*}]="${1#*:}" + tmp=( "${(@P)tmp}" ) fi - else - mopts[${1[2,-1]}]='' - fi - elif [[ "$1" = \*:* ]]; then + if [[ "$1" = -i* ]]; then + iopts=( "$iopts[@]" "$tmp[@]" ) + else + sopts=( "$sopts[@]" "$tmp[@]" ) + fi + shift cur + done - # This is `*:...', describing `all other arguments'. + # Now get the long option names by calling the command with `--help'. + # The parameter expansion trickery first gets the lines as separate + # array elements. Then we select all lines whose first non-blank + # character is a hyphen. Since some commands document more than one + # option per line, separated by commas, we convert commas int + # newlines and then split the result again at newlines after joining + # the old array elements with newlines between them. Then we select + # those elements that start with two hyphens, remove anything up to + # those hyphens and anything from the space or comma after the + # option up to the end. - rest="${1[3,-1]}" - elif [[ "$1" = :* ]]; then + lopts=("--${(@)^${(@)${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$(_call options ${~words[1]} --help 2>&1)//\[--/ +--}:#[ ]#-*}//,/ +}}:#[ ]#--*}#*--}%%[], ]*}:#}") + lopts=( "${(@)lopts:#--}" ) - # This is `:...', describing `the next argument'. + # Now remove all ignored options ... - args[nth++]="${1#*:}" - else + while (( $#iopts )); do + lopts=( ${lopts:#$~iopts[1]} ) + shift iopts + done - # And this is `n:...', describing the `n'th argument. + # ... and add "same" options - args[${1%%:*}]="${1#*:}" - nth=$(( ${1%%:*} + 1 )) - fi - shift -done + while (( $#sopts )); do + lopts=( $lopts ${lopts/$sopts[1]/$sopts[2]} ) + shift 2 sopts + done -if [[ $#long -ne 0 && "$PREFIX" = --* ]]; then + # Then we walk through the descriptions plus a few builtin ones. - # If the current words starts with `--' and we should use long - # options, just call... + set -- "$@" '*=FILE*:file:_files' \ + '*=(DIR|PATH)*:directory:_files -/' '*: :' - _long_options "$long[@]" -else + while (( $# )); do - # Otherwise parse the command line... + # First, we get the pattern and the action to use and take them + # from the positional parameters. - ws=( "${(@)words[2,-1]}" ) - cur=$(( CURRENT-2 )) - nth=1 + pattern="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}" + descr="${1#${pattern}}" + shift - # ...until the current word is reached. + # We get all options matching the pattern and take them from the + # list we have built. If no option matches the pattern, we + # continue with the next. - while [[ cur -gt 0 ]]; do + tmp=("${(@M)lopts:##$~pattern}") + lopts=("${(@)lopts:##$~pattern}") - # `def' holds the description for the option we are currently after. - # Check if the next argument for the option is optional. + (( $#tmp )) || continue - if [[ "$def" = :* ]]; then - opt=yes - else opt='' - fi - arg='' - - # Remove one description/action pair from `def' if that isn't empty. - if [[ -n "$def" ]]; then - if [[ "$def" = ?*:*:* ]]; then - def="${def#?*:*:}" - else - def='' - fi - else + # If there are option strings with a `[=', we take these get an + # optional argument. - # 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. + tmpo=("${(@M)tmp:#*\[\=*}") + if (( $#tmpo )); then + tmp=("${(@)tmp:#*\[\=*}") + tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}") - if [[ $#long -eq 0 || "$ws[1]" != --* ]]; then - opt=yes - arg=yes - else - def='' + if [[ "$descr" = ::* ]]; then + cache=( "$cache[@]" "${(@)^tmpo}=${descr}" ) + else + cache=( "$cache[@]" "${(@)^tmpo}=:${descr}" ) + fi fi - fi - - if [[ -n "$opt" ]]; then - - # `opt' was set above if we have to test if the word is an option. - # We first test for the simple options -- those without arguments or - # those whose arguments have to be given as separate words. - - if (( $+opts[$ws[1]] )); then - - # Options that may only be given once are removed from the - # associative array so that we are not offered them again. - def="$opts[$ws[1]]" - unset "opts[$ws[1]]" - elif (( $+mopts[$ws[1]] )); then - def="$mopts[$ws[1]]" - else + # Descriptions with `=': mandatory argument. - # 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 four loops looking very much alike. + tmpo=("${(@M)tmp:#*\=*}") + if (( $#tmpo )); then + tmp=("${(@)tmp:#*\=*}") + tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}") - if (( $#dopts )); then + cache=( "$cache[@]" "${(@)^tmpo}=${descr}" ) + fi - # First we get the option names. + # Everything else is just added as a option without arguments. - tmp=( "${(@k)dopts}" ) + if (( $#tmp )); then + tmp=("${(@)tmp//[^a-zA-Z0-9-]}") + cache=( "$cache[@]" "$tmp[@]" ) + fi + done + eval "${name}=( \"\${(@)cache:# #}\" )" + fi + set -- "$tmpargv[@]" "${(@P)name}" +fi - # Then we loop over them and see if the current word begins - # with one of the option names. +subopts=() +while [[ "$1" = -(O*|C) ]]; do + case "$1" in + -C) usecc=yes; shift ;; + -O) subopts=( "${(@P)2}" ); shift 2 ;; + *) subopts=( "${(@P)1[3,-1]}" ); shift ;; + esac +done - while (( $#tmp )); do - [[ "$ws[1]" = ${tmp[1]}* ]] && break - shift 1 tmp - done +zstyle -s ":completion:${curcontext}:options" auto-description autod - if (( $#tmp )); then +if (( $# )) && comparguments -i "$autod" "$@"; then + local nm="$compstate[nmatches]" action noargs aret expl local + local next direct odirect equal single match matched ws tmp1 tmp2 tmp3 + local opts subc prefix suffix + local origpre="$PREFIX" origipre="$IPREFIX" - # 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. + if comparguments -D descr action; then + comparguments -C subc + curcontext="${oldcontext%:*}:$subc" - opt='' - def="$dopts[$tmp[1]]" - unset "dopts[$tmp[1]]" - if [[ "$def" = ?*:*:* ]]; then - def="${def#?*:*:}" - else - def='' - fi - fi - fi - if [[ -n "$opt" && $#dmopts -ne 0 ]]; then - tmp=( "${(@k)dmopts}" ) - while (( $#tmp )); do - [[ "$ws[1]" = ${tmp[1]}* ]] && break - shift 1 tmp - done - - if (( $#tmp )); then - opt='' - def="$dmopts[$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 - [[ "$ws[1]" = ${tmp[1]}* ]] && break - shift 1 tmp - done - - if (( $#tmp )); then - opt='' - def="$odopts[$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 [[ "$ws[1]" != "$tmp[1]" ]]; then - if [[ "$def" = ?*:*:* ]]; then - def="${def#?*:*:}" - else - def='' - fi - fi - fi - fi - if [[ -n "$opt" && $#odmopts -ne 0 ]]; then - tmp=( "${(@k)odmopts}" ) - while (( $#tmp )); do - [[ "$ws[1]" = ${tmp[1]}* ]] && break - shift 1 tmp - done - - if (( $#tmp )); then - opt='' - def="$odmopts[$tmp[1]]" - if [[ "$ws[1]" != "$tmp[1]" ]]; then - if [[ "$def" = ?*:*:* ]]; then - def="${def#?*:*:}" - else - def='' - fi - fi - fi - 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 [[ -n "$opt" && -n "$arg" ]]; then - def='' - (( nth++ )) - fi - fi + if comparguments -O next direct odirect equal; then + opts=yes + _tags arguments options + else + _tags arguments + fi + else + if comparguments -a; then + noargs='no more arguments' + else + noargs='no arguments' fi + comparguments -O next direct odirect equal || return 1 - shift 1 ws - (( cur-- )) - done + opts=yes + _tags options + fi - # Now generate the matches. + while true; do + while _tags; do + if [[ -n "$matched" ]] || _requested arguments; then + _description arguments expl "$descr" + + if [[ "$action" = -\>* ]]; then + comparguments -W line opt_args + state="${${action[3,-1]##[ ]#}%%[ ]#}" + if [[ -n "$usecc" ]]; then + curcontext="${oldcontext%:*}:$subc" + else + context="$subc" + fi + compstate[restore]='' + aret=yes + else + if [[ -z "$local" ]]; then + local line + typeset -A opt_args + local=yes + fi - nm="$compstate[nmatches]" + comparguments -W line opt_args - if [[ -z "$def" || "$def" = :* ]]; then + if [[ "$action" = \ # ]]; then - # We either don't have a description for an argument of an option - # or we have a description for a optional argument. + # An empty action means that we should just display a message. - if [[ -z "$def" ]]; then + [[ -n "$matched" ]] && compadd -n -Q -S '' -s "$SUFFIX" - "$PREFIX" + mesg="$descr" - # If we have none at all, use the one for this argument position. + elif [[ "$action" = \(\(*\)\) ]]; then - def="$args[nth]" - [[ -z "$def" ]] && def="$rest" - fi + # ((...)) contains literal strings with descriptions. - # In any case, we have to complete option names here, but we may - # be in a string that starts with an option names and continues with - # the first argument, test that (again, four loops). + eval ws\=\( "${action[3,-3]}" \) - opt=yes - if (( $#dopts )); then + _describe "$descr" ws -M "$match" "$subopts[@]" - # Get the option names. + elif [[ "$action" = \(*\) ]]; then - tmp=( "${(@k)dopts}" ) - while (( $#tmp )); do - if compset -P "$tmp[1]"; then + # Anything inside `(...)' is added directly. - # The current string starts with the option name, so ignore - # that and complete the rest of the string. + _all_labels arguments expl "$descr" \ + compadd "$subopts[@]" - ${=action[2,-2]} + elif [[ "$action" = \{*\} ]]; then - def="$dopts[$tmp[1]]" - opt='' - break - fi - shift 1 tmp - done - fi - if [[ -n "$opt" && $#dmopts -ne 0 ]]; then - tmp=( "${(@k)dmopts}" ) - while (( $#tmp )); do - if compset -P "$tmp[1]"; then - def="$dmopts[$tmp[1]]" - opt='' - break - fi - shift 1 tmp - done - fi - if [[ -n "$opt" && $#odopts -ne 0 ]]; then - tmp=( "${(@k)odopts}" ) - while (( $#tmp )); do - if compset -P "$tmp[1]"; then - def="$odopts[$tmp[1]]" - opt='' - break - fi - shift 1 tmp - done - fi - if [[ -n "$opt" && $#odmopts -ne 0 ]]; then - tmp=( "${(@k)odmopts}" ) - while (( $#tmp )); do - if compset -P "$tmp[1]"; then - def="$odmopts[$tmp[1]]" - opt='' - break - fi - shift 1 tmp - done - fi - if [[ -n "$opt" ]]; then - - # We aren't in an argument directly after a option name, so - # all option names are possible matches. - - _description expl option - compadd "$expl[@]" - "${(@k)opts}" "${(@k)mopts}" \ - "${(@k)dopts}" "${(@k)dmopts}" \ - "${(@k)odopts}" "${(@k)odmopts}" - fi - fi + # A string in braces is evaluated. - # Now add the matches from the description, if any. + while _next_label arguments expl "$descr"; do + eval "$action[2,-2]" + done + elif [[ "$action" = \ * ]]; then - if [[ -n "$def" ]]; then + # If the action starts with a space, we just call it. - # Ignore the leading colon describing optional arguments. + eval "action=( $action )" + while _next_label arguments expl "$descr"; do + "$action[@]" + done + else - [[ "$def" = :* ]] && def="$def[2,-1]" + # Otherwise we call it with the description-arguments. - # Get the description and the action. + eval "action=( $action )" + _all_labels arguments expl "$descr" \ + "$action[1]" "$subopts[@]" "${(@)action[2,-1]}" + fi + fi + fi - descr="${def%%:*}" - action="${${def#*:}%%:*}" + if [[ -z "$matched$hasopts" ]] && _requested options && + { ! zstyle -T ":completion:${curcontext}:options" prefix-needed || + [[ "$origpre" = [-+]* || + ( -z "$aret$mesg" && nm -eq compstate[nmatches] ) ]] } ; then + local prevpre="$PREFIX" previpre="$IPREFIX" + + hasopts=yes + + PREFIX="$origpre" + IPREFIX="$origipre" + + comparguments -M match + + if comparguments -s single; then + + _description options expl option + + if [[ "$single" = direct ]]; then + compadd "$expl[@]" -QS '' - "${PREFIX}${SUFFIX}" + elif [[ "$single" = next ]]; then + compadd "$expl[@]" -Q - "${PREFIX}${SUFFIX}" + elif [[ "$single" = equal ]]; then + compadd "$expl[@]" -QqS= - "${PREFIX}${SUFFIX}" + else + tmp1=( "$next[@]" "$direct[@]" "$odirect[@]" "$equal[@]" ) + tmp3=( "${(M@)tmp1:#[-+]?[^:]*}" ) + tmp1=( "${(M@)tmp1:#[-+]?(|:*)}" ) + tmp2=( "${PREFIX}${(@M)^${(@)${(@)tmp1%%:*}#[-+]}:#?}" ) + + _describe -o option \ + tmp1 tmp2 -Q -S '' -- \ + tmp3 -Q + fi + single=yes + else + next=( "$next[@]" "$odirect[@]" ) + _describe -o option \ + next -Q -M "$match" -- \ + direct -QS '' -M "$match" -- \ + equal -QqS= -M "$match" + fi + PREFIX="$prevpre" + IPREFIX="$previpre" + fi + done + if [[ -n "$opts" && -z "$aret$matched$mesg" && + nm -eq compstate[nmatches] ]]; then - _description expl "$descr" + PREFIX="$origpre" + IPREFIX="$origipre" - if [[ -z "$action" ]]; then + prefix="${PREFIX#*\=}" + suffix="$SUFFIX" + PREFIX="${PREFIX%%\=*}" + SUFFIX='' + compadd -M "$match" -D equal - "${(@)equal%%:*}" - # An empty action means that we should just display a message. - _message "$descr" - return 1 - elif [[ "$action[1]" = \( ]]; then + if [[ $#equal -eq 1 ]]; then + PREFIX="$prefix" + SUFFIX="$suffix" + IPREFIX="${IPREFIX}${equal[1]%%:*}=" + matched=yes - # Anything inside `(...)' is added directly. + comparguments -L "${equal[1]%%:*}" descr action subc + curcontext="${oldcontext%:*}:$subc" - compadd "$expl[@]" - ${=action[2,-2]} - elif [[ "$action" = \ * ]]; then + _tags arguments - # If the action starts with a space, we just call it. + continue + fi + fi + break + done - $=action - else + [[ -z "$aret" || -z "$usecc" ]] && curcontext="$oldcontext" - # Otherwise we call it with the description-arguments built above. + [[ -n "$aret" ]] && return 300 - action=( $=action ) - "$action[1]" "$expl[@]" "${(@)action[2,-1]}" - fi - fi + [[ -n "$mesg" ]] && _message "$mesg" + [[ -n "$noargs" ]] && _message "$noargs" # Set the return value. - [[ nm -ne "$compstate[nmatches]" ]] + [[ nm -ne "$compstate[nmatches]" ]] +else + return 1 fi diff --git a/Completion/Base/_default b/Completion/Base/_default index 8bcf14f6a..fd5869e2e 100644 --- a/Completion/Base/_default +++ b/Completion/Base/_default @@ -1,13 +1,23 @@ -#defcomp -default- +#compdef -default- -# We first try the `compctl's. This is without first (-T) and default (-D) -# completion. If you want them add `-T' and/or `-D' to this command. -# If there is a `compctl' for the command we are working on, we return -# immediatly. If you want to use new style completion anyway, remove the -# `|| return'. Also, you may want to use new style completion if the -# `compctl' didn't produce any matches. In that case remove the `|| return' -# and at the line `[[ -nmatches 0 ]] || return' after `compcall'. +local ctl -compcall || return +if { zstyle -s ":completion:${curcontext}:" use-compctl ctl || + zmodload -e zsh/compctl } && [[ "$ctl" != (no|false|0|off) ]]; then + local opt -_files + opt=() + [[ "$ctl" = *first* ]] && opt=(-T) + [[ "$ctl" = *default* ]] && opt=("$opt[@]" -D) + compcall "$opt[@]" || return 0 +fi + +_wanted files || return 1 + +_files && return 0 + +# magicequalsubst allows arguments like <any-old-stuff>=~/foo to do +# file name expansion after the =. In that case, it's natural to +# allow completion to handle file names after any equals sign. + +[[ -o magicequalsubst ]] && compset -P 1 '*=' && _files diff --git a/Completion/Base/_describe b/Completion/Base/_describe index e01c77509..6e6f4f4a9 100644 --- a/Completion/Base/_describe +++ b/Completion/Base/_describe @@ -2,154 +2,52 @@ # This can be used to add options or values with descriptions as matches. -setopt localoptions extendedglob +local _opt _expl _tmps _tmpd _tmpmd _tmpms _ret=1 _showd _nm _hide _args +local _type=values _descr -local gdescr isopt cmd opt nsets tmp descr match descrs matches adescr i -local disps disp expl tmps tmpd tmpmd tmpms name ret=1 showd _nm +# Get the option. -cmd="$words[1]" - -# Get the options. - -while getopts 'oc:' opt; do - if [[ "$opt" = o ]]; then - isopt=yes - else - cmd="$OPTARG" - fi -done -shift OPTIND-1 +if [[ "$1" = -o ]]; then + _type=options + shift +fi # Do the tests. `showd' is set if the descriptions should be shown. -if [[ -n "$isopt" ]]; then - - # We take the value to test the number of patches from a non-local - # parameter `nm' if that exists and contains only digits. It's a hack. - - if [[ "$nm" = [0-9]## ]]; then - _nm="$nm" - else - _nm=0 - fi - [[ -n "$compconfig[option_prefix]" && - "$compconfig[option_prefix]" != *\!${cmd}* && - "$PREFIX" != [-+]* && - ( "$compconfig[option_prefix]" = *nodefault* || - _nm -ne compstate[nmatches] ) ]] && return 1 +_wanted "$_type" || return 1 - [[ -n "$compconfig[describe_options]" && - "$compconfig[describe_options]" != *\!${cmd}* ]] && showd=yes -else - [[ -n "$compconfig[describe_values]" && - "$compconfig[describe_values]" != *\!${cmd}* ]] && showd=yes -fi +zstyle -T ":completion:${curcontext}:$_type" verbose && _showd=yes -gdescr="$1" +_descr="$1" shift -# Now interpret the arguments. +[[ "$_type" = options ]] && + zstyle -t ":completion:${curcontext}:options" prefix-hidden && _hide=yes -nsets=0 -adescr=() -descrs=() -matches=() -while (( $# )); do - (( nsets++ )) - descr="$1" - [[ -n "$showd" ]] && adescr=( "$adescr[@]" "${(@PM)^descr:#*:?*},$nsets" ) - if [[ "$2" = -* ]]; then - match='' - shift - else - match="$2" - shift 2 - fi - tmp=$argv[(i)--] - if [[ tmp -eq 1 ]]; then - opt=() - else - opt=( "${(@)argv[1,tmp-1]}" ) - fi - if [[ tmp -gt $# ]]; then - argv=() +while _next_label "$_type" _expl "$_descr"; do + + if [[ -n "$_showd" ]]; then + compdescribe -I ' -- ' "$@" else - shift tmp + compdescribe -i "$@" fi - # `descr' and `matches' collect the names of the arrays containing the - # possible matches with descriptions and the matches to add. - # The options to give to `compadd' are stored in local arrays. + while compdescribe -g _args _tmpd _tmpmd _tmps _tmpms; do - descrs[nsets]="$descr" - matches[nsets]="$match" - typeset -a _descr_opts_$nsets - eval "_descr_opts_${nsets}=( \"\$opt[@]\" )" -done - -(( nsets )) || return 1 - -# Build the display strings if needed. - -[[ -n "$showd" ]] && _display disps "$adescr[@]" -_description expl "$gdescr" + # See if we should remove the option prefix characters. -# Loop through the array/option sets we have. - -i=0 -while [[ ++i -le nsets ]]; do - name=_descr_opts_$i - [[ -n "$showd" ]] && disp=( "${(@)${(@M)disps:#*,${i}}%,*}" ) - descr=( "${(@P)descrs[i]}" ) - - # We collect the strings to display in `tmpd' (one string per line) - # and `tmps' (in columns) and the matches to add in `tmpmd' and `tmpms'. - - tmpd=() - tmps=() - tmpmd=() - tmpms=() - if [[ -n "$matches[i]" ]]; then - match=( "${(@P)matches[i]}" ) - while (( $#match )); do - if [[ -n "$showd" && "$descr[1]" = *:?* ]]; then - tmpd=( "$tmpd[@]" "$disp[1]" ) - tmpmd=( "$tmpmd[@]" "$match[1]" ) - shift 1 disp - else - tmps=( "$tmps[@]" "${descr[1]%%:*}" ) - tmpms=( "$tmpms[@]" "$match[1]" ) + if [[ -n "$_hide" ]]; then + if [[ "$PREFIX" = --* ]]; then + _tmpd=( "${(@)_tmpd#--}" ) + _tmps=( "${(@)_tmps#--}" ) + elif [[ "$PREFIX" = [-+]* ]]; then + _tmpd=( "${(@)_tmpd#[-+]}" ) + _tmps=( "${(@)_tmps#[-+]}" ) fi - shift 1 match - shift 1 descr - done - else - while (( $#descr )); do - if [[ -n "$showd" && "$descr[1]" = *:?* ]]; then - tmpd=( "$tmpd[@]" "$disp[1]" ) - tmpmd=( "$tmpmd[@]" "${descr[1]%%:*}" ) - shift 1 disp - else - tmps=( "$tmps[@]" "${descr[1]%%:*}" ) - tmpms=( "$tmpms[@]" "${descr[1]%%:*}" ) - fi - shift 1 descr - done - fi - - # See if we should remove the option prefix characters. - - if [[ -n "$isopt" && "$compconfig[option_prefix]" = hide* ]]; then - if [[ "$PREFIX" = --* ]]; then - tmpd=( "${(@)tmpd#--}" ) - tmps=( "${(@)tmps#--}" ) - elif [[ "$PREFIX" = [-+]* ]]; then - tmpd=( "${(@)tmpd#[-+]}" ) - tmps=( "${(@)tmps#[-+]}" ) fi - fi - compadd "${(@P)name}" "$expl[@]" -ld tmpd - "$tmpmd[@]" && ret=0 - compadd "${(@P)name}" "$expl[@]" -d tmps - "$tmpms[@]" && ret=0 -done -return ret + compadd "$_args[@]" "$_expl[@]" -ld _tmpd - "$_tmpmd[@]" && _ret=0 + compadd "$_args[@]" "$_expl[@]" -d _tmps - "$_tmpms[@]" && _ret=0 + done +done +return _ret diff --git a/Completion/Base/_jobs b/Completion/Base/_jobs index 869aeeb8a..45983ad16 100644 --- a/Completion/Base/_jobs +++ b/Completion/Base/_jobs @@ -1,27 +1,85 @@ #autoload -local expl disp jobs job jids +local expl disp jobs job jids pfx='%' desc how expls + +_wanted jobs || return 1 + +if [[ "$1" = -t ]]; then + zstyle -T ":completion:${curcontext}:jobs" prefix-needed && + [[ "$PREFIX" != %* && compstate[nmatches] -ne 0 ]] && return 1 + shift +fi +zstyle -t ":completion:${curcontext}:jobs" prefix-hidden && pfx='' +zstyle -T ":completion:${curcontext}:jobs" verbose && desc=yes if [[ "$1" = -r ]]; then jids=( "${(@k)jobstates[(R)running*]}" ) shift - _description expl 'running job' + expls='running job' elif [[ "$1" = -s ]]; then jids=( "${(@k)jobstates[(R)running*]}" ) shift - _description expl 'suspended job' + expls='suspended job' else [[ "$1" = - ]] && shift jids=( "${(@k)jobtexts}" ) - _description expl job + expls=job fi -disp=() -jobs=() -for job in "$jids[@]"; do - disp=( "$disp[@]" "${(l:3:: ::%:)job} -- ${jobtexts[$job]}" ) - jobs=( "$jobs[@]" "$job" ) -done +if [[ -n "$desc" ]]; then + disp=() + for job in "$jids[@]"; do + [[ -n "$desc" ]] && + disp=( "$disp[@]" "${pfx}${(r:2:: :)job} -- ${(r:COLUMNS-8:: :)jobtexts[$job]}" ) + done +fi + +zstyle -s ":completion:${curcontext}:jobs" numbers how + +if [[ "$how" = (yes|true|on|1) ]]; then + jobs=( "$jids[@]" ) +else + local texts i text str tmp num max=0 -compadd "$@" "$expl[@]" -ld disp - "%$^jobs[@]" + # Find shortest unambiguous strings. + texts=( "$jobtexts[@]" ) + jobs=() + for i in "$jids[@]"; do + text="$jobtexts[$i]" + str="${text%% *}" + if [[ "$text" = *\ * ]]; then + text="${text#* }" + else + text="" + fi + tmp=( "${(@M)texts:#${str}*}" ) + num=1 + while [[ -n "$text" && $#tmp -ge 2 ]]; do + str="${str} ${text%% *}" + if [[ "$text" = *\ * ]]; then + text="${text#* }" + else + text="" + fi + tmp=( "${(@M)texts:#${str}*}" ) + (( num++ )) + done + + [[ num -gt max ]] && max="$num" + + jobs=( "$jobs[@]" "$str" ) + done + + if [[ "$how" = [0-9]## && max -gt how ]]; then + jobs=( "$jids[@]" ) + else + [[ -z "$pfx" && -n "$desc" ]] && disp=( "${(@)disp#%}" ) + fi +fi + +if [[ -n "$desc" ]]; then + _all_labels jobs expl "$expls" compadd "$@" -ld disp - "%$^jobs[@]" +else + _all_labels jobs expl "$expls" compadd "$@" - "%$^jobs[@]" +fi diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript index 2b827a117..60d45370b 100644 --- a/Completion/Base/_subscript +++ b/Completion/Base/_subscript @@ -1,4 +1,56 @@ -#defcomp -subscript- +#compdef -subscript- -_compalso -math- "$@" -[[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )" +local expl + +if [[ "$PREFIX" = :* ]]; then + _wanted characters expl 'character class' \ + compadd -p: -S ':]' alnum alpha blank cntrl digit graph \ + lower print punct space upper xdigit +elif [[ ${(Pt)${compstate[parameter]}} = assoc* ]]; then + local suf + + [[ "$RBUFFER" != \]* ]] && suf=']' + + _wanted association-keys expl 'association key' \ + compadd -S "$suf" - "${(@kP)${compstate[parameter]}}" +elif [[ ${(Pt)${compstate[parameter]}} = array* ]]; then + local list i j ret=1 disp + + _tags indexes parameters + + while _tags; do + if _requested indexes; then + ind=( {1..${#${(P)${compstate[parameter]}}}} ) + if zstyle -T ":completion:${curcontext}:indexes" verbose; then + list=() + for i in "$ind[@]"; do + if [[ "$i" = ${PREFIX}*${SUFFIX} ]]; then + list=( "$list[@]" + "${i}:$(print -D ${(P)${compstate[parameter]}[$i]})" ) + else + list=( "$list[@]" '' ) + fi + done + zformat -a list ' -- ' "$list[@]" + disp=( -d list) + else + disp=() + fi + + if [[ "$RBUFFER" = \]* ]]; then + _all_labels -V indexes expl 'array index' \ + compadd -S '' "$disp[@]" - "$ind[@]" && ret=0 + else + _all_labels -V indexes expl 'array index' \ + compadd -S ']' "$disp[@]" - "$ind[@]" && ret=0 + fi + fi + _requested parameters && _parameters && ret=0 + + (( ret )) || return 0 + done + + return 1 +else + _compalso -math- +fi diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde index aef575e19..7ab058e01 100644 --- a/Completion/Base/_tilde +++ b/Completion/Base/_tilde @@ -1,10 +1,53 @@ -#defcomp -tilde- +#compdef -tilde- # We use all named directories and user names here. If this is too slow # for you or if there are too many of them, you may want to use -# `compgen -k friends -qS/' or something like that. To get all user names -# if there are no matches in the `friends' array, add -# `(( compstate[nmatches] )) || compgen -nu -qS/' -# below that. +# `compadd -qS/ - "$friends[@]"' or something like that. -compgen -nu -qS/ +local expl suf dirs list lines revlines i ret disp nm="$compstate[nmatches]" + +if [[ "$SUFFIX" = */* ]]; then + ISUFFIX="/${SUFFIX#*/}$ISUFFIX" + SUFFIX="${SUFFIX%%/*}" + suf=(-S '') +else + suf=(-qS/) +fi + +_tags users named-directories directory-stack + +while _tags; do + _requested users && _users "$suf[@]" "$@" && ret=0 + _requested named-directories expl 'named directory' \ + compadd "$suf[@]" "$@" - "${(@k)nameddirs}" + + if _requested directory-stack && + { ! zstyle -T ":completion:${curcontext}:directory-stack" prefix-needed || + [[ "$PREFIX" = [-+]* || nm -eq compstate[nmatches] ]] }; then + if zstyle -T ":completion:${curcontext}:directory-stack" verbose; then + integer i + + lines=("${PWD}" "${dirstack[@]}") + + if [[ ( -prefix - && ! -o pushdminus ) || + ( -prefix + && -o pushdminus ) ]]; then + revlines=( $lines ) + for (( i = 1; i <= $#lines; i++ )); do + lines[$i]="$((i-1)) -- ${revlines[-$i]}" + done + else + for (( i = 1; i <= $#lines; i++ )); do + lines[$i]="$((i-1)) -- ${lines[$i]}" + done + fi + list=( ${PREFIX[1]}${^lines%% *} ) + disp=( -ld lines ) + else + list=( ${PREFIX[1]}{0..${#dirstack}} ) + disp=() + fi + _all_labels -V directory-stack expl 'directory stack' \ + compadd "$suf[@]" "$disp[@]" -Q - "$list[@]" && ret=0 + fi + (( ret )) || return 0 +done diff --git a/Completion/Base/_values b/Completion/Base/_values index 4be3e8203..62cf0e409 100644 --- a/Completion/Base/_values +++ b/Completion/Base/_values @@ -1,322 +1,103 @@ #autoload -setopt localoptions extendedglob +local subopts opt usecc -local name arg def descr xor str tmp ret=1 expl nm="$compstate[nmatches]" -local snames odescr gdescr sep -typeset -A names onames xors _values +subopts=() +while [[ "$1" = -(O*|C) ]]; do + case "$1" in + -C) usecc=yes; shift ;; + -O) subopts=( "${(@P)2}" ); shift 2 ;; + *) subopts=( "${(@P)1[3,-1]}" ); shift ;; + esac +done -# Probably fill our cache. +if compvalues -i "$@"; then -if [[ "$*" != "$_vals_cache_args" ]]; then - _vals_cache_args="$*" + local noargs args opts descr action expl sep subc + local oldcontext="$curcontext" - unset _vals_cache_{sep,descr,names,onames,snames,xors,odescr} + if ! compvalues -D descr action; then - typeset -gA _vals_cache_{names,onames,xors} - _vals_cache_snames=() - _vals_cache_odescr=() + _wanted values || return 1 - # Get the separator, if any. + curcontext="${oldcontext%:*}:values" - if [[ "$1" = -s ]]; then - _vals_cache_sep="$2" - shift 2 - fi - - # This is the description string for the values. - - _vals_cache_descr="$1" - shift - - # Now parse the descriptions. - - while (( $# )); do - - # Get the `name', anything before an unquoted colon. - - if [[ "$1" = *[^\\]:* ]]; then - name="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}" - else - name="$1" - fi - - descr='' - xor='' - - # Get a description, if any. - - if [[ "$name" = *\[*\] ]]; then - descr="${${name#*\[}[1,-2]}" - name="${name%%\[*}" - fi - - # Get the names of other values that are mutually exclusive with - # this one. - - if [[ "$name" = \(*\)* ]]; then - xor="${${name[2,-1]}%%\)*}" - name="${name#*\)}" - fi - - # Finally see if this value may appear more than once. - - if [[ "$name" = \** ]]; then - name="$name[2,-1]" - else - xor="$xor $name" - fi - - # Store the information in the cache. - - _vals_cache_odescr=( "$_vals_cache_odescr[@]" "${name}:$descr" ) - [[ -n "$xor" ]] && _vals_cache_xors[$name]="${${xor##[ ]#}%%[ ]#}" - - # Get the description and store that. - - if [[ "$1" = *[^\\]:* ]]; then - descr=":${1#*[^\\]:}" - else - descr='' - fi - - if [[ "$descr" = ::* ]]; then + compvalues -V noargs args opts - # Optional argument. - - _vals_cache_onames[$name]="$descr[3,-1]" - elif [[ "$descr" = :* ]]; then - - # Mandatory argument. - - _vals_cache_names[$name]="$descr[2,-1]" - else - - # No argument. - - _vals_cache_snames=( "$_vals_cache_snames[@]" "$name" ) - fi - shift - done -fi - -snames=( "$_vals_cache_snames[@]" ) -names=( "${(@kv)_vals_cache_names}" ) -onames=( "${(@kv)_vals_cache_onames}" ) -xors=( "${(@kv)_vals_cache_xors}" ) -odescr=( "$_vals_cache_odescr[@]" ) -gdescr="$_vals_cache_descr" -sep="$_vals_cache_sep" - -if [[ -n "$sep" ]]; then - - # We have a separator character. We parse the PREFIX and SUFFIX to - # see if any of the values that must not appear more than once are - # already on the line. - - while [[ "$PREFIX" = *${sep}* ]]; do - - # Get one part, remove it from PREFIX and put it into IPREFIX. - - tmp="${PREFIX%%${sep}*}" - PREFIX="${PREFIX#*${sep}}" - IPREFIX="${IPREFIX}${tmp}${sep}" - - # Get the value `name'. - - name="${tmp%%\=*}" - - if [[ "$tmp" = *\=* ]]; then - _values[$name]="${tmp#*\=}" - else - _values[$name]='' - fi - - # And remove the descriptions for the values this one makes - # superfluous. - - if [[ -n "$xors[$name]" ]]; then - snames=( "${(@)snames:#(${(j:|:)~${=xors[$name]}})}" ) - odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$name]}}):*}" ) - unset {names,onames,xors}\[${^=tmp}\] - fi - done - if [[ "$SUFFIX" = *${sep}* ]]; then - - # The same for the suffix. + if [[ "$PREFIX" = *\=* ]]; then + local name - str="${SUFFIX%%${sep}*}" - SUFFIX="${SUFFIX#*${sep}}" - while [[ -n "$SUFFIX" ]]; do - tmp="${PREFIX%%${sep}*}" - if [[ "$SUFFIX" = *${sep}* ]]; then - SUFFIX="${SUFFIX#*${sep}}" + name="${PREFIX%%\=*}" + if compvalues -L "$name" descr action; then + IPREFIX="${IPREFIX}${name}=" + PREFIX="${PREFIX#*\=}" else - SUFFIX='' + local prefix suffix + + prefix="${PREFIX#*\=}" + suffix="$SUFFIX" + PREFIX="$name" + SUFFIX='' + args=( "$args[@]" "$opts[@]" ) + compadd -M 'r:|[_-]=* r:|=*' -D args - "${(@)args[@]%%:*}" + + [[ $#args -ne 1 ]] && return 1 + + PREFIX="$prefix" + SUFFIX="$suffix" + IPREFIX="${IPREFIX}${args[1]%%:*}=" + compvalues -L "${args[1]%%:*}" descr action subc + curcontext="${oldcontext%:*}:$subc" fi - PREFIX="${PREFIX#*${sep}}" - IPREFIX="${IPREFIX}${tmp}${sep}" - - name="${tmp%%\=*}" - - if [[ "$tmp" = *\=* ]]; then - _values[$name]="${tmp#*\=}" + else + compvalues -d descr + if [[ ${#noargs}+${#args}+${#opts} -ne 1 ]] && compvalues -s sep; then + sep=( "-qQS" "$sep" ) else - _values[$name]='' + sep=() fi - if [[ -n "$xors[$name]" ]]; then - snames=( "${(@)snames:#(${(j:|:)~${=xors[$name]}})}" ) - odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$name]}}):*}" ) - unset {names,onames,xors}\[${^=tmp}\] - fi - done - SUFFIX="$str" - fi -fi - -descr='' -str="$PREFIX$SUFFIX" - -if [[ "$str" = *\=* ]]; then - - # The string from the line contains a `=', so we get the stuff before - # it and after it and see what we can do here... - - name="${str%%\=*}" - arg="${str#*\=}" - - if (( $snames[(I)${name}] )); then - - # According to our information, the value doesn't get an argument, - # so give up. - - _message "\`${name}' gets no value" - return 1 - elif (( $+names[$name] )); then - - # It has to get an argument, we skip over the name and complete - # the argument (below). - - def="$names[$name]" - if ! compset -P '*\='; then - IPREFIX="${IPREFIX}${name}=" - PREFIX="$arg" - SUFFIX='' - fi - elif (( $+onames[$name] )); then + _describe "$descr" \ + noargs "$sep[@]" -M 'r:|[_-]=* r:|=*' -- \ + args -S= -M 'r:|[_-]=* r:|=*' -- \ + opts -qS= -M 'r:|[_-]=* r:|=*' - # Gets an optional argument, same as previous case. + curcontext="$oldcontext" - def="$onames[$name]" - if ! compset -P '*\='; then - IPREFIX="${IPREFIX}${name}=" - PREFIX="$arg" - SUFFIX='' + return fi else - local pre="$PREFIX" suf="$SUFFIX" - - # The part before the `=' isn't a known value name, so we see if - # it matches only one of the known names. - - if [[ "$PREFIX" = *\=* ]]; then - PREFIX="${PREFIX%%\=*}" - pre="${pre#*\=}" - SUFFIX='' - else - SUFFIX="${SUFFIX%%\=*}" - pre="${suf#*\=}" - suf='' - fi - - tmp=( "${(@k)names}" "${(@k)onames}" ) - compadd -M 'r:|[-_]=* r:|=*' -D tmp - "$tmp[@]" - - if [[ $#tmp -eq 1 ]]; then - - # It does, so we use that name and immediatly start completing - # the argument for it. - - IPREFIX="${IPREFIX}${tmp[1]}=" - PREFIX="$pre" - SUFFIX="$suf" - - def="$names[$tmp[1]]" - [[ -z "$def" ]] && def="$onames[$tmp[1]]" - elif (( $#tmp )); then - _message "ambiguous option \`${PREFIX}${SUFFIX}'" - return 1 - else - _message "unknown option \`${PREFIX}${SUFFIX}'" - return 1 - fi + compvalues -C subc + curcontext="${oldcontext%:*}:$subc" fi -else - - # No `=', just complete value names. - - _description expl "$gdescr" - [[ -n "$sep" && ${#snames}+${#names}+${#onames} -ne 1 ]] && - expl=( "-qS$sep" "$expl[@]" ) - - tmp='' - if [[ -n "$compconfig[describe_values]" && - "$compconfig[describe_values]" != *\!${words[1]}* ]]; then - if _display tmp odescr -M 'r:|[_-]=* r:|=*'; then - if (( $#snames )); then - compadd "$expl[@]" -y tmp -M 'r:|[_-]=* r:|=*' - \ - "$snames[@]" && ret=0 - compadd -n -S= -J "_$gdescr" -M 'r:|[_-]=* r:|=*' - \ - "${(@k)names}" && ret=0 - compadd -n -qS= -J "_$gdescr" -M 'r:|[_-]=* r:|=*' - \ - "${(@k)onames}" && ret=0 - elif (( $#names )); then - compadd -n -S= "$expl[@]" -y tmp -M 'r:|[_-]=* r:|=*' - \ - "${(@k)names}" && ret=0 - compadd -n -qS= -J "_$gdescr" -M 'r:|[_-]=* r:|=*' - \ - "${(@k)onames}" && ret=0 - else - compadd -n -qS= "$expl[@]" -y tmp -M 'r:|[_-]=* r:|=*' - \ - "${(@k)onames}" && ret=0 - fi - fi - fi - if [[ -z "$tmp" ]]; then - compadd "$expl[@]" -M 'r:|[_-]=* r:|=*' - "$snames[@]" && ret=0 - compadd -S= "$expl[@]" -M 'r:|[_-]=* r:|=*' - "${(@k)names}" && ret=0 - compadd -qS= "$expl[@]" -M 'r:|[_-]=* r:|=*' - "${(@k)onames}" && ret=0 + if ! _tags arguments; then + curcontext="$oldcontext" + return 1 fi - return ret -fi - -if [[ -z "$def" ]]; then - _message 'no value' - return 1 -else - local action - - descr="${${${(M)def#*[^\\]:}[1,-2]}//\\\\:/:}" - action="${${def#*[^\\]:}//\\\\:/:}" - _description expl "$descr" + _description arguments expl "$descr" # We add the separator character as a autoremovable suffix unless # we have only one possible value left. - [[ -n "$sep" && ${#snames}+${#names}+${#onames} -ne 1 ]] && + [[ ${#snames}+${#names}+${#onames} -ne 1 ]] && compvalues -s sep && expl=( "-qS$sep" "$expl[@]" ) if [[ "$action" = -\>* ]]; then - values=( "${(@kv)_values}" ) + compvalues -v val_args state="${${action[3,-1]##[ ]#}%%[ ]#}" + if [[ -n "$usecc" ]]; then + curcontext="${oldcontext%:*}:$subc" + else + context="$subc" + fi compstate[restore]='' return 1 else - typeset -A values + typeset -A val_args - values=( "${(@kv)_values}" ) + compvalues -v val_args if [[ "$action" = \ # ]]; then @@ -332,36 +113,44 @@ else eval ws\=\( "${action[3,-3]}" \) - if _display tmp ws; then - compadd "$expl[@]" -y tmp - "${(@)ws%%:*}" - else - _message "$descr" - return 1 - fi + _describe "$descr" ws -M 'r:|[_-]=* r:|=*' "$subopts[@]" + elif [[ "$action" = \(*\) ]]; then # Anything inside `(...)' is added directly. - compadd "$expl[@]" - ${=action[2,-2]} + _all_labels arguments expl "$descr" \ + compadd "$subopts[@]" - ${=action[2,-2]} elif [[ "$action" = \{*\} ]]; then # A string in braces is evaluated. - eval "$action[2,-2]" - + while _next_label arguments expl "$descr"; do + eval "$action[2,-2]" + done elif [[ "$action" = \ * ]]; then # If the action starts with a space, we just call it. - ${(e)=~action} + eval "action=( $action )" + while _next_label arguments expl "$descr"; do + "$action[@]" + done else # Otherwise we call it with the description-arguments built above. - action=( $=action ) - ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]} + eval "action=( $action )" + _all_labels arguments expl "$descr" \ + "$action[1]" "$subopts[@]" "${(@)action[2,-1]}" fi fi -fi -[[ nm -ne "$compstate[nmatches]" ]] + curcontext="$oldcontext" + + [[ nm -ne "$compstate[nmatches]" ]] +else + curcontext="$oldcontext" + + return 1; +fi diff --git a/Completion/Builtins/_autoload b/Completion/Builtins/_autoload index 4f506baeb..238b79e95 100644 --- a/Completion/Builtins/_autoload +++ b/Completion/Builtins/_autoload @@ -1,3 +1,10 @@ -#defcomp autoload +#compdef autoload -complist -s '${^fpath}/*(N:t)' +local expl + +if (( $words[(I)[-+]*w*] )); then + _description files expl 'zwc file' + _files "$expl[@]" -g '*.zwc' +else + _wanted functions expl 'shell function' compadd - ${^fpath}/*(N:t) +fi diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd index f3ce67ec7..803bcbda5 100644 --- a/Completion/Builtins/_cd +++ b/Completion/Builtins/_cd @@ -1,3 +1,47 @@ -#defcomp cd +#compdef cd chdir pushd -_files -W cdpath -g '*(-/)' +# Handling of cd. +# - Normally just completes directories. Uses cdpath if that's set +# and the string doesn't begin with ~, /, ./ or ../. +# - In the second argument to cd for the form `cd old new', completes +# possible `new' strings by examining `old' and $PWD. +# - After - or +, completes numbers, but the listing +# gives you the list of directories to complete. This turns on +# menu-completion and lists the possibilities automatically, otherwise +# it's not a lot of use. If you don't type the + or - it will +# complete directories as normal. + +setopt localoptions nonomatch + +local expl + +if [[ CURRENT -eq 3 ]]; then + # cd old new: look for old in $PWD and see what can replace it + local rep + # Get possible completions using word in position 2 + rep=(${~PWD/$words[2]/*}~$PWD(-/N)) + # Now remove all the common parts of $PWD and the completions from this + rep=(${${rep#${PWD%%$words[2]*}}%${PWD#*$words[2]}}) + (( $#rep )) && _wanted -C replacement strings expl replacement compadd $rep +elif _popd || [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then + local tdir tdir2 + + # With cdablevars, we can convert foo/bar/... to ~foo/bar/... if + # there is no directory foo. In that case we could also complete + # variable names, but it hardly seems worth it. + # Note we need a tilde because cdablevars also allows user home + # directories, hence we also need nonomatch to suppress error messages. + if [[ -o cdablevars && -n "$PREFIX" && ! -d ${tdir::=${PREFIX%%/*}} && + -d ${~tdir2::="~$tdir"} ]]; then + PREFIX="~$PREFIX" + _wanted directories expl directory _path_files -/ + else + local tmpcdpath + tmpcdpath=(${${(@)cdpath:#.}:#$PWD}) + _alternative \ + 'local-directories:local directories:_path_files -/' \ + "path-directories:directories in cdpath:_path_files -W tmpcdpath -/" + fi +else + _wanted directories expl directory _path_files -/ +fi diff --git a/Completion/Builtins/_compdef b/Completion/Builtins/_compdef index 1df5758b3..d47a560c9 100644 --- a/Completion/Builtins/_compdef +++ b/Completion/Builtins/_compdef @@ -1,22 +1,40 @@ #compdef compdef -local func base=2 +local state line expl list disp -while [[ $words[base] = -* ]]; do - case $words[base] in - -d) delete=yes ;; - -p) type=pattern ;; - -k) type=key ;; - esac - (( base++ )) -done +_arguments -C -s \ + '(-d)-a[make function autoloadable]' \ + '(-d -p -P)-n[leave existing definitions intact]' \ + '(-a -n -p -P -k -K)-d[delete]:*:completed command:->ccom' \ + '(-n -d -P -k -K)-p[completion for command matching pattern]:completion function:->cfun:pattern' \ + '(-n -d -p -k -K)-P[as -p for commands without own completion]:completion function:->cfun:pattern' \ + '(-d -p -P -K)-k[define widget and key binding]:completion function:->cfun:widget name::style:->style:*:key' \ + '(-d -p -P -k)-K[define multiple widgets based on function]:completion function:->cfun:widget name::style:->style:*:key' \ + '1:completion function:->cfun' \ + '2:commands:_command_names' + -if [ "$delete" ]; then - compadd ${(k)_comps} -else - if [[ CURRENT -eq base ]]; then - for func in ${^~fpath:/.}/_(|*[^~])(N:t); compadd -P_ - ${func#_} - else - compgen -c - fi -fi +case $state in + ccom) + _wanted commands expl 'completed command' compadd - ${(k)_comps} + ;; + cfun) + if _wanted functions; then + list=( ${^fpath:/.}/_(|*[^~])(N:t) ) + if zstyle -T ":completion:${curcontext}:functions" prefix-hidden; then + disp=( ${list[@]#_} ) + _all_labels functions expl 'completion function' \ + compadd -d disp - "$list[@]" + else + _all_labels functions expl 'completion function' compadd - "$list[@]" + fi + fi + ;; + style) + _wanted widgetstyle expl 'widget style' \ + compadd -M 'r:|-=* r:|=*' \ + complete-word delete-char-or-list expand-or-complete \ + expand-or-complete-prefix list-choices menu-complete \ + menu-expand-or-complete reverse-menu-complete + ;; +esac diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable index 063b65a7d..b3c2632ed 100644 --- a/Completion/Builtins/_disable +++ b/Completion/Builtins/_disable @@ -1,6 +1,8 @@ -#defcomp disable +#compdef disable -[[ -mcurrent -1 -*a* ]] && complist -ea -[[ -mcurrent -1 -*f* ]] && complist -eF -[[ -mcurrent -1 -*r* ]] && complist -ew -[[ ! -mcurrent -1 -* ]] && complist -eB +_arguments -C -s \ + "(-f -r)-a[act on aliases]:*:aliases:(${(k)aliases} ${(k)galiases})" \ + "(-a -r)-f[act on functions]:*:functions:(${(k)functions})" \ + "(-a -f)-r[act on reserved words]:*:reserved-words:(${(k)reswords})" \ + '-m[treat arguments as patterns]' \ + "*:builtin command:(${(k)builtins})" diff --git a/Completion/Builtins/_emulate b/Completion/Builtins/_emulate new file mode 100644 index 000000000..82096a77e --- /dev/null +++ b/Completion/Builtins/_emulate @@ -0,0 +1,6 @@ +#compdef emulate + +_arguments -C -s \ + '-L[set local_options and local_traps as well]' \ + '-R[reset all options instead of only those needed for script portability]' \ + '1::shell to emulate:(zsh sh ksh csh)' diff --git a/Completion/Builtins/_enable b/Completion/Builtins/_enable index 22ff53ee7..991286276 100644 --- a/Completion/Builtins/_enable +++ b/Completion/Builtins/_enable @@ -1,6 +1,8 @@ -#defcomp enable +#compdef enable -[[ -mcurrent -1 -*a* ]] && complist -da -[[ -mcurrent -1 -*f* ]] && complist -dF -[[ -mcurrent -1 -*r* ]] && complist -dw -[[ ! -mcurrent -1 -* ]] && complist -dB +_arguments -C -s \ + "(-f -r)-a[act on aliases]:*:aliases:(${(k)dis_aliases})" \ + "(-a -r)-f[act on functions]:*:functions:(${(k)dis_functions})" \ + "(-a -f)-r[act on reserved words]:*:reserved-words:(${(k)dis_reswords})" \ + '-m[treat arguments as patterns]' \ + "*:builtin command:(${(@k)dis_builtins})" diff --git a/Completion/Builtins/_fc b/Completion/Builtins/_fc index f0d2c03fd..e97492604 100644 --- a/Completion/Builtins/_fc +++ b/Completion/Builtins/_fc @@ -1,7 +1,27 @@ -#defcomp fc +#compdef fc history -if [[ -mcurrent -1 -*e ]]; then - complist -c -elif [[ -mcurrent -1 -[ARWI]## ]]; then - _files +local fc_common + +fc_common=( \ + '(-A -R -W -I)-m[treat first argument as a pattern]' \ + '(-A -R -W -I)-r[reverse order of the commands]' \ + '(-A -R -W -I -e)-n[suppress line numbers]' \ + '(-A -R -W -I -e -f -E -i)-d[print time-stamps]' \ + '(-A -R -W -I -e -d -E -i)-f[mm/dd/yyyy format time-stamps]' \ + '(-A -R -W -I -e -d -f -i)-E[dd.mm.yyyy format time-stamps]' \ + '(-A -R -W -I -e -d -f -E)-i[yyyy-mm-dd format time-stamps]' \ + '(-A -R -W -I -e)-D[print elapsed times]' \ + '(-A -R -W -I)*::commands:_command_names -e' ) + +if [[ $words[1] = *history ]]; then + _arguments -C -s "$fc_common[@]" +else + _arguments -C -s \ + '(-A -R -W -I -e)-l[list resulting commands on stdout]' \ + '(-A -R -W -I -l -n -d -f -E -i -D)-e[specify editor to invoke]:editor to invoke:_command_names -e' \ + '(-l -m -e -r -n -d -f -E -i -D -A -W *)-R[read history from file]:history file:_files' \ + '(-l -m -e -r -n -d -f -E -i -D -R -W *)-A[append history to file]:history file:_files' \ + '(-l -m -e -r -n -d -f -E -i -D -R -A *)-W[write history to file]:history file:_files' \ + '(-l -m -e -r -n -d -f -E -i -D -A -W *)-I[read/write new events only]:history file:_files' \ + "$fc_common[@]" fi diff --git a/Completion/Builtins/_nothing b/Completion/Builtins/_nothing index 35a2558cc..38f6bee77 100644 --- a/Completion/Builtins/_nothing +++ b/Completion/Builtins/_nothing @@ -1,3 +1,3 @@ -#compdef true false +#compdef true false log times whoami _message 'no argument or option' diff --git a/Completion/Builtins/_pids b/Completion/Builtins/_pids index 0ffda900b..7dec90e7d 100644 --- a/Completion/Builtins/_pids +++ b/Completion/Builtins/_pids @@ -3,16 +3,32 @@ # If given the `-m <pattern>' option, this tries to complete only pids # of processes whose command line match the `<pattern>'. -local list expl match +local out list expl match desc listargs args + +_wanted processes || return 1 if [[ "$1" = -m ]]; then match="${2}*" shift 2 fi -_description expl 'process ID' +zstyle -s ":completion:${curcontext}:pids" command args + +out="$(_call pids ps 2>/dev/null)" -list=("${(@Mr:COLUMNS-1:)${(f@)$(ps ${=compconfig[ps_listargs]:-$=compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ ]#${PREFIX}[0-9]#${SUFFIX}[ ]*${~match}}") +if zstyle -T ":completion:${curcontext}:processes" verbose; then + zstyle -s ":completion:${curcontext}:pids-list" command listargs + (( $#listargs )) || listargs=( "$args[@]" ) + if [[ "$listargs" = "$args" ]]; then + list=("${(@Mr:COLUMNS-1:)${(f@)out}[2,-1]:#[ ]#${PREFIX}[0-9]#${SUFFIX}[ ]*${~match}}") + else + list=("${(@Mr:COLUMNS-1:)${(f@)$(_call pids-list ps 2>/dev/null)}[2,-1]:#[ ]#${PREFIX}[0-9]#${SUFFIX}[ ]*${~match}}") + fi + desc=(-ld list) +else + desc=() +fi -compadd "$expl[@]" "$@" -ld list - \ - ${${${(M)${(f)"$(ps $=compconfig[ps_args] 2>/dev/null)"}[2,-1]:#*${~match}}## #}%% *} +_all_labels processes expl 'process ID' \ + compadd "$@" "$desc[@]" - \ + ${${${(M)${(f)"${out}"}[2,-1]:#[ ]#${PREFIX}[0-9]#${SUFFIX}[ ]#*${~match}}## #}%% *} diff --git a/Completion/Builtins/_popd b/Completion/Builtins/_popd index 9054befb7..2a3413253 100644 --- a/Completion/Builtins/_popd +++ b/Completion/Builtins/_popd @@ -5,36 +5,39 @@ # way round if pushdminus is set). Note that this function is also called # from _cd for cd and pushd. -emulate -L zsh setopt extendedglob nonomatch -[[ $PREFIX = [-+]* ]] || return 1 +local expl list lines revlines disp -local expl list lines revlines ret=1 i +! zstyle -T ":completion:${curcontext}:directory-stack" prefix-needed || + [[ $PREFIX = [-+]* ]] || return 1 -IPREFIX=$PREFIX[1] -PREFIX=$PREFIX[2,-1] +_wanted directory-stack || return 1 -# get the list of directories with their canonical number -# and turn the lines into an array, removing the current directory -lines=( ${${(f)"$(dirs -v)"}##0*} ) -if [[ ( $IPREFIX = - && ! -o pushdminus ) || - ( $IPREFIX = + && -o pushdminus ) ]]; then - integer i - revlines=( $lines ) - for (( i = 1; i <= $#lines; i++ )); do - lines[$i]="$((i-1)) -- ${revlines[-$i]##[0-9]#[ ]#}" - done +if zstyle -T ":completion:${curcontext}:directory-stack" verbose; then + # get the list of directories with their canonical number + # and turn the lines into an array, removing the current directory + lines=("${dirstack[@]}") + + if [[ ( $PREFIX[1] = - && ! -o pushdminus ) || + ( $PREFIX[1] = + && -o pushdminus ) ]]; then + integer i + revlines=( $lines ) + for (( i = 1; i <= $#lines; i++ )); do + lines[$i]="$((i-1)) -- ${revlines[-$i]##[0-9]#[ ]#}" + done + else + for (( i = 1; i <= $#lines; i++ )); do + lines[$i]="$i -- ${lines[$i]##[0-9]#[ ]#}" + done + fi + # get the array of numbers only + list=( ${PREFIX[1]}${^lines%% *} ) + disp=( -ld lines ) else - for (( i = 1; i <= $#lines; i++ )); do - lines[$i]="$i -- ${lines[$i]##[0-9]#[ ]#}" - done + list=( ${PREFIX[1]}{0..${#dirstack}} ) + disp=() fi -# get the array of numbers only -list=(${lines%% *}) -_description expl 'directory stack index' -compadd "$expl[@]" -ld lines -V dirs -Q - "$list[@]" && ret=0 -[[ -z $compstate[list] ]] && compstate[list]=list && ret=0 -[[ -n $compstate[insert] ]] && compstate[insert]=menu && ret=0 - -return ret + +_all_labels -V directory-stack expl 'directory stack' \ + compadd "$@" "$disp[@]" -Q - "$list[@]" diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched index 1e8ae3445..98ecb3642 100644 --- a/Completion/Builtins/_sched +++ b/Completion/Builtins/_sched @@ -1,3 +1,23 @@ -#defcomp sched +#compdef sched -[[ -position 2 -1 ]] && _normal "$@" +local expl lines disp + +if [[ CURRENT -eq 2 ]]; then + if compset -P -; then + _wanted -C - jobs || return 1 + + lines=(${(f)"$(sched)"}) + if zstyle -T ":completion:${curcontext}:jobs" verbose; then + disp=( -ld lines ) + else + disp=() + fi + [[ -z $lines ]] || _all_labels jobs expl 'scheduled jobs' \ + compadd "$disp[@]" - {1..$#lines} + return + else + _message 'time specification' + return 1 + fi +fi +compset -n 3 && _normal diff --git a/Completion/Builtins/_signals b/Completion/Builtins/_signals index c79350044..aa95a8499 100644 --- a/Completion/Builtins/_signals +++ b/Completion/Builtins/_signals @@ -20,17 +20,19 @@ done [[ "$1" = -(|-) ]] && shift -if _wanted signals expl signal && - { [[ -z "$minus" ]] || ! _style signals prefix-needed || +if _wanted signals && + { [[ -z "$minus" ]] || + ! zstyle -T ":completion:${curcontext}:signals" prefix-needed || [[ "$PREFIX" = -* ]] } ; then local disp tmp - if _style signals prefix-hidden; then + if zstyle -t ":completion:${curcontext}:signals" prefix-hidden; then tmp=( "${(@)signals[1,last]}" ) disp=(-d tmp) else disp=() fi - compadd "$@" "$expl[@]" "$disp[@]" -M 'm:{a-z}=${A-Z}' - \ - "${minus}${(@)^signals[1,last]}" + _all_labels signals expl signal \ + compadd "$@" "$disp[@]" -M 'm:{a-z}={A-Z}' - \ + "${minus}${(@)^signals[1,last]}" fi diff --git a/Completion/Builtins/_stat b/Completion/Builtins/_stat index 3cdbb2618..5ba06388b 100644 --- a/Completion/Builtins/_stat +++ b/Completion/Builtins/_stat @@ -1,10 +1,20 @@ #compdef stat +local expl ret=1 + if [[ "$words[CURRENT-1]" = -[AH] ]]; then - compgen -A + _arrays else - [[ "$PREFIX[1]" = + ]] && - compadd - +device +inode +mode +nlink +uid +gid +rdev +size \ - +atime +mtime +ctime +blksize +block +link - _files + _tags files options || return 1 + + while _tags; do + _requested files && _files && ret=0 + _requested options && + { ! zstyle -T ":completion:${curcontext}:options" prefix-needed || + [[ "$PREFIX[1]" = + || ret -eq 1 ]] } && + _all_labels options expl 'inode element' \ + compadd - +device +inode +mode +nlink +uid +gid +rdev \ + +size +atime +mtime +ctime +blksize +block +link + (( ret )) || return 0 + done fi diff --git a/Completion/Builtins/_zcompile b/Completion/Builtins/_zcompile new file mode 100644 index 000000000..5ec6f96ce --- /dev/null +++ b/Completion/Builtins/_zcompile @@ -0,0 +1,22 @@ +#compdef zcompile + +local context state line expl +typeset -A opt_args + +_arguments -s \ + '(-c -m -a)-U[don'\''t expand aliases]' \ + '(-M)-R[mark as read]' \ + '(-R)-M[mark as mapped]' \ + '(-c -z -m -a)-k[ksh-style autoloading]' \ + '(-c -k -m -a)-z[zsh-style autoloading]' \ + '(-U -z -k)-c[currently defined functions]' \ + '(-U -z -k)-m[use names as patterns]' \ + '(-U -z -k)-a[write autoload functions]' \ + ':zwc file:_files' \ + '*:function:->function' && return 0 + +if (( $+opt_args[-c] )); then + _wanted functions expl 'function to write' compadd - ${(k)functions} +else + _wanted file expl 'zsh source file' _files +fi diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp index 9be9c94db..0d6530dfc 100644 --- a/Completion/Builtins/_zftp +++ b/Completion/Builtins/_zftp @@ -1,50 +1,92 @@ -#defpatcomp zf* - -# Don't try any more completion after this. -_compskip=1 +#compdef -p zf* # Completion for zftp builtin and zf* functions. The functions -# zfcd_match and zfget_match (used for old-style completion) +# zfcd_match and zfget_match (also used for old-style completion) # need to be installed for remote file and directory completion to work. -local subcom +# emulate -L zsh + +# Don't try any more completion after this. +_compskip=all + +local subcom expl curcontext="${curcontext}" -if [[ $COMMAND = zftp ]]; then - if [[ $CURRENT -eq 1 ]]; then - compadd -m open params user login type ascii binary mode put \ - putat get getat append appendat ls dir local remote mkdir rmdir +if [[ $words[1] = zftp ]]; then + if [[ $CURRENT -eq 2 ]]; then + _wanted commands expl sub-command \ + compadd open params user login type ascii binary mode put \ + putat get getat append appendat ls dir local remote mkdir rmdir \ + session rmsession return fi - subcom=$1 + subcom=$words[2] + curcontext="${curcontext/:zftp:/:zftp-${words[2]}:}" else - subcom=$COMMAND + subcom=$words[1] fi case $subcom in *(cd|ls|dir)) - # complete remote directories; we could be smarter about hiding prefixes - zfcd_match $PREFIX $SUFFIX - (( $#reply )) && compadd -m -S/ -q $reply - ;; + # complete remote directories + _wanted directories && zfcd_match $PREFIX $SUFFIX + ;; *(get(|at)|gcp|delete|remote)) - # complete remote files - zfget_match $PREFIX $SUFFIX - (( $#reply )) && compadd -F fignore -m $reply - ;; + # complete remote files + _wanted files && zfget_match $PREFIX $SUFFIX + ;; *(put(|at)|pcp)) - # complete local files - _files - ;; + # complete local files + _wanted files && _files + ;; *(open|anon|params)) - # complete hosts: should do cleverer stuff with user names - complist -k hosts - ;; + # complete hosts: should do cleverer stuff with user names + _wanted hosts && _hosts + ;; + + *(goto|mark)) + # complete bookmarks. First decide if ncftp mode is go. + _wanted bookmarks || return 1 + if [[ $words[2] = -*n* ]]; then + if [[ -f ~/.ncftp/bookmarks ]]; then + _all_labels bookmarks expl bookmark \ + compadd - $(awk -F, 'NR > 2 { print $1 }' ~/.ncftp/bookmarks) + fi + else + if [[ -f ${ZFTP_BMFILE:=${ZDOTDIR:-$HOME}/.zfbkmarks} ]]; then + _all_labels bookmarks expl bookmark \ + compadd - $(awk '{print $1}' $ZFTP_BMFILE) + fi + fi + ;; + + *session) + # complete sessions, excluding the current one. + _wanted sessions expl 'another FTP session' \ + compadd - ${$(zftp session):#$ZFTP_SESSION} + ;; + + *transfer) + # complete arguments like sess1:file1 sess2:file2 + if [[ $PREFIX = *:* ]]; then + # complete file in the given session + _wanted files || return 1 + local sess=${PREFIX%%:*} oldsess=$ZFTP_SESSION + compset -p $(( $#sess + 1 )) + [[ -n $sess ]] && zftp session $sess + zfget_match $PREFIX $SUFFIX + [[ -n $sess && -n $oldsess ]] && zftp session $oldsess + else + # note here we can complete the current session + _wanted sessions expl 'FTP session' compadd -S : - $(zftp session) + fi + ;; *) - # dunno... try ordinary completion after all. - unset _compskip - ;; + # dunno... try ordinary completion after all. + _compskip='' + return 1 + ;; esac diff --git a/Completion/Builtins/_zpty b/Completion/Builtins/_zpty index b197b4128..d8c77ff2e 100644 --- a/Completion/Builtins/_zpty +++ b/Completion/Builtins/_zpty @@ -7,17 +7,17 @@ _arguments -C -s \ '(-d -w -r -L)-b[io to pseudo-terminal blocking]' \ '(-e -b -w -r -L)-d[delete command]:*:name:->name' \ '(-e -b -d -r -L)-w[send string to command]:name:->name:*:strings to write' \ - '(-e -b -d -w -L)-r[read string from command]:name:->name:param:_parameters:*:nothing:_nothing' \ + '(-e -b -d -w -L *)-r[read string from command]:name:->name:param:_parameters' \ '(-e -b -d -w -r)-L[list defined commands as calls]' \ - '*::args:_normal' + '(-r)*::args:_normal' -if [[ $state = name ]] && _wanted zptynames expl 'zpty command names'; then +if [[ $state = name ]] && _wanted names; then list=( ${${(f)"$(zpty)"}#*\) } ) names=( ${list%%:*} ) if zstyle -T ":completion:${curcontext}" verbose; then zformat -a list ' --' ${${(f)"$(zpty)"}#*\) } - compadd "$expl[@]" -d list - "$names[@]" + _all_labels names expl 'zpty command names' compadd -d list - "$names[@]" else - compadd "$expl[@]" - "$names[@]" + _all_labels names expl 'zpty command names' compadd - "$names[@]" fi fi diff --git a/Completion/Builtins/_zstyle b/Completion/Builtins/_zstyle index f072f79ae..cd470598a 100644 --- a/Completion/Builtins/_zstyle +++ b/Completion/Builtins/_zstyle @@ -1,7 +1,8 @@ #compdef zstyle -local curcontext="$curcontext" state ostate line expl ctop -local nm=$compstat[nmatches] +local curcontext="$curcontext" state context ostate line expl ctop +local nm=$compstate[nmatches] mesg +typeset -A opt_args typeset -A styles # Assoc array of styles; the values give the possible top-level @@ -9,15 +10,18 @@ typeset -A styles # followed by a colon, followed by a state to enter, empty if none. styles=( accept-exact c:bool + add-space c:bool arguments c: auto-description c: - cache-path 'c:_path_files -/' + break c: completer c:completer completions c: condition c: - cursor c:bool + cursor c:cursor disable-stat c:bool + domains c: expand c: + file-patterns c:filepat format c: glob c: group-name c: @@ -26,8 +30,9 @@ styles=( hidden c:bool hosts c:_hosts hosts-ports c:host-port - hosts-ports-users c:host-port-user - ignored-suffixes c: + users-hosts-ports c:user-host-port + ignore-parents c:ignorepar + ignored-patterns c: insert-unambiguous c:bool last-prompt c:bool list c:listwhen @@ -36,21 +41,26 @@ styles=( list-packed c:bool list-rows-first c:bool local c: + matcher-list c: max-errors c: menu c:boolauto numbers c:bool original c:bool - path 'c:_path_files -/' + packageset c:packageset + path 'c:_wanted directories expl directory _path_files -/' ports c:_ports prefix-hidden c:bool prefix-needed c:bool prompt c: remove-all-dups c:bool + single-ignored c:single-ignored sort c:bool - tag-order c:tag special-dirs c:sdirs + squeeze-slashes c:bool stop c:stop + subst-glob-only c: substitute c: + tag-order c:tag users c:_users users-hosts c:user-host verbose c:bool @@ -83,9 +93,20 @@ while [[ -n $state ]]; do case "$ostate" in contexts) - if [[ $PREFIX != :*: ]]; then - _wanted contexts expl context && - compadd -P : -S : "$expl[@]" completion zftp + if _wanted contexts; then + if [[ $PREFIX != :*: ]]; then + _all_labels contexts expl context compadd -P : -S : completion zftp + elif [[ $PREFIX = :completion:* ]]; then + mesg='' + case "$PREFIX" in + :completion:[^:]#) mesg=function ;; + :completion:[^:]#:[^:]#) mesg=completer ;; + :completion:[^:]#:[^:]#:[^:]#) mesg='command or context' ;; + :completion:[^:]#:[^:]#:[^:]#:[^:]#) mesg=argument ;; + :completion:[^:]#:[^:]#:[^:]#:[^:]#:[^:]#) mesg=tag ;; + esac + [[ -n "$mesg" ]] && _message "$mesg" + fi fi ;; @@ -96,8 +117,8 @@ while [[ -n $state ]]; do else ctop=cz fi - _wanted styles expl style && - compadd "$expl[@]" - ${(k)styles[(R)[^:]#[$ctop][^:]#:*]} + _wanted styles expl style \ + compadd -M 'r:|-=* r:|=*' - ${(k)styles[(R)[^:]#[$ctop][^:]#:*]} ;; style-arg) @@ -105,66 +126,116 @@ while [[ -n $state ]]; do ;; bool) - _wanted values expl boolean && - compadd "$expl[@]" true false + _wanted values expl boolean compadd true false ;; boolauto) - _wanted values expl boolean && - compadd "$expl[@]" true false auto select + _wanted values expl boolean compadd true false auto select + ;; + + cursor) + if [[ "$words[2]" = *:completion:inc* ]]; then + _wanted values expl 'cursor positioning' compadd complete key default + elif [[ "$words[2]" = *:completion::* ]]; then + _wanted values expl 'cursor positioning' compadd true false + else + _wanted values expl 'cursor positioning' \ + compadd complete key default true false + fi ;; completer) - _wanted values expl completer && - compadd "$expl[@]" _complete _approximate _correct _match \ - _expand _list _menu _oldlist + _wanted values expl completer \ + compadd _complete _approximate _correct _match \ + _expand _list _menu _oldlist _next_tags ;; - host-port*) + user-host-port) + if [[ $PREFIX != *[@:]* ]]; then + _users -S @ + elif [[ $PREFIX = *[@:]*[[@:]* ]]; then + compset -P 2 '*[:@]' + _ports + else + compset -P 1 '*[:@]' + _hosts -S : + fi + ;; + + host-port) if [[ $PREFIX != *:* ]]; then _hosts -S : - elif [[ $ostate != *user || $PREFIX != *:*:* ]]; then + else compset -P 1 '*:' _ports - else - compset -P 2 '*:' - _users fi ;; listwhen) - _wanted values expl 'when to list completions' && - compadd "$expl[@]" always never sometimes + _wanted values expl 'when to list completions' \ + compadd always never sometimes + ;; + + packageset) + _wanted values expl 'default package set' \ + compadd available installed uninstalled ;; progress) - _wanted values expl 'progress meter style' && - compadd "$expl[@]" none bar percent + _wanted values expl 'progress meter style' \ + compadd none bar percent ;; sdirs) - _wanted values expl 'whether to complete . or ..' && - compadd "$expl[@]" true false .. + _wanted values expl 'whether to complete . or ..' \ + compadd true false .. ;; stop) - _wanted values expl 'when to insert matches' && - compadd "$expl[@]" true false verbose + _wanted values expl 'when to insert matches' \ + compadd true false verbose ;; tag) - _wanted tags expl tag && compadd "$expl[@]" - $taglist + compset -q + if compset -P '*:*:'; then + _message description + elif compset -P '*:'; then + _message 'tag alias' + else + _wanted tags expl tag compadd - $taglist + fi + ;; + + filepat) + if compset -P '*:*:'; then + _message description + elif compset -P '*:'; then + _message tag + else + _message 'glob patterns' + fi ;; user-host) - if [[ $PREFIX = *:* ]]; then - compset -P '*:' + if [[ $PREFIX = *[@:]* ]]; then + compset -P '*[@:]' _hosts else - _users + _users -S @ fi ;; + ignorepar) + _wanted values expl 'which parents to ignore' \ + compadd parent pwd .. directory + ;; + + single-ignored) + _wanted values expl 'how to handle a single ignored match' \ + compadd - show menu + ;; + _*) ${=ostate} ;; diff --git a/Completion/Commands/_complete_help b/Completion/Commands/_complete_help index cfefdcf90..cfc922df5 100644 --- a/Completion/Commands/_complete_help +++ b/Completion/Commands/_complete_help @@ -1,35 +1,80 @@ #compdef -k complete-word \C-xh _complete_help() { - local _sort_tags=_help_sort_tags text i - typeset -A help_tags - typeset -U help_contexts - - help_contexts=() + local _sort_tags=_help_sort_tags text i j k + typeset -A help_funcs help_tags help_sfuncs help_styles compadd() { return 1 } + zstyle() { + local _f="${${(@)${(@)funcstack[2,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|loop|try)}% *}" + + [[ -z "$_f" ]] && _f="${${(@)funcstack[2,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|loop|try)}" + + if [[ "$help_sfuncs[$2]" != *${_f}* || + "$help_styles[${2}${_f}]" != *${3}* ]]; then + [[ "$help_sfuncs[$2]" != *${_f}* ]] && + help_sfuncs[$2]="${help_sfuncs[$2]}:${_f}" + local _t + + case "$1" in + -s) _t='[string] ';; + -a) _t='[array] ';; + -h) _t='[assoc] ';; + *) _t='[boolean]';; + esac + help_styles[${2}${_f}]="${help_styles[${2}${_f}]},${_t} ${3}:${_f}" + fi + builtin zstyle "$@" + } _main_complete - unfunction compadd + unfunction compadd zstyle - for i in "$help_contexts[@]"; do + for i in "${(@ok)help_funcs}"; do text="${text} -tags in context \`${i}': ${help_tags[$i]}" +tags in context :completion:${i}:" + tmp=() + for j in "${(@s.:.)help_funcs[$i][2,-1]}"; do + tmp=( "$tmp[@]" "${(@s.,.)help_tags[${i}${j}][2,-1]}" ) + done + zformat -a tmp ' (' "$tmp[@]" + tmp=( ' + '${^tmp}')' ) + text="${text}${tmp}" done - compstate[list]=list - compstate[force_list]=yes + text="$text +" + for i in "${(@ok)help_sfuncs}"; do + text="${text} +styles in context ${i}" + tmp=() + for j in "${(@s.:.)help_sfuncs[$i][2,-1]}"; do + tmp=( "$tmp[@]" "${(@s.,.)help_styles[${i}${j}][2,-1]}" ) + done + zformat -a tmp ' (' "$tmp[@]" + tmp=( ' + '${^tmp}')' ) + text="${text}${tmp}" + done + + compstate[list]='list force' compstate[insert]='' compadd -UX "$text[2,-1]" -n '' } _help_sort_tags() { - help_contexts=( "$help_contexts[@]" "$curcontext" ) - help_tags[$curcontext]="${help_tags[$curcontext]} - ${argv}" - comptry "$@" + local f="${${(@)${(@)funcstack[3,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|loop|try)}% *}" + + if [[ "$help_funcs[$curcontext]" != *${f}* || + "$help_tags[${curcontext}${f}]" != *(${(j:|:)~argv})* ]]; then + [[ "$help_funcs[$curcontext]" != *${f}* ]] && + help_funcs[$curcontext]="${help_funcs[$curcontext]}:${f}" + help_tags[${curcontext}${f}]="${help_tags[${curcontext}${f}]},${argv}:${f}" + comptry "$@" + fi } _complete_help "$@" diff --git a/Completion/Commands/_history_complete_word b/Completion/Commands/_history_complete_word index fc67c0f14..d904e01f1 100644 --- a/Completion/Commands/_history_complete_word +++ b/Completion/Commands/_history_complete_word @@ -1,2 +1,105 @@ -#compdef -k complete-word \e/ -compgen -Q -H 0 '' +#compdef -K _history-complete-older complete-word \e/ _history-complete-newer complete-word \e, +# +# Complete words from the history +# +# by Adam Spiers, with help gratefully received from +# Sven Wischnowsky and Bart Schaefer +# +# Available styles: +# +# :history-words:list -- display lists of available matches +# :history-words:stop -- prevent looping at beginning and end of matches +# during menu-completion +# :history-words:sort -- sort matches lexically (default is to sort by age) +# :history-words:remove-all-dups -- +# remove /all/ duplicate matches rather than just +# consecutives +# + +_history_complete_word () { + local expl direction stop + + if [[ $WIDGET = *newer ]]; then + direction=newer + else + direction=older + fi + + zstyle -s ":completion:${curcontext}:history-words" stop stop + + zstyle -t ":completion:${curcontext}:history-words" list || compstate[list]='' + + if [[ -n "$compstate[old_list]" && + ( -n "$stop" || "$compstate[insert]" = menu ) ]] ; then + # array of matches is newest -> oldest (reverse of history order) + if [[ "$direction" == 'older' ]]; then + if [[ compstate[old_insert] -eq $_hist_menu_length || + "$_hist_stop" == 'oldest' ]]; then + _hist_stop='oldest' + [[ "$stop" = verbose ]] && + _message 'beginning of history reached' + elif [[ "$_hist_stop" == 'newest' ]]; then + zle -Rc + _history_complete_word_gen_matches + else + compstate[old_list]=keep + (( compstate[insert] = compstate[old_insert] + 1 )) + fi + elif [[ "$direction" == 'newer' ]]; then + if [[ compstate[old_insert] -eq 1 || "$_hist_stop" == 'newest' ]]; then + _hist_stop='newest' + [[ "$stop" = verbose ]] && _message 'end of history reached' + elif [[ "$_hist_stop" == 'oldest' ]]; then + zle -Rc + _history_complete_word_gen_matches + else + compstate[old_list]=keep + (( compstate[insert] = compstate[old_insert] - 1 )) + fi + fi + else + _hist_stop='' + _hist_old_prefix="$PREFIX" + _history_complete_word_gen_matches + fi + + [[ -n "$compstate[nmatches]" ]] +} + +_history_complete_word_gen_matches () { + local opt + + [[ -n "$_hist_stop" ]] && PREFIX="$_hist_old_prefix" + + if zstyle -t ":completion:${curcontext}:history-words" remove-all-dups; then + opt=- + else + opt=-1 + fi + if zstyle -t ":completion:${curcontext}:history-words" sort; then + opt="${opt}J" + else + opt="${opt}V" + fi + + _wanted "$opt" history-words expl 'history word' \ + compadd -Q - "$historywords[@]" + + zstyle -t ":completion:${curcontext}:history-words" list || + compstate[list]= + + _hist_menu_length="$compstate[nmatches]" + + case "$direction" in + newer) compstate[insert]=$_hist_menu_length + [[ -n "$_hist_stop" ]] && (( compstate[insert]-- )) + ;; + older) compstate[insert]=1 + [[ -n "$_hist_stop" ]] && (( compstate[insert]++ )) + ;; + esac + + [[ -n "$_hist_stop" ]] && _hist_stop='' +} + +_history_complete_word "$@" diff --git a/Completion/Commands/_next_tags b/Completion/Commands/_next_tags index 8bd3f5921..4861d1adf 100644 --- a/Completion/Commands/_next_tags +++ b/Completion/Commands/_next_tags @@ -1,70 +1,92 @@ #compdef -k complete-word \C-xn -# Main widget/completer. +# Main widget. _next_tags() { + local comp - if [[ $#funcstack -gt 1 ]]; then + if [[ -z $compstate[old_list] ]]; then + comp=() + else + comp=(_complete) + fi - # Called as completer, probably `remove' our helper function. A better - # test would be nice, but I think one should still be able to edit the - # current word between attempts to complete it. + (( $+_sort_tags )) || _next_tags_not= - [[ $_next_tags_pre != ${LBUFFER%${PREFIX}} ]] && unset _sort_tags + _sort_tags=_next_tags_sort + _next_tags_pre="${LBUFFER%${PREFIX}}" + _next_tags_not="$_next_tags_not $_lastcomp[tags]" - return 1 - else - local comp + _main_complete "$comp[@]" - if [[ -z $compstate[old_list] ]]; then - comp=() - else - comp=(_next_tags _complete) - fi + [[ $compstate[insert] = automenu ]] && + compstate[insert]=automenu-unambiguous + + compstate[insert]='' + compstate[list]='list force' - (( $+_sort_tags )) || _next_tags_not= + compprefuncs=( "$compprefuncs[@]" _next_tags_pre ) +} - _sort_tags=_next_tags_sort - _next_tags_pre="${LBUFFER%${PREFIX}}" - _next_tags_not="$_next_tags_not $_lastcomp[tags]" +# Pre-completion function. - _main_complete "$comp[@]" +_next_tags_pre() { - [[ $compstate[insert] = automenu ]] && - compstate[insert]=automenu-unambiguous + # Probably `remove' our sort function. A better test would be nice, but + # I think one should still be able to edit the current word between + # attempts to complete it. - compstate[insert]='' - compstate[list]='list force' + if [[ $_next_tags_pre != ${LBUFFER%${PREFIX}} ]]; then + unset _sort_tags + else + compprefuncs=( "$compprefuncs[@]" _next_tags_pre ) fi } # Helper function for sorting tags. Most of this is copied from _tags. _next_tags_sort() { - local order tags tag nodef + local order tags tag nodef tmp zstyle -a ":completion:${curcontext}:" tag-order order || - order=( 'arguments values' options globbed-files directories all-files ) + order=('arguments values' options) # But we also remove the tags we've already tried... - tags=( "${(@)order:#(${(j:|:)~${=_next_tags_not}})}" ) + tags=( "${(@)order:#(${(j:|:)~${=_next_tags_not}})(|:*)}" ) # ... unless that would remove all offered tags. - [[ $#tags -ne $#order && "$tags" != *(${(j:|:)~argv})* ]] && - tags=( $order ) _next_tags_not= - + if [[ $funcstack[4] = _files ]]; then + if zstyle -a ":completion:${curcontext}:" file-patterns tmp; then + [[ "$tags" = *${${tmp[-1]##[^\\]:}%:*}* ]] && + tags=( $order ) _next_tags_not= + else + [[ "$tags" = *all-files* ]] && tags=( $order ) _next_tags_not= + fi + else + [[ $#tags -ne $#order && "$tags" != *(${(j:|:)~argv})* ]] && + tags=( $order ) _next_tags_not= + fi for tag in $tags; do case $tag in -) nodef=yes;; *\(\)) "${${tag%%[ ]#\(\)}##[ ]#}" "$@";; - \!*) comptry "${(@)argv:#(${(j:|:)~${=tag[2,-1]}})}";; - ?*) comptry ${=tag};; + \!*) comptry "${(@)argv:#(${(j:|:)~${=~tag[2,-1]}})}";; + ?*) comptry -m "$tag";; esac done - [[ -z "$nodef" ]] && comptry "$@" + if [[ -z "$nodef" ]]; then + if [[ $funcstack[4] = _files ]]; then + if zstyle -a ":completion:${curcontext}:" file-patterns tmp; then + [[ "$argv" = *${${tmp[-1]##[^\\]:}%:*}* ]] && _next_tags_not= + else + [[ "$argv" = *all-files* ]] && _next_tags_not= + fi + fi + comptry "${(@)argv:#(${(j:|:)~${=_next_tags_not}})(|:*)}" + fi } [[ -o kshautoload ]] || _next_tags "$@" diff --git a/Completion/Core/_all_labels b/Completion/Core/_all_labels new file mode 100644 index 000000000..fa7118ec4 --- /dev/null +++ b/Completion/Core/_all_labels @@ -0,0 +1,44 @@ +#autoload + +local gopt=-J len tmp pre suf tloop ret=1 descr + +if [[ "$1" = -t ]]; then + tloop=yes + shift +fi +if [[ "$1" = -([12]|)[VJ] ]]; then + gopt="$1" + shift +fi + +tmp=${argv[(ib:4:)-]} +len=$# +if [[ tmp -lt len ]]; then + pre=$(( tmp-1 )) + suf=$tmp +elif [[ tmp -eq $# ]]; then + pre=-2 + suf=$(( len+1 )) +else + pre=4 + suf=5 +fi + +while [[ -z "$tloop" ]] || comptags -N; do + while comptags -A "$1" curtag; do + if [[ "$curtag" = *:* ]]; then + zformat -f descr "${curtag#*:}" "d:$3" + _description "$gopt" "${curtag%:*}" "$2" "$descr" + curtag="${curtag%:*}" + + "$4" "${(P@)2}" "${(@)argv[5,-1]}" + else + _description "$gopt" "$curtag" "$2" "$3" + + "${(@)argv[4,pre]}" "${(P@)2}" "${(@)argv[suf,-1]}" && ret=0 + fi + done + [[ -z "$tloop" || ret -eq 0 ]] && break +done + +return ret diff --git a/Completion/Core/_alternative b/Completion/Core/_alternative index 158f3a07a..b038aa8a4 100644 --- a/Completion/Core/_alternative +++ b/Completion/Core/_alternative @@ -1,19 +1,23 @@ #autoload -local tags def expl descr action mesgs nm="$compstack[nmatches]" -local context +local tags def expl descr action mesgs nm="$compstate[nmatches]" subopts +local opt curcontext="$curcontext" + +subopts=() +while getopts 'O:C:' opt; do + case "$opt" in + O) subopts=( "${(@P)OPTARG}" ) ;; + C) curcontext="${curcontext%:*}:$OPTARG" ;; + esac +done + +shift OPTIND-1 -if [[ "$1" = -C?* ]]; then - context="${1[3,-1]}" - shift -elif [[ "$1" = -C ]]; then - context="$2" - shift 2 -fi +[[ "$1" = -(|-) ]] && shift mesgs=() -_tags -C "$context" "${(@)argv%%:*}" +_tags "${(@)argv%%:*}" while _tags; do for def; do @@ -21,7 +25,7 @@ while _tags; do descr="${${def#*:}%%:*}" action="${def#*:*:}" - _description expl "$descr" + _description "${def%%:*}" expl "$descr" if [[ "$action" = \ # ]]; then @@ -35,28 +39,35 @@ while _tags; do eval ws\=\( "${action[3,-3]}" \) - _describe "$descr" ws -M 'r:|[_-]=* r:|=*' + _describe "$descr" ws -M 'r:|[_-]=* r:|=*' "$subopts[@]" elif [[ "$action" = \(*\) ]]; then # Anything inside `(...)' is added directly. - compadd "$expl[@]" - ${=action[2,-2]} + _all_labels "${def%%:*}" expl "$descr" \ + compadd "$subopts[@]" - ${=action[2,-2]} elif [[ "$action" = \{*\} ]]; then # A string in braces is evaluated. - eval "$action[2,-2]" + while _next_label "${def%%:*}" expl "$descr"; do + eval "$action[2,-2]" + done elif [[ "$action" = \ * ]]; then # If the action starts with a space, we just call it. - ${(e)=~action} + eval "action=( $action )" + while _next_label "${def%%:*}" expl "$descr"; do + "$action[@]" + done else # Otherwise we call it with the description-arguments built above. - action=( $=action ) - ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]} + eval "action=( $action )" + _all_labels "${def%%:*}" expl "$descr" \ + "$action[1]" "$subopts[@]" "${(@)action[2,-1]}" fi fi done diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate index 1b40f7cbf..0815a308e 100644 --- a/Completion/Core/_approximate +++ b/Completion/Core/_approximate @@ -1,102 +1,30 @@ #autoload # This code will try to correct the string on the line based on the -# strings generated for the context if `compconfig[correct]' is set. -# These corrected strings will be shown in a list and one can -# cycle through them as in a menucompletion or get the corrected prefix. -# -# Supported configuration keys: -# -# approximate_accept -# This should be set to a number, specifying the maximum number -# of errors that should be accepted. If the string also contains -# a `n' or `N', the code will use the numeric argument as the -# maximum number of errors if a numeric argument was given. If no -# numeric argument was given, the number from the value of this -# key will be used. E.g. with `compconf approximate_accept=2n' two -# errors will be accepted, but if the user gives another number -# with the numeric argument, this will be prefered. Also, with -# `compconf approximate_accept=0n', normally no correction will be -# tried, but if a numeric argument is given, automatic correction -# will be used. On the other hand, if the string contains an `!' -# and a `n' or `N', correction is not attempted if a numeric -# argument is given. Once the number of errors to accept is -# determined, the code will repeatedly try to generate matches by -# allowing one error, two errors, and so on. Independent of the -# number of errors the user wants to accept, the code will allow -# only fewer errors than there are characters in the string from -# the line. -# -# approximate_original -# This value is used to determine if the original string should -# be included in the list (and thus be presented to the user when -# cycling through the corrections). If it is set to any non-empty -# value, the original string will be offered. If it contains the -# sub-string `last', the original string will appear as the last -# string when cycling through the corrections, otherwise it will -# appear as the first one (so that the command line does not -# change immediately). Also, if the value contains the sub-string -# `always', the original string will always be included, whereas -# normally it is included only if more than one possible -# correction was generated. -# -# approximate_prompt -# This can be set to a string that should be printed before the -# list of corrected strings when cycling through them. This string -# may contain the control sequences `%n', `%B', etc. known from -# the `-X' option of `compctl'. Also, the sequence `%e' will be -# replaced by the number of errors accepted to generate the -# corrected strings. -# -# approximate_insert -# If this is set to a string starting with `unambig', the code -# will try to insert a usable unambiguous string in the command -# line instead of always cycling through the corrected strings. -# If such a unambiguous string could be found, the original -# string is not used, independent of the setting of -# `approximate_original'. If no sensible string could be found, -# one can cycle through the corrected strings as usual. -# -# If any of these keys is not set, but the the same key with the -# prefix `correct' instead of `approximate' is set, that value will -# be used. - -local _comp_correct _correct_prompt comax -local cfgacc cfgorig cfgps cfgins - -# Only if all global matchers hav been tried. - -[[ compstate[matcher] -ne compstate[total_matchers] ]] && return 1 - -# We don't try correction if the string is too short. - -[[ "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1 - -# Get the configuration values, using either the prefix `correct' or -# `approximate'. - -if [[ "$compstate[pattern_match]" = (|\**) ]]; then - cfgacc="${compconfig[approximate_accept]:-$compconfig[correct_accept]}" - cfgorig="${compconfig[approximate_original]:-$compconfig[correct_original]}" - cfgps="${compconfig[approximate_prompt]:-$compconfig[correct_prompt]}" - cfgins="${compconfig[approximate_insert]:-$compconfig[correct_insert]}" -else - cfgacc="$compconfig[correct_accept]" - cfgorig="$compconfig[correct_original]" - cfgps="$compconfig[correct_prompt]" - cfgins="$compconfig[correct_insert]" -fi +# strings generated for the context. These corrected strings will be +# shown in a list and one can cycle through them as in a menucompletion +# or get the corrected prefix. + +# We don't try correction if the string is too short or we have tried it +# already. + +[[ _matcher_num -gt 1 || "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1 + +local _comp_correct _correct_expl comax cfgacc +local oldcontext="${curcontext}" opm="$compstate[pattern_match]" + +zstyle -s ":completion:${curcontext}:" max-errors cfgacc || cfgacc='2 numeric' # Get the number of errors to accept. -if [[ "$cfgacc" = *[nN]* && NUMERIC -ne 1 ]]; then - # Stop if we also have a `!'. +if [[ "$cfgacc" = *numeric* && ${NUMERIC:-1} -ne 1 ]]; then + # A numeric argument may mean that we should not try correction. - [[ "$cfgacc" = *\!* ]] && return 1 + [[ "$cfgacc" = *not-numeric* ]] && return 1 # Prefer the numeric argument if that has a sensible value. - comax="$NUMERIC" + comax="${NUMERIC:-1}" else comax="${cfgacc//[^0-9]}" fi @@ -105,13 +33,15 @@ fi [[ "$comax" -lt 1 ]] && return 1 -# Otherwise temporarily define functions to use instead of -# the builtins that add matches. This is used to be able -# to stick the `(#a...)' into the right place (after an +_tags corrections original + +# Otherwise temporarily define a function to use instead of +# the builtin that adds matches. This is used to be able +# to stick the `(#a...)' in the right place (after an # ignored prefix). compadd() { - [[ "$*" != *-([a-zA-Z/]#|)U* && + [[ ${argv[(I)-[a-zA-Z]#U[a-zA-Z]#]} -eq 0 && "${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] && return if [[ "$PREFIX" = \~*/* ]]; then @@ -119,79 +49,49 @@ compadd() { else PREFIX="(#a${_comp_correct})$PREFIX" fi - if [[ -n "$_correct_prompt" ]]; then - builtin compadd -X "$_correct_prompt" -J _correct "$@" - else - builtin compadd -J _correct "$@" - fi + builtin compadd "$_correct_expl[@]" "$@" } -compgen() { - [[ "$*" != *-([a-zA-Z/]#|)U* && - "${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] && return - - if [[ "$PREFIX" = \~*/* ]]; then - PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}" - else - PREFIX="(#a${_comp_correct})$PREFIX" - fi - if [[ -n "$_correct_prompt" ]]; then - builtin compgen "$@" -X "$_correct_prompt" -J _correct - else - builtin compgen "$@" -J _correct - fi -} - -# Now initialise our counter. We also set `compstate[matcher]' -# to `-1'. This allows completion functions to use the simple -# `[[ compstate[matcher] -gt 1 ]] && return' to avoid being -# called for multiple global match specs and still be called -# again when correction is done. Also, this makes it easy to -# test if correction is attempted since `compstate[matcher]' -# will never be set to a negative value by the completion code. - _comp_correct=1 -compstate[matcher]=-1 - -_correct_prompt="${cfgps//\%e/1}" - -# We also need to set `extendedglob' and make the completion -# code behave as if globcomplete were set. - -setopt extendedglob [[ -z "$compstate[pattern_match]" ]] && compstate[pattern_match]='*' while [[ _comp_correct -le comax ]]; do + curcontext="${oldcontext/(#b)([^:]#:[^:]#:)/${match[1][1,-2]}-${_comp_correct}:}" + + _description corrections _correct_expl corrections \ + "e:$_comp_correct" "o:$PREFIX$SUFFIX" + if _complete; then - if [[ "$cfgins" = unambig* && - "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then + if zstyle -t ":completion:${curcontext}:" insert-unambiguous && + [[ "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then compstate[pattern_insert]=unambiguous - elif [[ compstate[nmatches] -gt 1 || "$cfgorig" = *always* ]]; then - if [[ "$cfgorig" = *last* ]]; then - builtin compadd -U -V _correct_original -nQ - "$PREFIX$SUFFIX" - elif [[ -n "$cfgorig" ]]; then - builtin compadd -U -nQ - "$PREFIX$SUFFIX" - fi + elif _requested original && + { [[ compstate[nmatches] -gt 1 ]] || + zstyle -t ":completion:${curcontext}:" original }; then + local expl + + _description -V original expl original + + builtin compadd "$expl[@]" -U -Q - "$PREFIX$SUFFIX" # If you always want to see the list of possible corrections, - # set `compstate[list]=list' here. + # set `compstate[list]=list force' here. - compstate[force_list]=list + [[ "$compstate[list]" != list* ]] && + compstate[list]="$compstate[list] force" fi - compstate[matcher]="$compstate[total_matchers]" - unfunction compadd compgen + unfunction compadd + compstate[pattern_match]="$opm" return 0 fi [[ "${#:-$PREFIX$SUFFIX}" -le _comp_correct+1 ]] && break (( _comp_correct++ )) - - _correct_prompt="${cfgps//\%e/$_comp_correct}" done -compstate[matcher]="$compstate[total_matchers]" -unfunction compadd compgen +unfunction compadd +compstate[pattern_match]="$opm" return 1 diff --git a/Completion/Core/_call b/Completion/Core/_call index 345dae50d..b038a80bc 100644 --- a/Completion/Core/_call +++ b/Completion/Core/_call @@ -1,4 +1,4 @@ -#autoload +#autoload +X local tmp diff --git a/Completion/Core/_complete b/Completion/Core/_complete index 0f4d5ff4b..c2679dcb8 100644 --- a/Completion/Core/_complete +++ b/Completion/Core/_complete @@ -2,51 +2,65 @@ # Generate all possible completions. Note that this is not intended as # a normal completion function, but as one possible value for the -# compconfig[completer] parameter. +# completer style. -local comp name +local comp name oldcontext +typeset -T curcontext="$curcontext" ccarray + +oldcontext="$curcontext" + +# If we have a user-supplied context name, use only that. + +if [[ -n "$compcontext" ]]; then + ccarray[3]="$compcontext" + + comp="$_comps[$compcontext]" + [[ -z "$comp" ]] || "$comp" + + return +fi # An entry for `-first-' is the replacement for `compctl -T' -# Completion functions may set `_compskip' to any value to make the -# main loops stop calling other completion functions. comp="$_comps[-first-]" if [[ ! -z "$comp" ]]; then + ccarray[3]=-first- "$comp" - if (( $+_compskip )); then - unset _compskip + if [[ "$_compskip" = all ]]; then + _compskip='' (( compstate[nmatches] )) return fi fi + # For arguments and command names we use the `_normal' function. if [[ "$compstate[context]" = command ]]; then - _normal + curcontext="$oldcontext" + _normal -s else # Let's see if we have a special completion definition for the other # possible contexts. - comp='' - - case $compstate[context] in - equal) comp="$_comps[-equal-]";; - tilde) comp="$_comps[-tilde-]";; - redirect) comp="$_comps[-redirect-]";; - math) comp="$_comps[-math-]";; - subscript) comp="$_comps[-subscript-]";; - value) comp="$_comps[-value-]";; - array_value) comp="$_comps[-array-value-]";; - condition) comp="$_comps[-condition-]";; - parameter) comp="$_comps[-parameter-]";; - brace_parameter) comp="$_comps[-brace-parameter-]";; - esac + local cname="-${compstate[context]:s/_/-/}-" + + ccarray[3]="$cname" + + comp="$_comps[$cname]" # If not, we use default completion, if any. - [[ -z "$comp" ]] && comp="$_comps[-default-]" + if [[ -z "$comp" ]]; then + if [[ "$_compskip" = *default* ]]; then + _compskip='' + return 1 + fi + comp="$_comps[-default-]" + fi [[ -z "$comp" ]] || "$comp" fi +_compskip='' + (( compstate[nmatches] )) diff --git a/Completion/Core/_correct b/Completion/Core/_correct index 35ab01cf1..c9c3d999c 100644 --- a/Completion/Core/_correct +++ b/Completion/Core/_correct @@ -1,8 +1,8 @@ #autoload -# This is mainly a wrapper around the more general `_approximate. +# This is mainly a wrapper around the more general `_approximate'. # By setting `compstate[pattern_match]' to something unequal to `*' and -# then calling `_approximate, we get only corrections, not all strings +# then calling `_approximate', we get only corrections, not all strings # with the corrected prefix and something after it. # # Supported configuration keys are the same as for `_approximate', only diff --git a/Completion/Core/_description b/Completion/Core/_description index 874ba8a96..7db47228b 100644 --- a/Completion/Core/_description +++ b/Completion/Core/_description @@ -1,22 +1,56 @@ #autoload -local gropt=-J +local name gropt=-J format gname hidden hide match opts -if [[ "$1" = -V ]]; then - gropt=-V +opts=() + +if [[ "$1" = -([12]|)[VJ] ]]; then + gropt="$1" shift fi -if [[ -n "$compconfig[group_matches]" ]]; then - if [[ -n "$compconfig[description_format]" ]]; then - eval "$1=($gropt ${(q)2} -X ${(q)compconfig[description_format]//\\%d/$2})" +_lastdescr=( "$_lastdescr[@]" "$3" ) + +_setup "$1" + +name="$2" + +zstyle -s ":completion:${curcontext}:$1" format format || + zstyle -s ":completion:${curcontext}:descriptions" format format + +zstyle -s ":completion:${curcontext}:$1" hidden hidden +if [[ "$hidden" = (all|yes|true|1|on) ]]; then + [[ "$hidden" = all ]] && format='' + opts=(-n) +fi +zstyle -s ":completion:${curcontext}:$1" group-name gname && + [[ -z "$gname" ]] && gname="$1" +zstyle -s ":completion:${curcontext}:$1" matcher match && + opts=($opts -M "${(q)match}") +[[ -n "$_matcher" ]] && opts=($opts -M "${(q)_matcher}") + +if [[ -z "$_comp_no_ignore" ]] && + zstyle -a ":completion:${curcontext}:$1" ignored-patterns _comp_ignore; then + opts=( $opts -F _comp_ignore ) +else + _comp_ignore=() +fi + +shift 2 +[[ -n "$format" ]] && zformat -f format "$format" "d:$1" "${(@)argv[2,-1]}" + +if [[ -n "$gname" ]]; then + if [[ -n "$format" ]]; then + eval "${name}=($opts $gropt ${(q)gname} -X \"${format}\")" else - eval "$1=($gropt ${(q)2})" + eval "${name}=($opts $gropt ${(q)gname})" fi else - if [[ -n "$compconfig[description_format]" ]]; then - eval "$1=(-X ${(q)compconfig[description_format]//\\%d/$2})" + if [[ -n "$format" ]]; then + eval "${name}=($opts $gropt -default- -X \"${format}\")" else - eval "$1=()" + eval "${name}=($opts $gropt -default-)" fi fi + +return 0 diff --git a/Completion/Core/_expand b/Completion/Core/_expand index 9172b6cbf..eff8d8601 100644 --- a/Completion/Core/_expand +++ b/Completion/Core/_expand @@ -6,61 +6,20 @@ # This function will allow other completer functions to be called if # the expansions done produce no result or do not change the original # word from the line. -# -# Configuration keys: -# -# expand_substitute -# If this is unset or set to the empty string, the code will first -# try to expand all substitutions in the string (such as $(...) and -# ${...}). If this is set to an non-empty string it should be -# an expression usable inside a $[...] arithmetical expression. -# In this case, expansion of substitutions will be done if the -# expression evaluates to `1'. For example, with -# -# compconf expand_substitute='NUMERIC != 1' -# -# substitution will be performed only if given an explicit numeric -# argument other than `1', as by typing ESC 2 TAB. -# -# expand_glob -# If this is unset or set to an empty string, globbing will be -# attempted on the word resulting from substitution or the -# original string. The values accepted for this key are the same -# as for expand_substitute. -# -# expand_menu -# If this is unset or set to the empty string, the words resulting -# from expansion (if any) will simply be inserted in the ommand line, -# replacing the original string. However, if this key is set to an -# non-empty string, the user can cycle through the expansion as in -# a menucompletion. Unless the value contains the sub-string `only', -# the user will still be offered all expansions at once as one of -# the strings to insert in the command line. Also, if the value -# contains the sub-string `last', the string with all expansion will -# be offered first, whereas normally it is offered as the last string -# to insert. Finally, if the value contains the sub-string `sort', -# the expansions will be sorted alphabetically, normally they are -# kept in the order the expansion produced them in. -# -# expand_original -# If this is set to an non-empty string, the original string from the -# line will be included in the list of strings the user can cycle -# through as in a menucompletion. If the value contains the sub-string -# `last', the original string will appear as the last string, with -# other values it is inserted as the first one (so that the command -# line does not change immediatly). -# -# expand_prompt -# This may be set to a string that should be displayed before the -# possible expansions. This is given to the -X option and thus may -# contain the control sequences `%n', `%B', etc. Also, the sequence -# `%o' in this string will be replaced by the original string. - -local exp word="$PREFIX$SUFFIX" group=-V - -# Do this only for the first global matcher. - -[[ "$compstate[matcher]" -le 1 ]] || return 1 + +setopt localoptions nullglob + +[[ _matcher_num -gt 1 ]] && return 1 + +local exp word="$PREFIX$SUFFIX" sort expr expl subd suf=" " + +# First, see if we should insert all *completions*. + +if zstyle -s ":completion:${curcontext}:" completions expr && + [[ "${(e):-\$[$expr]}" -eq 1 ]]; then + compstate[insert]=all + return 1 +fi # In exp we will collect the expansion. @@ -69,79 +28,68 @@ exp=("$word") # First try substitution. That weird thing spanning multiple lines # changes quoted spaces, tabs, and newlines into spaces. -[[ -z "$compconfig[expand_substitute]" || - "${(e):-\$[$compconfig[expand_substitute]]}" -eq 1 ]] && +zstyle -s ":completion:${curcontext}:" substitute expr && + [[ "${(e):-\$[$expr]}" -eq 1 ]] && exp=( "${(e)exp//\\[ ]/ }" ) # If the array is empty, store the original string again. -[[ -z "$exp" ]] && exp=("$word") +(( $#exp )) || exp=("$word") + +subd=("$exp[@]") # Now try globbing. -[[ -z "$compconfig[expand_glob]" || - "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ]] && - exp=( ${~exp}(N) ) +zstyle -s ":completion:${curcontext}:" glob expr && + [[ "${(e):-\$[$expr]}" -eq 1 ]] && + exp=( ${~exp} ) # If we don't have any expansions or only one and that is the same # as the original string, we let other completers run. -[[ $#exp -eq 0 || - ( $#exp -eq 1 && "$exp[1]" = "$word" ) ]] && return 1 +(( $#exp )) || exp=("$subd[@]") -# We have expansions, should we menucomplete them? +[[ $#exp -eq 1 && "$exp[1]" = "$word"(|\(N\)) ]] && return 1 -if [[ -z "$compconfig[expand_menu]" ]]; then +# With subst-globs-only we bail out if there were no glob expansions, +# regardless of any substitutions - # No, so if the user only wants a list, we add the strings - # separately. Otherwise we add the whole array as one string, - # probably also adding the original string. +zstyle -s ":completion:${curcontext}:" subst-globs-only expr && + [[ "${(e):-\$[$expr]}" -eq 1 && "$subd" = "$exp"(|\(N\)) ]] && return 1 - if [[ -z "$compstate[insert]" ]]; then - compadd -U -V _expand -Q - "$exp[@]" - else - [[ -n "$compconfig[expand_original]" && - "$compconfig[expand_original]" != *last* ]] && - compadd -UnQ -V _expand_original - "$word" +# Now add as matches whatever the user requested. - compadd -UQ -V _expand - "$exp" +zstyle -s ":completion:${curcontext}:" sort sort - [[ -n "$compconfig[expand_original]" && - "$compconfig[expand_original]" = *last* ]] && - compadd -UnQ -V _expand_original - "$word" +[[ "$sort" = (yes|true|1|on) ]] && exp=( "${(@o)exp}" ) - compstate[insert]=menu - fi -else - # Sorting? We just use a different group type then. +# If there is only one expansion, add a suitable suffix +(($#exp == 1)) && suf='' && [[ -d $exp && "$exp[1]" != */ ]] && suf='/' - [[ "$compconfig[expand_menu]" = *sort* ]] && group=-J +if [[ -z "$compstate[insert]" ]] ;then + _description all-expansions expl 'all expansions' "o:$word" - # Now add the expansion string, probably also adding the original - # and/or the string containing all expanded string. + compadd "$expl[@]" -UQ -qS "$suf" - "$exp" +else + _tags all-expansions expansions original - [[ -n "$compconfig[expand_original]" && - "$compconfig[expand_original]" != *last* ]] && - compadd -UnQ -V _expand_original - "$word" - [[ "$compconfig[expand_menu]" = *last* && - "$compconfig[expand_menu]" != *only* ]] && - compadd -UnQ -V _expand_all - "$exp" + if _requested all-expansions; then + _description all-expansions expl 'all expansions' + compadd "$expl[@]" -UQ -qS "$suf" - "$exp" + fi - if [[ -z "$compconfig[expand_prompt]" ]]; then - compadd -UQ $group _expand - "$exp[@]" - else - compadd -UQ -X "${compconfig[expand_prompt]//\%o/$word}" \ - $group _expand - "$exp[@]" + if [[ $#exp -gt 1 ]] && _requested expansions; then + if [[ "$sort" = menu ]]; then + _description expansions expl expansions "o:$word" + else + _description -V expansions expl expansions "o:$word" + fi + compadd "$expl[@]" -UQ - "$exp[@]" fi - [[ "$compconfig[expand_menu]" != *last* && - "$compconfig[expand_menu]" != *only* ]] && - compadd -UnQ -V _expand_all - "$exp" - [[ -n "$compconfig[expand_original]" && - "$compconfig[expand_original]" = *last* ]] && - compadd -UnQ -V _expand_original - "$word" + _requested original expl original && compadd "$expl[@]" -UQ - "$word" compstate[insert]=menu fi diff --git a/Completion/Core/_files b/Completion/Core/_files index d2cce35e7..1755abebd 100644 --- a/Completion/Core/_files +++ b/Completion/Core/_files @@ -1,26 +1,49 @@ #autoload -# Utility function for completing files of a given type or any file. -# In many cases you will want to call this one instead of _path_files(). +local opts tmp glob pats expl tag i pat descr minus -local nm=$NMATCHES +zparseopts -a opts \ + '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X+: M+: F: J+: V+: -_path_files "$@" +type="${(@j::M)${(@)tmp#-}#?}" +(( $tmp[(I)-g*] )) && glob="${(j: :)${(M)tmp:#-g*}#-g}" -if [[ $# -ne 0 && -nmatches nm ]]; then - local opt opts +if zstyle -a ":completion:${curcontext}:" file-patterns pats; then + [[ "$type" = */* ]] && glob="$glob *(-/)" + pats=( \ ${(M)^${pats//\\%p/ ${glob:-\*} }:#*[^\\]:*} ) +else + if [[ "$type" = *g* ]]; then + if [[ "$type" = */* ]]; then + pats=( " ${glob//:/\\:} *(-/):globbed-files" '*:all-files' ) + else + pats=( " ${glob//:/\\:}:globbed-files" + '*(-/):directories' '*:all-files' ) + fi + elif [[ "$type" = */* ]]; then + pats=( '*(-/):directories' '*:all-files' ) + else + pats=( '*:all-files' ) + fi +fi - # We didn't get any matches for those types of files described by - # the `-g' or `-/' option. Now we try it again accepting all files. - # First we get those options that we have to use even if then. If - # we find out that the `-f' option was given, we already accepted - # all files and give up immediatly. +for tag in "${(@)${(@)pats#*[^\\]:}%%:*}"; do - opts=() - while getopts "P:S:W:F:J:V:X:f/g:" opt; do - [[ "$opt" = f ]] && return - [[ "$opt" = [PSWFJVX] ]] && opts=("$opts[@]" "-$opt" "$OPTARG") - done + i="$pats[(I)*[^\\\\]:${tag}(|:*)]" + pat="${${pats[i]%%:${tag}*}//\\\\:/:}" - _path_files "$opts[@]" -fi + if [[ i -gt 0 && "$pat" != \ # ]]; then + if [[ "$pats[i]" = *:${tag}:* ]]; then + descr="${pats[i]#*:${tag}:}" + minus=() + else + descr=file + minus=(-) + fi + fi + + _wanted "$tag" expl "$descr" \ + _path_files -g "$pat" "$opts[@]" "$minus[@]" && return 0 + +done + +return 1 diff --git a/Completion/Core/_ignored b/Completion/Core/_ignored index 69a5244cc..4046f4c2d 100644 --- a/Completion/Core/_ignored +++ b/Completion/Core/_ignored @@ -4,11 +4,10 @@ (( $compstate[ignored] )) || return 1 -local curcontext="${curcontext/:[^:]#:/:ignored-${(M)#_completers[1,_completer_num]:#_ignored}:}" local comp i _comp_no_ignore=yes tmp expl zstyle -a ":completion:${curcontext}:" completer comp || - comp=( "${(@)_completers[1,_completer_num-1][(R)_ignored,-1]}" ) + comp=( "${(@)_completers[1,_completer_num-1][(R)_ignored(|:*),-1]}" ) for i in "$comp[@]"; do if [[ "$i" != _ignored ]] && "$i"; then diff --git a/Completion/Core/_list b/Completion/Core/_list index 099c6bc7b..37167726c 100644 --- a/Completion/Core/_list +++ b/Completion/Core/_list @@ -1,38 +1,16 @@ #autoload # This completer function makes the other completer functions used -# insert possible completions only after once the list has been -# shown. -# -# Configuration keys: -# -# list_condition -# If this key is unset or set to the empty string, this completer -# will delay the insertion of matches unconditionally. However, -# if this value is set, it should be set to an expression usable -# inside a $[...] arithmetical expression. In this case, delaying -# will be done if the expression evaluates to `1'. -# For example, with -# -# compconf list_condition='NUMERIC != 1' -# -# delaying will be done only if given an explicit numeric argument -# other than `1'. -# -# list_word -# To find out if only listing should be done, the code normally -# compares the contents of the line with the contents the line -# had at the time of the last invocation. If this key is set to -# an non-empty string comparison is done using only the current -# word. So if it is set, attempting completion on a word equal -# to the one completion was called on the last time will not -# delay the generation of matches. - -local pre suf +# insert possible completions only after the list has been shown at +# least once. + +[[ _matcher_num -gt 1 ]] && return 1 + +local pre suf expr # Get the strings to compare. -if [[ -z "$compconfig[list_word]" ]]; then +if zstyle -t ":completion:${curcontext}:" word; then pre="$HISTNO$LBUFFER" suf="$RBUFFER" else @@ -42,16 +20,15 @@ fi # Should we only show a list now? -if [[ ( -z "$compconfig[list_condition]" || - "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ) && +zstyle -s ":completion:${curcontext}:" condition expr +if [[ ( -z "$expr" || "${(e):-\$[$expr]}" -eq 1 ) && ( "$pre" != "$_list_prefix" || "$suf" != "$_list_suffix" ) ]]; then # Yes. Tell the completion code about it and save the new values # to compare the next time. compstate[insert]='' - compstate[list]=list - compstate[force_list]=yes + compstate[list]='list force' _list_prefix="$pre" _list_suffix="$suf" fi diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete index c7f5a5a96..d9278f435 100644 --- a/Completion/Core/_main_complete +++ b/Completion/Core/_main_complete @@ -2,47 +2,206 @@ # The main loop of the completion code. This is what is called when # completion is attempted from the command line. -# The completion code gives us the special variables and the arguments -# from the command line are given as positional parameters. -local comp name -setopt localoptions nullglob rcexpandparam globdots -unsetopt markdirs globsubst shwordsplit nounset +# If you want to complete only set or unset options for the unsetopt +# and setopt builtin, un-comment these lines: +# +# local _set_options _unset_options +# +# _set_options=(${(k)options[(R)on]}) +# _unset_options=(${(k)options[(R)off]}) +# +# This is needed because completion functions may set options locally +# which makes the output of setopt and unsetopt reflect a different +# state than the global one for which you are completing. -# An entry for `-first-' is the replacement for `compctl -T' -# Completion functions may set `_compskip' to any value to make the -# main loops stop calling other completion functions. +setopt localoptions nullglob rcexpandparam extendedglob +unsetopt markdirs globsubst shwordsplit nounset ksharrays -comp="$_comps[-first-]" -if [[ ! -z "$comp" ]]; then - "$comp" "$@" - if (( $+_compskip )); then - unset _compskip - return - fi +local func funcs ret=1 tmp _compskip format _comp_ignore \ + _completers _completer _completer_num curtag \ + _matchers _matcher _matcher_num _comp_tags \ + context state line opt_args val_args curcontext="$curcontext" \ + _last_nmatches=-1 _last_menu_style _def_menu_style _menu_style sel \ + _saved_exact="${compstate[exact]}" \ + _saved_lastprompt="${compstate[last_prompt]}" \ + _saved_list="${compstate[list]}" \ + _saved_insert="${compstate[insert]}" + +typeset -U _lastdescr + +[[ -z "$curcontext" ]] && curcontext=::: + +# Special completion contexts after `~' and `='. + +if compset -P 1 '='; then + compstate[context]=equal +elif [[ "$PREFIX" != */* && "$PREFIX[1]" = '~' ]]; then + compset -p 1 + compstate[context]=tilde fi -# For arguments we use the `_normal function. +# Initial setup. + +_setup default +_def_menu_style=( "$_last_menu_style[@]" + +# We can't really do that because the current value of $SELECTMIN +# may be the one set by this function. +# There is a similar problem with $ZLS_COLORS in _setup. + +# ${SELECTMIN+select${SELECTMIN:+\=$SELECTMIN}} + + ) +_last_menu_style=() -if [[ $CONTEXT == argument || $CONTEXT == command ]]; then - _normal "$@" +# Get the names of the completers to use in the positional parameters. + +if (( $# )); then + _completers=( "$@" ) else - # Let's see if we have a special completion definition for the other - # possible contexts. + zstyle -a ":completion:${curcontext}:" completer _completers || + _completers=( _complete ) +fi + +# And now just call the completer functions defined. + +_completer_num=1 + +# Call the pre-functions. + +funcs=( "$compprefuncs[@]" ) +compprefuncs=() +for func in "$funcs[@]"; do + "$func" +done + +for tmp in "$_completers[@]"; do + + if [[ "$tmp" = *:-* ]]; then + _completer="${${tmp%:*}[2,-1]//_/-}${tmp#*:}" + tmp="${tmp%:*}" + elif [[ $tmp = *:* ]]; then + _completer="${tmp#*:}" + tmp="${tmp%:*}" + else + _completer="${tmp[2,-1]//_/-}" + fi + curcontext="${curcontext/:[^:]#:/:${_completer}:}" - comp='' + zstyle -a ":completion:${curcontext}:" matcher-list _matchers || + _matchers=( '' ) - case $CONTEXT in - redirect) comp="$_comps[-redirect-]";; - math) comp="$_comps[-math-]";; - subscript) comp="$_comps[-subscript-]";; - value) comp="$_comps[-value-]";; - condition) comp="$_comps[-condition-]";; - esac + _matcher_num=1 + for _matcher in "$_matchers[@]"; do + if "$tmp"; then + ret=0 + break 2 + fi + (( _matcher_num++ )) + done + (( _completer_num++ )) +done - # If not, we use default completion, if any. +curcontext="${curcontext/:[^:]#:/::}" - [[ -z "$comp" ]] && comp="$_comps[-default-]" - [[ -z "$comp" ]] || "$comp" "$@" +if [[ $compstate[old_list] = keep || $compstate[nmatches] -gt 1 ]]; then + [[ _last_nmatches -ge 0 && _last_nmatches -ne $compstate[nmatches] ]] && + _menu_style=( "$_last_menu_style[@]" "$_menu_style[@]" ) + + if [[ "$compstate[insert]" = "$_saved_insert" ]]; then + if [[ -n "$_menu_style[(r)(yes|true|1|on)]" || + ( -n "$_menu_style[(r)auto*]" && + "$compstate[insert]" = automenu ) ]]; then + compstate[insert]=menu + elif [[ -n "$_menu_style[(r)auto*]" && + "$compstate[insert]" != automenu ]]; then + compstate[insert]=automenu-unambiguous + elif [[ -n "$_menu_style[(r)(no|false|0|off)]" ]]; then + compstate[insert]=unambiguous + elif [[ -n "$_def_menu_style[(r)(yes|true|1|on)]" || + ( -n "$_def_menu_style[(r)auto*]" && + "$compstate[insert]" = automenu ) ]]; then + compstate[insert]=menu + elif [[ -n "$_def_menu_style[(r)auto*]" && + "$compstate[insert]" != automenu ]]; then + compstate[insert]=automenu-unambiguous + elif [[ -n "$_def_menu_style[(r)(no|false|0|off)]" ]]; then + compstate[insert]=unambiguous + fi + fi + + _menu_style=( "$_menu_style[@]" "$_def_menu_style[@]" ) + + if [[ "$compstate[insert]" = *menu* ]]; then + if [[ -n "$_menu_style[(r)no-select*]" ]]; then + unset SELECTMIN + else + sel=( "${(@M)_menu_style:#select*}" ) + + if (( $# )); then + local min=9999999 i num + + for i in "$sel[@]"; do + if [[ "$i" = *\=* ]]; then + num="${i#*\=}" + [[ num -lt 0 ]] && num=0 + else + num=0 + fi + [[ num -lt min ]] && min="$num" + + (( min )) || break + done + + zmodload -i zsh/complist + SELECTMIN="$min" + fi + fi + fi +elif [[ $compstate[nmatches] -eq 0 && + $#_lastdescr -ne 0 && $compstate[old_list] != keep ]] && + zstyle -s ":completion:${curcontext}:warnings" format format; then + + compstate[list]='list force' + compstate[insert]='' + + if [[ "$format" = *%d* ]]; then + local str mesg + + _lastdescr=( "\`${(@)^_lastdescr:#}'" ) + + case $#_lastdescr in + 1) str="$_lastdescr[1]";; + 2) str="$_lastdescr[1] or $_lastdescr[2]";; + *) str="${(j:, :)_lastdescr[1,-2]}, or $_lastdescr[-1]";; + esac + + zformat -f mesg "$format" "d:$str" + compadd -UX "$mesg" -n - '' + else + _setup warnings + compadd -UQX "$format" -V warnings - "${(@)_lastdescr:#}" + fi fi + +# Now call the post-functions. + +funcs=( "$comppostfuncs[@]" ) +comppostfuncs=() +for func in "$funcs[@]"; do + "$func" +done + +_lastcomp=( "${(@kv)compstate}" ) +_lastcomp[completer]="$_completer" +_lastcomp[prefix]="$PREFIX" +_lastcomp[suffix]="$SUFFIX" +_lastcomp[iprefix]="$IPREFIX" +_lastcomp[isuffix]="$ISUFFIX" +_lastcomp[qiprefix]="$QIPREFIX" +_lastcomp[qisuffix]="$QISUFFIX" +_lastcomp[tags]="$_comp_tags" + +return ret diff --git a/Completion/Core/_match b/Completion/Core/_match index 3c639935c..18dab7423 100644 --- a/Completion/Core/_match +++ b/Completion/Core/_match @@ -1,53 +1,51 @@ #autoload # This is intended to be used as a completer function after the normal -# completer as in: `compconf completer=_complete:_match'. +# completer as in: `zstyle ":completion:::::" completer _complete _match'. # It temporarily switches on pattern matching, allowing you to try # completion on patterns without having to setopt glob_complete. # # Note, however, that this is only really useful if you don't use the # expand-or-complete function because otherwise the pattern will # be expanded using globbing. -# -# Configuration key used: -# -# match_original -# If this is set to a `only', pattern matching will only be tried -# with the string from the line. If it is set to any other non-empty -# string, the original pattern will be tried first and if that yields -# no completions, matching will be tried again with a `*' inserted -# at the cursor position. If this key is not set or set to an empty -# string, matching will only be attempted with the `*' inserted. -local tmp opm="$compstate[pattern_match]" ret=0 +[[ _matcher_num -gt 1 ]] && return 1 + +local tmp opm="$compstate[pattern_match]" ret=0 orig ins -# Do nothing if we don't have a pattern or there are still global -# match specifications to try. +# Do nothing if we don't have a pattern. tmp="${${:-$PREFIX$SUFFIX}#[~=]}" -[[ "$tmp:q" = "$tmp" || - compstate[matcher] -ne compstate[total_matchers] ]] && return 1 +[[ "$tmp:q" = "$tmp" ]] && return 1 + +zstyle -s ":completion:${curcontext}:" match-original orig +zstyle -b ":completion:${curcontext}:" insert-unambiguous ins # Try completion without inserting a `*'? -if [[ -n "$compconfig[match_original]" ]]; then - compstate[matcher]=-1 +if [[ -n "$orig" ]]; then compstate[pattern_match]='-' _complete && ret=1 compstate[pattern_match]="$opm" - compstate[matcher]="$compstate[total_matchers]" - (( ret )) && return 0 + if (( ret )); then + [[ "$ins" = yes && + $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] && + compstate[pattern_insert]=unambiguous + return 0 + fi fi # No completion with inserting `*'? -[[ "$compconfig[match_original]" = only ]] && return 1 +[[ "$orig" = only ]] && return 1 -compstate[matcher]=-1 compstate[pattern_match]='*' _complete && ret=1 compstate[pattern_match]="$opm" -compstate[matcher]="$compstate[total_matchers]" + +[[ ret -eq 1 && "$ins" = yes && + $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] && + compstate[pattern_insert]=unambiguous return 1-ret diff --git a/Completion/Core/_menu b/Completion/Core/_menu index 4cbda4e14..41fc178ba 100644 --- a/Completion/Core/_menu +++ b/Completion/Core/_menu @@ -1,10 +1,12 @@ #autoload +[[ _matcher_num -gt 1 ]] && return 1 + # This completer is an example showing how menucompletion can be # implemented with the new completion system. # Use this one before the normal _complete completer, as in: # -# compconf completer=_menu:_complete +# zstyle ":completion:::::" completer _menu _complete if [[ -n "$compstate[old_list]" ]]; then diff --git a/Completion/Core/_next_label b/Completion/Core/_next_label new file mode 100644 index 000000000..e309e53ea --- /dev/null +++ b/Completion/Core/_next_label @@ -0,0 +1,24 @@ +#autoload + +local gopt=-J descr + +if [[ "$1" = -([12]|)[VJ] ]]; then + gopt="$1" + shift +fi + +if comptags -A "$1" curtag; then + if [[ "$curtag" = *:* ]]; then + zformat -f descr "${curtag#*:}" "d:$3" + _description "$gopt" "${curtag%:*}" "$2" "$descr" + curtag="${curtag%:*}" + eval "${2}=( \${(P)2} \$argv[4,-1] )" + else + _description "$gopt" "$curtag" "$2" "$3" + eval "${2}=( \$argv[4,-1] \${(P)2} )" + fi + + return 0 +fi + +return 1 diff --git a/Completion/Core/_oldlist b/Completion/Core/_oldlist new file mode 100644 index 000000000..bcb3e148a --- /dev/null +++ b/Completion/Core/_oldlist @@ -0,0 +1,53 @@ +#autoload + +[[ _matcher_num -gt 1 ]] && return 1 + +local list + +zstyle -s ":completion:${curcontext}:" old-list list + +# If this is a listing widget and there is already an old list, +# and either the style :oldlist:old-list is `always', or it is not `never' +# and the list is not already shown, then use the existing list for listing +# (even if it was generated by another widget). +# Do this also if there is an old list and it was generated by the +# completer named by the oldlist_list key. + +if [[ -n $compstate[old_list] && $list != never ]]; then + if [[ $WIDGET = *list* && ( $list = always || $list != shown ) ]]; then + compstate[old_list]=keep + return 0 + elif [[ $list = *${_lastcomp[completer]}* ]]; then + [[ "$_lastcomp[insert]" = unambig* ]] && compstate[to_end]=single + compstate[old_list]=keep + if [[ -o automenu ]]; then + compstate[insert]=menu + else + compadd -Qs "$SUFFIX" - "$PREFIX" + fi + return 0 + fi +fi + +# If this is a completion widget, and we have a completion inserted already, +# and the style :oldlist:old-menu is `true', then we cycle through the +# existing list (even if it was generated by another widget). + +if [[ -z $compstate[old_insert] && -n $compstate[old_list] ]]; then + compstate[old_list]=keep +elif [[ $WIDGET = *complete(|-prefix|-word) ]] && + zstyle -t ":completion:${curcontext}:" old-menu; then + if [[ -n $compstate[old_insert] ]]; then + compstate[old_list]=keep + if [[ $WIDGET = *reverse* ]]; then + compstate[insert]=$(( compstate[old_insert] - 1 )) + else + compstate[insert]=$(( compstate[old_insert] + 1 )) + fi + else + return 1 + fi + return 0 +fi + +return 1 diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 83b6e8a09..ac4614dd8 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -1,85 +1,64 @@ #autoload -# Utility function for in-path completion. -# Supported arguments are: `-f', `-/', `-g <patterns>', `-J <group>', -# `-V <group>', `-W paths', `-X explanation', and `-F <ignore>'. All but -# the last have the same syntax and meaning as for `complist'. The -# `-F <ignore>' option may be used to give a list of suffixes either by -# giving the name of an array or literally by giving them in a string -# surrounded by parentheses. Files with one of the suffixes thus given -# are treated like files with one of the suffixes in the `fignore' array -# in normal completion. -# -# This function uses the helper functions `_match_test' and `_match_pattern'. +# Utility function for in-path completion. This allows `/u/l/b<TAB>' +# to complete to `/usr/local/bin'. -# First see if we should generate matches for the global matcher in use. +local linepath realpath donepath prepath testpath exppath skips skipped +local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre +local pats haspats=no ignore pfxsfx rem remt sopt gopt opt +local nm=$compstate[nmatches] menu matcher mopts atmp sort match -_match_test _path_files || return +typeset -U prepaths exppaths -# Yes, so... - -local nm prepaths str linepath realpath donepath patstr prepath testpath rest -local tmp1 collect tmp2 suffixes i ignore matchflags opt group sopt pats gopt -local addpfx addsfx expl - -setopt localoptions nullglob rcexpandparam globdots extendedglob +setopt localoptions nullglob rcexpandparam unsetopt markdirs globsubst shwordsplit nounset -prepaths=('') -ignore=() -group=() -sopt='-' -gopt='' -pats=() -addpfx=() -addsfx=() -expl=() +exppaths=() # Get the options. -while getopts "P:S:W:F:J:V:X:f/g:" opt; do - case "$opt" in - P) addpfx=(-P "$OPTARG") - ;; - S) addsfx=(-S "$OPTARG") - ;; - W) tmp1="$OPTARG" - if [[ "$tmp1[1]" = '(' ]]; then - prepaths=( ${^=tmp1[2,-2]}/ ) - else - prepaths=( ${(P)=${tmp1}} ) - (( ! $#prepaths )) && prepaths=( ${tmp1}/ ) - fi - (( ! $#prepaths )) && prepaths=( '' ) - ;; - F) tmp1="$OPTARG" - if [[ "$tmp1[1]" = '(' ]]; then - ignore=( ${^=tmp1[2,-2]}/ ) - else - ignore=( ${(P)${tmp1}} ) - fi - (( $#ignore )) && ignore=(-F "( $ignore )") - ;; - [JV]) group=("-$opt" "$OPTARG") - ;; - X) expl=(-X "$OPTARG") - ;; - f) sopt="${sopt}f" - pats=("$pats[@]" '*') - ;; - /) sopt="${sopt}/" - pats=("$pats[@]" '*(-/)') - ;; - g) gopt='-g' - pats=("$pats[@]" ${=OPTARG}) - ;; - esac -done +zparseopts -a mopts \ + 'P:=pfxsfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \ + 'W:=prepaths' 'F:=ignore' 'M+:=matcher' \ + J+: V+: X+: 1: 2: n: 'f=tmp1' '/=tmp1' 'g+:-=tmp1' + +sopt="-${(@j::M)${(@)tmp1#-}#?}" +(( $tmp1[(I)-[/g]*] )) && haspats=yes +(( $tmp1[(I)-g*] )) && gopt=yes +if (( $tmp1[(I)-/] )); then + pats=( '*(-/)' ${=${(M)tmp1:#-g*}#-g} ) +else + pats=( "${(@)=${(@M)tmp1:#-g*}#-g}" ) +fi +pats=( "${(@)pats:# #}" ) + +if (( $#prepaths )); then + tmp1="${prepaths[2]}" + if [[ "$tmp1[1]" = '(' ]]; then + prepaths=( ${^=tmp1[2,-2]%/}/ ) + elif [[ "$tmp1[1]" = '/' ]]; then + prepaths=( "${tmp1%/}/" ) + else + prepaths=( ${(P)^tmp1%/}/ ) + (( ! $#prepaths )) && prepaths=( ${tmp1%/}/ ) + fi + (( ! $#prepaths )) && prepaths=( '' ) +else + prepaths=( '' ) +fi + +if (( $#ignore )); then + if [[ "${ignore[2]}" = \(* ]]; then + ignore=( ${=ignore[2][2,-2]} ) + else + ignore=( ${(P)ignore[2]} ) + fi +fi # If we were given no file selection option, we behave as if we were given # a `-f'. -if [[ "$sopt" = - ]]; then +if [[ "$sopt" = -(f|) ]]; then if [[ -z "$gopt" ]]; then sopt='-f' pats=('*') @@ -88,224 +67,472 @@ if [[ "$sopt" = - ]]; then fi fi -# str holds the whole string from the command line with a `*' between -# the prefix and the suffix. - -str="${PREFIX:q}*${SUFFIX:q}" - -# If the string began with a `~', the quoting turned this into `\~', -# remove the slash. +if (( ! $mopts[(I)-[JVX]] )); then + local expl -[[ "$str" = \\\~* ]] && str="$str[2,-1]" - -# We will first try normal completion called with `complist', but only if we -# weren't given a `-F' option. - -if (( ! $#ignore )); then - # First build an array containing the `-W' option, if there is any and we - # want to use it. We don't want to use it if the string from the command line - # is a absolute path or relative to the current directory. - - if [[ -z "$tmp1[1]" || "$str[1]" = [~/] || "$str" = (.|..)/* ]]; then - tmp1=() + if [[ -z "$gopt" && "$sopt" = -/ ]]; then + _description directories expl directory else - tmp1=(-W "( $prepaths )") + _description files expl file + fi + tmp1=$expl[(I)-M*] + if (( tmp1 )); then + if (( $#matcher )); then + matcher[2]="$matcher[2] $expl[1+tmp1]" + else + matcher=(-M "$expl[1+tmp1]") + fi fi + mopts=( "$mopts[@]" "$expl[@]" ) +fi - # Now call complist. +if zstyle -s ":completion:${curcontext}:files" sort tmp1; then + case "$tmp1" in + *size*) sort=oL;; + *links*) sort=ol;; + *(time|date|modi)*) sort=om;; + *access*) sort=oa;; + *(inode|change)*) sort=oc;; + *) sort=on;; + esac + [[ "$tmp1" = *rev* ]] && sort[1]=O - nm=$NMATCHES - if [[ -z "$gopt" ]]; then - complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt + if [[ "$sort" = on ]]; then + sort='' else - complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats" + mopts=( "${(@)mopts/#-J/-V}" ) + + tmp2=() + for tmp1 in "$pats[@]"; do + if [[ "$tmp1" = (#b)(?*)(\(\([^\|~]##\)\)) ]]; then + tmp2=( "$tmp2[@]" "${match[1]}((${sort}${match[2][3,-1]}" ) + elif [[ "$tmp1" = (#b)(?*)(\([^\|~]##\)) ]]; then + tmp2=( "$tmp2[@]" "${match[1]}(${sort}${match[2][2,-1]}" ) + else + tmp2=( "$tmp2[@]" "${tmp1}(${sort})" ) + fi + done + pats=( "$tmp2[@]" ) fi +fi + +# Check if we have to skip over sequences of slashes. The value of $skips +# is used below to match the pathname components we always have to accept +# immediatly. + +if zstyle -t ":completion:${curcontext}:paths" squeeze-slashes; then + skips='((.|..|)/)##' +else + skips='((.|..)/)##' +fi + +# We get the prefix and the suffix from the line and save the whole +# original string. Then we see if we will do menucompletion. + +pre="$PREFIX" +suf="$SUFFIX" +opre="$PREFIX" +osuf="$SUFFIX" +orig="${PREFIX}${SUFFIX}" +eorig="$orig" - # If this generated any matches, we don't want to do in-path completion. +[[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" || + ( -n "$compstate[pattern_match]" && + "${orig#\~}" != "${${orig#\~}:q}" ) ]] && menu=yes - [[ -nmatches nm ]] || return +# If given no `-F' option, we may want to use $fignore, turned into patterns. - # No `-F' option, so we want to use `fignore'. +[[ -z "$_comp_no_ignore" && $#ignore -eq 0 && + ( -z $gopt || "$pats" = \ #\*\ # ) && -n $FIGNORE ]] && + ignore=( "?*${^fignore[@]}" ) - ignore=(-F fignore) +if (( $#ignore )); then + _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" ) + (( $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore ) fi +(( $#matcher )) && mopts=( "$mopts[@]" "$matcher[@]" ) + # Now let's have a closer look at the string to complete. -if [[ "$str[1]" = \~ ]]; then +if [[ "$pre[1]" = \~ ]]; then # It begins with `~', so remember anything before the first slash to be able # to report it to the completion code. Also get an expanded version of it # (in `realpath'), so that we can generate the matches. Then remove that # prefix from the string to complete, set `donepath' to build the correct # paths and make sure that the loop below is run only once with an empty # prefix path by setting `prepaths'. - - linepath="${str%%/*}/" - eval realpath\=$linepath - str="${str#*/}" + + linepath="${pre[2,-1]%%/*}" + if [[ -z "$linepath" ]]; then + realpath="${HOME%/}/" + elif (( $+userdirs[$linepath] )); then + realpath="${userdirs[$linepath]%/}/" + elif (( $+nameddirs[$linepath] )); then + realpath="${nameddirs[$linepath]%/}/" + else + _message "unknown user \`$linepath'" + return 1 + fi + linepath="~${linepath}/" + [[ "$realpath" = "$linepath" ]] && return 1 + pre="${pre#*/}" + orig="${orig#*/}" + donepath='' + prepaths=( '' ) +elif [[ "$pre" = *\$*/* ]]; then + + # If there is a parameter expansion in the word from the line, we try + # to complete the beast by expanding the prefix and completing anything + # after the first slash after the parameter expansion. + # This fails for things like `f/$foo/b/<TAB>' where the first `f' is + # meant as a partial path. + + linepath="${(M)pre##*\$[^/]##/}" + realpath=${(e)~linepath} + [[ "$realpath" = "$linepath" ]] && return 1 + pre="${pre#${linepath}}" + i="${#linepath//[^\\/]}" + orig="${orig[1,(in:i:)/][1,-2]}" donepath='' prepaths=( '' ) else # If the string does not start with a `~' we don't remove a prefix from the # string. - liniepath='' + linepath='' realpath='' - if [[ "$str[1]" = / ]]; then + if [[ "$pre[1]" = / ]]; then # If it is a absolut path name, we remove the first slash and put it in # `donepath' meaning that we treat it as the path that was already handled. # Also, we don't use the paths from `-W'. - str="$str[2,-1]" + pre="$pre[2,-1]" + orig="$orig[2,-1]" donepath='/' prepaths=( '' ) else # The common case, we just use the string as it is, unless it begins with # `./' or `../' in which case we don't use the paths from `-W'. - [[ "$str" = (.|..)/* ]] && prepaths=( '' ) + [[ "$pre" = (.|..)/* ]] && prepaths=( '' ) donepath='' fi fi -# First we skip over all pathname components in `str' which really exist in -# the file-system, so that `/usr/lib/l<TAB>' doesn't offer you `lib' and -# `lib5'. Pathname components skipped this way are taken from `str' and added -# to `donepath'. +# Now we generate the matches. First we loop over all prefix paths given +# with the `-W' option. -while [[ "$str" = */* ]] do - [[ -e "$realpath$donepath${str%%/*}" ]] || break - donepath="$donepath${str%%/*}/" - str="${str#*/}" -done +for prepath in "$prepaths[@]"; do -# Now build the glob pattern by calling `_match_pattern'. -patstr="$str" -matchflags="" -_match_pattern _path_files patstr matchflags + # Get local copies of the prefix, suffix, and the prefix path to use + # in the following loop, which walks through the pathname components + # in the string from the line. -# We almost expect the pattern to have changed `..' into `*.*.', `/.' into -# `/*.', and probably to contain two or more consecutive `*'s. Since these -# have special meaning for globbing, we remove them. But before that, we -# add the pattern for matching any characters before a slash. + tpre="$pre" + tsuf="$suf" + testpath="$donepath" -patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/" + tmp2="${(M)tpre##${~skips}}" + tpre="${tpre#$tmp2}" -# Finally, generate the matches. First we loop over all the paths from `-W'. -# Note that in this loop `str' is used as a modifyable version of `patstr' -# and `testpath' is a modifyable version of `donepath'. + tmp1=( "$prepath$realpath$donepath$tmp2" ) -for prepath in "$prepaths[@]"; do - str="$patstr" - testpath="$donepath" + while true; do - # The second loop tests the components of the path in `str' to get the - # possible matches. + # Get the prefix and suffix for matching. - while [[ "$str" = */* ]] do - # `rest' is the pathname after the first slash that is left. In `tmp1' - # we get the globbing matches for the pathname component currently - # handled. + if [[ "$tpre" = */* ]]; then + PREFIX="${tpre%%/*}" + SUFFIX="" + else + PREFIX="${tpre}" + SUFFIX="${tsuf%%/*}" + fi - rest="${str#*/}" - tmp1="${prepath}${realpath}${testpath}${~matchflags}${str%%/*}(-/)" - tmp1=( $~tmp1 ) + # Get the matching files by globbing. - if [[ $#tmp1 -eq 0 ]]; then - # If this didn't produce any matches, we don't need to test this path - # any further, so continue with the next `-W' path, if any. + tmp2=( "$tmp1[@]" ) + if [[ "$tpre$tsuf" = */* ]]; then + if [[ ! -o globdots && "$PREFIX" = .* ]]; then + tmp1=( ${^tmp1}${skipped}*(-/) ${^tmp1}${skipped}.*(-/) ) + else + tmp1=( ${^tmp1}${skipped}*(-/) ) + fi + if [[ -o globdots || "$PREFIX" = .* ]] && + zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then + if [[ "$atmp" = (yes|true|1|on) ]]; then + tmp1=( "$tmp1[@]" . .. ) + elif [[ "$atmp" = .. ]]; then + tmp1=( "$tmp1[@]" .. ) + fi + fi + else + if [[ ! -o globdots && "$PREFIX" = .* ]]; then + tmp1=( ${^tmp1}${skipped}${^~pats} ${^tmp1}${skipped}.${^~pats:#.*} ) + else + tmp1=( ${^tmp1}${skipped}${^~pats} ) + fi + if [[ "$sopt" = *[/f]* && ( -o globdots || "$PREFIX" = .* ) ]] && + zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then + if [[ "$atmp" = (yes|true|1|on) ]]; then + tmp1=( "$tmp1[@]" . .. ) + elif [[ "$atmp" = .. ]]; then + tmp1=( "$tmp1[@]" .. ) + fi + fi + fi - continue 2 - elif [[ $#tmp1 -gt 1 ]]; then - # If it produced more than one match, we want to remove those which - # don't have possible following pathname components matching the - # rest of the string we are completing. (The case with only one - # match is handled below.) - # In `collect' we will collect those of the produced pathnames that - # have a matching possible path-suffix. In `suffixes' we build an - # array containing strings build from the rest of the string to - # complete and the glob patterns we were given as arguments. - - collect=() - suffixes=( $rest$^pats ) - suffixes=( "${(@)suffixes:gs.**.*.}" ) - - # In the loop the prefixes from the `tmp1' array produced above and - # the suffixes we just built are used to produce possible matches - # via globbing. - - for i in $tmp1; do - tmp2=( ${~i}/${~matchflags}${~suffixes} ) - [[ $#tmp2 -ne 0 ]] && collect=( $collect $i ) - done - - # If this test showed that none of the matches from the glob in `tmp1' - # has a possible sub-path matching what's on the line, we give up and - # continue with the next `-W' path. - - if [[ $#collect -eq 0 ]]; then + if [[ -n "$PREFIX$SUFFIX" ]]; then + # See which of them match what's on the line. + + if [[ -n "$_comp_correct" ]]; then + tmp2=( "$tmp1[@]" ) + builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}" + + if [[ $#tmp1 -eq 0 ]]; then + tmp1=( "$tmp2[@]" ) + compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}" + fi + else + [[ "$tmp1[1]" = */* ]] && tmp2=( "$tmp1[@]" ) + + builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}" + fi + + # If no file matches, save the expanded path and continue with + # the outer loop. + + if (( ! $#tmp1 )); then + if [[ "$tmp2[1]" = */* ]]; then + tmp2=( "${(@)tmp2#${prepath}${realpath}}" ) + if [[ "$tmp2[1]" = */* ]]; then + tmp2=( "${(@)tmp2:h}" ) + compquote tmp2 + if [[ "$tmp2" = */ ]]; then + exppaths=( "$exppaths[@]" ${^tmp2}${tpre}${tsuf} ) + else + exppaths=( "$exppaths[@]" ${^tmp2}/${tpre}${tsuf} ) + fi + else + exppaths=( "$exppaths[@]" ${tpre}${tsuf} ) + fi + fi continue 2 - elif [[ $#collect -ne 1 ]]; then - # If we have more than one possible match, this means that the - # pathname component currently handled is ambiguous, so we give - # it to the completion code. - # First we build the full path prefix in `tmp1'. + fi + elif (( ! $#tmp1 )); then + # A little extra hack: if we were completing `foo/<TAB>' and `foo' + # contains no files, this will normally produce no matches and other + # completers might think that's it's their time now. But if the next + # completer is _correct or something like that, this will result in + # an attempt to correct a valid directory name. So we just add the + # original string in such a case so that the command line doesn't + # change but other completers still think there are matches. + # We do this only if we weren't given a `-g' or `-/' option because + # otherwise this would keep `_files' from completing all filenames + # if none of the patterns match. + + if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then + pfxsfx=(-S '' "$pfxsfx[@]") + ### Don't remember what the break was good for. We explicitly + ### execute this only when there are no matches in the directory, + ### so why continue? + ### + ### tmp1=( "$tmp2[@]" ) + ### break + elif [[ "$haspats" = no && -z "$tpre$tsuf" && + "$pre" = */ && -z "$suf" ]]; then + PREFIX="${opre}" + SUFFIX="${osuf}" + compadd -nQS '' - "$linepath$donepath$orig" + tmp4=- + fi + continue 2 + fi - tmp1="$prepath$realpath$testpath" + if [[ -z "$_comp_no_ignore" && "$tpre$tsuf" != */* && $#tmp1 -ne 0 ]] && + zstyle -s ":completion:${curcontext}:files" ignore-parents rem && + [[ ( "$rem" != *dir* || "$pats" = '*(-/)' ) && + ( "$rem" != *..* || "$tmp1" = *../* ) ]]; then + if [[ "$rem" = *parent* ]]; then + for i in ${(M)^tmp1:#*/*}(-/); do + remt="${${i#$prepath$realpath$donepath}%/*}" + while [[ "$remt" = */* && + ! "$prepath$realpath$donepath$remt" -ef "$i" ]]; do + remt="${remt%/*}" + done + [[ "$remt" = */* || "$remt" -ef "$i" ]] && + _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" ) + done + fi + if [[ "$rem" = *pwd* ]]; then + for i in ${^tmp1}(-/); do + [[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" ) + done + fi + (( $#_comp_ignore && $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore ) + fi - # Now produce all matching pathnames in `collect'. + # Step over to the next component, if any. - collect=( ${~collect}/${~matchflags}${~suffixes} ) + if [[ "$tpre" = */* ]]; then + tpre="${tpre#*/}" + elif [[ "$tsuf" = */* ]]; then + tpre="${tsuf#*/}" + tsuf="" + else + break + fi - # And then remove the common path prefix from all these matches. + # There are more components, so skip over the next components and make a + # slash be added. - collect=( ${collect#$tmp1} ) + tmp2="${(M)tpre##((.|..|)/)##}" + if [[ -n "$tmp2" ]]; then + skipped="/$tmp2" + tpre="${tpre#$tmp2}" + else + skipped=/ + fi + done + + # The next loop searches the first ambiguous component. + + tmp3="$pre$suf" + tpre="$pre" + tsuf="$suf" + tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" ) - # Finally, we add all these matches with the common (unexpanded) - # pathprefix (the `-p' option), the path-prefix (the `-W' option) - # to allow the completion code to test file type, and the path- - # suffix (the `-s' option). We also tell the completion code that - # these are file names and that `fignore' should be used as usual - # (the `-f' and `-F' options). + while true; do - for i in $collect; do - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}" - done + # First we check if some of the files match the original string + # for this component. If there are some we remove all other + # names. This avoids having `foo' complete to `foo' and `foobar'. - # We have just finished handling all the matches from above, so we - # can continue with the next `-W' path. + if [[ "$tmp3" = */* ]]; then + tmp4=( "${(@M)tmp1:#${tmp3%%/*}/*}" ) + (( $#tmp4 )) && tmp1=( "$tmp4[@]" ) + fi + + # Next we see if this component is ambiguous. - continue 2 + if [[ "$tmp3" = */* ]]; then + tmp4=$tmp1[(I)^${(q)tmp1[1]%%/*}/*] + else + tmp4=$tmp1[(I)^${(q)tmp1[1]}] + fi + + if [[ "$tpre" = */* ]]; then + tmp2="${cpre}${tpre%%/*}" + PREFIX="${donepath}${linepath}${tmp2}" + SUFFIX="/${tpre#*/}${tsuf#*/}" + else + tmp2="${cpre}${tpre}" + PREFIX="${donepath}${linepath}${tmp2}" + SUFFIX="${tsuf}" + fi + + if (( tmp4 )) || + [[ -n "$compstate[pattern_match]" && "$tmp2" != "${(q)tmp2}" ]]; then + # It is. For menucompletion we now add the possible completions + # for this component with the unambigous prefix we have built + # and the rest of the string from the line as the suffix. + # For normal completion we add the rests of the filenames + # collected as the suffixes to make the completion code expand + # it as far as possible. + + tmp2="$testpath" + compquote tmp1 tmp2 + + if [[ -n $menu || -z "$compstate[insert]" ]] || + ! zstyle -t ":completion:${curcontext}:paths" expand suffix; then + (( tmp4 )) && zstyle -t ":completion:${curcontext}:paths" cursor && + compstate[to_end]='' + if [[ "$tmp3" = */* ]]; then + compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \ + -W "$prepath$realpath$testpath" \ + "$pfxsfx[@]" -M "r:|/=* r:|=*" \ + - "${(@)tmp1%%/*}" + else + compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ + -W "$prepath$realpath$testpath" \ + "$pfxsfx[@]" -M "r:|/=* r:|=*" \ + - "$tmp1[@]" + fi + else + if [[ "$tmp3" = */* ]]; then + atmp=( -Qf "$mopts[@]" -p "$linepath$tmp2" + -W "$prepath$realpath$testpath" + "$pfxsfx[@]" -M "r:|/=* r:|=*" ) + for i in "$tmp1[@]"; do + compadd "$atmp[@]" -s "/${i#*/}" - "${i%%/*}" + done + else + compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ + -W "$prepath$realpath$testpath" \ + "$pfxsfx[@]" -M "r:|/=* r:|=*" \ + - "$tmp1[@]" + fi fi - # We reach this point if only one of the path prefixes in `tmp1' - # has a existing path-suffix matching the string from the line. - # In this case we accept this match and continue with the next - # path-name component. + tmp4=- + break + fi + + # If we have checked all components, we stop now and add the + # strings collected after the loop. - tmp1=( "$collect[1]" ) + if [[ "$tmp3" != */* ]]; then + tmp4="" + break fi - # This is also reached if the first globbing produced only one match - # in this case we just continue with the next pathname component, too. - tmp1="$tmp1[1]" - testpath="$testpath${tmp1##*/}/" - str="$rest" + # Otherwise we add the unambiguous component to `testpath' and + # take it from the filenames. + + testpath="${testpath}${tmp1[1]%%/*}/" + tmp1=( "${(@)tmp1#*/}" ) + + tmp3="${tmp3#*/}" + + if [[ "$tpre" = */* ]]; then + cpre="${cpre}${tpre%%/*}/" + tpre="${tpre#*/}" + elif [[ "$tsuf" = */* ]]; then + cpre="${cpre}${tpre}/" + tpre="${tsuf#*/}" + tsuf="" + else + tpre="" + tsuf="" + fi done - # We are here if all pathname components except the last one (which is still - # not tested) are unambiguous. So we add matches with the full path prefix, - # no path suffix, the `-W' we are currently handling, all the matches we - # can produce in this directory, if any. - - tmp1="$prepath$realpath$testpath" - suffixes=( $str$^pats ) - suffixes=( "${(@)suffixes:gs.**.*.}" ) - tmp2=( ${~tmp1}${~matchflags}${~suffixes} ) - if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then - [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]" - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath" - else - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1} + if [[ -z "$tmp4" ]]; then + if [[ "$osuf" = */* ]]; then + PREFIX="${opre}${osuf}" + SUFFIX="" + else + PREFIX="${opre}" + SUFFIX="${osuf}" + fi + tmp4="$testpath" + compquote tmp4 tmp1 + compadd -Qf "$mopts[@]" -p "$linepath$tmp4" -W "$prepath$realpath$testpath" \ + "$pfxsfx[@]" -M "r:|/=* r:|=*" - "$tmp1[@]" fi done + +# If we are configured to expand paths as far as possible and we collected +# expanded paths that are different from the string on the line, we add +# them as possible matches. + +if zstyle -t ":completion:${curcontext}:paths" expand prefix && + [[ nm -eq compstate[nmatches] && $#exppaths -ne 0 && + "$exppaths" != "$eorig" ]]; then + PREFIX="${opre}" + SUFFIX="${osuf}" + compadd -Q "$mopts[@]" -S '' -M "r:|/=* r:|=*" -p "$linepath" - "$exppaths[@]" +fi + +[[ nm -ne compstate[nmatches] ]] diff --git a/Completion/Core/_prefix b/Completion/Core/_prefix index 6306b4aa0..f6e3b0831 100644 --- a/Completion/Core/_prefix +++ b/Completion/Core/_prefix @@ -4,10 +4,10 @@ [[ -n "$SUFFIX" ]] || return 1 -local curcontext="${curcontext/:[^:]#:/:prefix:}" comp i +local comp i zstyle -a ":completion:${curcontext}:" completer comp || - comp=( "${(@)_completers[1,-${#_completers_left}-1][(R)_prefix,-1]}" ) + comp=( "${(@)_completers[1,_completer_num-1][(R)_prefix(|:*),-1]}" ) if zstyle -t ":completion:${curcontext}:" add-space; then ISUFFIX=" $SUFFIX" diff --git a/Completion/Core/_requested b/Completion/Core/_requested index 082c45820..bd838a28e 100644 --- a/Completion/Core/_requested +++ b/Completion/Core/_requested @@ -1,9 +1,20 @@ #autoload -local tag tname="$funcstack[2,-1]" +local gopt=-J -for tag; do - [[ "${_cur_tags[${tname}]}" = *:${tag}(:|\[*\]:)* ]] && return 0 -done +if [[ "$1" = -([12]|)[VJ] ]]; then + gopt="$1" + shift +fi -return 1 +if comptags -R "$1"; then + _comp_tags="$_comp_tags $1" + if [[ $# -gt 3 ]]; then + _all_labels "$gopt" "$@" + elif [[ $# -gt 1 ]]; then + _description "$gopt" "$@" + fi + return 0 +else + return 1 +fi diff --git a/Completion/Core/_setup b/Completion/Core/_setup index f12c34b34..ed7307e69 100644 --- a/Completion/Core/_setup +++ b/Completion/Core/_setup @@ -1,13 +1,61 @@ #autoload -local colors i - -for i; do - if _style -a "$i" list-colors colors; then - if [[ "$1" = default ]]; then - ZLS_COLORS="${(j.:.)${(@)colors:gs/:/\\\:}}" - else - eval "ZLS_COLORS=\"(${i})\${(j.:(${i}).)\${(@)colors:gs/:/\\\:}}:\${ZLS_COLORS}\"" - fi +local val nm="$compstate[nmatches]" + +if zstyle -a ":completion:${curcontext}:$1" list-colors val; then + zmodload -i zsh/complist + if [[ "$1" = default ]]; then + ZLS_COLORS="${(j.:.)${(@)val:gs/:/\\\:}}" + else + eval "ZLS_COLORS=\"(${1})\${(j.:(${1}).)\${(@)val:gs/:/\\\:}}:\${ZLS_COLORS}\"" fi -done + +# Here is the problem mentioned in _main_complete. + +# elif [[ "$1" = default && -n "$ZLS_COLORS$ZLS_COLOURS" ]]; then +# zmodload -i zsh/complist +# ZLS_COLORS="$ZLS_COLORS$ZLS_COLOURS" + +fi + +if zstyle -t ":completion:${curcontext}:$1" list-packed; then + compstate[list]="${compstate[list]} packed" +elif [[ $? -eq 1 ]]; then + compstate[list]="${compstate[list]:gs/packed//}" +else + compstate[list]="$_saved_list" +fi + +if zstyle -t ":completion:${curcontext}:$1" list-rows-first; then + compstate[list]="${compstate[list]} rows" +elif [[ $? -eq 1 ]]; then + compstate[list]="${compstate[list]:gs/rows//}" +else + compstate[list]="$_saved_list" +fi + +if zstyle -t ":completion:${curcontext}:$1" last-prompt; then + compstate[last_prompt]=yes +elif [[ $? -eq 1 ]]; then + compstate[last_prompt]='' +else + compstate[last_prompt]="$_saved_lastprompt" +fi + +if zstyle -t ":completion:${curcontext}:$1" accept-exact; then + compstate[exact]=accept +elif [[ $? -eq 1 ]]; then + compstate[exact]='' +else + compstate[exact]="$_saved_exact" +fi + +[[ _last_nmatches -ge 0 && _last_nmatches -ne nm ]] && + _menu_style=( "$_last_menu_style[@]" "$_menu_style[@]" ) + +if zstyle -a ":completion:${curcontext}:$1" menu val; then + _last_nmatches=$nm + _last_menu_style=( "$val[@]" ) +else + _last_nmatches=-1 +fi diff --git a/Completion/Core/_tags b/Completion/Core/_tags index af8dc21dd..496f5b7e0 100644 --- a/Completion/Core/_tags +++ b/Completion/Core/_tags @@ -1,81 +1,83 @@ #autoload -if (( $# )); then - local cmd="$words[1]" func="$funcstack[2]" defs i tags tag pat style prio - - while getopts 'c:f:' i; do - if [[ "$i" = c ]]; then - cmd="$OPTARG" - else - func="$OPTARG" - fi - done - - shift OPTIND-1 - - defs=( "${(@M)argv:#${(kj:|:)~override_tags[(R)(|+*)]}}" ) - (( $#defs )) && set -- "$defs[@]" - - _offered_tags=( "$_offered_tags[@]" "$@" ) - _last_tags=() - - defs=() - for i; do - if [[ -n ${override_tags[$i]} && ${override_tags[$i]} != (\[|+\[)* ]]; then - if [[ ${override_tags[$i]} = *\[* ]]; then - prio=( "${i}:*=${override_tags[$i]#+}" ) - else - prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" ) - (( $#prio )) || prio=( "${i}:${comptags[any]}" ) - prio="${${${prio[(r)(|*:)\*=[^:]#\[*\](|:*)]}##(|*:)\*}%%:*}" - prio=( "${i}:*=${override_tags[$i]#+}${(M)prio%%\[*\]}" ) - fi - else - prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" ) - (( $#prio )) || prio=( "${i}:${comptags[any]}" ) - fi - defs=( "$defs[@]" "$prio[@]" ) - done - - tags=() - for i in "$defs[@]"; do - tag="${i%%:*}" - for pat in "${(s.:.)i#*:}"; do - if [[ ( "$pat" = _* && "$func" = ${~pat%%\=*} ) || - "$cmd" = ${~pat%%\=*} ]]; then - prio="${pat#*\=}" - [[ "$prio" = -* ]] && continue 2 - - if [[ "$prio" = *\[*\] ]]; then - style="${(M)prio%%\[*}" - prio="${prio%%\[*}" - else - style='' - fi - [[ ${override_tags[$tag]} = (|+)\[* ]] && - style="${override_tags[$tag]#+}" - - (( prio++ )) - - tags[$prio]="${tags[$prio]}:${tag}${style}" - break - fi - done - done +local prev - prios=( "${(@)tags:#}" ) +# A `--' as the first argument says that we should tell comptags to use +# the preceding function nesting level. This is only documented here because +# if everythings goes well, users won't have to worry about it and should +# not mess with it. - return 0 +if [[ "$1" = -- ]]; then + prev=- + shift fi -_failed_tags=( "$_failed_tags[@]" "$_last_tags[@]" ) +if (( $# )); then + + # We have arguments: the tags supported in this context. + + local curcontext="$curcontext" order tag nodef tmp + + if [[ "$1" = -C?* ]]; then + curcontext="${curcontext%:*}:${1[3,-1]}" + shift + elif [[ "$1" = -C ]]; then + curcontext="${curcontext%:*}:${2}" + shift 2 + else + targs=() + fi + + [[ "$1" = -(|-) ]] && shift -(( $#prios )) || return 1 + if zstyle -a ":completion:${curcontext}:" group-order order; then + local name -tags="${prios[1]}:" -shift 1 prios + for name in "$order[@]"; do + compadd -J "$name" + compadd -V "$name" + compadd -J "$name" -1 + compadd -V "$name" -1 + compadd -J "$name" -2 + compadd -V "$name" -2 + done + fi + + # Set and remember offered tags. + + comptags "-i$prev" "$curcontext" "$@" + + # Sort the tags. + + if [[ -n "$_sort_tags" ]]; then + "$_sort_tags" "$@" + else + zstyle -a ":completion:${curcontext}:" tag-order order || + order=('arguments values' options) + + for tag in $order; do + case $tag in + -) nodef=yes;; + *\(\)) if ! "${${tag%%[ ]#\(\)}##[ ]#}" "$@"; then + nodef=yes + break + fi + ;; + \!*) comptry "${(@)argv:#(${(j:|:)~${=~tag[2,-1]}})}";; + ?*) comptry -m "$tag";; + esac + done + + [[ -z "$nodef" ]] && comptry "$@" + fi + + # Return non-zero if at least one set of tags should be used. + + comptags "-T$prev" + + return +fi -_last_tags=( "${(@s.:.)${${tags#:}%:}}" ) -_tried_tags=( "$_tried_tags[@]" "$_last_tags[@]" ) +# The other mode: switch to the next set of tags. -return 0 +comptags "-N$prev" diff --git a/Completion/Core/_wanted b/Completion/Core/_wanted index 7baa3e724..32875ec57 100644 --- a/Completion/Core/_wanted +++ b/Completion/Core/_wanted @@ -1,6 +1,6 @@ #autoload -local targs +local targs gopt=-J if [[ "$1" = -C?* ]]; then targs=( -C "${1[3,-1]}" ) @@ -12,10 +12,22 @@ else targs=() fi -[[ "$1" = -(|-) ]] && shift +if [[ "$1" = -([12]|)[VJ] ]]; then + gopt="$1" + shift +fi + +if [[ $# -gt 3 ]]; then + if _tags "$targs[@]" "$1"; then + _comp_tags="$_comp_tags $1" -if [[ $# -gt 1 ]]; then - _tags "$targs[@]" "$1" && _description "${(@)argv[2,-1]}" + _all_labels -t "$gopt" "$@" + else + return 1 + fi +elif [[ $# -gt 1 ]]; then + _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1" && + _description "$gopt" "$@" else - _tags "$targs[@]" "$1" + _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1" fi diff --git a/Completion/Core/compdump b/Completion/Core/compdump index 8be096f50..3cccbd06e 100644 --- a/Completion/Core/compdump +++ b/Completion/Core/compdump @@ -1,4 +1,4 @@ -# This is a file to be sourced to dump the definitions for new-style +# This is a function to dump the definitions for new-style # completion defined by 'compinit' in the same directory. The output # should be directed into the "compinit.dump" in the same directory as # compinit. If you rename init, just stick .dump onto the end of whatever @@ -9,33 +9,46 @@ # To do this, simply remove the .dump file, start a new shell, and # create the .dump file as before. Again, compinit -d handles this # automatically. -# -# It relies on KSH_ARRAYS not being set. # Print the number of files used for completion. This is used in compinit # to see if auto-dump should re-dump the dump-file. -_d_file=${COMPDUMP-${0:h}/compinit.dump} +emulate -L zsh +setopt extendedglob + +typeset _d_file _d_f _d_bks _d_line _d_als + +_d_file=${_comp_dumpfile-${0:h}/compinit.dump}.$HOST.$$ typeset -U _d_files -_d_files=( ${^~fpath}/_*~*~(N:t) ) +_d_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) ) print "#files: $#_d_files" > $_d_file -unset _d_files - # First dump the arrays _comps and _patcomps. The quoting hieroglyphyics # 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 - "'${_d_f//\'/'\\''}'" "'${_comps[$_d_f]//\'/'\\''}'" + print -r - "${(q)_d_f}" "${(q)_comps[$_d_f]}" done >> $_d_file print ")" >> $_d_file print "\n_patcomps=(" >> $_d_file -for _d_f in "$_patcomps[@]"; do - print -r - "'${_d_f//\'/'\\''}'" +for _d_f in "${(ok@)_patcomps}"; do + print -r - "${(q)_d_f}" "${(q)_patcomps[$_d_f]}" +done >> $_d_file +print ")" >> $_d_file + +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 + print -r - "${(q)_d_f}" "${(q)_compautos[$_d_f]}" done >> $_d_file print ")" >> $_d_file @@ -44,11 +57,13 @@ print >> $_d_file # Now dump the key bindings. We dump all bindings for zle widgets # whose names start with a underscore. # We need both the zle -C's and the bindkey's to recreate. +# We can ignore any zle -C which rebinds a standard widget (second +# argument to zle does not begin with a `_'). _d_bks=() zle -lL | while read -rA _d_line; do - if [[ ${_d_line[5]} = _* ]]; then + if [[ ${_d_line[3]} = _* && ${_d_line[5]} = _* ]]; then print -r - ${_d_line} _d_bks=($_d_bks ${_d_line[3]}) fi @@ -73,17 +88,26 @@ done)) # print them out: about five to a line looks neat +_i=5 +print -n autoload -U >> $_d_file while (( $#_d_als )); do - print -n autoload - for (( _i = 0; _i < 5; _i++ )); do - if (( $#_d_als )); then - print -n " $_d_als[1]" - shift _d_als + if (( ! $+_compautos[$_d_als[1]] )); then + print -n " $_d_als[1]" + if (( _i-- && $#_d_als > 1 )); then + _i=5 + print -n '\nautoload -U' fi - done - print + fi + shift _d_als done >> $_d_file print >> $_d_file -unset _d_line _d_zle _d_bks _d_als _d_f _f_file +for _i in "${(ok@)_compautos}"; do + print "autoload -U $_compautos[$_i] $_i" >> $_d_file +done + +mv $_d_file ${_d_file%.$HOST.$$} + +unfunction compdump +autoload -U compdump diff --git a/Completion/Core/compinit b/Completion/Core/compinit index ec5867838..6a35d17a7 100644 --- a/Completion/Core/compinit +++ b/Completion/Core/compinit @@ -1,25 +1,23 @@ # Initialisation for new style completion. This mainly contains some helper -# function and aliases. Everything else is split into different files in this -# directory that will automatically be made autoloaded (see the end of this -# file). +# functions and aliases. Everything else is split into different files that +# will automatically be made autoloaded (see the end of this file). # The names of the files that will be considered for autoloading have to -# start with a underscores (like `_setopt). +# start with an underscores (like `_setopt'). # The first line of these files will be read and has to say what should be # done with its contents: # -# `#defcomp <names ...>' -# 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 <name> is given +# `#compdef <names ...>' +# 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 <names> are given. # -# `#defpatcomp <pattern>' -# this defines a function that should be called to generate -# matches for commands whose name matches <pattern>; note -# that only one pattern may be given +# `#compdef -p <pattern>' +# This defines a function that should be called to generate matches +# for commands whose name matches <pattern>. Note that only one pattern +# may be given. # -# `#defkeycomp <style> [ <key-sequence> ... ] -# this is used to bind special completions to all the given +# `#compdef -k <style> [ <key-sequence> ... ]' +# This is used to bind special completions to all the given # <key-sequence>(s). The <style> is the name of one of the built-in # completion widgets (complete-word, delete-char-or-list, # expand-or-complete, expand-or-complete-prefix, list-choices, @@ -29,35 +27,89 @@ # rather than by the context. The widget has the same name as # the autoload file and can be bound using bindkey in the normal way. # -# `#autoload' -# this is for helper functions that are not used to +# `#compdef -K <widget-name> <style> <key-sequence> [ ... ]' +# This is similar to -k, except it takes any number of sets of +# three arguments. In each set, the widget <widget-name> will +# be defined, which will behave as <style>, as with -k, and will +# be bound to <key-sequence>, exactly one of which must be defined. +# <widget-name> must be different for each: this must begin with an +# underscore, else one will be added, and should not clash with other +# completion widgets (names based on the name of the function are the +# clearest), but is otherwise arbitrary. It can be tested in the +# function by the parameter $WIDGET. +# +# `#autoload [ <options> ]' +# This is for helper functions that are not used to # generate matches, but should automatically be loaded -# when they are called +# when they are called. The <options> will be given to the +# autoload builtin when making the function autoloaded. Note +# that this need not include `-U'. # # Note that no white space is allowed between the `#' and the rest of # the string. # -# See the file `compdump' for how to speed up initialiation. -# -# If you are using global matching specifications with `compctl -M ...' -# have a look at the files `_match_test' and `_match_pattern'. To make -# all the example functions use matching as specified with `-M' these -# need some editing. +# Functions that are used to generate matches should return zero if they +# were able to add matches and non-zero otherwise. # +# See the file `compdump' for how to speed up initialisation. + # If we got the `-d'-flag, we will automatically dump the new state (at -# the end). +# the end). This takes the dumpfile as an argument. -d (with the +# default dumpfile) is now the default; to turn off dumping use -D. + +emulate -L zsh +setopt extendedglob + +typeset _i_dumpfile _i_files _i_line _i_done _i_dir _i_autodump=1 +typeset _i_tag _i_file _i_addfiles + +while [[ $# -gt 0 && $1 = -[dDf] ]]; do + if [[ "$1" = -d ]]; then + _i_autodump=1 + shift + if [[ $# -gt 0 && "$1" != -[df] ]]; then + _i_dumpfile="$1" + shift + fi + elif [[ "$1" = -D ]]; then + _i_autodump=0 + shift + elif [[ "$1" = -f ]]; then + # Not used any more; use _compdir + shift + shift + fi +done -if [[ "$1" = -d ]]; then - _i_autodump=1 +# The associative array containing the definitions for the commands. +# Definitions for patterns will be stored in the associations `_patcomps' +# and `_postpatcomps'. `_compautos' contains the names and options +# for autoloaded functions that get options. + +typeset -gA _comps _patcomps _postpatcomps _compautos + +# The associative array use to report information about the last +# cmpletion to the outside. + +typeset -gA _lastcomp + +# Remember dumpfile. +if [[ -n $_i_dumpfile ]]; then + # Explicitly supplied dumpfile. + _comp_dumpfile="$_i_dumpfile" else - _i_autodump=0 + _comp_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump" fi -# The associative array containing the definitions for the commands. -# Definitions for patterns will be stored in the normal array `_patcomps'. +# These can hold names of functions that are to be called before/after all +# matches have been generated. -typeset -A _comps -_patcomps=() +compprefuncs=() +comppostfuncs=() + +# Loading it now ensures that the `funcstack' parameter is always correct. + +: $funcstack # This function is used to register or delete completion functions. For # registering completion functions, it is invoked with the name of the @@ -70,6 +122,9 @@ _patcomps=() # function will be invoked when completing for a command whose name # matches the pattern given as argument after the function name (in this # case only one argument is accepted). +# 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. # With the `-k' option a function for a special completion keys is # defined and immediatly bound to those keys. Here, the extra arguments # are the name of one of the builtin completion widgets and any number @@ -78,7 +133,8 @@ _patcomps=() # whose name is given as the first argument be autoloaded. When defining # a function for command names the `-n' option may be given and keeps # the definitions from overriding any previous definitions for the -# commands. +# commands; with `-k', the `-n' option prevents compdef from rebinding +# a key sequence which is already bound. # For deleting definitions, the `-d' option must be given. Without the # `-p' option, this deletes definitions for functions for the commands # whose names are given as arguments. If combined with the `-p' option @@ -110,11 +166,16 @@ compdef() { # Get the options. - while getopts "anpkd" opt; do + if [[ $#* -eq 0 ]]; then + echo "compdef needs parameters" + return 1 + fi + + while getopts "anpPkKd" opt; do case "$opt" in a) autol=yes;; n) new=yes;; - [pk]) if [[ -n "$type" ]]; then + [pPkK]) if [[ -n "$type" ]]; then # Error if both `-p' and `-k' are given (or one of them # twice). echo "$0: type already set to $type" @@ -122,6 +183,10 @@ compdef() { fi if [[ "$opt" = p ]]; then type=pattern + elif [[ "$opt" = P ]]; then + type=postpattern + elif [[ "$opt" = K ]]; then + type=widgetkey else type=key fi @@ -131,12 +196,17 @@ compdef() { done shift OPTIND-1 + if [[ $#* -eq 0 ]]; then + echo "compdef needs parameters" + return 1 + fi + if [[ -z "$delete" ]]; then # Adding definitions, first get the name of the function name # and probably do autoloading. func="$1" - [[ -n "$autol" ]] && autoload "$func" + [[ -n "$autol" ]] && autoload -U "$func" shift case "$type" in @@ -145,11 +215,33 @@ compdef() { echo "$0: only one pattern allowed" return 1 fi - # Patterns are stored in strings like `c* foo', with a space - # between the pattern and the function name. - - _patcomps=("$_patcomps[@]" "$1 $func") + _patcomps[$1]="$func" ;; + postpattern) + if [[ $# -gt 1 ]]; then + echo "$0: only one pattern allowed" + return 1 + fi + _postpatcomps[$1]="$func" + ;; + widgetkey) + while [[ -n $1 ]]; do + if [[ $# -lt 3 ]]; then + echo "$0: compdef -K requires <widget> <comp-widget> <key>" + return 1 + fi + [[ $1 = _* ]] || 1="_$1" + [[ $2 = .* ]] || 2=".$2" + zle -C "$1" "$2" "$func" + if [[ -n $new ]]; then + bindkey "$3" | read -A opt + [[ $opt[-1] = undefined-key ]] && bindkey "$3" "$1" + else + bindkey "$3" "$1" + fi + shift 3 + done + ;; key) if [[ $# -lt 2 ]]; then echo "$0: missing keys" @@ -157,30 +249,44 @@ compdef() { fi # Define the widget. - zle -C "$func" "$1" "$func" + if [[ $1 = .* ]]; then + zle -C "$func" "$1" "$func" + else + zle -C "$func" ".$1" "$func" + fi shift # And bind the keys... for i; do + if [[ -n $new ]]; then + bindkey "$i" | read -A opt + [[ $opt[-1] = undefined-key ]] || continue + fi bindkey "$i" "$func" done ;; *) # For commands store the function name in the `_comps' # associative array, command names as keys. - for i; do - [[ -z "$new" || "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func" - done + if [[ -z "$new" ]]; then + for i; do + _comps[$i]="$func" + done + else + for i; do + [[ "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func" + done + fi ;; esac else # Handle the `-d' option, deleting. case "$type" in pattern) - # Note the space. - for i; do - _patcomps=("${(@)patcomps:#$i *}") - done + unset "_patcomps[$^@]" + ;; + postpattern) + unset "_postpatcomps[$^@]" ;; key) # Oops, cannot do that yet. @@ -189,81 +295,210 @@ compdef() { return 1 ;; *) - # Deleting definitons for command is even simpler. - for i; do - unset "_comps[$i]" - done + unset "_comps[$^@]" esac fi } -# Now we automatically make the definition files autoloaded. +# Do *not* use this... -# First we get the name of a dump file if this will be used. +compconf() { -: ${COMPDUMP:=$0.dump} + local style name val i tmp cmt -if [[ ! -o extendedglob ]]; then - _i_noextglob=yes - setopt extendedglob -fi + if [[ -z "$_compconf_warn" ]]; then + _compconf_warn=yep + + print " + +Hello + +\`compconf' will be removed in the near future, we now use a more +general (and powerful) mechanism using the \`zstyle' builtin. An +approximation to your old setup using \`zstyle' should be available +in the file: + + \`${HOME}/.zsh-styles' + +Note that the values for the styles may be partly incorrect. Please +read the manual to find out how to configure the completion system +with styles. + +Have fun + + Sven +" 1>&2 + command rm -f ${HOME}/.zsh-styles + fi + + for i; do + name="${i%%\=*}" + val="${i#*\=}" + + tmp='' + cmt='' + + case "$name" in + urls_path) + tmp="'*:urls' path ${(qq)val}" + ;; + urls_localhttp) + tmp="'*:urls' local ${${(qqs.:.)val}}" + ;; + describe_options) + tmp="'*:options' verbose 'yes'" + ;; + describe_values) + tmp="'*:values' verbose 'yes'" + ;; + autodescribe_options) + tmp="'*:options' auto-description ${(qq)val}" + ;; + description_format) + tmp="'*:descriptions' format ${(qq)val}" + ;; + message_format) + tmp="'*:messages' format ${(qq)val}" + ;; + warning_format) + tmp="'*:warnings' format ${(qq)val}" + ;; + option_prefix) + tmp="'*:options' prefix-needed yes" + [[ "$val" = hide* ]] && + tmp="$tmp +zstyle ':completion:*:options' prefix-hidden yes" + ;; + group_matches) + tmp="'*' group-name ''" + ;; + colors_path) + tmp="'*:colors' path ${(qq)val}" + ;; + path_expand) + tmp="'*:paths' expand ${(qq)val}" + ;; + path_cursor) + tmp="'*:paths' cursor ${(qq)val}" + ;; + (approximate|incremental|predict|list|oldlist|match)_*) + tmp="'*${name%%_*}:*' ${${name#*_}//_/-} ${(qq)val}" + ;; + correct_*) + cmt="# This one is a bit ugly. You may want to use only \`*:correct' +# if you also have the \`correctword_*' or \`approximate_*' keys. +" + tmp="'*(correct(|-word)|approximate):*' ${name#*_} ${(qq)val}" + ;; + correctword_*) + tmp="'*:correct-word' ${name#correctword_} ${(qq)val}" + ;; + expand_*) + cmt="# This one is a bit ugly. You may want to use only \`*:expand' +# if you also have the \`expandword_*' keys. +" + tmp="'*expand(|expand-word):*' ${name#*_} ${(qq)val}" + ;; + expandword_*) + tmp="'expand-word:*' ${name#expandword_} ${(qq)val}" + ;; + history_*) + tmp="'history-words:*' ${name#history_} ${(qq)val}" + ;; + completer) + tmp="'*' completer ${${(qqs.:.)val}}" + ;; + last_prompt) + tmp="'*' last-prompt 'yes'" + ;; + esac + [[ -n "$tmp" ]] && style="${style}${cmt}zstyle :completion:${tmp} +" + done + + eval "${style}" + + print "$style" >>! ${HOME}/.zsh-styles +} + +# Now we automatically make the definition files autoloaded. typeset -U _i_files -_i_files=( ${^~fpath}/_*~*~(N:t) ) -_i_initname=$0 +_i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) ) +if [[ $#_i_files -lt 20 || $_compdir = */Core || -d $_compdir/Core ]]; then + # Too few files: we need some more directories, + # or we need to check that all directories (not just Core) are present. + if [[ -n $_compdir ]]; then + _i_addfiles=() + if [[ $_compdir = */Core ]]; then + # Add all the Completion subdirectories + _i_addfiles=(${_compdir:h}/*(/)) + elif [[ -d $_compdir/Core ]]; then + # Likewise + _i_addfiles=(${_compdir}/*(/)) + fi + for _i_line in {1..$#i_addfiles}; do + _i_file=${_i_addfiles[$_i_line]} + [[ -d $_i_file && -z ${fpath[(r)$_i_file]} ]] || + _i_addfiles[$_i_line]= + done + fpath=($fpath $_i_addfiles) + _i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) ) + fi +fi + + +# Rebind the standard widgets +for _i_line in complete-word delete-char-or-list expand-or-complete \ + expand-or-complete-prefix list-choices menu-complete \ + menu-expand-or-complete reverse-menu-complete; do + zle -C $_i_line .$_i_line _main_complete +done +zle -la menu-select && zle -C menu-select .menu-select _main_complete + _i_done='' +# Make sure compdump is available, even if we aren't going to use it. +autoload -U compdump compinstall + # If we have a dump file, load it. -if [[ -f "$COMPDUMP" ]]; then - read -rA _i_line < "$COMPDUMP" +if [[ -f "$_comp_dumpfile" ]]; then + read -rA _i_line < "$_comp_dumpfile" if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then - builtin . "$COMPDUMP" + builtin . "$_comp_dumpfile" _i_done=yes fi - unset _i_line fi if [[ -z "$_i_done" ]]; then for _i_dir in $fpath; do [[ $_i_dir = . ]] && continue - for _i_file in $_i_dir/_*~*~(N); do + for _i_file in $_i_dir/^([^_]*|*~|*.zwc)(N); do read -rA _i_line < $_i_file _i_tag=$_i_line[1] shift _i_line - if [[ $_i_tag = '#defcomp' ]]; then - compdef -na "${_i_file:t}" "${_i_line[@]}" - elif [[ $_i_tag = '#defpatcomp' ]]; then - compdef -pa "${_i_file:t}" "${_i_line[@]}" - elif [[ $_i_tag = '#defkeycomp' ]]; then - compdef -ka "${_i_file:t}" "${_i_line[@]}" - elif [[ $_i_tag = '#autoload' ]]; then - autoload ${_i_file:t} - fi + case $_i_tag in + (\#compdef) + if [[ $_i_line[1] = -[pPkK](n|) ]]; then + compdef ${_i_line[1]}na "${_i_file:t}" "${(@)_i_line[2,-1]}" + else + compdef -na "${_i_file:t}" "${_i_line[@]}" + fi + ;; + (\#autoload) + autoload -U "$_i_line[@]" ${_i_file:t} + [[ "$_i_line" != \ # ]] && _compautos[${_i_file:t}]="$_i_line" + ;; + esac done done - bindkey | - while read -rA _i_line; do - if [[ "$_i_line[2]" = complete-word || - "$_i_line[2]" = delete-char-or-list || - "$_i_line[2]" = expand-or-complete || - "$_i_line[2]" = expand-or-complete-prefix || - "$_i_line[2]" = list-choices || - "$_i_line[2]" = menu-complete || - "$_i_line[2]" = menu-expand-or-complete || - "$_i_line[2]" = reverse-menu-complete ]]; then - zle -C _complete_$_i_line[2] $_i_line[2] _main_complete - bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2] - fi - done - - unset _i_dir _i_line _i_file _i_tag - # If autodumping was requested, do it now. - (( _i_autodump )) && builtin . ${_i_initname:h}/compdump + if [[ $_i_autodump = 1 ]]; then + compdump + fi fi -[[ -z "$_i_noextglob" ]] || unsetopt extendedglob - -unset _i_files _i_initname _i_done _i_autodump _i_noextglob +unfunction compinit +autoload -U compinit diff --git a/Completion/Core/compinstall b/Completion/Core/compinstall index d96121cf2..ad05cb5a1 100644 --- a/Completion/Core/compinstall +++ b/Completion/Core/compinstall @@ -1,72 +1,149 @@ -# This script is to be run by a user to setup the new function based +# This script is to be run by a user to set up the new function based # completion system. The functions themselves are assumed to be already # available in some directory; they should have been installed with the -# the shell (except we haven't written that yet). +# the shell. If they have been, the commands `autoload -U compinit; compinit' +# in the shell startup file should be enough, although you can run +# compinstall for more configuration choices. # -# Run it as a script under zsh and answer the questions. -# You can run it as `zsh compinstall $FPATH' and it will be able to check -# your function path for the completion functions. -# -# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it), -# but you can make that unwritable and it will leave the lines in a -# temporary file instead. -# -# You can use this script to modify what compinstall previously -# added to ~/.zshrc. +# Simply run this script as a function and answer the questions. +# Normally it will alter ~/.zshrc (or wherever ZDOTDIR puts it), but you +# can make that unwritable and it will leave the lines in a temporary file +# instead. It doesn't matter if .zshrc didn't exist before. If your +# .zshrc usually exits before the end, then you should take the code added +# by compinstall and put it (including the comment lines at the start and +# end) at the point you want it to be executed. If you run compinstall +# again it will find and replace those lines, so you can use this script to +# modify what compinstall previously added to ~/.zshrc. # # It is safe to abort with ^C any time you are being prompted for # information; your .zshrc will not be altered. # # To do: -# - Maybe this should be sourced, then it can check the user's current -# setup better. But then there is a potentially horrendous option -# setting/resetting problem. (Maybe we need another way of doing that.) # - Should probably offer to set different options for _approximate than # for _complete if both are used. # - Could add code for setting other completers and options. # - Could add keys for context-sensitive help. -# - Probably should allow a set of directories to be added to $fpath, -# like Core, Base, etc. -# In case a startup script changed options -emulate zsh -[[ -n $1 ]] && FPATH=$1 +emulate -L zsh -for f in $fpath; do - if [[ $f != . && -f $f/compinit && -f $f/compdump ]]; then - fdir=$f - break - fi -done +typeset _ci_options _ci_f _ci_fdir _ci_files _ci_dumpfile _ci_lines +typeset _ci_type _ci_completer _ci_accept _ci_cprompt _ci_startline +typeset _ci_endline _ci_ifile _ci_tmpf _ci_compstyle _ci_warn +typeset _ci_dtype _ci_existing _ci_line _ci_end -if [[ -z $fdir ]]; then - print "Trying to find where the completion functions are..." - if [[ $0 = */* && -f $0:h/compinit && -f $0:h/compdump ]]; then - fdir=$0:h - else - # more guesses? - print \ +# Look for the defaults. +_ci_startline='# The following lines were added by compinstall' +_ci_endline='# End of lines added by compinstall' + +_ci_ifile=${ZDOTDIR:-~}/.zshrc +_ci_lines='' +_ci_existing='' + +typeset -A _ci_defaults + +if [[ -f $_ci_ifile ]]; then + # This assumes the lines haven't been altered by the user too much + # after they were added. + _ci_compstyle=0 + sed -n "/^$_ci_startline/,/^$_ci_endline/p" $_ci_ifile | + while read -rA _ci_line; do + if (( $_ci_compstyle )); then + # parse a compstyle component as first argument + if [[ $_ci_line[-1] != \\ ]]; then + _ci_end=-1 + _ci_compstyle=0 + else + _ci_end=-2 + fi + if [[ $_ci_line[1] = *=* ]]; then + _ci_f="${${_ci_line[1,$_ci_end]}#*=}" + if [[ $_ci_f = \'*\' ]]; then + # strip quotes + _ci_f=${_ci_f[2,-2]//\'\\\'\'/\'} + fi + _ci_defaults[${_ci_line[1]%%\=*}]=$_ci_f + fi + _ci_existing="${_ci_existing} $_ci_line +" + elif [[ $_ci_line[1] = compinit ]]; then + # parse the line running compinit + [[ $_ci_line[2] = -f ]] && _ci_fdir=$_ci_line[3] + [[ $_ci_line[-2] = -d ]] && _ci_dumpfile=$_ci_line[-1] + elif [[ $_ci_line[1] = _compdir=* ]]; then + _ci_fdir=${_ci_line[1]##_compdir=} + elif [[ $_ci_line[1] = compstyle ]]; then + # parse a compstyle component as second argument (should be completer) + [[ $_ci_line[3] = completer ]] && + _ci_completer=${_ci_line[3,-1]} + [[ $_ci_line[-1] == \\ ]] && _ci_compstyle=1 + _ci_existing="${_ci_existing}$_ci_line +" + elif [[ $_ci_line[1] != \#* && $_ci_line[1] != (autoload|\[\[) ]]; then + if [[ -z $_ci_warn ]]; then + _ci_warn=1 + print "Warning: existing lines in compinstall setup not understood:" + fi + print - $_ci_line + _ci_existing="${_ci_existing}$_ci_line +" + fi + done +fi + + +# Find out where the completion functions are kept. + +if [[ -z $_ci_fdir || ! -f ${~_ci_fdir}/compinit || + ! -f ${~_ci_fdir}/compdump ]]; then + for _ci_f in $fpath; do + if [[ $_ci_f != . && -f $_ci_f/compinit && -f $_ci_f/compdump ]]; then + _ci_fdir=$_ci_f + break + elif [[ $_ci_f != . && -f $_ci_f/Core/compinit && + -f $_ci_f/Core/compdump ]] + then + _ci_fdir=$_ci_f/Core + break + fi + done +fi + +if [[ -z $_ci_fdir || ! -d ${~_ci_fdir} ]]; then + print \ "Please edit the name of the directory where the completion functions are installed. If they are not installed, you will need to find them in the Completion/* directories of the zsh distribution and install them yourself, or insult your system manager for incompetence." - vared -c fdir - while [[ ! -d ${~fdir} || ! -f ${~fdir}/compinit || - ! -f ${~fdir}/compdump ]]; do - print "I can't find them in that directory. Try again or abort." - vared fdir - done + vared -c _ci_fdir + while [[ ! -d ${~_ci_fdir} || + ((! -f ${~_ci_fdir}/compinit || ! -f ${~_ci_fdir}/compdump) && + (! -f ${~_ci_fdir}/Core/compinit || ! -f ${~_ci_fdir}/Core/compdump)) ]] + do + print "I can't find them in that directory. Try again or abort." + vared _ci_fdir + done + if [[ -f ${~_ci_fdir}/Core/compinit && ! -f ${~_ci_fdir}/compinit ]]; then + _ci_fdir=$_ci_fdir/Core fi - eval "fpath=($fdir \$fpath)" - fdir=${fdir/#$HOME/\~} - lines="fpath=($fdir \$fpath)\n" else - print "Found completion functions in your fpath, will not alter it." + print "Keeping existing completion directiory $_ci_fdir" +fi + +if [[ ${~_ci_fdir} != /* ]]; then + _ci_fdir=$(cd $_ci_fdir;builtin pwd) fi -files=( ${^~fpath:/.}/_(|*[^~])(N:t) ) -if [[ $#files -lt 20 ]]; then +# Check if this is in fpath already, else put it there (with ~'s expanded). +_ci_f=${~_ci_fdir} +[[ -z ${fpath[(r)$_ci_f]} ]] && fpath=($fpath $_ci_f) + +# Contract $HOME to ~ in the parameter to be used for writing. +_ci_fdir=${_ci_fdir/#$HOME/\~} + +# Now check the fpath, ignoring the directory . +_ci_files=( ${^~fpath:/.}/_(|*[^~])(N:t) ) +if [[ $#_ci_files -lt 20 ]]; then print " Hmmm, completion functions seem a bit thin on the ground. There should be lots of files with names beginning with an underscore (_). You should @@ -75,12 +152,20 @@ look and see what's happened to these. read fi -if [[ -w ${~fdir} && ( ! -f ${~fdir}/compinit.dump || - -w ${~fdir}/compinit.dump ) ]] + +# Set up the dumpfile +_ci_dtype=existing +if [[ -z $_ci_dumpfile ]]; then + _ci_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump" + _ci_dtype=standard +fi + +if [[ -w ${~_ci_dumpfile:h} && ( ! -f ${~_ci_dumpfile} || + -w ${~_ci_dumpfile} ) ]] then print " -Using standard dumpfile - ${~fdir}/compinit.dump +Using $_ci_dtype dumpfile + ${_ci_dumpfile} to speed up initialisation. [Hit return to continue]" read @@ -88,23 +173,32 @@ else print " I will force completion to dump its status, which will speed up the shell's start-up considerably. However, I can't write the file I'd like to, namely -$fdir/compinit.dump. Please edit a replacement." - dumpfile='~/.compinit.dump' - vared dumpfile - while ! touch ${~dumpfile} >& /dev/null; do +${_ci_dumpfile}. Please edit a replacement." + vared _ci_dumpfile + while ! touch ${~_ci_dumpfile} >& /dev/null; do print "Sorry, I can't write that either. Try again." - vared dumpfile + vared _ci_dumpfile done - [[ -s $dumpfile ]] || rm -f $dumpfile - dumpfile=" $dumpfile" + [[ -s $_ci_dumpfile ]] || rm -f $_ci_dumpfile fi -fdir=${fdir/#$HOME/\~} - -lines="${lines}. $fdir/compinit -d$dumpfile\n" +_ci_lines="${_ci_lines}_compdir=$_ci_fdir +[[ -z \$fpath[(r)\$_compdir] ]] && fpath=(\$fpath \$_compdir) +autoload -U compinit +compinit" +[[ $_ci_dtype != standard ]] && _ci_lines="${_ci_lines} $_ci_dumpfile" +_ci_lines="${_ci_lines} +" print " +Would you like to set some more advanced options? Otherwise, you +can re-run compinstall later to set these. [n]" + +# The whole of the next part should be indented, but I can't be bothered. +if read -q; then + + print " In addition to completion, zsh can also perform correction of the current word, or approximate completion, i.e. completion where the part of the word typed so far can be corrected; or it can try correction, then @@ -112,105 +206,156 @@ approximate completion if that fails. Would you like: 0: Just ordinary completion C: Correction A: Approximate completion - B: Both? -Please type one of the keys above:" -while read -k type; do - print - case $type in - 0*) completer=_complete - break - ;; - [cC]*) completer=_complete:_correct - break - ;; - [aA]*) completer=_complete:_approximate - break; - ;; - [bB]*) completer=_complete:_correct:_approximate - break - ;; - *) print Try again - ;; - esac -done - -lines="${lines}compconf completer=$completer" - - -if [[ $completer = *(correct|approx)* ]]; then - print " -Correction and approximation will normally allow up to two errors, -and you will be able to use a numeric prefix (e.g. <Esc>4) to allow -more. The standard prompt is \`correct to:'. Do you want to change -any of this? [n]" - if read -q; then - print "Number of errors to accept normally (0 is OK):" - read accept - while [[ $accept != <-> ]]; do - read accept"?Please enter a number: " - done - print \ + B: Both" + if [[ -n $_ci_completer ]]; then + print " Default: use the current completers:\n$_ci_completer" + else + print "Please type one of the keys above." + fi + while read -k _ci_type; do + print + case $_ci_type in + 0*) _ci_completer=_complete + break + ;; + [cC]*) _ci_completer='_complete _correct' + break + ;; + [aA]*) _ci_completer='_complete _approximate' + break; + ;; + [bB]*) _ci_completer='_complete _correct _approximate' + break + ;; + *) [[ -n $_ci_completer ]] && break + print Try again + ;; + esac + done + + _ci_lines="${_ci_lines}zstyle ':completion*' completer $_ci_completer" + + + if [[ $_ci_completer = *(correct|approx)* ]]; then + _ci_accept=${_ci_defaults[correct_accept]} + _ci_cprompt=${_ci_defaults[correct_prompt]} + print " +Correction and approximation will allow up to ${${_ci_accept:-2}%%[^0-9]*} \ +errors. " + case $_ci_accept in + *n*!*|*!*n) print "A numeric prefix, if not 1, will cause correction \ +not to be done." + ;; + *n*) print "A numeric prefix gives the maximum number of errors which \ +will be accepted." + ;; + *) print "The numeric prefix will not be used." + esac +print "The correction prompt is \`${_ci_cprompt:-correct to:}'. +Do you want to change any of this? [n]" + if read -q; then + print "Number of errors to accept normally (0 is OK):" + _ci_accept=${_ci_accept%%[^0-9]*} + vared _ci_accept + while [[ $_ci_accept != <-> ]]; do + print "Please enter a number:" + vared _ci_accept + done + print \ "How would you like the numeric prefix to be treated: 0: Not used by correction - U: Used to given the number of errors + U: The number gives the largest number of errors which will be + accepted when correcting I: If present, and not 1, do not perform correction? Please type one of the keys above:" - while read -k type; do - print - case $type in - 0*) break - ;; - [uU]*) accept="${accept}n" - break - ;; - [Ii]*) accept="${accept}!n" - break - ;; - *) print Try again - ;; - esac - done - lines="$lines \\\\ - correct_accept='$accept'" - print " + while read -k _ci_type; do + print + case $_ci_type in + 0*) break + ;; + [uU]*) _ci_accept="${_ci_accept}n" + break + ;; + [Ii]*) _ci_accept="${_ci_accept}!n" + break + ;; + *) print Try again + ;; + esac + done + print " Instead of the prompt \`correct to:', you can have no prompt, or a prompt of your choosing which can display the number of errors found by containing the string \`%e'. Do you wish to change the correction prompt? [n]" - if read -q; then - cprompt='' - print "Edit a new prompt (may be empty):" - vared cprompt - lines="$lines \\\\ - correct_prompt='${cprompt//\'/\'\\\'\'}'" + if read -q; then + print "Edit a new prompt (may be empty):" + vared _ci_cprompt + [[ -z $_ci_cprompt ]] && _ci_cprompt=':empty:' + fi + fi + if [[ -n $_ci_accept ]]; then + _ci_lines="$_ci_lines \\ + correct_accept='$_ci_accept'" + unset '_ci_defaults[correct_accept]' + fi + if [[ -n $_ci_cprompt ]]; then + _ci_cprompt=${_ci_cprompt##:empty:} + _ci_lines="$_ci_lines \\ + correct_prompt='${_ci_cprompt//\'/\'\\\'\'}'" + unset '_ci_defaults[correct_prompt]' fi fi -fi -lines="$lines\n" + _ci_warn='' + for _ci_f in ${(k)_ci_defaults}; do + if [[ -z $_ci_warn ]]; then + print " +(Keeping other existing configuration settings...)" + _ci_warn=1 + fi + _ci_lines="$_ci_lines \\ + ${_ci_f}='${_ci_defaults[$_ci_f]//\'/\'\\\'\'}'" + done + _ci_lines="$_ci_lines +" -startline='# The following lines were added by compinstall' -endline='# End of lines added by compinstall' +else -ifile=${ZDOTDIR:-~}/.zshrc -[[ -f $ifile ]] || touch $ifile -tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$ + if [[ -n $_ci_existing ]]; then + print -nr " +I will retain the following lines from the existing completion setup: +$_ci_existing" + _ci_lines="$_ci_lines${_ci_existing}" + fi + +fi # End of advanced options -if [[ ! -w $ifile ]]; then - print "\nI can't write to $ifile. I will leave the lines to add in -\`$tmpf' and you must add them by hand." - print "\n$startline\n$lines\n$endline" >$tmpf - return 0 -fi -if grep $endline $ifile >& /dev/null; then - print -- "$startline\n$lines$endline" >$tmpf - sed -e "/^$endline/r $tmpf -/^$startline/,/^$endline/d" $ifile >${tmpf}2 && mv ${tmpf}2 $ifile && - print "\nSuccesfully modified old compinstall lines in $ifile." - rm -f $tmpf ${tmpf}2 +[[ -f $_ci_ifile ]] || touch $_ci_ifile +_ci_tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$ + +if [[ ! -w $_ci_ifile ]]; then + print "\nI can't write to $_ci_ifile. I will leave the lines to add in +\`$_ci_tmpf' and you must add them by hand." + print -r - "$_ci_startline +$_ci_lines$_ci_endline" >$_ci_tmpf +elif grep $_ci_endline $_ci_ifile >& /dev/null; then + print -r - "$_ci_startline +$_ci_lines$_ci_endline" >$_ci_tmpf + sed -e "/^$_ci_endline/r $_ci_tmpf +/^$_ci_startline/,/^$_ci_endline/d" $_ci_ifile >${_ci_tmpf}2 && + mv ${_ci_tmpf}2 $_ci_ifile && + print "\nSuccesfully modified old compinstall lines in $_ci_ifile." + rm -f $_ci_tmpf ${_ci_tmpf}2 else - print "\n$startline\n$lines\n$endline" >>$ifile && - print "\nSuccessfully appended lines to $ifile." + print -r - "$_ci_startline +$_ci_lines$_ci_endline" >>$_ci_ifile && + print "\nSuccessfully appended lines to $_ci_ifile." fi + +unfunction compinstall +autoload -U compinstall + +return 0 diff --git a/Completion/Linux/_rpm b/Completion/Linux/_rpm index 7fdc80ab0..9ef2d57d9 100644 --- a/Completion/Linux/_rpm +++ b/Completion/Linux/_rpm @@ -3,7 +3,7 @@ # 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 +# function exists, we return with its return status immediately. This # allows users to override the default completions by simply defining # these functions. # The states (and possible values for the `<state>' above) are: @@ -43,28 +43,36 @@ local ret=1 tmp expl # Used by `_arguments', made local here. -local state lstate line -tyeset -A options +local curcontext="$curcontext" state lstate line +typeset -A opt_args state='' # Do simple completions or get the first state. -_arguments \ +_arguments -C -s \ '--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' \ + '-q+[query mode]:*:query:->query' \ + '*-v[verbose mode]' \ + --{setperms,setugids,querytags,initdb,showrc} \ + '--pipe:pipe command:_command_names -e' \ + -{V,y}'[verify mode]:*:verify:->verify' \ + '--verify[verify mode]:*:verify:->verify' \ + '-i+[install mode]:*:install:->install' \ + '--install:*:install:->install' \ + '-U+[upgrade mode]:*:upgrade:->upgrade' \ + '--upgrade:*:upgrade:->upgrade' \ + '-F+[freshen mode]:*:upgrade:->upgrade' \ + '--freshen:*:upgrade:->upgrade' \ + '-e+[uninstall mode]:*:uninstall:->uninstall' \ + '--erase:*:uninstall:->uninstall' \ + -'b+[build mode (spec file)]: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 mode (tar file)]: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' \ + '-K+[signature check mode]:*:sigcheck:->sigcheck' \ + '--checksig:*:sigcheck:->sigcheck' \ '--rebuilddb:*:rebuild:->rebuild' && ret=0 # As long as we have a state name... @@ -73,7 +81,7 @@ while [[ -n "$state" ]]; do # First try to call a user-defined function. - funcall ret _rpm_$state && return ret + _funcall ret _rpm_$state && return ret # Copy the state and reset `state', to simplify the test above. @@ -85,24 +93,24 @@ while [[ -n "$state" ]]; do case "$lstate" in query) - _arguments \ - -{v,vv} \ + _arguments -s \ + '*-v[verbose mode]' -q \ '--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' \ + '-f[specify file to query owner of]:file:_files' \ + '-p+[specify uninstalled package file to query]:*: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} \ + _arguments -s \ + '*-v[verbose mode]' '(-y)-V' '(-V)-y' \ '--rcfile:resource file:_files' \ '--ftpproxy:FTP proxy server:_hosts' \ '--ftpport:FTP port number:' \ @@ -112,15 +120,18 @@ while [[ -n "$state" ]]; do '*:RPM package:->package' && ret=0 ;; upgrade) - tmp=( --oldpackage ) + tmp=( -U --oldpackage ) ;& install) - _arguments "$tmp[@]" \ - -{v,vv} \ + (( $#tmp )) || tmp=(-i) + _arguments -s "$tmp[@]" \ + '*-v[verbose mode]' \ '--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} \ + '(-h)--hash' '(--hash)-h' \ + '(--replacepkgs --replacefiles --oldpackage)--force' \ + --{badreloc,excludedocs,allfiles,ignorearch,ignoreos,includedocs,justdb,nodeps,noorder,noscripts,notriggers,percent,replacefiles,replacepkgs,test} \ '--relocate:relocate:->relocate' \ '--prefix:package prefix directory:_files -/' \ '--root:RPM root directory:_files -/' \ @@ -128,8 +139,8 @@ while [[ -n "$state" ]]; do '*:pkg file:->package_file' && ret=0 ;; uninstall) - _arguments \ - -{v,vv} \ + _arguments -s \ + '*-v[verbose mode]' -e \ '--rcfile:resource file:_files' \ '--ftpproxy:FTP proxy server:_hosts' \ '--ftpport:FTP port number:' \ @@ -139,13 +150,13 @@ while [[ -n "$state" ]]; do '*:RPM package:->package' && ret=0 ;; build_b) - tmp=( '*:RPM package:->package' ) + tmp=( '*:spec file:_files -g \*.spec' ) ;& build_t) (( $#tmp )) || tmp=( '*:tar file:_files -g \*.\(\#i\)tar\(.\*\|\)' ) - _arguments \ - -{v,vv} \ + _arguments -s \ + '*-v[verbose mode]' \ '--rcfile:resource file:_files' \ '--ftpproxy:FTP proxy server:_hosts' \ '--ftpport:FTP port number:' \ @@ -156,8 +167,8 @@ while [[ -n "$state" ]]; do '--timecheck:time check (seconds):' "$tmp[1]" && ret=0 ;; sigcheck) - _arguments \ - -{v,vv} \ + _arguments -s \ + '*-v[verbose mode]' -K \ '--rcfile:resource file:_files' \ '--ftpproxy:FTP proxy server:_hosts' \ '--ftpport:FTP port number:' \ @@ -165,8 +176,8 @@ while [[ -n "$state" ]]; do '*:RPM package file:->package_or_file' && ret=0 ;; rebuild) - _arguments \ - -{v,vv} \ + _arguments -s \ + '*-v[verbose mode]' \ '--rcfile:resource file:_files' \ '--ftpproxy:FTP proxy server:_hosts' \ '--ftpport:FTP port number:' \ @@ -178,21 +189,23 @@ while [[ -n "$state" ]]; do state=package_file ;& package) - _description expl 'RPM package' - compadd "$expl[@]" -M 'r:|-=* r:|=*' - $(rpm -qa) && ret=0 + _wanted packages expl 'RPM package' \ + compadd -M 'r:|-=* r:|=*' - $(_call packages rpm -qa) && ret=0 ;; package_file) - if compset -P ftp:; then + if compset -P ftp://; then _hosts -S/ && ret=0 else - _files -g '*.(#i)rpm' && ret=0 + _alternative \ + 'files:RPM package file:_files -g \*.\(\#i\)rpm' \ + 'prefixes:ftp URL prefix:compadd ftp://' && 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 + _wanted tags expl 'RPM tag' \ + compadd -M 'm:{a-z}={A-Z}' -S '\}' - \ + "${(@)${(@f)$(_call tags rpm --querytags)}#RPMTAG_}" && ret=0 else _message 'RPM format' fi @@ -201,10 +214,10 @@ while [[ -n "$state" ]]; do _message 'RPM capability' ;; relocate) - if compset -P '*\='; then - _description expl 'new path' + if compset -P '*='; then + _description directories expl 'new path' else - _description expl 'old path' + _description directories expl 'old path' fi _files "$expl[@]" -/ && ret=0 diff --git a/Completion/User/_gdb b/Completion/User/_gdb index ff54e6a07..55e149bb7 100644 --- a/Completion/User/_gdb +++ b/Completion/User/_gdb @@ -1,36 +1,44 @@ #compdef gdb -# This uses the configuration keys `ps_args' and `ps_listargs' -# described in the `_wait' function. +local cur="$words[CURRENT]" prev w list ret=1 expl -local cur="$words[CURRENT]" prev w list ret=1 - -_long_options -t '*=(CORE|SYM)FILE' '_files' \ - '*=EXECFILE' '_files *(*)' \ - '*=TTY' 'compadd /dev/tty*' && return 0 +[[ "$PREFIX" = --* ]] && + _arguments -- '*=(CORE|SYM)FILE:core file:_files' \ + '*=EXECFILE:executable:_files \*\(-\*\)' \ + '*=TTY:terminal device:compadd /dev/tty\*' && return 0 if compset -P '-(cd|directory)='; then _files -/ elif compset -P '-tty='; then - compadd - /dev/tty* + _wanted devices expl 'terminal device' compadd - /dev/tty* elif compset -P '-(exec|se)='; then - _files -/g '*(*)' + _description files expl executable + _files "$expl[@]" -g '*(-*)' elif compset -P '-(symbols|core|command)='; then _files -elif compset -P -; then - compadd -QS '' - symbols\= exec\= se\= core\= command\= directory\= \ - cd\= tty\= - compadd - help h s e c x d nx n quiet q batch fullname f b +elif [[ "$PREFIX" = -* ]]; then + if _wanted options; then + while _next_label options expl option; do + compadd "$expl[@]" -QS '' - -symbols\= -exec\= -se\= -core\= -command\= \ + -directory\= -cd\= -tty\= && ret=0 + compadd "$expl[@]" - -help -h -s -e -c -x -d -nx -n -quiet -q \ + -batch -fullname -f -b && ret=0 + (( ret )) || return 0 + done + fi else prev="$words[CURRENT-1]" case "$prev" in - (-d) _files -/ && return 0 ;; - (-e) _files -/g '*(*)' && return 0 ;; + (-d) _files -/ && return 0 ;; (-[csx]) _files && return 0 ;; - (-b) compadd -V baud 0 50 75 110 134 150 200 300 600 1200 1800 2400 4800 \ - 9600 19200 38400 57600 115200 230400 && return 0 ;; + (-e) _description files expl executable + _files "$expl[@]" -g '*(-*)' && return 0 ;; + (-b) _wanted -V values expl 'baud rate' \ + compadd 0 50 75 110 134 150 200 300 600 1200 1800 2400 4800 \ + 9600 19200 38400 57600 115200 230400 && return 0 ;; esac + w=( "${(@)words[2,-1]}" ) while [[ "$w[1]" = -* ]]; do [[ "$w[1]" = -[decsxb] ]] && shift 1 w @@ -38,13 +46,9 @@ else done if [[ $#w -gt 1 ]]; then - _files && ret=0 - list=("${(F)${(@Mr:COLUMNS-1:)${(f)$(ps ${compconfig[ps_listargs]:-$compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ ]#${PREFIX}[0-9]#${SUFFIX}[ ]*${w[1]:t}}} -") - compadd -y list - ${${${(M)${(f)"$(ps $compconfig[ps_args] 2>/dev/null)"}:#*${w[1]:t}*}## #}%% *} && ret=0 - - return ret + _alternative 'files:: _files' "processes:: _pids -m ${w[1]:t}" else - _files -/g '*(*)' + _description files expl executable + _files "$expl[@]" -g '*(-*)' fi fi diff --git a/Completion/User/_getconf b/Completion/User/_getconf index 7ce709588..59e9a83bc 100644 --- a/Completion/User/_getconf +++ b/Completion/User/_getconf @@ -1,20 +1,19 @@ #compdef getconf -local expl +local expl ret=1 if [[ CURRENT -eq 2 ]]; then _tags syswideconfig pathconfig standardsconfig while _tags; do - if _requested -V syswideconfig expl 'systemwide configuration variables' - then - compadd "$expl[@]" -S '' ARG_MAX BC_BASE_MAX BC_DIM_MAX BC_SCALE_MAX \ + _requested -V syswideconfig expl 'systemwide configuration variables' \ + compadd -S '' ARG_MAX BC_BASE_MAX BC_DIM_MAX BC_SCALE_MAX \ BC_STRING_MAX CHILD_MAX COLL_WEIGHTS_MAX EXPR_NEST_MAX LINE_MAX \ - NGROUPS_MAX OPEN_MAX RE_DUP_MAX STREAM_MAX TZNAME_MAX - fi - if _requested -V standardsconfig \ - expl 'system-standards configuration variables'; then - compadd "$expl[@]" -S '' _POSIX_CHILD_MAX _POSIX_LINK_MAX \ + NGROUPS_MAX OPEN_MAX RE_DUP_MAX STREAM_MAX TZNAME_MAX && ret=0 + + _requested -V standardsconfig \ + expl 'system-standards configuration variables' \ + compadd -S '' _POSIX_CHILD_MAX _POSIX_LINK_MAX \ _POSIX_MAX_CANON _POSIX_MAX_INPUT _POSIX_NAME_MAX _POSIX_NGROUPS_MAX \ _POSIX_OPEN_MAX _POSIX_PATH_MAX _POSIX_PIPE_BUF _POSIX_SSIZE_MAX \ _POSIX_STREAM_MAX _POSIX_TZNAME_MAX _POSIX_VERSION \ @@ -22,15 +21,17 @@ if [[ CURRENT -eq 2 ]]; then POSIX2_BC_STRING_MAX POSIX2_COLL_WEIGHTS_MAX POSIX2_EXPR_NEST_MAX \ POSIX2_LINE_MAX POSIX2_RE_DUP_MAX POSIX2_VERSION POSIX2_C_BIND \ POSIX2_C_DEV POSIX2_FORT_DEV POSIX2_FORT_RUN POSIX2_LOCALEDEF \ - POSIX2_SW_DEV _XOPEN_VERSION - fi - if _requested -V pathconfig expl 'system path configuration variables' - then - compadd "$expl[@]" -S '' PIPE_BUF _POSIX_CHOWN_RESTRICTED \ - _POSIX_NO_TRUNC _POSIX_VDISABLE - compadd "$expl[@]" -S ' ' LINK_MAX MAX_CANON MAX_INPUT NAME_MAX PATH_MAX \ - PIPE_BUF - fi + POSIX2_SW_DEV _XOPEN_VERSION && ret=0 + + _requested pathconfig && + while _next_label -V pathconfig expl 'system path configuration variables'; do + compadd "$expl[@]" -S '' PIPE_BUF _POSIX_CHOWN_RESTRICTED \ + _POSIX_NO_TRUNC _POSIX_VDISABLE && ret=0 + compadd "$expl[@]" -S ' ' LINK_MAX MAX_CANON MAX_INPUT NAME_MAX \ + PATH_MAX PIPE_BUF && ret=0 + (( ret )) || break + done + (( ret )) || return 0 done else _files -/ diff --git a/Completion/User/_groups b/Completion/User/_groups index 975189174..27444d26d 100644 --- a/Completion/User/_groups +++ b/Completion/User/_groups @@ -1,6 +1,19 @@ #compdef newgrp -: ${(A)groups:=${${(s: :)$(</etc/group)}%%:*}} -# : ${(A)groups:=${${(s: :)$(ypcat group.byname)}%%:*}} # If you use NIS +local expl groups tmp -compadd $groups +_wanted groups || return 1 + +if ! zstyle -a ":completion:${curcontext}:" groups groups; then + (( $+_cache_groups )) || + if (( ${+commands[ypcat]} )) && + tmp=$(_call groups ypcat group.byname); then + : ${(A)_cache_groups:=${${(f)tmp}%%:*}} # If you use YP + else + : ${(A)_cache_groups:=${${(s: :)$(</etc/group)}%%:*}} + fi + + groups=( "$_cache_groups[@]" ) +fi + +_all_labels groups expl group compadd "$@" - "$groups[@]" diff --git a/Completion/User/_lp b/Completion/User/_lp index f37c62a14..cfa2a147c 100644 --- a/Completion/User/_lp +++ b/Completion/User/_lp @@ -1,50 +1,98 @@ #compdef lp lpr lpq lprm -local file expl ret=1 list disp strs shown +local expl ret=1 printer list disp strs shown if (( ! $+_lp_cache )); then + local file entry names i + file=( /etc/(printcap|printers.conf)(N) ) - if (( $#file )); then - _lp_cache=( "${(@)${(@s:|:)${(@)${(@f)$(< $file[1])}:#[ \#]*}%%:*}%%[ ]*}" ) - else - # Default value. Could probably be improved + _lp_cache=() + _lp_alias_cache=() - _lp_cache=( lp0 ) + if (( $#file )); then + while read entry; do + if [[ "$entry" = [^[:blank:]\#\*_]*:* ]]; then + names=( "${(s:|:)entry%%:*}" ) + if [[ "$entry" = *:description=* ]]; then + disp="${${entry##*:description=}%%:*}" + elif [[ $#names -gt 1 && "$names[-1]" = *\ * ]] ;then + disp="$names[-1]" + else + disp='' + fi + if [[ -n "$disp" ]]; then + _lp_cache=( "$_lp_cache[@]" "${names[1]}:${disp}" ) + _lp_alias_cache=( "$_lp_alias_cache[@]" "${(@)^names[2,-1]:#*\ *}:${disp}" ) + else + _lp_cache=( "$_lp_cache[@]" "${names[1]}" ) + _lp_alias_cache=( "$_lp_alias_cache[@]" "${(@)names[2,-1]:#*\ *}" ) + fi + fi + done < $file[1] fi + (( $#_lp_cache )) || _lp_cache=( 'lp0:Guessed default printer' ) + (( $#_lp_alias_cache )) || unset _lp_alias_cache fi if compset -P -P || [[ "$words[CURRENT-1]" = -P ]]; then - _wanted printers expl printer && compadd "$expl" - "$_lp_cache[@]" + if _wanted printers; then + if zstyle -T ":completion:${curcontext}:printers" verbose; then + zformat -a list ' -- ' "$_lp_cache[@]" + disp=(-ld list) + else + disp=() + fi + _all_labels printers expl printer \ + compadd "$disp[@]" - "${(@)_lp_cache%%:*}" && return 0 + + (( $+_lp_alias_cache )) || return 1 + + if zstyle -T ":completion:${curcontext}:printers" verbose; then + zformat -a list ' -- ' "$_lp_alias_cache[@]" + disp=(-ld list) + else + disp=() + fi + compadd "$expl[@]" "$disp[@]" - "${(@)_lp_alias_cache%%:*}" + else + return 1 + fi else if [[ "$words[1]" = (lpq|lprm) ]]; then - list=( "${(@M)${(f@)$(lpq)}:#[0-9]*}" ) + if [[ "$words" = *-P* ]]; then + printer=(-P "${${words##*-P( |)}%% *}") + else + printer=() + fi + list=( ${(M)"${(f@)$(_call jobs lpq $printer 2> /dev/null)}":#[0-9]*} ) if (( $#list )); then _tags users jobs while _tags; do - if _requested users expl user; then + if _requested users; then strs=( "${(@)${(@)list##[^ ]##[ ]##[^ ]##[ ]##}%%[ ]*}" ) if [[ -z "$shown" ]] && - zstyle -t ":completion:${curcontext}:users" verbose; then + zstyle -T ":completion:${curcontext}:users" verbose; then disp=(-ld list) shown=yes else disp=() fi - compadd "$expl[@]" "$disp[@]" - "$strs[@]" || _users && ret=0 + _all_labels users expl user compadd "$disp[@]" - "$strs[@]" || + _users && ret=0 fi - if _requested jobs expl job; then + if _requested jobs; then strs=( "${(@)${(@)list##[^ ]##[ ]##[^ ]##[ ]##[^ ]##[ ]##}%%[ ]*}" ) if [[ -z "$shown" ]] && - zstyle -t ":completion:${curcontext}:jobs" verbose; then + zstyle -T ":completion:${curcontext}:jobs" verbose; then disp=(-ld list) shown=yes else disp=() fi - compadd "$expl[@]" "$disp[@]" - "$strs[@]" && ret=0 + _all_labels jobs expl job compadd "$disp[@]" - "$strs[@]" && ret=0 fi (( ret )) || return 0 done diff --git a/Completion/User/_make b/Completion/User/_make index d576b0308..741cbb7dc 100644 --- a/Completion/User/_make +++ b/Completion/User/_make @@ -1,3 +1,32 @@ -#defcomp make gmake pmake +#compdef make gmake pmake -complist -s "\$(awk '/^[a-zA-Z0-9][^/ ]+:/ {print \$1}' FS=: [mM]akefile)" +local prev="$words[CURRENT-1]" file expl tmp + +if [[ "$prev" = -[CI] ]]; then + _files -/ +elif [[ "$prev" = -[foW] ]]; then + _files +else + file="$words[(I)-f]" + if (( file )); then + file="$words[file+1]" + elif [[ -e Makefile ]]; then + file=Makefile + elif [[ -e makefile ]]; then + file=makefile + else + file='' + fi + + if [[ -n "$file" ]] && _wanted targets; then + tmp=( + $(awk '/^[a-zA-Z0-9][^\/ \t]+:/ {print $1} + /^\.include *<bsd\.port\.(subdir\.|pre\.)?mk>/ || /^\.include *".*mk\/bsd\.pkg\.(subdir\.)?mk"/ { + print "fetch fetch-list extract patch configure build install reinstall deinstall package describe checkpatch checksum makesum" }' \ + FS=: $file) + ) + _all_labels targets expl 'make target' compadd "$tmp[@]" && return 0 + fi + compset -P 1 '*=' + _files +fi diff --git a/Completion/User/_mh b/Completion/User/_mh index 67ce49fd2..c1f397744 100644 --- a/Completion/User/_mh +++ b/Completion/User/_mh @@ -1,28 +1,36 @@ -#defcomp folder comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath mhpatch +#compdef folder folders comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath # Completion for all possible MH commands. # Alter the following two to your own mh directory and the directory # where standard mh library files live. (It works anyway, but this # will save a little time.) + local mymhdir=~/Mail local mhlib=/usr/lib/mh +local prev="$words[CURRENT-1]" expl + # To be on the safe side, check this exists and if not, get it anyway. [[ -d $mymhdir ]] || mymhdir=$(mhpath +) -if [[ -iprefix - ]]; then +if compset -P 1 -; then # get list of options, which MH commands can generate themselves # awk is just too icky to use for this, sorry. send me one if # you come up with it. - compadd -m $($COMMAND -help | perl -ne 'if (/^\s*-\(?(\S+)/) { - $n = $1; - $n =~ s/\)//g; - print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n"; - }') - return -elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then + if _wanted options; then + _all_labels options expl option \ + compadd - $($words[1] -help | perl -ne 'if (/^\s*-\(?(\S+)/) { + $n = $1; + $n =~ s/\)//g; + print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n"; + }') + return + fi + return 1 +elif compset -P 1 '[+@]' || [[ "$prev" = -draftfolder ]]; then # Complete folder names. local mhpath + if [[ $IPREFIX != '@' ]]; then [[ $IPREFIX = '+' ]] || IPREFIX=+ mhpath=$mymhdir @@ -30,13 +38,12 @@ elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then mhpath=$(mhpath) fi - # painless, or what? - complist -W mhpath -/ -elif [[ -mcurrent -1 -(editor|(whatnow|rmm|show|more)proc) ]]; then - complist -c -elif [[ -current -1 -file ]]; then - complist -f -elif [[ -mcurrent -1 -(form|audit|filter) ]]; then + _wanted files expl 'MH folder' _path_files -W mhpath -/ +elif [[ "$prev" = -(editor|(whatnow|rmm|show|more)proc) ]]; then + _command_names -e +elif [[ "$prev" = -file ]]; then + _files +elif [[ "$prev" = -(form|audit|filter) ]]; then # Need some MH template file, which may be in our own MH directory # or with the standard library. local mhfpath @@ -44,15 +51,16 @@ elif [[ -mcurrent -1 -(form|audit|filter) ]]; then [[ -d $mhlib ]] || { mhlib=$(mhparam mhlproc); mhlib=$mhlib:h; } mhfpath=($mymhdir $mhlib) - complist -W mhfpath -g '*(.)' -elif [[ -mcurrent -1 -(no|)cc ]]; then - compadd -m all to cc me -elif [[ -mcurrent -1 -[rw]cache ]]; then - compadd -m public private never ask + _wanted files expl 'MH template file' _files -W mhfpath -g '*(.)' +elif [[ "$prev" = -(no|)cc ]]; then + _wanted -C "$prev" values expl 'CC address' compadd all to cc me +elif [[ "$prev" = -[rw]cache ]]; then + _wanted -C "$prev" values expl cache compadd public private never ask else # Generate sequences. - local foldnam folddir f - for f in $argv; do + local foldnam folddir f ret + + for f in $words; do [[ $f = [@+]* ]] && foldnam=$f done if [[ $foldnam = '+'* ]]; then @@ -64,7 +72,14 @@ else # leaving foldnam empty works here fi - complist -s '$(mark $foldnam | awk -F: '\''{ print $1 }'\'')' - compadd -m reply next cur prev first last all unseen - complist -W folddir -g '<->' + if _wanted sequences; then + while _next_label sequences expl sequence; do + compadd "$expl[@]" $(mark $foldnam 2>/dev/null | awk -F: '{ print $1 }') && + ret=0 + compadd "$expl[@]" reply next cur prev first last all unseen && ret=0 + _files "$expl[@]" -W folddir -g '<->' && ret=0 + (( ret )) || return 0 + done + fi + return ret fi diff --git a/Completion/User/_nedit b/Completion/User/_nedit index 1f030e369..a3fcd9785 100644 --- a/Completion/User/_nedit +++ b/Completion/User/_nedit @@ -40,10 +40,11 @@ else '(-background)-bg[specify background color]:background color:_x_color' \ '(-fg)-foreground:foreground color:_x_color' \ '(-foreground)-fg[specify foreground color]:foreground color:_x_color' \ - '-import[load additional preferences file]:nedit preferences file:_files' \ + '*-import[load additional preferences file]:nedit preferences file:_files' \ "$nedit_common[@]" fi -[[ $state = lang ]] && _wanted neditlanguages expl 'language mode' && - compadd "$expl[@]" - ${(f)"$(sed -n \ - '/^nedit.languageMode/,/^nedit/ s/.* \([^:]*\).*/\1/p' < ~/.nedit)"} +[[ $state = lang ]] && + _wanted neditlanguages expl 'language mode' \ + compadd - ${(f)"$(sed -n \ + '/^nedit.languageMode/,/^nedit/ s/.* \([^:]*\).*/\1/p' < ~/.nedit)"} diff --git a/Completion/User/_netscape b/Completion/User/_netscape index f176083d2..b29c27c6c 100644 --- a/Completion/User/_netscape +++ b/Completion/User/_netscape @@ -1,8 +1,9 @@ #compdef netscape -local state +local curcontext="$curcontext" state line ret=1 +typeset -A opt_args -_x_arguments \ +_x_arguments -C \ '-xrm:resource:_x_resource' \ '-help[show usage message]' \ '-version[show the version number and build date]' \ @@ -21,55 +22,70 @@ _x_arguments \ -{,no-}{,irix-}session-management \ -{done-save,ignore}-geometry-prefs \ -{component-bar,composer,edit,messenger,mail,discussions,news} \ - '*:location:->urls' + '*:location:->urls' && ret=0 + +[[ "$state" = "urls" ]] && + _files "$@" && return 0 -[ "$state" = "urls" ] && _files "$@" && return # Handle netscape remote commands -if [ "$state" = "remote" ]; then +if [[ "$state" = "remote" ]]; then local -a remote_commands remote_commands=(openURL openFile saveAs mailto addBookmark) [[ $compstate[quoting] = (double|single) ]] && compset -q compset -P '*\(' case $IPREFIX in - openURL*|addBookmark* ) state=urls;; - openFile* ) _files -W ~;; - saveAs* ) + openURL*|addBookmark*) state=urls;; + openFile*) _files -W ~;; + saveAs*) if compset -P "*,"; then - compadd -s")" -M 'm:{a-zA-Z}={A-Za-z}' HTML Text PostScript + _wanted types expl 'data type' \ + compadd -s")" -M 'm:{a-zA-Z}={A-Za-z}' HTML Text PostScript && + ret=0 else - _path_files -W ~ + _files -W ~ && ret=0 fi ;; - mailto* ) + mailto*) compset -P "*," if compset -P '*@'; then - _description expl 'remote host name' - _hosts "$expl[@]" -q -S, + _wanted hosts expl 'remote host name' _hosts -q -S, && ret=0 else - _description expl 'login name' - _users "$expl[@]" -q -S@ + _wanted users expl 'login name' _users -q -S@ && ret=0 fi ;; - * ) - if [ "$QIPREFIX" ]; then - compadd -q -S '(' -M 'm:{a-zA-Z}={A-Za-z}' $remote_commands - else - compadd -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' $remote_commands + *) + if _wanted commands; then + if [[ -z "$QIPREFIX" ]]; then + _all_labels commands expl 'remote commands' \ + compadd -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' - \ + $remote_commands && ret=0 + else + _all_labels commands expl 'remote commands' \ + compadd -qS '(' -M 'm:{a-zA-Z}={A-Za-z}' - \ + $remote_commands && ret=0 + fi fi ;; esac fi -if [ "$state" = "urls" ]; then +if [[ "$state" = "urls" ]]; then # Complete netscape urls - if [[ -prefix about: ]]; then - compset -P about: - compadd authors blank cache document fonts global hype image-cache \ - license logo memory-cache mozilla plugins + if compset -P about: ; then + _wanted values expl 'about what' \ + compadd authors blank cache document fonts global hype image-cache \ + license logo memory-cache mozilla plugins && ret=0 else - compadd -S '' about: mocha: javascript: - _urls "$@" + if _wanted prefixes; then + while _next_label prefixes expl 'URL prefix'; do + compadd "$expl[@]" -S '' about: mocha: javascript: && ret=0 + _urls "$@" && ret=0 + (( ret )) || return 0 + done + fi fi fi + +return ret diff --git a/Completion/User/_tiff b/Completion/User/_tiff index bbc331442..8fd008f0f 100644 --- a/Completion/User/_tiff +++ b/Completion/User/_tiff @@ -10,21 +10,22 @@ fi if [[ $# -ne 0 || $+_in_tiff -ne 0 ]]; then if (( ! $# )); then - _description expl 'picture file' + _description files expl 'picture file' set -- "$expl[@]" fi - _path_files "$@" -g "$pat" || _files "$@" -g '*.(#i)tiff' + _wanted files expl 'picture file' _path_files "$@" -g "$pat" - || + _files "$@" "$expl[@]" -g '*.(#i)tiff' return fi local _in_tiff=yes -local state line ret=1 -typeset -A options +local curcontext="$curcontext" state line ret=1 +typeset -A opt_args case "$words[1]" in tiff2bw) - _arguments \ + _arguments -C \ '-c[specify compression scheme]:compression scheme:->compress' \ '-r[specify rows per strip]:rows per strip:' \ '-R[specify percentage of red channel]:percentage of red channel:' \ @@ -59,7 +60,7 @@ tiffcmp) ':second input TIFF file:_files -g \*.\(\#i\)' && ret=0 ;; tiffcp) - _arguments \ + _arguments -C \ '-B[write output in bin-endian byte order]' \ '-c[specify compression scheme]:compression scheme:->compress' \ '-o[set initial TIFF directory (file offset)]:file offset:' \ @@ -74,7 +75,7 @@ tiffcp) '*:input TIFF file:_files -g \*.\(\#i\)' && ret=0 ;; tiffdither) - _arguments \ + _arguments -C \ '-c[specify compression scheme]:compression scheme:->compress' \ '-f[specify fill order]:fill order:(lsb2msb msb2lsb)' \ '-r[specify rows per strip]:rows per strip:' \ @@ -102,7 +103,7 @@ tiffinfo) '*:input TIFF file:_files -g \*.\(\#i\)' && ret=0 ;; tiffmedian) - _arguments \ + _arguments -C \ '-r[specify rows per strip]:rows per strip:' \ '-C[specify number of colormap entries]:number of colormap entries:' \ '-c[specify compression scheme]:compression scheme:->compress' \ @@ -135,14 +136,14 @@ fax2tiff) ':FAX input file:_files -g \*.\(\#i\)\(g\[34\]\|fax\)' && ret=0 ;; gif2tiff) - _arguments \ + _arguments -C \ '-r[specify rows per strip]:rows per strip:' \ '-c[specify compression scheme]:compression scheme:->compress' \ ':input GIF file:_files -g \*.\(\#i\)gif' \ ':output file:_files -g \*.\(\#i\)tiff' && ret=0 ;; ppm2tiff) - _arguments \ + _arguments -C \ '-r[specify rows per strip]:rows per strip:' \ '-c[specify compression scheme]:compression scheme:->compress' \ '-R[specify resolution]:resolution:' \ @@ -150,14 +151,14 @@ ppm2tiff) ':output file:_files -g \*.\(\#i\)tiff' && ret=0 ;; ras2tiff) - _arguments \ + _arguments -C \ '-r[specify rows per strip]:rows per strip:' \ '-c[specify compression scheme]:compression scheme:->compress' \ ':input raster image file:_files -g \*.\(\#i\)ras\(\|t\)' \ ':output file:_files -g \*.\(\#i\)tiff' && ret=0 ;; pal2rgb) - _arguments \ + _arguments -C \ '-C[specify number of bits for colormap entries]:bits for colormap entries:(8 16)' \ '-p[set sample packing]:sample packing:(contig separate)' \ '-c[specify compression scheme]:compression scheme:->compress' \ @@ -166,7 +167,7 @@ pal2rgb) ':output file:_files -g \*.\(\#i\)tiff' && ret=0 ;; *) - _description expl 'picture file' + _description files expl 'picture file' _files "$expl[@]" -g "$pat" && ret=0 esac @@ -194,9 +195,13 @@ if [[ -n "$state" ]]; then ;; esac else - _description expl 'compression scheme' - compadd "$expl[@]" - none g4 packbits && ret=0 - compadd "$expl[@]" -qS: - lzw zip jpeg g3 && ret=0 + if _wanted values; then + while _next_label values expl 'compression scheme'; do + compadd "$expl[@]" - none g4 packbits && ret=0 + compadd "$expl[@]" -qS: - lzw zip jpeg g3 && ret=0 + (( ret )) || return 0 + done + fi fi fi diff --git a/Completion/User/_urls b/Completion/User/_urls index 19f7eea3a..03e8902cb 100644 --- a/Completion/User/_urls +++ b/Completion/User/_urls @@ -1,65 +1,155 @@ -#autoload +#compdef curl # Usage: _urls [-f] # Options: -# -f : complete files. - -# To complete URLs, you must make a URL database locally such as: +# -f : complete files first. +# +# Configuration styles used: +# +# path +# The path to a directory containing a URL database, such as: +# +# % cd ~/.zsh/urls +# % find . -ls +# ... drwxr-xr-x ... 512 Sep 3 02:46 . +# ... drwxr-xr-x ... 512 Sep 3 02:48 ./http +# ... drwxr-xr-x ... 512 Sep 3 02:52 ./http/www.zsh.org +# ... drwxr-xr-x ... 512 Sep 3 03:01 ./http/www.zsh.org/mla +# ... drwxr-xr-x ... 512 Sep 3 03:01 ./http/www.zsh.org/mla/workers +# ... drwxr-xr-x ... 512 Sep 3 03:01 ./http/www.zsh.org/mla/workers/1999 +# ... -rw-r--r-- ... 0 Sep 3 03:01 ./http/www.zsh.org/mla/workers/1999/index.html +# ... drwxr-xr-x ... 512 Sep 3 02:48 ./http/sunsite.auc.dk +# ... drwxr-xr-x ... 512 Sep 3 02:48 ./http/sunsite.auc.dk/zsh +# ... drwxr-xr-x ... 512 Sep 3 02:47 ./bookmark +# ... drwxr-xr-x ... 512 Sep 3 02:48 ./bookmark/zsh +# ... -rw-r--r-- ... 27 Sep 3 02:47 ./bookmark/zsh/home +# ... -rw-r--r-- ... 20 Sep 3 02:48 ./bookmark/zsh/meta +# % cat bookmark/zsh/home +# http://sunsite.auc.dk/zsh/ +# % cat bookmark/zsh/meta +# http://www.zsh.org/ # -# % cd ~/.zsh/urls -# % find . -ls -# ... drwxr-xr-x ... 512 Sep 3 02:46 . -# ... drwxr-xr-x ... 512 Sep 3 02:48 ./http -# ... drwxr-xr-x ... 512 Sep 3 02:52 ./http/www.zsh.org -# ... drwxr-xr-x ... 512 Sep 3 03:01 ./http/www.zsh.org/mla -# ... drwxr-xr-x ... 512 Sep 3 03:01 ./http/www.zsh.org/mla/workers -# ... drwxr-xr-x ... 512 Sep 3 03:01 ./http/www.zsh.org/mla/workers/1999 -# ... -rw-r--r-- ... 0 Sep 3 03:01 ./http/www.zsh.org/mla/workers/1999/index.html -# ... drwxr-xr-x ... 512 Sep 3 02:48 ./http/sunsite.auc.dk -# ... drwxr-xr-x ... 512 Sep 3 02:48 ./http/sunsite.auc.dk/zsh -# ... drwxr-xr-x ... 512 Sep 3 02:47 ./bookmark -# ... drwxr-xr-x ... 512 Sep 3 02:48 ./bookmark/zsh -# ... -rw-r--r-- ... 27 Sep 3 02:47 ./bookmark/zsh/home -# ... -rw-r--r-- ... 20 Sep 3 02:48 ./bookmark/zsh/meta +# local +# Specify a local web server as an array with three elements: +# <hostname> <doc root> <user area> +# where hostname is the name of the web server, doc root is the path to +# the default web pages for the server and user area is the directory +# name used by a user placing web pages within their home area. +# E.g.: +# zstyle ':completion:*:urls' local www /usr/local/apache/htdocs public_html -local ipre scheme dirs files +local ipre scheme host user uhosts ret=1 expl +local urls_path localhttp +zstyle -s ":completion:${curcontext}:urls" path urls_path || + urls_path="${ZDOTDIR:-$HOME}/.zsh/urls" +zstyle -a ":completion:${curcontext}:urls" local localhttp +local localhttp_servername="$localhttp[1]" +local localhttp_documentroot="$localhttp[2]" +local localhttp_userdir="$localhttp[3]" if [[ "$1" = -f ]]; then shift - _files "$@" && return -fi - -if [[ -z "$compconfig[_urls_dir]" ]]; then - compconfig[_urls_dir]=${ZDOTDIR:-$HOME}/.zsh/urls + _wanted -C -f files && _files "$@" && return fi ipre="$IPREFIX" -if [[ -prefix [-+.a-z0-9]#: ]]; then - scheme="${PREFIX%%:*}" - compset -P "[-+.a-z0-9]#:" -else - compadd -S '' http:// ftp:// bookmark: - return +if ! compset -P '(#b)([-+.a-z0-9]#):' && _wanted -C argument prefixes; then + while _next_label prefixes expl 'URL prefix' "$@"; do + [[ -d $urls_path/bookmark ]] && + compadd "$expl[@]" -S '' bookmark: && ret=0 + compadd "$expl[@]" -S '' file: ftp:// gopher:// http:// && ret=0 + (( ret )) || return 0 + done + return ret fi +scheme="$match[1]" case "$scheme" in - http) compset -P // || { compadd "$@" -S '' //; return };; - ftp) compset -P // || { compadd "$@" -S '' //; return };; + http|ftp|gopher) + if ! compset -P //; then + _wanted -C "$scheme" prefixes expl 'end of prefix' compadd "$@" -S '' // + return + fi + ;; + file) + if ! compset -P //; then + _wanted -C file files || return 1 + + while _next_label files expl 'local file' "$@"; do + if [[ -prefix / ]]; then + _path_files "$expl[@]" -S '' -g '*(^/)' && ret=0 + _path_files "$expl[@]" -S/ -r '/' -/ && ret=0 + elif [[ -z "$PREFIX" ]]; then + compadd "$expl[@]" -S '/' -r '/' - "${PWD%/}" && ret=0 + fi + (( ret )) || return 0 + done + return ret + fi + ;; + bookmark) + if [[ -f "$urls_path/$scheme/${(Q)PREFIX}${(Q)SUFFIX}" && + -s "$urls_path/$scheme/${(Q)PREFIX}${(Q)SUFFIX}" ]]; then + _wanted -C bookmark bookmarks expl bookmarks \ + compadd "$@" -U - \ + "$ipre$(<"$urls_path/$scheme/${(Q)PREFIX}${(Q)SUFFIX}")" && ret=0 + else + if _wanted -C bookmark files; then + while _next_label files expl 'bookmark'; do + _path_files -W "$urls_path/$scheme" "$expl[@]" -S '' -g '*(^/)' && + ret=0 + _path_files -W "$urls_path/$scheme" -S/ -r '/' -/ && ret=0 + (( ret )) || return 0 + done + fi + fi + return ret + ;; 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")" -else - dirs=($compconfig[_urls_dir]/$scheme/$PREFIX*$SUFFIX(/:t)) - files=($compconfig[_urls_dir]/$scheme/$PREFIX*$SUFFIX(.:t)) - compset -P '*/' - compadd "$@" -Q -S '/' - $dirs - if [[ "$scheme" = bookmark ]]; then - compadd "$@" -QS '' - $files +# Complete hosts +if ! compset -P '(#b)([^/]#)/' && _wanted hosts; then + uhosts=($urls_path/$scheme/$PREFIX*$SUFFIX(/:t)) + + while _next_label hosts expl host "$@"; do + (( $#uhosts )) || _hosts -S/ && ret=0 + [[ "$scheme" = http ]] && uhosts=($uhosts $localhttp_servername) + compadd "$expl[@]" -S/ - $uhosts && ret=0 + (( ret )) || return 0 + done + return ret +fi +host="$match[1]" + +# Complete part after hostname + +_wanted -C local files || return 1 + +if [[ "$localhttp_servername" = "$host" ]]; then + if compset -P \~; then + if ! compset -P '(#b)([^/]#)/'; then + _users -S/ + return + fi + user="$match[1]" + while _next_label files expl 'local file'; do + _path_files "$expl[@]" -W ~$user/$localhttp_userdir -g '*(^/)' && ret=0 + _path_files "$expl[@]" -W ~$user/$localhttp_userdir -S/ -r '/' -/ && ret=0 + (( ret )) || return 0 + done else - compadd "$@" -Q - $files + while _next_label files expl 'local file'; do + _path_files "$expl[@]" -W $localhttp_documentroot -g '*(^/)' && ret=0 + _path_files "$expl[@]" -W $localhttp_documentroot -S/ -r '/' -/ && ret=0 + (( ret )) || return 0 + done fi +else + while _next_label files expl 'local file'; do + _path_files "$expl[@]" -W $urls_path/$scheme/$host -g '*(^/)' && ret=0 + _path_files "$expl[@]" -W $urls_path/$scheme/$host -S/ -r '/' -/ && ret=0 + (( ret )) || return 0 + done fi +return $ret diff --git a/Completion/User/_users b/Completion/User/_users index fc1e87e52..d04731af9 100644 --- a/Completion/User/_users +++ b/Completion/User/_users @@ -1,6 +1,10 @@ -#autoload +#compdef last passwd groups -local expl +local expl users -_description expl user -compgen "$@" "$expl[@]" -u +_wanted users || return 1 + +zstyle -a ":completion:${curcontext}:" users users && + _all_labels users expl user compadd "$@" - "$users[@]" && return 0 + +_all_labels users expl user compadd "$@" - "${(@k)userdirs}" diff --git a/Completion/User/_users_on b/Completion/User/_users_on index 920688089..b19cff6e7 100644 --- a/Completion/User/_users_on +++ b/Completion/User/_users_on @@ -1,10 +1,12 @@ -#autoload write +#compdef write local expl +_wanted users || return 1 + if which users >/dev/null; then - _description expl users logged on - compadd "$@" "$expl[@]" - $(users) && return 0 + _all_labels users expl 'users logged on' \ + compadd "$@" - $(_call users users) && return 0 else # Other methods of finding out users logged on should be added here return 1 diff --git a/Completion/X/_x_colormapid b/Completion/X/_x_colormapid index 4fe6aac42..3c637c1d9 100644 --- a/Completion/X/_x_colormapid +++ b/Completion/X/_x_colormapid @@ -2,7 +2,7 @@ local expl list desc -_wanted colormapids expl 'colormap id' || return 1 +_wanted colormapids || return 1 list=(${(f)"$(xprop -root -f RGB_COLOR_MAP 32xcccccccxx ': $0\n'|awk -F'[ ():]' '/^[a-zA-Z_]+\(RGB_COLOR_MAP\)/ {print $5, "--", $1}')"}) @@ -12,4 +12,5 @@ else desc=() fi -compadd "$expl[@]" "$@" "$desc[@]" - "${(@)list%% *}" +_all_labels colormapids expl 'colormap id' \ + compadd "$@" "$desc[@]" - "${(@)list%% *}" diff --git a/Completion/X/_x_extension b/Completion/X/_x_extension index 967938e28..11e53fa6c 100644 --- a/Completion/X/_x_extension +++ b/Completion/X/_x_extension @@ -2,16 +2,18 @@ local expl -(( $+_xe_cache )) || _xe_cache=( "${(@)${(@f)$(xdpyinfo)}[(r)number of extensions:*,-1][2,(r)default screen number:*][1,-2]//[ ]}" ) +_wanted extensions || return 1 -_description expl 'X extension' +(( $+_xe_cache )) || _xe_cache=( "${(@)${(@f)$(xdpyinfo)}[(r)number of extensions:*,-1][2,(r)default screen number:*][1,-2]//[ ]}" ) if [[ "$1" = -a ]]; then shift - compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - all "$_xe_cache[@]" + _all_labels extensions expl 'X extensions' \ + compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - all "$_xe_cache[@]" else [[ "$1" = - ]] && shift - compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - "$_xe_cache[@]" + _all_labels extensions expl 'X extensions' \ + compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - "$_xe_cache[@]" fi diff --git a/Completion/X/_x_font b/Completion/X/_x_font index e0acb4014..43a713b34 100644 --- a/Completion/X/_x_font +++ b/Completion/X/_x_font @@ -1,3 +1,16 @@ #autoload -_message 'font' +local expl + +_wanted fonts || return 1 + +# This *has* to be improved some day... + +if (( ! $+_font_cache )); then + typeset -gU _font_cache + + _font_cache=( "${(@)^${(@f)$(_call fonts xlsfonts)}%%--*}--" ) +fi + +_all_labels fonts expl font \ + compadd -M 'r:|-=* r:|=*' "$@" -S '' - "$_font_cache[@]" diff --git a/Completion/X/_x_keysym b/Completion/X/_x_keysym index 6b031014a..f50762f7e 100644 --- a/Completion/X/_x_keysym +++ b/Completion/X/_x_keysym @@ -2,6 +2,8 @@ local expl +_wanted keysyms || return 1 + if (( ! $+_keysym_cache )); then local file @@ -16,5 +18,5 @@ if (( ! $+_keysym_cache )); then fi fi -_description expl 'key symbol' -compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - $_keysym_cache +_all_labels keysyms expl 'key symbol' \ + compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - $_keysym_cache diff --git a/Completion/X/_x_window b/Completion/X/_x_window index 118c7f131..1862db9a7 100644 --- a/Completion/X/_x_window +++ b/Completion/X/_x_window @@ -1,19 +1,18 @@ #autoload -setopt localoptions extendedglob - local list expl -list=( "${(@)${(M@)${(@f)$(xwininfo -root -tree)}:#[ ]#0x[0-9a-f]# \"*}##[ ]#}" ) +_wanted windows || return 1 + +list=( "${(@)${(M@)${(@f)$(_call windows xwininfo -root -tree)}:#[ ]#0x[0-9a-f]# \"*}##[ ]#}" ) if [[ "$1" = -n ]]; then shift - _description expl 'window name' - compadd "$@" "$expl[@]" -d list - "${(@)${(@)list#*\"}%%\"*}" + _all_labels windows expl 'window name' \ + compadd "$@" -d list - "${(@)${(@)list#*\"}%%\"*}" else [[ "$1" = - ]] && shift - _description expl 'window ID' - compadd "$@" "$expl[@]" -d list - "${(@)list%% *}" + _all_labels windows expl 'window ID' compadd "$@" -d list - "${(@)list%% *}" fi diff --git a/Completion/X/_xmodmap b/Completion/X/_xmodmap index 0f6514eb6..1cd461d4c 100644 --- a/Completion/X/_xmodmap +++ b/Completion/X/_xmodmap @@ -1,11 +1,9 @@ #compdef xmodmap -setopt localoptions extendedglob +local curcontext="$curcontext" state line ret=1 +typeset -A opt_args -local state line ret=1 -typeset -A options - -_x_arguments \ +_x_arguments -C \ -{help,grammar,verbose,quiet} \ '-n[only show what would be done]' \ '*-e[specify expression]:expression:->expr' \ @@ -57,7 +55,7 @@ if [[ -n "$state" ]]; then pointer*) if compset -P '*=[ ]#'; then compset -P '*[ ]' - _description expl 'button code' + _description values expl 'button code' compadd "$expl[@]" -qS ' ' 1 2 3 4 5 default return else @@ -84,9 +82,13 @@ if [[ -n "$state" ]]; then [[ "$what" = *ksym* ]] && _x_keysym "$suf[@]" && ret=0 else - _description expl command - compadd "$expl[@]" -S ' ' keycode keysym clear add remove && ret=0 - compadd "$expl[@]" -S ' = ' pointer && ret=0 + if _wanted commands; then + while _next_label commands expl command; do + compadd "$expl[@]" -S ' ' keycode keysym clear add remove && ret=0 + compadd "$expl[@]" -S ' = ' pointer && ret=0 + (( ret )) || return 0 + done + fi fi fi diff --git a/Completion/X/_xutils b/Completion/X/_xutils index 1818b447f..4eea8ded1 100644 --- a/Completion/X/_xutils +++ b/Completion/X/_xutils @@ -8,7 +8,7 @@ xdpyinfo) ;; xwininfo) _x_arguments \ - -{help,int,stats,bits,events,size,wm,shape,frame,all,english,metric} \ + -{help,int,children,tree,stats,bits,events,size,wm,shape,frame,all,english,metric} \ '(-id -name)-root' \ '(-id -root)-name:name: _x_window -n' \ '(-name -root)-id:id: _x_window' @@ -46,12 +46,33 @@ xev) '-rv' ;; xhost) - local expl type ret=1 + local expl type ret=1 tmp if compset -P '-'; then - _description expl 'disallow access' - compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - \ - "${${(@M)${(@f)$(xhost)}[2,-1]:#LOCAL:*}#INET:}" + tmp=(${(f)"$(xhost)"}) + shift tmp + tmp=(${tmp:#LOCAL:|<*>}) + if [[ "$tmp" = *:* ]]; then + if compset -P '(#b)(*):'; then + type="$match[1]" + _wanted displays && + while _next_label displays expl 'disallow access'; do + { compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - \ + ${${(M)tmp:#(#i)$type:*}#(#i)$type:} || + _hosts "$expl[@]" } && return 0 + done + else + _alternative \ + 'types:name family:compadd -S: ${(L)tmp%%:*}' \ + 'hosts:host:compadd ${(@)tmp#*:}' && ret=0 + fi + else + _wanted displays && + while _next_label displays expl 'disallow access'; do + { compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - $tmp || + _hosts "$expl[@]" } && return 0 + done + fi else compset -P + @@ -66,9 +87,9 @@ xhost) krb) _message 'Kerberos V5 principal';; esac else - _description expl 'name family' - compadd -S: - inet dnet nis krb && ret=0 - _hosts && ret=0 + _alternative \ + 'types:name family:compadd -S: - inet dnet nis krb' \ + 'hosts:: _hosts' && ret=0 fi return ret fi @@ -120,7 +141,7 @@ xrdb) '(-global -all -screens)-screen' \ '(-global -all -screen)-screens' \ '-n[only display on stdout]' \ - '(-nocpp)-cpp:preprocessor program:_files -g \*\(\*\)' \ + '(-nocpp)-cpp:preprocessor program:_files -g \*\(-\*\)' \ '(-cpp)-nocpp' \ '(-load -override -merge -remove)-query' \ '(-query -override -merge -remove)-load' \ @@ -131,6 +152,7 @@ xrdb) '-backup:backup extension:' \ '*-D-:symbol to define:' \ '*-U-:symbol to undefine:' \ - '*-I-:include directory:_files -/' + '*-I-:include directory:_files -/' \ + '*:defaults file:_files' ;; esac diff --git a/Completion/X/_xwit b/Completion/X/_xwit index e86443a32..998627869 100644 --- a/Completion/X/_xwit +++ b/Completion/X/_xwit @@ -16,8 +16,8 @@ _xwit_guard () { _xwit_compopts () { local expl - _description options expl option - compadd "$expl[@]" - ${(k)no[(R)*~0]} || compadd "$expl[@]" - ${(k)no} + _wanted options expl option compadd - ${(k)no[(R)*~0]} || + _all_labels options expl option compadd - ${(k)no} } _regex_arguments _xwit_parse \ @@ -39,8 +39,8 @@ _regex_arguments _xwit_parse \ \| "/iconmove$nul/" "$guard" "/$word/" ":_message x" "/$word/" ":_message y" \ \| "/id$nul/" "$guard" "/$word/" ":_x_window" \ \| "/(no|)keyrepeat$nul/" "$guard" \ - \( "/[0-9]##$nul/" ":_message keycode" \ - \( "/-$nul/" "/[0-9]##$nul/" ":_message 'last keycode'" \| \) \) \# \ + \( "/[0-9]##$nul/" ":[[ -prefix [0-9]# ]] && _message keycode" \ + \( "/-$nul/" "/[0-9]##$nul/" ":[[ -prefix [0-9]# ]] && _message 'last keycode'" \| \) \) \# \ \| "/names$nul/" "$guard" "/$word/" ":_x_window -n" \# \ \| "/[]/" ':_xwit_compopts' \ \) \ |