From e025336f2f6d9f107ee1e03b9900f04af0544ba9 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sat, 1 Apr 2000 20:43:43 +0000 Subject: Updated from list as far as 10376 --- Completion/Base/_arguments | 571 ++++++++++++------------- Completion/Base/_default | 30 +- Completion/Base/_describe | 164 ++----- Completion/Base/_jobs | 80 +++- Completion/Base/_subscript | 58 ++- Completion/Base/_tilde | 55 ++- Completion/Base/_values | 383 ++++------------- Completion/Builtins/_autoload | 11 +- Completion/Builtins/_cd | 48 ++- Completion/Builtins/_compdef | 54 ++- Completion/Builtins/_disable | 12 +- Completion/Builtins/_emulate | 6 + Completion/Builtins/_enable | 12 +- Completion/Builtins/_fc | 30 +- Completion/Builtins/_nothing | 2 +- Completion/Builtins/_pids | 26 +- Completion/Builtins/_popd | 55 +-- Completion/Builtins/_sched | 24 +- Completion/Builtins/_signals | 12 +- Completion/Builtins/_stat | 20 +- Completion/Builtins/_zcompile | 22 + Completion/Builtins/_zftp | 100 +++-- Completion/Builtins/_zpty | 10 +- Completion/Builtins/_zstyle | 145 +++++-- Completion/Commands/_complete_help | 73 +++- Completion/Commands/_history_complete_word | 107 ++++- Completion/Commands/_next_tags | 86 ++-- Completion/Core/_all_labels | 44 ++ Completion/Core/_alternative | 45 +- Completion/Core/_approximate | 192 ++------- Completion/Core/_call | 2 +- Completion/Core/_complete | 58 ++- Completion/Core/_correct | 4 +- Completion/Core/_description | 54 ++- Completion/Core/_expand | 152 +++---- Completion/Core/_files | 59 ++- Completion/Core/_ignored | 3 +- Completion/Core/_list | 43 +- Completion/Core/_main_complete | 221 ++++++++-- Completion/Core/_match | 44 +- Completion/Core/_menu | 4 +- Completion/Core/_next_label | 24 ++ Completion/Core/_oldlist | 53 +++ Completion/Core/_path_files | 661 +++++++++++++++++++---------- Completion/Core/_prefix | 4 +- Completion/Core/_requested | 21 +- Completion/Core/_setup | 68 ++- Completion/Core/_tags | 144 +++---- Completion/Core/_wanted | 22 +- Completion/Core/compdump | 62 ++- Completion/Core/compinit | 427 ++++++++++++++----- Completion/Core/compinstall | 431 ++++++++++++------- Completion/Linux/_rpm | 101 +++-- Completion/User/_gdb | 52 +-- Completion/User/_getconf | 37 +- Completion/User/_groups | 19 +- Completion/User/_lp | 76 +++- Completion/User/_make | 33 +- Completion/User/_mh | 67 +-- Completion/User/_nedit | 9 +- Completion/User/_netscape | 70 +-- Completion/User/_tiff | 37 +- Completion/User/_urls | 180 ++++++-- Completion/User/_users | 12 +- Completion/User/_users_on | 8 +- Completion/X/_x_colormapid | 5 +- Completion/X/_x_extension | 10 +- Completion/X/_x_font | 15 +- Completion/X/_x_keysym | 6 +- Completion/X/_x_window | 13 +- Completion/X/_xmodmap | 20 +- Completion/X/_xutils | 42 +- Completion/X/_xwit | 8 +- 73 files changed, 3647 insertions(+), 2211 deletions(-) create mode 100644 Completion/Builtins/_emulate create mode 100644 Completion/Builtins/_zcompile create mode 100644 Completion/Core/_all_labels create mode 100644 Completion/Core/_next_label create mode 100644 Completion/Core/_oldlist (limited to 'Completion') 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 =~/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 ' option, this tries to complete only pids # of processes whose command line match the `'. -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 ', `-J ', -# `-V ', `-W paths', `-X explanation', and `-F '. All but -# the last have the same syntax and meaning as for `complist'. The -# `-F ' 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' +# 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/' 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' 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/' 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 ' -# 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 is given +# `#compdef ' +# If the first line looks like this, the file is autoloaded as a +# function and that function will be called to generate the matches +# when completing for one of the commands whose are given. # -# `#defpatcomp ' -# this defines a function that should be called to generate -# matches for commands whose name matches ; note -# that only one pattern may be given +# `#compdef -p ' +# This defines a function that should be called to generate matches +# for commands whose name matches . Note that only one pattern +# may be given. # -# `#defkeycomp