diff options
Diffstat (limited to 'Completion/Core')
-rw-r--r-- | Completion/Core/_all_labels | 44 | ||||
-rw-r--r-- | Completion/Core/_alternative | 45 | ||||
-rw-r--r-- | Completion/Core/_approximate | 192 | ||||
-rw-r--r-- | Completion/Core/_call | 2 | ||||
-rw-r--r-- | Completion/Core/_complete | 58 | ||||
-rw-r--r-- | Completion/Core/_correct | 4 | ||||
-rw-r--r-- | Completion/Core/_description | 54 | ||||
-rw-r--r-- | Completion/Core/_expand | 152 | ||||
-rw-r--r-- | Completion/Core/_files | 59 | ||||
-rw-r--r-- | Completion/Core/_ignored | 3 | ||||
-rw-r--r-- | Completion/Core/_list | 43 | ||||
-rw-r--r-- | Completion/Core/_main_complete | 221 | ||||
-rw-r--r-- | Completion/Core/_match | 44 | ||||
-rw-r--r-- | Completion/Core/_menu | 4 | ||||
-rw-r--r-- | Completion/Core/_next_label | 24 | ||||
-rw-r--r-- | Completion/Core/_oldlist | 53 | ||||
-rw-r--r-- | Completion/Core/_path_files | 661 | ||||
-rw-r--r-- | Completion/Core/_prefix | 4 | ||||
-rw-r--r-- | Completion/Core/_requested | 21 | ||||
-rw-r--r-- | Completion/Core/_setup | 68 | ||||
-rw-r--r-- | Completion/Core/_tags | 144 | ||||
-rw-r--r-- | Completion/Core/_wanted | 22 | ||||
-rw-r--r-- | Completion/Core/compdump | 62 | ||||
-rw-r--r-- | Completion/Core/compinit | 427 | ||||
-rw-r--r-- | Completion/Core/compinstall | 431 |
25 files changed, 1866 insertions, 976 deletions
diff --git a/Completion/Core/_all_labels b/Completion/Core/_all_labels new file mode 100644 index 000000000..fa7118ec4 --- /dev/null +++ b/Completion/Core/_all_labels @@ -0,0 +1,44 @@ +#autoload + +local gopt=-J len tmp pre suf tloop ret=1 descr + +if [[ "$1" = -t ]]; then + tloop=yes + shift +fi +if [[ "$1" = -([12]|)[VJ] ]]; then + gopt="$1" + shift +fi + +tmp=${argv[(ib:4:)-]} +len=$# +if [[ tmp -lt len ]]; then + pre=$(( tmp-1 )) + suf=$tmp +elif [[ tmp -eq $# ]]; then + pre=-2 + suf=$(( len+1 )) +else + pre=4 + suf=5 +fi + +while [[ -z "$tloop" ]] || comptags -N; do + while comptags -A "$1" curtag; do + if [[ "$curtag" = *:* ]]; then + zformat -f descr "${curtag#*:}" "d:$3" + _description "$gopt" "${curtag%:*}" "$2" "$descr" + curtag="${curtag%:*}" + + "$4" "${(P@)2}" "${(@)argv[5,-1]}" + else + _description "$gopt" "$curtag" "$2" "$3" + + "${(@)argv[4,pre]}" "${(P@)2}" "${(@)argv[suf,-1]}" && ret=0 + fi + done + [[ -z "$tloop" || ret -eq 0 ]] && break +done + +return ret diff --git a/Completion/Core/_alternative b/Completion/Core/_alternative index 158f3a07a..b038aa8a4 100644 --- a/Completion/Core/_alternative +++ b/Completion/Core/_alternative @@ -1,19 +1,23 @@ #autoload -local tags def expl descr action mesgs nm="$compstack[nmatches]" -local context +local tags def expl descr action mesgs nm="$compstate[nmatches]" subopts +local opt curcontext="$curcontext" + +subopts=() +while getopts 'O:C:' opt; do + case "$opt" in + O) subopts=( "${(@P)OPTARG}" ) ;; + C) curcontext="${curcontext%:*}:$OPTARG" ;; + esac +done + +shift OPTIND-1 -if [[ "$1" = -C?* ]]; then - context="${1[3,-1]}" - shift -elif [[ "$1" = -C ]]; then - context="$2" - shift 2 -fi +[[ "$1" = -(|-) ]] && shift mesgs=() -_tags -C "$context" "${(@)argv%%:*}" +_tags "${(@)argv%%:*}" while _tags; do for def; do @@ -21,7 +25,7 @@ while _tags; do descr="${${def#*:}%%:*}" action="${def#*:*:}" - _description expl "$descr" + _description "${def%%:*}" expl "$descr" if [[ "$action" = \ # ]]; then @@ -35,28 +39,35 @@ while _tags; do eval ws\=\( "${action[3,-3]}" \) - _describe "$descr" ws -M 'r:|[_-]=* r:|=*' + _describe "$descr" ws -M 'r:|[_-]=* r:|=*' "$subopts[@]" elif [[ "$action" = \(*\) ]]; then # Anything inside `(...)' is added directly. - compadd "$expl[@]" - ${=action[2,-2]} + _all_labels "${def%%:*}" expl "$descr" \ + compadd "$subopts[@]" - ${=action[2,-2]} elif [[ "$action" = \{*\} ]]; then # A string in braces is evaluated. - eval "$action[2,-2]" + while _next_label "${def%%:*}" expl "$descr"; do + eval "$action[2,-2]" + done elif [[ "$action" = \ * ]]; then # If the action starts with a space, we just call it. - ${(e)=~action} + eval "action=( $action )" + while _next_label "${def%%:*}" expl "$descr"; do + "$action[@]" + done else # Otherwise we call it with the description-arguments built above. - action=( $=action ) - ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]} + eval "action=( $action )" + _all_labels "${def%%:*}" expl "$descr" \ + "$action[1]" "$subopts[@]" "${(@)action[2,-1]}" fi fi done diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate index 1b40f7cbf..0815a308e 100644 --- a/Completion/Core/_approximate +++ b/Completion/Core/_approximate @@ -1,102 +1,30 @@ #autoload # This code will try to correct the string on the line based on the -# strings generated for the context if `compconfig[correct]' is set. -# These corrected strings will be shown in a list and one can -# cycle through them as in a menucompletion or get the corrected prefix. -# -# Supported configuration keys: -# -# approximate_accept -# This should be set to a number, specifying the maximum number -# of errors that should be accepted. If the string also contains -# a `n' or `N', the code will use the numeric argument as the -# maximum number of errors if a numeric argument was given. If no -# numeric argument was given, the number from the value of this -# key will be used. E.g. with `compconf approximate_accept=2n' two -# errors will be accepted, but if the user gives another number -# with the numeric argument, this will be prefered. Also, with -# `compconf approximate_accept=0n', normally no correction will be -# tried, but if a numeric argument is given, automatic correction -# will be used. On the other hand, if the string contains an `!' -# and a `n' or `N', correction is not attempted if a numeric -# argument is given. Once the number of errors to accept is -# determined, the code will repeatedly try to generate matches by -# allowing one error, two errors, and so on. Independent of the -# number of errors the user wants to accept, the code will allow -# only fewer errors than there are characters in the string from -# the line. -# -# approximate_original -# This value is used to determine if the original string should -# be included in the list (and thus be presented to the user when -# cycling through the corrections). If it is set to any non-empty -# value, the original string will be offered. If it contains the -# sub-string `last', the original string will appear as the last -# string when cycling through the corrections, otherwise it will -# appear as the first one (so that the command line does not -# change immediately). Also, if the value contains the sub-string -# `always', the original string will always be included, whereas -# normally it is included only if more than one possible -# correction was generated. -# -# approximate_prompt -# This can be set to a string that should be printed before the -# list of corrected strings when cycling through them. This string -# may contain the control sequences `%n', `%B', etc. known from -# the `-X' option of `compctl'. Also, the sequence `%e' will be -# replaced by the number of errors accepted to generate the -# corrected strings. -# -# approximate_insert -# If this is set to a string starting with `unambig', the code -# will try to insert a usable unambiguous string in the command -# line instead of always cycling through the corrected strings. -# If such a unambiguous string could be found, the original -# string is not used, independent of the setting of -# `approximate_original'. If no sensible string could be found, -# one can cycle through the corrected strings as usual. -# -# If any of these keys is not set, but the the same key with the -# prefix `correct' instead of `approximate' is set, that value will -# be used. - -local _comp_correct _correct_prompt comax -local cfgacc cfgorig cfgps cfgins - -# Only if all global matchers hav been tried. - -[[ compstate[matcher] -ne compstate[total_matchers] ]] && return 1 - -# We don't try correction if the string is too short. - -[[ "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1 - -# Get the configuration values, using either the prefix `correct' or -# `approximate'. - -if [[ "$compstate[pattern_match]" = (|\**) ]]; then - cfgacc="${compconfig[approximate_accept]:-$compconfig[correct_accept]}" - cfgorig="${compconfig[approximate_original]:-$compconfig[correct_original]}" - cfgps="${compconfig[approximate_prompt]:-$compconfig[correct_prompt]}" - cfgins="${compconfig[approximate_insert]:-$compconfig[correct_insert]}" -else - cfgacc="$compconfig[correct_accept]" - cfgorig="$compconfig[correct_original]" - cfgps="$compconfig[correct_prompt]" - cfgins="$compconfig[correct_insert]" -fi +# strings generated for the context. These corrected strings will be +# shown in a list and one can cycle through them as in a menucompletion +# or get the corrected prefix. + +# We don't try correction if the string is too short or we have tried it +# already. + +[[ _matcher_num -gt 1 || "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1 + +local _comp_correct _correct_expl comax cfgacc +local oldcontext="${curcontext}" opm="$compstate[pattern_match]" + +zstyle -s ":completion:${curcontext}:" max-errors cfgacc || cfgacc='2 numeric' # Get the number of errors to accept. -if [[ "$cfgacc" = *[nN]* && NUMERIC -ne 1 ]]; then - # Stop if we also have a `!'. +if [[ "$cfgacc" = *numeric* && ${NUMERIC:-1} -ne 1 ]]; then + # A numeric argument may mean that we should not try correction. - [[ "$cfgacc" = *\!* ]] && return 1 + [[ "$cfgacc" = *not-numeric* ]] && return 1 # Prefer the numeric argument if that has a sensible value. - comax="$NUMERIC" + comax="${NUMERIC:-1}" else comax="${cfgacc//[^0-9]}" fi @@ -105,13 +33,15 @@ fi [[ "$comax" -lt 1 ]] && return 1 -# Otherwise temporarily define functions to use instead of -# the builtins that add matches. This is used to be able -# to stick the `(#a...)' into the right place (after an +_tags corrections original + +# Otherwise temporarily define a function to use instead of +# the builtin that adds matches. This is used to be able +# to stick the `(#a...)' in the right place (after an # ignored prefix). compadd() { - [[ "$*" != *-([a-zA-Z/]#|)U* && + [[ ${argv[(I)-[a-zA-Z]#U[a-zA-Z]#]} -eq 0 && "${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] && return if [[ "$PREFIX" = \~*/* ]]; then @@ -119,79 +49,49 @@ compadd() { else PREFIX="(#a${_comp_correct})$PREFIX" fi - if [[ -n "$_correct_prompt" ]]; then - builtin compadd -X "$_correct_prompt" -J _correct "$@" - else - builtin compadd -J _correct "$@" - fi + builtin compadd "$_correct_expl[@]" "$@" } -compgen() { - [[ "$*" != *-([a-zA-Z/]#|)U* && - "${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] && return - - if [[ "$PREFIX" = \~*/* ]]; then - PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}" - else - PREFIX="(#a${_comp_correct})$PREFIX" - fi - if [[ -n "$_correct_prompt" ]]; then - builtin compgen "$@" -X "$_correct_prompt" -J _correct - else - builtin compgen "$@" -J _correct - fi -} - -# Now initialise our counter. We also set `compstate[matcher]' -# to `-1'. This allows completion functions to use the simple -# `[[ compstate[matcher] -gt 1 ]] && return' to avoid being -# called for multiple global match specs and still be called -# again when correction is done. Also, this makes it easy to -# test if correction is attempted since `compstate[matcher]' -# will never be set to a negative value by the completion code. - _comp_correct=1 -compstate[matcher]=-1 - -_correct_prompt="${cfgps//\%e/1}" - -# We also need to set `extendedglob' and make the completion -# code behave as if globcomplete were set. - -setopt extendedglob [[ -z "$compstate[pattern_match]" ]] && compstate[pattern_match]='*' while [[ _comp_correct -le comax ]]; do + curcontext="${oldcontext/(#b)([^:]#:[^:]#:)/${match[1][1,-2]}-${_comp_correct}:}" + + _description corrections _correct_expl corrections \ + "e:$_comp_correct" "o:$PREFIX$SUFFIX" + if _complete; then - if [[ "$cfgins" = unambig* && - "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then + if zstyle -t ":completion:${curcontext}:" insert-unambiguous && + [[ "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then compstate[pattern_insert]=unambiguous - elif [[ compstate[nmatches] -gt 1 || "$cfgorig" = *always* ]]; then - if [[ "$cfgorig" = *last* ]]; then - builtin compadd -U -V _correct_original -nQ - "$PREFIX$SUFFIX" - elif [[ -n "$cfgorig" ]]; then - builtin compadd -U -nQ - "$PREFIX$SUFFIX" - fi + elif _requested original && + { [[ compstate[nmatches] -gt 1 ]] || + zstyle -t ":completion:${curcontext}:" original }; then + local expl + + _description -V original expl original + + builtin compadd "$expl[@]" -U -Q - "$PREFIX$SUFFIX" # If you always want to see the list of possible corrections, - # set `compstate[list]=list' here. + # set `compstate[list]=list force' here. - compstate[force_list]=list + [[ "$compstate[list]" != list* ]] && + compstate[list]="$compstate[list] force" fi - compstate[matcher]="$compstate[total_matchers]" - unfunction compadd compgen + unfunction compadd + compstate[pattern_match]="$opm" return 0 fi [[ "${#:-$PREFIX$SUFFIX}" -le _comp_correct+1 ]] && break (( _comp_correct++ )) - - _correct_prompt="${cfgps//\%e/$_comp_correct}" done -compstate[matcher]="$compstate[total_matchers]" -unfunction compadd compgen +unfunction compadd +compstate[pattern_match]="$opm" return 1 diff --git a/Completion/Core/_call b/Completion/Core/_call index 345dae50d..b038a80bc 100644 --- a/Completion/Core/_call +++ b/Completion/Core/_call @@ -1,4 +1,4 @@ -#autoload +#autoload +X local tmp diff --git a/Completion/Core/_complete b/Completion/Core/_complete index 0f4d5ff4b..c2679dcb8 100644 --- a/Completion/Core/_complete +++ b/Completion/Core/_complete @@ -2,51 +2,65 @@ # Generate all possible completions. Note that this is not intended as # a normal completion function, but as one possible value for the -# compconfig[completer] parameter. +# completer style. -local comp name +local comp name oldcontext +typeset -T curcontext="$curcontext" ccarray + +oldcontext="$curcontext" + +# If we have a user-supplied context name, use only that. + +if [[ -n "$compcontext" ]]; then + ccarray[3]="$compcontext" + + comp="$_comps[$compcontext]" + [[ -z "$comp" ]] || "$comp" + + return +fi # An entry for `-first-' is the replacement for `compctl -T' -# Completion functions may set `_compskip' to any value to make the -# main loops stop calling other completion functions. comp="$_comps[-first-]" if [[ ! -z "$comp" ]]; then + ccarray[3]=-first- "$comp" - if (( $+_compskip )); then - unset _compskip + if [[ "$_compskip" = all ]]; then + _compskip='' (( compstate[nmatches] )) return fi fi + # For arguments and command names we use the `_normal' function. if [[ "$compstate[context]" = command ]]; then - _normal + curcontext="$oldcontext" + _normal -s else # Let's see if we have a special completion definition for the other # possible contexts. - comp='' - - case $compstate[context] in - equal) comp="$_comps[-equal-]";; - tilde) comp="$_comps[-tilde-]";; - redirect) comp="$_comps[-redirect-]";; - math) comp="$_comps[-math-]";; - subscript) comp="$_comps[-subscript-]";; - value) comp="$_comps[-value-]";; - array_value) comp="$_comps[-array-value-]";; - condition) comp="$_comps[-condition-]";; - parameter) comp="$_comps[-parameter-]";; - brace_parameter) comp="$_comps[-brace-parameter-]";; - esac + local cname="-${compstate[context]:s/_/-/}-" + + ccarray[3]="$cname" + + comp="$_comps[$cname]" # If not, we use default completion, if any. - [[ -z "$comp" ]] && comp="$_comps[-default-]" + if [[ -z "$comp" ]]; then + if [[ "$_compskip" = *default* ]]; then + _compskip='' + return 1 + fi + comp="$_comps[-default-]" + fi [[ -z "$comp" ]] || "$comp" fi +_compskip='' + (( compstate[nmatches] )) diff --git a/Completion/Core/_correct b/Completion/Core/_correct index 35ab01cf1..c9c3d999c 100644 --- a/Completion/Core/_correct +++ b/Completion/Core/_correct @@ -1,8 +1,8 @@ #autoload -# This is mainly a wrapper around the more general `_approximate. +# This is mainly a wrapper around the more general `_approximate'. # By setting `compstate[pattern_match]' to something unequal to `*' and -# then calling `_approximate, we get only corrections, not all strings +# then calling `_approximate', we get only corrections, not all strings # with the corrected prefix and something after it. # # Supported configuration keys are the same as for `_approximate', only diff --git a/Completion/Core/_description b/Completion/Core/_description index 874ba8a96..7db47228b 100644 --- a/Completion/Core/_description +++ b/Completion/Core/_description @@ -1,22 +1,56 @@ #autoload -local gropt=-J +local name gropt=-J format gname hidden hide match opts -if [[ "$1" = -V ]]; then - gropt=-V +opts=() + +if [[ "$1" = -([12]|)[VJ] ]]; then + gropt="$1" shift fi -if [[ -n "$compconfig[group_matches]" ]]; then - if [[ -n "$compconfig[description_format]" ]]; then - eval "$1=($gropt ${(q)2} -X ${(q)compconfig[description_format]//\\%d/$2})" +_lastdescr=( "$_lastdescr[@]" "$3" ) + +_setup "$1" + +name="$2" + +zstyle -s ":completion:${curcontext}:$1" format format || + zstyle -s ":completion:${curcontext}:descriptions" format format + +zstyle -s ":completion:${curcontext}:$1" hidden hidden +if [[ "$hidden" = (all|yes|true|1|on) ]]; then + [[ "$hidden" = all ]] && format='' + opts=(-n) +fi +zstyle -s ":completion:${curcontext}:$1" group-name gname && + [[ -z "$gname" ]] && gname="$1" +zstyle -s ":completion:${curcontext}:$1" matcher match && + opts=($opts -M "${(q)match}") +[[ -n "$_matcher" ]] && opts=($opts -M "${(q)_matcher}") + +if [[ -z "$_comp_no_ignore" ]] && + zstyle -a ":completion:${curcontext}:$1" ignored-patterns _comp_ignore; then + opts=( $opts -F _comp_ignore ) +else + _comp_ignore=() +fi + +shift 2 +[[ -n "$format" ]] && zformat -f format "$format" "d:$1" "${(@)argv[2,-1]}" + +if [[ -n "$gname" ]]; then + if [[ -n "$format" ]]; then + eval "${name}=($opts $gropt ${(q)gname} -X \"${format}\")" else - eval "$1=($gropt ${(q)2})" + eval "${name}=($opts $gropt ${(q)gname})" fi else - if [[ -n "$compconfig[description_format]" ]]; then - eval "$1=(-X ${(q)compconfig[description_format]//\\%d/$2})" + if [[ -n "$format" ]]; then + eval "${name}=($opts $gropt -default- -X \"${format}\")" else - eval "$1=()" + eval "${name}=($opts $gropt -default-)" fi fi + +return 0 diff --git a/Completion/Core/_expand b/Completion/Core/_expand index 9172b6cbf..eff8d8601 100644 --- a/Completion/Core/_expand +++ b/Completion/Core/_expand @@ -6,61 +6,20 @@ # This function will allow other completer functions to be called if # the expansions done produce no result or do not change the original # word from the line. -# -# Configuration keys: -# -# expand_substitute -# If this is unset or set to the empty string, the code will first -# try to expand all substitutions in the string (such as $(...) and -# ${...}). If this is set to an non-empty string it should be -# an expression usable inside a $[...] arithmetical expression. -# In this case, expansion of substitutions will be done if the -# expression evaluates to `1'. For example, with -# -# compconf expand_substitute='NUMERIC != 1' -# -# substitution will be performed only if given an explicit numeric -# argument other than `1', as by typing ESC 2 TAB. -# -# expand_glob -# If this is unset or set to an empty string, globbing will be -# attempted on the word resulting from substitution or the -# original string. The values accepted for this key are the same -# as for expand_substitute. -# -# expand_menu -# If this is unset or set to the empty string, the words resulting -# from expansion (if any) will simply be inserted in the ommand line, -# replacing the original string. However, if this key is set to an -# non-empty string, the user can cycle through the expansion as in -# a menucompletion. Unless the value contains the sub-string `only', -# the user will still be offered all expansions at once as one of -# the strings to insert in the command line. Also, if the value -# contains the sub-string `last', the string with all expansion will -# be offered first, whereas normally it is offered as the last string -# to insert. Finally, if the value contains the sub-string `sort', -# the expansions will be sorted alphabetically, normally they are -# kept in the order the expansion produced them in. -# -# expand_original -# If this is set to an non-empty string, the original string from the -# line will be included in the list of strings the user can cycle -# through as in a menucompletion. If the value contains the sub-string -# `last', the original string will appear as the last string, with -# other values it is inserted as the first one (so that the command -# line does not change immediatly). -# -# expand_prompt -# This may be set to a string that should be displayed before the -# possible expansions. This is given to the -X option and thus may -# contain the control sequences `%n', `%B', etc. Also, the sequence -# `%o' in this string will be replaced by the original string. - -local exp word="$PREFIX$SUFFIX" group=-V - -# Do this only for the first global matcher. - -[[ "$compstate[matcher]" -le 1 ]] || return 1 + +setopt localoptions nullglob + +[[ _matcher_num -gt 1 ]] && return 1 + +local exp word="$PREFIX$SUFFIX" sort expr expl subd suf=" " + +# First, see if we should insert all *completions*. + +if zstyle -s ":completion:${curcontext}:" completions expr && + [[ "${(e):-\$[$expr]}" -eq 1 ]]; then + compstate[insert]=all + return 1 +fi # In exp we will collect the expansion. @@ -69,79 +28,68 @@ exp=("$word") # First try substitution. That weird thing spanning multiple lines # changes quoted spaces, tabs, and newlines into spaces. -[[ -z "$compconfig[expand_substitute]" || - "${(e):-\$[$compconfig[expand_substitute]]}" -eq 1 ]] && +zstyle -s ":completion:${curcontext}:" substitute expr && + [[ "${(e):-\$[$expr]}" -eq 1 ]] && exp=( "${(e)exp//\\[ ]/ }" ) # If the array is empty, store the original string again. -[[ -z "$exp" ]] && exp=("$word") +(( $#exp )) || exp=("$word") + +subd=("$exp[@]") # Now try globbing. -[[ -z "$compconfig[expand_glob]" || - "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ]] && - exp=( ${~exp}(N) ) +zstyle -s ":completion:${curcontext}:" glob expr && + [[ "${(e):-\$[$expr]}" -eq 1 ]] && + exp=( ${~exp} ) # If we don't have any expansions or only one and that is the same # as the original string, we let other completers run. -[[ $#exp -eq 0 || - ( $#exp -eq 1 && "$exp[1]" = "$word" ) ]] && return 1 +(( $#exp )) || exp=("$subd[@]") -# We have expansions, should we menucomplete them? +[[ $#exp -eq 1 && "$exp[1]" = "$word"(|\(N\)) ]] && return 1 -if [[ -z "$compconfig[expand_menu]" ]]; then +# With subst-globs-only we bail out if there were no glob expansions, +# regardless of any substitutions - # No, so if the user only wants a list, we add the strings - # separately. Otherwise we add the whole array as one string, - # probably also adding the original string. +zstyle -s ":completion:${curcontext}:" subst-globs-only expr && + [[ "${(e):-\$[$expr]}" -eq 1 && "$subd" = "$exp"(|\(N\)) ]] && return 1 - if [[ -z "$compstate[insert]" ]]; then - compadd -U -V _expand -Q - "$exp[@]" - else - [[ -n "$compconfig[expand_original]" && - "$compconfig[expand_original]" != *last* ]] && - compadd -UnQ -V _expand_original - "$word" +# Now add as matches whatever the user requested. - compadd -UQ -V _expand - "$exp" +zstyle -s ":completion:${curcontext}:" sort sort - [[ -n "$compconfig[expand_original]" && - "$compconfig[expand_original]" = *last* ]] && - compadd -UnQ -V _expand_original - "$word" +[[ "$sort" = (yes|true|1|on) ]] && exp=( "${(@o)exp}" ) - compstate[insert]=menu - fi -else - # Sorting? We just use a different group type then. +# If there is only one expansion, add a suitable suffix +(($#exp == 1)) && suf='' && [[ -d $exp && "$exp[1]" != */ ]] && suf='/' - [[ "$compconfig[expand_menu]" = *sort* ]] && group=-J +if [[ -z "$compstate[insert]" ]] ;then + _description all-expansions expl 'all expansions' "o:$word" - # Now add the expansion string, probably also adding the original - # and/or the string containing all expanded string. + compadd "$expl[@]" -UQ -qS "$suf" - "$exp" +else + _tags all-expansions expansions original - [[ -n "$compconfig[expand_original]" && - "$compconfig[expand_original]" != *last* ]] && - compadd -UnQ -V _expand_original - "$word" - [[ "$compconfig[expand_menu]" = *last* && - "$compconfig[expand_menu]" != *only* ]] && - compadd -UnQ -V _expand_all - "$exp" + if _requested all-expansions; then + _description all-expansions expl 'all expansions' + compadd "$expl[@]" -UQ -qS "$suf" - "$exp" + fi - if [[ -z "$compconfig[expand_prompt]" ]]; then - compadd -UQ $group _expand - "$exp[@]" - else - compadd -UQ -X "${compconfig[expand_prompt]//\%o/$word}" \ - $group _expand - "$exp[@]" + if [[ $#exp -gt 1 ]] && _requested expansions; then + if [[ "$sort" = menu ]]; then + _description expansions expl expansions "o:$word" + else + _description -V expansions expl expansions "o:$word" + fi + compadd "$expl[@]" -UQ - "$exp[@]" fi - [[ "$compconfig[expand_menu]" != *last* && - "$compconfig[expand_menu]" != *only* ]] && - compadd -UnQ -V _expand_all - "$exp" - [[ -n "$compconfig[expand_original]" && - "$compconfig[expand_original]" = *last* ]] && - compadd -UnQ -V _expand_original - "$word" + _requested original expl original && compadd "$expl[@]" -UQ - "$word" compstate[insert]=menu fi diff --git a/Completion/Core/_files b/Completion/Core/_files index d2cce35e7..1755abebd 100644 --- a/Completion/Core/_files +++ b/Completion/Core/_files @@ -1,26 +1,49 @@ #autoload -# Utility function for completing files of a given type or any file. -# In many cases you will want to call this one instead of _path_files(). +local opts tmp glob pats expl tag i pat descr minus -local nm=$NMATCHES +zparseopts -a opts \ + '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X+: M+: F: J+: V+: -_path_files "$@" +type="${(@j::M)${(@)tmp#-}#?}" +(( $tmp[(I)-g*] )) && glob="${(j: :)${(M)tmp:#-g*}#-g}" -if [[ $# -ne 0 && -nmatches nm ]]; then - local opt opts +if zstyle -a ":completion:${curcontext}:" file-patterns pats; then + [[ "$type" = */* ]] && glob="$glob *(-/)" + pats=( \ ${(M)^${pats//\\%p/ ${glob:-\*} }:#*[^\\]:*} ) +else + if [[ "$type" = *g* ]]; then + if [[ "$type" = */* ]]; then + pats=( " ${glob//:/\\:} *(-/):globbed-files" '*:all-files' ) + else + pats=( " ${glob//:/\\:}:globbed-files" + '*(-/):directories' '*:all-files' ) + fi + elif [[ "$type" = */* ]]; then + pats=( '*(-/):directories' '*:all-files' ) + else + pats=( '*:all-files' ) + fi +fi - # We didn't get any matches for those types of files described by - # the `-g' or `-/' option. Now we try it again accepting all files. - # First we get those options that we have to use even if then. If - # we find out that the `-f' option was given, we already accepted - # all files and give up immediatly. +for tag in "${(@)${(@)pats#*[^\\]:}%%:*}"; do - opts=() - while getopts "P:S:W:F:J:V:X:f/g:" opt; do - [[ "$opt" = f ]] && return - [[ "$opt" = [PSWFJVX] ]] && opts=("$opts[@]" "-$opt" "$OPTARG") - done + i="$pats[(I)*[^\\\\]:${tag}(|:*)]" + pat="${${pats[i]%%:${tag}*}//\\\\:/:}" - _path_files "$opts[@]" -fi + if [[ i -gt 0 && "$pat" != \ # ]]; then + if [[ "$pats[i]" = *:${tag}:* ]]; then + descr="${pats[i]#*:${tag}:}" + minus=() + else + descr=file + minus=(-) + fi + fi + + _wanted "$tag" expl "$descr" \ + _path_files -g "$pat" "$opts[@]" "$minus[@]" && return 0 + +done + +return 1 diff --git a/Completion/Core/_ignored b/Completion/Core/_ignored index 69a5244cc..4046f4c2d 100644 --- a/Completion/Core/_ignored +++ b/Completion/Core/_ignored @@ -4,11 +4,10 @@ (( $compstate[ignored] )) || return 1 -local curcontext="${curcontext/:[^:]#:/:ignored-${(M)#_completers[1,_completer_num]:#_ignored}:}" local comp i _comp_no_ignore=yes tmp expl zstyle -a ":completion:${curcontext}:" completer comp || - comp=( "${(@)_completers[1,_completer_num-1][(R)_ignored,-1]}" ) + comp=( "${(@)_completers[1,_completer_num-1][(R)_ignored(|:*),-1]}" ) for i in "$comp[@]"; do if [[ "$i" != _ignored ]] && "$i"; then diff --git a/Completion/Core/_list b/Completion/Core/_list index 099c6bc7b..37167726c 100644 --- a/Completion/Core/_list +++ b/Completion/Core/_list @@ -1,38 +1,16 @@ #autoload # This completer function makes the other completer functions used -# insert possible completions only after once the list has been -# shown. -# -# Configuration keys: -# -# list_condition -# If this key is unset or set to the empty string, this completer -# will delay the insertion of matches unconditionally. However, -# if this value is set, it should be set to an expression usable -# inside a $[...] arithmetical expression. In this case, delaying -# will be done if the expression evaluates to `1'. -# For example, with -# -# compconf list_condition='NUMERIC != 1' -# -# delaying will be done only if given an explicit numeric argument -# other than `1'. -# -# list_word -# To find out if only listing should be done, the code normally -# compares the contents of the line with the contents the line -# had at the time of the last invocation. If this key is set to -# an non-empty string comparison is done using only the current -# word. So if it is set, attempting completion on a word equal -# to the one completion was called on the last time will not -# delay the generation of matches. - -local pre suf +# insert possible completions only after the list has been shown at +# least once. + +[[ _matcher_num -gt 1 ]] && return 1 + +local pre suf expr # Get the strings to compare. -if [[ -z "$compconfig[list_word]" ]]; then +if zstyle -t ":completion:${curcontext}:" word; then pre="$HISTNO$LBUFFER" suf="$RBUFFER" else @@ -42,16 +20,15 @@ fi # Should we only show a list now? -if [[ ( -z "$compconfig[list_condition]" || - "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ) && +zstyle -s ":completion:${curcontext}:" condition expr +if [[ ( -z "$expr" || "${(e):-\$[$expr]}" -eq 1 ) && ( "$pre" != "$_list_prefix" || "$suf" != "$_list_suffix" ) ]]; then # Yes. Tell the completion code about it and save the new values # to compare the next time. compstate[insert]='' - compstate[list]=list - compstate[force_list]=yes + compstate[list]='list force' _list_prefix="$pre" _list_suffix="$suf" fi diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete index c7f5a5a96..d9278f435 100644 --- a/Completion/Core/_main_complete +++ b/Completion/Core/_main_complete @@ -2,47 +2,206 @@ # The main loop of the completion code. This is what is called when # completion is attempted from the command line. -# The completion code gives us the special variables and the arguments -# from the command line are given as positional parameters. -local comp name -setopt localoptions nullglob rcexpandparam globdots -unsetopt markdirs globsubst shwordsplit nounset +# If you want to complete only set or unset options for the unsetopt +# and setopt builtin, un-comment these lines: +# +# local _set_options _unset_options +# +# _set_options=(${(k)options[(R)on]}) +# _unset_options=(${(k)options[(R)off]}) +# +# This is needed because completion functions may set options locally +# which makes the output of setopt and unsetopt reflect a different +# state than the global one for which you are completing. -# An entry for `-first-' is the replacement for `compctl -T' -# Completion functions may set `_compskip' to any value to make the -# main loops stop calling other completion functions. +setopt localoptions nullglob rcexpandparam extendedglob +unsetopt markdirs globsubst shwordsplit nounset ksharrays -comp="$_comps[-first-]" -if [[ ! -z "$comp" ]]; then - "$comp" "$@" - if (( $+_compskip )); then - unset _compskip - return - fi +local func funcs ret=1 tmp _compskip format _comp_ignore \ + _completers _completer _completer_num curtag \ + _matchers _matcher _matcher_num _comp_tags \ + context state line opt_args val_args curcontext="$curcontext" \ + _last_nmatches=-1 _last_menu_style _def_menu_style _menu_style sel \ + _saved_exact="${compstate[exact]}" \ + _saved_lastprompt="${compstate[last_prompt]}" \ + _saved_list="${compstate[list]}" \ + _saved_insert="${compstate[insert]}" + +typeset -U _lastdescr + +[[ -z "$curcontext" ]] && curcontext=::: + +# Special completion contexts after `~' and `='. + +if compset -P 1 '='; then + compstate[context]=equal +elif [[ "$PREFIX" != */* && "$PREFIX[1]" = '~' ]]; then + compset -p 1 + compstate[context]=tilde fi -# For arguments we use the `_normal function. +# Initial setup. + +_setup default +_def_menu_style=( "$_last_menu_style[@]" + +# We can't really do that because the current value of $SELECTMIN +# may be the one set by this function. +# There is a similar problem with $ZLS_COLORS in _setup. + +# ${SELECTMIN+select${SELECTMIN:+\=$SELECTMIN}} + + ) +_last_menu_style=() -if [[ $CONTEXT == argument || $CONTEXT == command ]]; then - _normal "$@" +# Get the names of the completers to use in the positional parameters. + +if (( $# )); then + _completers=( "$@" ) else - # Let's see if we have a special completion definition for the other - # possible contexts. + zstyle -a ":completion:${curcontext}:" completer _completers || + _completers=( _complete ) +fi + +# And now just call the completer functions defined. + +_completer_num=1 + +# Call the pre-functions. + +funcs=( "$compprefuncs[@]" ) +compprefuncs=() +for func in "$funcs[@]"; do + "$func" +done + +for tmp in "$_completers[@]"; do + + if [[ "$tmp" = *:-* ]]; then + _completer="${${tmp%:*}[2,-1]//_/-}${tmp#*:}" + tmp="${tmp%:*}" + elif [[ $tmp = *:* ]]; then + _completer="${tmp#*:}" + tmp="${tmp%:*}" + else + _completer="${tmp[2,-1]//_/-}" + fi + curcontext="${curcontext/:[^:]#:/:${_completer}:}" - comp='' + zstyle -a ":completion:${curcontext}:" matcher-list _matchers || + _matchers=( '' ) - case $CONTEXT in - redirect) comp="$_comps[-redirect-]";; - math) comp="$_comps[-math-]";; - subscript) comp="$_comps[-subscript-]";; - value) comp="$_comps[-value-]";; - condition) comp="$_comps[-condition-]";; - esac + _matcher_num=1 + for _matcher in "$_matchers[@]"; do + if "$tmp"; then + ret=0 + break 2 + fi + (( _matcher_num++ )) + done + (( _completer_num++ )) +done - # If not, we use default completion, if any. +curcontext="${curcontext/:[^:]#:/::}" - [[ -z "$comp" ]] && comp="$_comps[-default-]" - [[ -z "$comp" ]] || "$comp" "$@" +if [[ $compstate[old_list] = keep || $compstate[nmatches] -gt 1 ]]; then + [[ _last_nmatches -ge 0 && _last_nmatches -ne $compstate[nmatches] ]] && + _menu_style=( "$_last_menu_style[@]" "$_menu_style[@]" ) + + if [[ "$compstate[insert]" = "$_saved_insert" ]]; then + if [[ -n "$_menu_style[(r)(yes|true|1|on)]" || + ( -n "$_menu_style[(r)auto*]" && + "$compstate[insert]" = automenu ) ]]; then + compstate[insert]=menu + elif [[ -n "$_menu_style[(r)auto*]" && + "$compstate[insert]" != automenu ]]; then + compstate[insert]=automenu-unambiguous + elif [[ -n "$_menu_style[(r)(no|false|0|off)]" ]]; then + compstate[insert]=unambiguous + elif [[ -n "$_def_menu_style[(r)(yes|true|1|on)]" || + ( -n "$_def_menu_style[(r)auto*]" && + "$compstate[insert]" = automenu ) ]]; then + compstate[insert]=menu + elif [[ -n "$_def_menu_style[(r)auto*]" && + "$compstate[insert]" != automenu ]]; then + compstate[insert]=automenu-unambiguous + elif [[ -n "$_def_menu_style[(r)(no|false|0|off)]" ]]; then + compstate[insert]=unambiguous + fi + fi + + _menu_style=( "$_menu_style[@]" "$_def_menu_style[@]" ) + + if [[ "$compstate[insert]" = *menu* ]]; then + if [[ -n "$_menu_style[(r)no-select*]" ]]; then + unset SELECTMIN + else + sel=( "${(@M)_menu_style:#select*}" ) + + if (( $# )); then + local min=9999999 i num + + for i in "$sel[@]"; do + if [[ "$i" = *\=* ]]; then + num="${i#*\=}" + [[ num -lt 0 ]] && num=0 + else + num=0 + fi + [[ num -lt min ]] && min="$num" + + (( min )) || break + done + + zmodload -i zsh/complist + SELECTMIN="$min" + fi + fi + fi +elif [[ $compstate[nmatches] -eq 0 && + $#_lastdescr -ne 0 && $compstate[old_list] != keep ]] && + zstyle -s ":completion:${curcontext}:warnings" format format; then + + compstate[list]='list force' + compstate[insert]='' + + if [[ "$format" = *%d* ]]; then + local str mesg + + _lastdescr=( "\`${(@)^_lastdescr:#}'" ) + + case $#_lastdescr in + 1) str="$_lastdescr[1]";; + 2) str="$_lastdescr[1] or $_lastdescr[2]";; + *) str="${(j:, :)_lastdescr[1,-2]}, or $_lastdescr[-1]";; + esac + + zformat -f mesg "$format" "d:$str" + compadd -UX "$mesg" -n - '' + else + _setup warnings + compadd -UQX "$format" -V warnings - "${(@)_lastdescr:#}" + fi fi + +# Now call the post-functions. + +funcs=( "$comppostfuncs[@]" ) +comppostfuncs=() +for func in "$funcs[@]"; do + "$func" +done + +_lastcomp=( "${(@kv)compstate}" ) +_lastcomp[completer]="$_completer" +_lastcomp[prefix]="$PREFIX" +_lastcomp[suffix]="$SUFFIX" +_lastcomp[iprefix]="$IPREFIX" +_lastcomp[isuffix]="$ISUFFIX" +_lastcomp[qiprefix]="$QIPREFIX" +_lastcomp[qisuffix]="$QISUFFIX" +_lastcomp[tags]="$_comp_tags" + +return ret diff --git a/Completion/Core/_match b/Completion/Core/_match index 3c639935c..18dab7423 100644 --- a/Completion/Core/_match +++ b/Completion/Core/_match @@ -1,53 +1,51 @@ #autoload # This is intended to be used as a completer function after the normal -# completer as in: `compconf completer=_complete:_match'. +# completer as in: `zstyle ":completion:::::" completer _complete _match'. # It temporarily switches on pattern matching, allowing you to try # completion on patterns without having to setopt glob_complete. # # Note, however, that this is only really useful if you don't use the # expand-or-complete function because otherwise the pattern will # be expanded using globbing. -# -# Configuration key used: -# -# match_original -# If this is set to a `only', pattern matching will only be tried -# with the string from the line. If it is set to any other non-empty -# string, the original pattern will be tried first and if that yields -# no completions, matching will be tried again with a `*' inserted -# at the cursor position. If this key is not set or set to an empty -# string, matching will only be attempted with the `*' inserted. -local tmp opm="$compstate[pattern_match]" ret=0 +[[ _matcher_num -gt 1 ]] && return 1 + +local tmp opm="$compstate[pattern_match]" ret=0 orig ins -# Do nothing if we don't have a pattern or there are still global -# match specifications to try. +# Do nothing if we don't have a pattern. tmp="${${:-$PREFIX$SUFFIX}#[~=]}" -[[ "$tmp:q" = "$tmp" || - compstate[matcher] -ne compstate[total_matchers] ]] && return 1 +[[ "$tmp:q" = "$tmp" ]] && return 1 + +zstyle -s ":completion:${curcontext}:" match-original orig +zstyle -b ":completion:${curcontext}:" insert-unambiguous ins # Try completion without inserting a `*'? -if [[ -n "$compconfig[match_original]" ]]; then - compstate[matcher]=-1 +if [[ -n "$orig" ]]; then compstate[pattern_match]='-' _complete && ret=1 compstate[pattern_match]="$opm" - compstate[matcher]="$compstate[total_matchers]" - (( ret )) && return 0 + if (( ret )); then + [[ "$ins" = yes && + $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] && + compstate[pattern_insert]=unambiguous + return 0 + fi fi # No completion with inserting `*'? -[[ "$compconfig[match_original]" = only ]] && return 1 +[[ "$orig" = only ]] && return 1 -compstate[matcher]=-1 compstate[pattern_match]='*' _complete && ret=1 compstate[pattern_match]="$opm" -compstate[matcher]="$compstate[total_matchers]" + +[[ ret -eq 1 && "$ins" = yes && + $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] && + compstate[pattern_insert]=unambiguous return 1-ret diff --git a/Completion/Core/_menu b/Completion/Core/_menu index 4cbda4e14..41fc178ba 100644 --- a/Completion/Core/_menu +++ b/Completion/Core/_menu @@ -1,10 +1,12 @@ #autoload +[[ _matcher_num -gt 1 ]] && return 1 + # This completer is an example showing how menucompletion can be # implemented with the new completion system. # Use this one before the normal _complete completer, as in: # -# compconf completer=_menu:_complete +# zstyle ":completion:::::" completer _menu _complete if [[ -n "$compstate[old_list]" ]]; then diff --git a/Completion/Core/_next_label b/Completion/Core/_next_label new file mode 100644 index 000000000..e309e53ea --- /dev/null +++ b/Completion/Core/_next_label @@ -0,0 +1,24 @@ +#autoload + +local gopt=-J descr + +if [[ "$1" = -([12]|)[VJ] ]]; then + gopt="$1" + shift +fi + +if comptags -A "$1" curtag; then + if [[ "$curtag" = *:* ]]; then + zformat -f descr "${curtag#*:}" "d:$3" + _description "$gopt" "${curtag%:*}" "$2" "$descr" + curtag="${curtag%:*}" + eval "${2}=( \${(P)2} \$argv[4,-1] )" + else + _description "$gopt" "$curtag" "$2" "$3" + eval "${2}=( \$argv[4,-1] \${(P)2} )" + fi + + return 0 +fi + +return 1 diff --git a/Completion/Core/_oldlist b/Completion/Core/_oldlist new file mode 100644 index 000000000..bcb3e148a --- /dev/null +++ b/Completion/Core/_oldlist @@ -0,0 +1,53 @@ +#autoload + +[[ _matcher_num -gt 1 ]] && return 1 + +local list + +zstyle -s ":completion:${curcontext}:" old-list list + +# If this is a listing widget and there is already an old list, +# and either the style :oldlist:old-list is `always', or it is not `never' +# and the list is not already shown, then use the existing list for listing +# (even if it was generated by another widget). +# Do this also if there is an old list and it was generated by the +# completer named by the oldlist_list key. + +if [[ -n $compstate[old_list] && $list != never ]]; then + if [[ $WIDGET = *list* && ( $list = always || $list != shown ) ]]; then + compstate[old_list]=keep + return 0 + elif [[ $list = *${_lastcomp[completer]}* ]]; then + [[ "$_lastcomp[insert]" = unambig* ]] && compstate[to_end]=single + compstate[old_list]=keep + if [[ -o automenu ]]; then + compstate[insert]=menu + else + compadd -Qs "$SUFFIX" - "$PREFIX" + fi + return 0 + fi +fi + +# If this is a completion widget, and we have a completion inserted already, +# and the style :oldlist:old-menu is `true', then we cycle through the +# existing list (even if it was generated by another widget). + +if [[ -z $compstate[old_insert] && -n $compstate[old_list] ]]; then + compstate[old_list]=keep +elif [[ $WIDGET = *complete(|-prefix|-word) ]] && + zstyle -t ":completion:${curcontext}:" old-menu; then + if [[ -n $compstate[old_insert] ]]; then + compstate[old_list]=keep + if [[ $WIDGET = *reverse* ]]; then + compstate[insert]=$(( compstate[old_insert] - 1 )) + else + compstate[insert]=$(( compstate[old_insert] + 1 )) + fi + else + return 1 + fi + return 0 +fi + +return 1 diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 83b6e8a09..ac4614dd8 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -1,85 +1,64 @@ #autoload -# Utility function for in-path completion. -# Supported arguments are: `-f', `-/', `-g <patterns>', `-J <group>', -# `-V <group>', `-W paths', `-X explanation', and `-F <ignore>'. All but -# the last have the same syntax and meaning as for `complist'. The -# `-F <ignore>' option may be used to give a list of suffixes either by -# giving the name of an array or literally by giving them in a string -# surrounded by parentheses. Files with one of the suffixes thus given -# are treated like files with one of the suffixes in the `fignore' array -# in normal completion. -# -# This function uses the helper functions `_match_test' and `_match_pattern'. +# Utility function for in-path completion. This allows `/u/l/b<TAB>' +# to complete to `/usr/local/bin'. -# First see if we should generate matches for the global matcher in use. +local linepath realpath donepath prepath testpath exppath skips skipped +local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre +local pats haspats=no ignore pfxsfx rem remt sopt gopt opt +local nm=$compstate[nmatches] menu matcher mopts atmp sort match -_match_test _path_files || return +typeset -U prepaths exppaths -# Yes, so... - -local nm prepaths str linepath realpath donepath patstr prepath testpath rest -local tmp1 collect tmp2 suffixes i ignore matchflags opt group sopt pats gopt -local addpfx addsfx expl - -setopt localoptions nullglob rcexpandparam globdots extendedglob +setopt localoptions nullglob rcexpandparam unsetopt markdirs globsubst shwordsplit nounset -prepaths=('') -ignore=() -group=() -sopt='-' -gopt='' -pats=() -addpfx=() -addsfx=() -expl=() +exppaths=() # Get the options. -while getopts "P:S:W:F:J:V:X:f/g:" opt; do - case "$opt" in - P) addpfx=(-P "$OPTARG") - ;; - S) addsfx=(-S "$OPTARG") - ;; - W) tmp1="$OPTARG" - if [[ "$tmp1[1]" = '(' ]]; then - prepaths=( ${^=tmp1[2,-2]}/ ) - else - prepaths=( ${(P)=${tmp1}} ) - (( ! $#prepaths )) && prepaths=( ${tmp1}/ ) - fi - (( ! $#prepaths )) && prepaths=( '' ) - ;; - F) tmp1="$OPTARG" - if [[ "$tmp1[1]" = '(' ]]; then - ignore=( ${^=tmp1[2,-2]}/ ) - else - ignore=( ${(P)${tmp1}} ) - fi - (( $#ignore )) && ignore=(-F "( $ignore )") - ;; - [JV]) group=("-$opt" "$OPTARG") - ;; - X) expl=(-X "$OPTARG") - ;; - f) sopt="${sopt}f" - pats=("$pats[@]" '*') - ;; - /) sopt="${sopt}/" - pats=("$pats[@]" '*(-/)') - ;; - g) gopt='-g' - pats=("$pats[@]" ${=OPTARG}) - ;; - esac -done +zparseopts -a mopts \ + 'P:=pfxsfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \ + 'W:=prepaths' 'F:=ignore' 'M+:=matcher' \ + J+: V+: X+: 1: 2: n: 'f=tmp1' '/=tmp1' 'g+:-=tmp1' + +sopt="-${(@j::M)${(@)tmp1#-}#?}" +(( $tmp1[(I)-[/g]*] )) && haspats=yes +(( $tmp1[(I)-g*] )) && gopt=yes +if (( $tmp1[(I)-/] )); then + pats=( '*(-/)' ${=${(M)tmp1:#-g*}#-g} ) +else + pats=( "${(@)=${(@M)tmp1:#-g*}#-g}" ) +fi +pats=( "${(@)pats:# #}" ) + +if (( $#prepaths )); then + tmp1="${prepaths[2]}" + if [[ "$tmp1[1]" = '(' ]]; then + prepaths=( ${^=tmp1[2,-2]%/}/ ) + elif [[ "$tmp1[1]" = '/' ]]; then + prepaths=( "${tmp1%/}/" ) + else + prepaths=( ${(P)^tmp1%/}/ ) + (( ! $#prepaths )) && prepaths=( ${tmp1%/}/ ) + fi + (( ! $#prepaths )) && prepaths=( '' ) +else + prepaths=( '' ) +fi + +if (( $#ignore )); then + if [[ "${ignore[2]}" = \(* ]]; then + ignore=( ${=ignore[2][2,-2]} ) + else + ignore=( ${(P)ignore[2]} ) + fi +fi # If we were given no file selection option, we behave as if we were given # a `-f'. -if [[ "$sopt" = - ]]; then +if [[ "$sopt" = -(f|) ]]; then if [[ -z "$gopt" ]]; then sopt='-f' pats=('*') @@ -88,224 +67,472 @@ if [[ "$sopt" = - ]]; then fi fi -# str holds the whole string from the command line with a `*' between -# the prefix and the suffix. - -str="${PREFIX:q}*${SUFFIX:q}" - -# If the string began with a `~', the quoting turned this into `\~', -# remove the slash. +if (( ! $mopts[(I)-[JVX]] )); then + local expl -[[ "$str" = \\\~* ]] && str="$str[2,-1]" - -# We will first try normal completion called with `complist', but only if we -# weren't given a `-F' option. - -if (( ! $#ignore )); then - # First build an array containing the `-W' option, if there is any and we - # want to use it. We don't want to use it if the string from the command line - # is a absolute path or relative to the current directory. - - if [[ -z "$tmp1[1]" || "$str[1]" = [~/] || "$str" = (.|..)/* ]]; then - tmp1=() + if [[ -z "$gopt" && "$sopt" = -/ ]]; then + _description directories expl directory else - tmp1=(-W "( $prepaths )") + _description files expl file + fi + tmp1=$expl[(I)-M*] + if (( tmp1 )); then + if (( $#matcher )); then + matcher[2]="$matcher[2] $expl[1+tmp1]" + else + matcher=(-M "$expl[1+tmp1]") + fi fi + mopts=( "$mopts[@]" "$expl[@]" ) +fi - # Now call complist. +if zstyle -s ":completion:${curcontext}:files" sort tmp1; then + case "$tmp1" in + *size*) sort=oL;; + *links*) sort=ol;; + *(time|date|modi)*) sort=om;; + *access*) sort=oa;; + *(inode|change)*) sort=oc;; + *) sort=on;; + esac + [[ "$tmp1" = *rev* ]] && sort[1]=O - nm=$NMATCHES - if [[ -z "$gopt" ]]; then - complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt + if [[ "$sort" = on ]]; then + sort='' else - complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats" + mopts=( "${(@)mopts/#-J/-V}" ) + + tmp2=() + for tmp1 in "$pats[@]"; do + if [[ "$tmp1" = (#b)(?*)(\(\([^\|~]##\)\)) ]]; then + tmp2=( "$tmp2[@]" "${match[1]}((${sort}${match[2][3,-1]}" ) + elif [[ "$tmp1" = (#b)(?*)(\([^\|~]##\)) ]]; then + tmp2=( "$tmp2[@]" "${match[1]}(${sort}${match[2][2,-1]}" ) + else + tmp2=( "$tmp2[@]" "${tmp1}(${sort})" ) + fi + done + pats=( "$tmp2[@]" ) fi +fi + +# Check if we have to skip over sequences of slashes. The value of $skips +# is used below to match the pathname components we always have to accept +# immediatly. + +if zstyle -t ":completion:${curcontext}:paths" squeeze-slashes; then + skips='((.|..|)/)##' +else + skips='((.|..)/)##' +fi + +# We get the prefix and the suffix from the line and save the whole +# original string. Then we see if we will do menucompletion. + +pre="$PREFIX" +suf="$SUFFIX" +opre="$PREFIX" +osuf="$SUFFIX" +orig="${PREFIX}${SUFFIX}" +eorig="$orig" - # If this generated any matches, we don't want to do in-path completion. +[[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" || + ( -n "$compstate[pattern_match]" && + "${orig#\~}" != "${${orig#\~}:q}" ) ]] && menu=yes - [[ -nmatches nm ]] || return +# If given no `-F' option, we may want to use $fignore, turned into patterns. - # No `-F' option, so we want to use `fignore'. +[[ -z "$_comp_no_ignore" && $#ignore -eq 0 && + ( -z $gopt || "$pats" = \ #\*\ # ) && -n $FIGNORE ]] && + ignore=( "?*${^fignore[@]}" ) - ignore=(-F fignore) +if (( $#ignore )); then + _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" ) + (( $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore ) fi +(( $#matcher )) && mopts=( "$mopts[@]" "$matcher[@]" ) + # Now let's have a closer look at the string to complete. -if [[ "$str[1]" = \~ ]]; then +if [[ "$pre[1]" = \~ ]]; then # It begins with `~', so remember anything before the first slash to be able # to report it to the completion code. Also get an expanded version of it # (in `realpath'), so that we can generate the matches. Then remove that # prefix from the string to complete, set `donepath' to build the correct # paths and make sure that the loop below is run only once with an empty # prefix path by setting `prepaths'. - - linepath="${str%%/*}/" - eval realpath\=$linepath - str="${str#*/}" + + linepath="${pre[2,-1]%%/*}" + if [[ -z "$linepath" ]]; then + realpath="${HOME%/}/" + elif (( $+userdirs[$linepath] )); then + realpath="${userdirs[$linepath]%/}/" + elif (( $+nameddirs[$linepath] )); then + realpath="${nameddirs[$linepath]%/}/" + else + _message "unknown user \`$linepath'" + return 1 + fi + linepath="~${linepath}/" + [[ "$realpath" = "$linepath" ]] && return 1 + pre="${pre#*/}" + orig="${orig#*/}" + donepath='' + prepaths=( '' ) +elif [[ "$pre" = *\$*/* ]]; then + + # If there is a parameter expansion in the word from the line, we try + # to complete the beast by expanding the prefix and completing anything + # after the first slash after the parameter expansion. + # This fails for things like `f/$foo/b/<TAB>' where the first `f' is + # meant as a partial path. + + linepath="${(M)pre##*\$[^/]##/}" + realpath=${(e)~linepath} + [[ "$realpath" = "$linepath" ]] && return 1 + pre="${pre#${linepath}}" + i="${#linepath//[^\\/]}" + orig="${orig[1,(in:i:)/][1,-2]}" donepath='' prepaths=( '' ) else # If the string does not start with a `~' we don't remove a prefix from the # string. - liniepath='' + linepath='' realpath='' - if [[ "$str[1]" = / ]]; then + if [[ "$pre[1]" = / ]]; then # If it is a absolut path name, we remove the first slash and put it in # `donepath' meaning that we treat it as the path that was already handled. # Also, we don't use the paths from `-W'. - str="$str[2,-1]" + pre="$pre[2,-1]" + orig="$orig[2,-1]" donepath='/' prepaths=( '' ) else # The common case, we just use the string as it is, unless it begins with # `./' or `../' in which case we don't use the paths from `-W'. - [[ "$str" = (.|..)/* ]] && prepaths=( '' ) + [[ "$pre" = (.|..)/* ]] && prepaths=( '' ) donepath='' fi fi -# First we skip over all pathname components in `str' which really exist in -# the file-system, so that `/usr/lib/l<TAB>' doesn't offer you `lib' and -# `lib5'. Pathname components skipped this way are taken from `str' and added -# to `donepath'. +# Now we generate the matches. First we loop over all prefix paths given +# with the `-W' option. -while [[ "$str" = */* ]] do - [[ -e "$realpath$donepath${str%%/*}" ]] || break - donepath="$donepath${str%%/*}/" - str="${str#*/}" -done +for prepath in "$prepaths[@]"; do -# Now build the glob pattern by calling `_match_pattern'. -patstr="$str" -matchflags="" -_match_pattern _path_files patstr matchflags + # Get local copies of the prefix, suffix, and the prefix path to use + # in the following loop, which walks through the pathname components + # in the string from the line. -# We almost expect the pattern to have changed `..' into `*.*.', `/.' into -# `/*.', and probably to contain two or more consecutive `*'s. Since these -# have special meaning for globbing, we remove them. But before that, we -# add the pattern for matching any characters before a slash. + tpre="$pre" + tsuf="$suf" + testpath="$donepath" -patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/" + tmp2="${(M)tpre##${~skips}}" + tpre="${tpre#$tmp2}" -# Finally, generate the matches. First we loop over all the paths from `-W'. -# Note that in this loop `str' is used as a modifyable version of `patstr' -# and `testpath' is a modifyable version of `donepath'. + tmp1=( "$prepath$realpath$donepath$tmp2" ) -for prepath in "$prepaths[@]"; do - str="$patstr" - testpath="$donepath" + while true; do - # The second loop tests the components of the path in `str' to get the - # possible matches. + # Get the prefix and suffix for matching. - while [[ "$str" = */* ]] do - # `rest' is the pathname after the first slash that is left. In `tmp1' - # we get the globbing matches for the pathname component currently - # handled. + if [[ "$tpre" = */* ]]; then + PREFIX="${tpre%%/*}" + SUFFIX="" + else + PREFIX="${tpre}" + SUFFIX="${tsuf%%/*}" + fi - rest="${str#*/}" - tmp1="${prepath}${realpath}${testpath}${~matchflags}${str%%/*}(-/)" - tmp1=( $~tmp1 ) + # Get the matching files by globbing. - if [[ $#tmp1 -eq 0 ]]; then - # If this didn't produce any matches, we don't need to test this path - # any further, so continue with the next `-W' path, if any. + tmp2=( "$tmp1[@]" ) + if [[ "$tpre$tsuf" = */* ]]; then + if [[ ! -o globdots && "$PREFIX" = .* ]]; then + tmp1=( ${^tmp1}${skipped}*(-/) ${^tmp1}${skipped}.*(-/) ) + else + tmp1=( ${^tmp1}${skipped}*(-/) ) + fi + if [[ -o globdots || "$PREFIX" = .* ]] && + zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then + if [[ "$atmp" = (yes|true|1|on) ]]; then + tmp1=( "$tmp1[@]" . .. ) + elif [[ "$atmp" = .. ]]; then + tmp1=( "$tmp1[@]" .. ) + fi + fi + else + if [[ ! -o globdots && "$PREFIX" = .* ]]; then + tmp1=( ${^tmp1}${skipped}${^~pats} ${^tmp1}${skipped}.${^~pats:#.*} ) + else + tmp1=( ${^tmp1}${skipped}${^~pats} ) + fi + if [[ "$sopt" = *[/f]* && ( -o globdots || "$PREFIX" = .* ) ]] && + zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then + if [[ "$atmp" = (yes|true|1|on) ]]; then + tmp1=( "$tmp1[@]" . .. ) + elif [[ "$atmp" = .. ]]; then + tmp1=( "$tmp1[@]" .. ) + fi + fi + fi - continue 2 - elif [[ $#tmp1 -gt 1 ]]; then - # If it produced more than one match, we want to remove those which - # don't have possible following pathname components matching the - # rest of the string we are completing. (The case with only one - # match is handled below.) - # In `collect' we will collect those of the produced pathnames that - # have a matching possible path-suffix. In `suffixes' we build an - # array containing strings build from the rest of the string to - # complete and the glob patterns we were given as arguments. - - collect=() - suffixes=( $rest$^pats ) - suffixes=( "${(@)suffixes:gs.**.*.}" ) - - # In the loop the prefixes from the `tmp1' array produced above and - # the suffixes we just built are used to produce possible matches - # via globbing. - - for i in $tmp1; do - tmp2=( ${~i}/${~matchflags}${~suffixes} ) - [[ $#tmp2 -ne 0 ]] && collect=( $collect $i ) - done - - # If this test showed that none of the matches from the glob in `tmp1' - # has a possible sub-path matching what's on the line, we give up and - # continue with the next `-W' path. - - if [[ $#collect -eq 0 ]]; then + if [[ -n "$PREFIX$SUFFIX" ]]; then + # See which of them match what's on the line. + + if [[ -n "$_comp_correct" ]]; then + tmp2=( "$tmp1[@]" ) + builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}" + + if [[ $#tmp1 -eq 0 ]]; then + tmp1=( "$tmp2[@]" ) + compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}" + fi + else + [[ "$tmp1[1]" = */* ]] && tmp2=( "$tmp1[@]" ) + + builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}" + fi + + # If no file matches, save the expanded path and continue with + # the outer loop. + + if (( ! $#tmp1 )); then + if [[ "$tmp2[1]" = */* ]]; then + tmp2=( "${(@)tmp2#${prepath}${realpath}}" ) + if [[ "$tmp2[1]" = */* ]]; then + tmp2=( "${(@)tmp2:h}" ) + compquote tmp2 + if [[ "$tmp2" = */ ]]; then + exppaths=( "$exppaths[@]" ${^tmp2}${tpre}${tsuf} ) + else + exppaths=( "$exppaths[@]" ${^tmp2}/${tpre}${tsuf} ) + fi + else + exppaths=( "$exppaths[@]" ${tpre}${tsuf} ) + fi + fi continue 2 - elif [[ $#collect -ne 1 ]]; then - # If we have more than one possible match, this means that the - # pathname component currently handled is ambiguous, so we give - # it to the completion code. - # First we build the full path prefix in `tmp1'. + fi + elif (( ! $#tmp1 )); then + # A little extra hack: if we were completing `foo/<TAB>' and `foo' + # contains no files, this will normally produce no matches and other + # completers might think that's it's their time now. But if the next + # completer is _correct or something like that, this will result in + # an attempt to correct a valid directory name. So we just add the + # original string in such a case so that the command line doesn't + # change but other completers still think there are matches. + # We do this only if we weren't given a `-g' or `-/' option because + # otherwise this would keep `_files' from completing all filenames + # if none of the patterns match. + + if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then + pfxsfx=(-S '' "$pfxsfx[@]") + ### Don't remember what the break was good for. We explicitly + ### execute this only when there are no matches in the directory, + ### so why continue? + ### + ### tmp1=( "$tmp2[@]" ) + ### break + elif [[ "$haspats" = no && -z "$tpre$tsuf" && + "$pre" = */ && -z "$suf" ]]; then + PREFIX="${opre}" + SUFFIX="${osuf}" + compadd -nQS '' - "$linepath$donepath$orig" + tmp4=- + fi + continue 2 + fi - tmp1="$prepath$realpath$testpath" + if [[ -z "$_comp_no_ignore" && "$tpre$tsuf" != */* && $#tmp1 -ne 0 ]] && + zstyle -s ":completion:${curcontext}:files" ignore-parents rem && + [[ ( "$rem" != *dir* || "$pats" = '*(-/)' ) && + ( "$rem" != *..* || "$tmp1" = *../* ) ]]; then + if [[ "$rem" = *parent* ]]; then + for i in ${(M)^tmp1:#*/*}(-/); do + remt="${${i#$prepath$realpath$donepath}%/*}" + while [[ "$remt" = */* && + ! "$prepath$realpath$donepath$remt" -ef "$i" ]]; do + remt="${remt%/*}" + done + [[ "$remt" = */* || "$remt" -ef "$i" ]] && + _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" ) + done + fi + if [[ "$rem" = *pwd* ]]; then + for i in ${^tmp1}(-/); do + [[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" ) + done + fi + (( $#_comp_ignore && $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore ) + fi - # Now produce all matching pathnames in `collect'. + # Step over to the next component, if any. - collect=( ${~collect}/${~matchflags}${~suffixes} ) + if [[ "$tpre" = */* ]]; then + tpre="${tpre#*/}" + elif [[ "$tsuf" = */* ]]; then + tpre="${tsuf#*/}" + tsuf="" + else + break + fi - # And then remove the common path prefix from all these matches. + # There are more components, so skip over the next components and make a + # slash be added. - collect=( ${collect#$tmp1} ) + tmp2="${(M)tpre##((.|..|)/)##}" + if [[ -n "$tmp2" ]]; then + skipped="/$tmp2" + tpre="${tpre#$tmp2}" + else + skipped=/ + fi + done + + # The next loop searches the first ambiguous component. + + tmp3="$pre$suf" + tpre="$pre" + tsuf="$suf" + tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" ) - # Finally, we add all these matches with the common (unexpanded) - # pathprefix (the `-p' option), the path-prefix (the `-W' option) - # to allow the completion code to test file type, and the path- - # suffix (the `-s' option). We also tell the completion code that - # these are file names and that `fignore' should be used as usual - # (the `-f' and `-F' options). + while true; do - for i in $collect; do - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}" - done + # First we check if some of the files match the original string + # for this component. If there are some we remove all other + # names. This avoids having `foo' complete to `foo' and `foobar'. - # We have just finished handling all the matches from above, so we - # can continue with the next `-W' path. + if [[ "$tmp3" = */* ]]; then + tmp4=( "${(@M)tmp1:#${tmp3%%/*}/*}" ) + (( $#tmp4 )) && tmp1=( "$tmp4[@]" ) + fi + + # Next we see if this component is ambiguous. - continue 2 + if [[ "$tmp3" = */* ]]; then + tmp4=$tmp1[(I)^${(q)tmp1[1]%%/*}/*] + else + tmp4=$tmp1[(I)^${(q)tmp1[1]}] + fi + + if [[ "$tpre" = */* ]]; then + tmp2="${cpre}${tpre%%/*}" + PREFIX="${donepath}${linepath}${tmp2}" + SUFFIX="/${tpre#*/}${tsuf#*/}" + else + tmp2="${cpre}${tpre}" + PREFIX="${donepath}${linepath}${tmp2}" + SUFFIX="${tsuf}" + fi + + if (( tmp4 )) || + [[ -n "$compstate[pattern_match]" && "$tmp2" != "${(q)tmp2}" ]]; then + # It is. For menucompletion we now add the possible completions + # for this component with the unambigous prefix we have built + # and the rest of the string from the line as the suffix. + # For normal completion we add the rests of the filenames + # collected as the suffixes to make the completion code expand + # it as far as possible. + + tmp2="$testpath" + compquote tmp1 tmp2 + + if [[ -n $menu || -z "$compstate[insert]" ]] || + ! zstyle -t ":completion:${curcontext}:paths" expand suffix; then + (( tmp4 )) && zstyle -t ":completion:${curcontext}:paths" cursor && + compstate[to_end]='' + if [[ "$tmp3" = */* ]]; then + compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \ + -W "$prepath$realpath$testpath" \ + "$pfxsfx[@]" -M "r:|/=* r:|=*" \ + - "${(@)tmp1%%/*}" + else + compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ + -W "$prepath$realpath$testpath" \ + "$pfxsfx[@]" -M "r:|/=* r:|=*" \ + - "$tmp1[@]" + fi + else + if [[ "$tmp3" = */* ]]; then + atmp=( -Qf "$mopts[@]" -p "$linepath$tmp2" + -W "$prepath$realpath$testpath" + "$pfxsfx[@]" -M "r:|/=* r:|=*" ) + for i in "$tmp1[@]"; do + compadd "$atmp[@]" -s "/${i#*/}" - "${i%%/*}" + done + else + compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ + -W "$prepath$realpath$testpath" \ + "$pfxsfx[@]" -M "r:|/=* r:|=*" \ + - "$tmp1[@]" + fi fi - # We reach this point if only one of the path prefixes in `tmp1' - # has a existing path-suffix matching the string from the line. - # In this case we accept this match and continue with the next - # path-name component. + tmp4=- + break + fi + + # If we have checked all components, we stop now and add the + # strings collected after the loop. - tmp1=( "$collect[1]" ) + if [[ "$tmp3" != */* ]]; then + tmp4="" + break fi - # This is also reached if the first globbing produced only one match - # in this case we just continue with the next pathname component, too. - tmp1="$tmp1[1]" - testpath="$testpath${tmp1##*/}/" - str="$rest" + # Otherwise we add the unambiguous component to `testpath' and + # take it from the filenames. + + testpath="${testpath}${tmp1[1]%%/*}/" + tmp1=( "${(@)tmp1#*/}" ) + + tmp3="${tmp3#*/}" + + if [[ "$tpre" = */* ]]; then + cpre="${cpre}${tpre%%/*}/" + tpre="${tpre#*/}" + elif [[ "$tsuf" = */* ]]; then + cpre="${cpre}${tpre}/" + tpre="${tsuf#*/}" + tsuf="" + else + tpre="" + tsuf="" + fi done - # We are here if all pathname components except the last one (which is still - # not tested) are unambiguous. So we add matches with the full path prefix, - # no path suffix, the `-W' we are currently handling, all the matches we - # can produce in this directory, if any. - - tmp1="$prepath$realpath$testpath" - suffixes=( $str$^pats ) - suffixes=( "${(@)suffixes:gs.**.*.}" ) - tmp2=( ${~tmp1}${~matchflags}${~suffixes} ) - if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then - [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]" - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath" - else - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1} + if [[ -z "$tmp4" ]]; then + if [[ "$osuf" = */* ]]; then + PREFIX="${opre}${osuf}" + SUFFIX="" + else + PREFIX="${opre}" + SUFFIX="${osuf}" + fi + tmp4="$testpath" + compquote tmp4 tmp1 + compadd -Qf "$mopts[@]" -p "$linepath$tmp4" -W "$prepath$realpath$testpath" \ + "$pfxsfx[@]" -M "r:|/=* r:|=*" - "$tmp1[@]" fi done + +# If we are configured to expand paths as far as possible and we collected +# expanded paths that are different from the string on the line, we add +# them as possible matches. + +if zstyle -t ":completion:${curcontext}:paths" expand prefix && + [[ nm -eq compstate[nmatches] && $#exppaths -ne 0 && + "$exppaths" != "$eorig" ]]; then + PREFIX="${opre}" + SUFFIX="${osuf}" + compadd -Q "$mopts[@]" -S '' -M "r:|/=* r:|=*" -p "$linepath" - "$exppaths[@]" +fi + +[[ nm -ne compstate[nmatches] ]] diff --git a/Completion/Core/_prefix b/Completion/Core/_prefix index 6306b4aa0..f6e3b0831 100644 --- a/Completion/Core/_prefix +++ b/Completion/Core/_prefix @@ -4,10 +4,10 @@ [[ -n "$SUFFIX" ]] || return 1 -local curcontext="${curcontext/:[^:]#:/:prefix:}" comp i +local comp i zstyle -a ":completion:${curcontext}:" completer comp || - comp=( "${(@)_completers[1,-${#_completers_left}-1][(R)_prefix,-1]}" ) + comp=( "${(@)_completers[1,_completer_num-1][(R)_prefix(|:*),-1]}" ) if zstyle -t ":completion:${curcontext}:" add-space; then ISUFFIX=" $SUFFIX" diff --git a/Completion/Core/_requested b/Completion/Core/_requested index 082c45820..bd838a28e 100644 --- a/Completion/Core/_requested +++ b/Completion/Core/_requested @@ -1,9 +1,20 @@ #autoload -local tag tname="$funcstack[2,-1]" +local gopt=-J -for tag; do - [[ "${_cur_tags[${tname}]}" = *:${tag}(:|\[*\]:)* ]] && return 0 -done +if [[ "$1" = -([12]|)[VJ] ]]; then + gopt="$1" + shift +fi -return 1 +if comptags -R "$1"; then + _comp_tags="$_comp_tags $1" + if [[ $# -gt 3 ]]; then + _all_labels "$gopt" "$@" + elif [[ $# -gt 1 ]]; then + _description "$gopt" "$@" + fi + return 0 +else + return 1 +fi diff --git a/Completion/Core/_setup b/Completion/Core/_setup index f12c34b34..ed7307e69 100644 --- a/Completion/Core/_setup +++ b/Completion/Core/_setup @@ -1,13 +1,61 @@ #autoload -local colors i - -for i; do - if _style -a "$i" list-colors colors; then - if [[ "$1" = default ]]; then - ZLS_COLORS="${(j.:.)${(@)colors:gs/:/\\\:}}" - else - eval "ZLS_COLORS=\"(${i})\${(j.:(${i}).)\${(@)colors:gs/:/\\\:}}:\${ZLS_COLORS}\"" - fi +local val nm="$compstate[nmatches]" + +if zstyle -a ":completion:${curcontext}:$1" list-colors val; then + zmodload -i zsh/complist + if [[ "$1" = default ]]; then + ZLS_COLORS="${(j.:.)${(@)val:gs/:/\\\:}}" + else + eval "ZLS_COLORS=\"(${1})\${(j.:(${1}).)\${(@)val:gs/:/\\\:}}:\${ZLS_COLORS}\"" fi -done + +# Here is the problem mentioned in _main_complete. + +# elif [[ "$1" = default && -n "$ZLS_COLORS$ZLS_COLOURS" ]]; then +# zmodload -i zsh/complist +# ZLS_COLORS="$ZLS_COLORS$ZLS_COLOURS" + +fi + +if zstyle -t ":completion:${curcontext}:$1" list-packed; then + compstate[list]="${compstate[list]} packed" +elif [[ $? -eq 1 ]]; then + compstate[list]="${compstate[list]:gs/packed//}" +else + compstate[list]="$_saved_list" +fi + +if zstyle -t ":completion:${curcontext}:$1" list-rows-first; then + compstate[list]="${compstate[list]} rows" +elif [[ $? -eq 1 ]]; then + compstate[list]="${compstate[list]:gs/rows//}" +else + compstate[list]="$_saved_list" +fi + +if zstyle -t ":completion:${curcontext}:$1" last-prompt; then + compstate[last_prompt]=yes +elif [[ $? -eq 1 ]]; then + compstate[last_prompt]='' +else + compstate[last_prompt]="$_saved_lastprompt" +fi + +if zstyle -t ":completion:${curcontext}:$1" accept-exact; then + compstate[exact]=accept +elif [[ $? -eq 1 ]]; then + compstate[exact]='' +else + compstate[exact]="$_saved_exact" +fi + +[[ _last_nmatches -ge 0 && _last_nmatches -ne nm ]] && + _menu_style=( "$_last_menu_style[@]" "$_menu_style[@]" ) + +if zstyle -a ":completion:${curcontext}:$1" menu val; then + _last_nmatches=$nm + _last_menu_style=( "$val[@]" ) +else + _last_nmatches=-1 +fi diff --git a/Completion/Core/_tags b/Completion/Core/_tags index af8dc21dd..496f5b7e0 100644 --- a/Completion/Core/_tags +++ b/Completion/Core/_tags @@ -1,81 +1,83 @@ #autoload -if (( $# )); then - local cmd="$words[1]" func="$funcstack[2]" defs i tags tag pat style prio - - while getopts 'c:f:' i; do - if [[ "$i" = c ]]; then - cmd="$OPTARG" - else - func="$OPTARG" - fi - done - - shift OPTIND-1 - - defs=( "${(@M)argv:#${(kj:|:)~override_tags[(R)(|+*)]}}" ) - (( $#defs )) && set -- "$defs[@]" - - _offered_tags=( "$_offered_tags[@]" "$@" ) - _last_tags=() - - defs=() - for i; do - if [[ -n ${override_tags[$i]} && ${override_tags[$i]} != (\[|+\[)* ]]; then - if [[ ${override_tags[$i]} = *\[* ]]; then - prio=( "${i}:*=${override_tags[$i]#+}" ) - else - prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" ) - (( $#prio )) || prio=( "${i}:${comptags[any]}" ) - prio="${${${prio[(r)(|*:)\*=[^:]#\[*\](|:*)]}##(|*:)\*}%%:*}" - prio=( "${i}:*=${override_tags[$i]#+}${(M)prio%%\[*\]}" ) - fi - else - prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" ) - (( $#prio )) || prio=( "${i}:${comptags[any]}" ) - fi - defs=( "$defs[@]" "$prio[@]" ) - done - - tags=() - for i in "$defs[@]"; do - tag="${i%%:*}" - for pat in "${(s.:.)i#*:}"; do - if [[ ( "$pat" = _* && "$func" = ${~pat%%\=*} ) || - "$cmd" = ${~pat%%\=*} ]]; then - prio="${pat#*\=}" - [[ "$prio" = -* ]] && continue 2 - - if [[ "$prio" = *\[*\] ]]; then - style="${(M)prio%%\[*}" - prio="${prio%%\[*}" - else - style='' - fi - [[ ${override_tags[$tag]} = (|+)\[* ]] && - style="${override_tags[$tag]#+}" - - (( prio++ )) - - tags[$prio]="${tags[$prio]}:${tag}${style}" - break - fi - done - done +local prev - prios=( "${(@)tags:#}" ) +# A `--' as the first argument says that we should tell comptags to use +# the preceding function nesting level. This is only documented here because +# if everythings goes well, users won't have to worry about it and should +# not mess with it. - return 0 +if [[ "$1" = -- ]]; then + prev=- + shift fi -_failed_tags=( "$_failed_tags[@]" "$_last_tags[@]" ) +if (( $# )); then + + # We have arguments: the tags supported in this context. + + local curcontext="$curcontext" order tag nodef tmp + + if [[ "$1" = -C?* ]]; then + curcontext="${curcontext%:*}:${1[3,-1]}" + shift + elif [[ "$1" = -C ]]; then + curcontext="${curcontext%:*}:${2}" + shift 2 + else + targs=() + fi + + [[ "$1" = -(|-) ]] && shift -(( $#prios )) || return 1 + if zstyle -a ":completion:${curcontext}:" group-order order; then + local name -tags="${prios[1]}:" -shift 1 prios + for name in "$order[@]"; do + compadd -J "$name" + compadd -V "$name" + compadd -J "$name" -1 + compadd -V "$name" -1 + compadd -J "$name" -2 + compadd -V "$name" -2 + done + fi + + # Set and remember offered tags. + + comptags "-i$prev" "$curcontext" "$@" + + # Sort the tags. + + if [[ -n "$_sort_tags" ]]; then + "$_sort_tags" "$@" + else + zstyle -a ":completion:${curcontext}:" tag-order order || + order=('arguments values' options) + + for tag in $order; do + case $tag in + -) nodef=yes;; + *\(\)) if ! "${${tag%%[ ]#\(\)}##[ ]#}" "$@"; then + nodef=yes + break + fi + ;; + \!*) comptry "${(@)argv:#(${(j:|:)~${=~tag[2,-1]}})}";; + ?*) comptry -m "$tag";; + esac + done + + [[ -z "$nodef" ]] && comptry "$@" + fi + + # Return non-zero if at least one set of tags should be used. + + comptags "-T$prev" + + return +fi -_last_tags=( "${(@s.:.)${${tags#:}%:}}" ) -_tried_tags=( "$_tried_tags[@]" "$_last_tags[@]" ) +# The other mode: switch to the next set of tags. -return 0 +comptags "-N$prev" diff --git a/Completion/Core/_wanted b/Completion/Core/_wanted index 7baa3e724..32875ec57 100644 --- a/Completion/Core/_wanted +++ b/Completion/Core/_wanted @@ -1,6 +1,6 @@ #autoload -local targs +local targs gopt=-J if [[ "$1" = -C?* ]]; then targs=( -C "${1[3,-1]}" ) @@ -12,10 +12,22 @@ else targs=() fi -[[ "$1" = -(|-) ]] && shift +if [[ "$1" = -([12]|)[VJ] ]]; then + gopt="$1" + shift +fi + +if [[ $# -gt 3 ]]; then + if _tags "$targs[@]" "$1"; then + _comp_tags="$_comp_tags $1" -if [[ $# -gt 1 ]]; then - _tags "$targs[@]" "$1" && _description "${(@)argv[2,-1]}" + _all_labels -t "$gopt" "$@" + else + return 1 + fi +elif [[ $# -gt 1 ]]; then + _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1" && + _description "$gopt" "$@" else - _tags "$targs[@]" "$1" + _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1" fi diff --git a/Completion/Core/compdump b/Completion/Core/compdump index 8be096f50..3cccbd06e 100644 --- a/Completion/Core/compdump +++ b/Completion/Core/compdump @@ -1,4 +1,4 @@ -# This is a file to be sourced to dump the definitions for new-style +# This is a function to dump the definitions for new-style # completion defined by 'compinit' in the same directory. The output # should be directed into the "compinit.dump" in the same directory as # compinit. If you rename init, just stick .dump onto the end of whatever @@ -9,33 +9,46 @@ # To do this, simply remove the .dump file, start a new shell, and # create the .dump file as before. Again, compinit -d handles this # automatically. -# -# It relies on KSH_ARRAYS not being set. # Print the number of files used for completion. This is used in compinit # to see if auto-dump should re-dump the dump-file. -_d_file=${COMPDUMP-${0:h}/compinit.dump} +emulate -L zsh +setopt extendedglob + +typeset _d_file _d_f _d_bks _d_line _d_als + +_d_file=${_comp_dumpfile-${0:h}/compinit.dump}.$HOST.$$ typeset -U _d_files -_d_files=( ${^~fpath}/_*~*~(N:t) ) +_d_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) ) print "#files: $#_d_files" > $_d_file -unset _d_files - # First dump the arrays _comps and _patcomps. The quoting hieroglyphyics # ensure that a single quote inside a variable is itself correctly quoted. print "_comps=(" >> $_d_file for _d_f in ${(ok)_comps}; do - print -r - "'${_d_f//\'/'\\''}'" "'${_comps[$_d_f]//\'/'\\''}'" + print -r - "${(q)_d_f}" "${(q)_comps[$_d_f]}" done >> $_d_file print ")" >> $_d_file print "\n_patcomps=(" >> $_d_file -for _d_f in "$_patcomps[@]"; do - print -r - "'${_d_f//\'/'\\''}'" +for _d_f in "${(ok@)_patcomps}"; do + print -r - "${(q)_d_f}" "${(q)_patcomps[$_d_f]}" +done >> $_d_file +print ")" >> $_d_file + +print "\n_postpatcomps=(" >> $_d_file +for _d_f in "${(ok@)_postpatcomps}"; do + print -r - "${(q)_d_f}" "${(q)_postpatcomps[$_d_f]}" +done >> $_d_file +print ")" >> $_d_file + +print "\n_compautos=(" >> $_d_file +for _d_f in "${(ok@)_compautos}"; do + print -r - "${(q)_d_f}" "${(q)_compautos[$_d_f]}" done >> $_d_file print ")" >> $_d_file @@ -44,11 +57,13 @@ print >> $_d_file # Now dump the key bindings. We dump all bindings for zle widgets # whose names start with a underscore. # We need both the zle -C's and the bindkey's to recreate. +# We can ignore any zle -C which rebinds a standard widget (second +# argument to zle does not begin with a `_'). _d_bks=() zle -lL | while read -rA _d_line; do - if [[ ${_d_line[5]} = _* ]]; then + if [[ ${_d_line[3]} = _* && ${_d_line[5]} = _* ]]; then print -r - ${_d_line} _d_bks=($_d_bks ${_d_line[3]}) fi @@ -73,17 +88,26 @@ done)) # print them out: about five to a line looks neat +_i=5 +print -n autoload -U >> $_d_file while (( $#_d_als )); do - print -n autoload - for (( _i = 0; _i < 5; _i++ )); do - if (( $#_d_als )); then - print -n " $_d_als[1]" - shift _d_als + if (( ! $+_compautos[$_d_als[1]] )); then + print -n " $_d_als[1]" + if (( _i-- && $#_d_als > 1 )); then + _i=5 + print -n '\nautoload -U' fi - done - print + fi + shift _d_als done >> $_d_file print >> $_d_file -unset _d_line _d_zle _d_bks _d_als _d_f _f_file +for _i in "${(ok@)_compautos}"; do + print "autoload -U $_compautos[$_i] $_i" >> $_d_file +done + +mv $_d_file ${_d_file%.$HOST.$$} + +unfunction compdump +autoload -U compdump diff --git a/Completion/Core/compinit b/Completion/Core/compinit index ec5867838..6a35d17a7 100644 --- a/Completion/Core/compinit +++ b/Completion/Core/compinit @@ -1,25 +1,23 @@ # Initialisation for new style completion. This mainly contains some helper -# function and aliases. Everything else is split into different files in this -# directory that will automatically be made autoloaded (see the end of this -# file). +# functions and aliases. Everything else is split into different files that +# will automatically be made autoloaded (see the end of this file). # The names of the files that will be considered for autoloading have to -# start with a underscores (like `_setopt). +# start with an underscores (like `_setopt'). # The first line of these files will be read and has to say what should be # done with its contents: # -# `#defcomp <names ...>' -# if the first line looks like this, the file is -# autoloaded as a function and that function will -# be called to generate the matches when completing -# for one of the commands whose <name> is given +# `#compdef <names ...>' +# If the first line looks like this, the file is autoloaded as a +# function and that function will be called to generate the matches +# when completing for one of the commands whose <names> are given. # -# `#defpatcomp <pattern>' -# this defines a function that should be called to generate -# matches for commands whose name matches <pattern>; note -# that only one pattern may be given +# `#compdef -p <pattern>' +# This defines a function that should be called to generate matches +# for commands whose name matches <pattern>. Note that only one pattern +# may be given. # -# `#defkeycomp <style> [ <key-sequence> ... ] -# this is used to bind special completions to all the given +# `#compdef -k <style> [ <key-sequence> ... ]' +# This is used to bind special completions to all the given # <key-sequence>(s). The <style> is the name of one of the built-in # completion widgets (complete-word, delete-char-or-list, # expand-or-complete, expand-or-complete-prefix, list-choices, @@ -29,35 +27,89 @@ # rather than by the context. The widget has the same name as # the autoload file and can be bound using bindkey in the normal way. # -# `#autoload' -# this is for helper functions that are not used to +# `#compdef -K <widget-name> <style> <key-sequence> [ ... ]' +# This is similar to -k, except it takes any number of sets of +# three arguments. In each set, the widget <widget-name> will +# be defined, which will behave as <style>, as with -k, and will +# be bound to <key-sequence>, exactly one of which must be defined. +# <widget-name> must be different for each: this must begin with an +# underscore, else one will be added, and should not clash with other +# completion widgets (names based on the name of the function are the +# clearest), but is otherwise arbitrary. It can be tested in the +# function by the parameter $WIDGET. +# +# `#autoload [ <options> ]' +# This is for helper functions that are not used to # generate matches, but should automatically be loaded -# when they are called +# when they are called. The <options> will be given to the +# autoload builtin when making the function autoloaded. Note +# that this need not include `-U'. # # Note that no white space is allowed between the `#' and the rest of # the string. # -# See the file `compdump' for how to speed up initialiation. -# -# If you are using global matching specifications with `compctl -M ...' -# have a look at the files `_match_test' and `_match_pattern'. To make -# all the example functions use matching as specified with `-M' these -# need some editing. +# Functions that are used to generate matches should return zero if they +# were able to add matches and non-zero otherwise. # +# See the file `compdump' for how to speed up initialisation. + # If we got the `-d'-flag, we will automatically dump the new state (at -# the end). +# the end). This takes the dumpfile as an argument. -d (with the +# default dumpfile) is now the default; to turn off dumping use -D. + +emulate -L zsh +setopt extendedglob + +typeset _i_dumpfile _i_files _i_line _i_done _i_dir _i_autodump=1 +typeset _i_tag _i_file _i_addfiles + +while [[ $# -gt 0 && $1 = -[dDf] ]]; do + if [[ "$1" = -d ]]; then + _i_autodump=1 + shift + if [[ $# -gt 0 && "$1" != -[df] ]]; then + _i_dumpfile="$1" + shift + fi + elif [[ "$1" = -D ]]; then + _i_autodump=0 + shift + elif [[ "$1" = -f ]]; then + # Not used any more; use _compdir + shift + shift + fi +done -if [[ "$1" = -d ]]; then - _i_autodump=1 +# The associative array containing the definitions for the commands. +# Definitions for patterns will be stored in the associations `_patcomps' +# and `_postpatcomps'. `_compautos' contains the names and options +# for autoloaded functions that get options. + +typeset -gA _comps _patcomps _postpatcomps _compautos + +# The associative array use to report information about the last +# cmpletion to the outside. + +typeset -gA _lastcomp + +# Remember dumpfile. +if [[ -n $_i_dumpfile ]]; then + # Explicitly supplied dumpfile. + _comp_dumpfile="$_i_dumpfile" else - _i_autodump=0 + _comp_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump" fi -# The associative array containing the definitions for the commands. -# Definitions for patterns will be stored in the normal array `_patcomps'. +# These can hold names of functions that are to be called before/after all +# matches have been generated. -typeset -A _comps -_patcomps=() +compprefuncs=() +comppostfuncs=() + +# Loading it now ensures that the `funcstack' parameter is always correct. + +: $funcstack # This function is used to register or delete completion functions. For # registering completion functions, it is invoked with the name of the @@ -70,6 +122,9 @@ _patcomps=() # function will be invoked when completing for a command whose name # matches the pattern given as argument after the function name (in this # case only one argument is accepted). +# The option `-P' is like `-p', but the function will be called after +# trying to find a function defined for the command on the line if no +# such function could be found. # With the `-k' option a function for a special completion keys is # defined and immediatly bound to those keys. Here, the extra arguments # are the name of one of the builtin completion widgets and any number @@ -78,7 +133,8 @@ _patcomps=() # whose name is given as the first argument be autoloaded. When defining # a function for command names the `-n' option may be given and keeps # the definitions from overriding any previous definitions for the -# commands. +# commands; with `-k', the `-n' option prevents compdef from rebinding +# a key sequence which is already bound. # For deleting definitions, the `-d' option must be given. Without the # `-p' option, this deletes definitions for functions for the commands # whose names are given as arguments. If combined with the `-p' option @@ -110,11 +166,16 @@ compdef() { # Get the options. - while getopts "anpkd" opt; do + if [[ $#* -eq 0 ]]; then + echo "compdef needs parameters" + return 1 + fi + + while getopts "anpPkKd" opt; do case "$opt" in a) autol=yes;; n) new=yes;; - [pk]) if [[ -n "$type" ]]; then + [pPkK]) if [[ -n "$type" ]]; then # Error if both `-p' and `-k' are given (or one of them # twice). echo "$0: type already set to $type" @@ -122,6 +183,10 @@ compdef() { fi if [[ "$opt" = p ]]; then type=pattern + elif [[ "$opt" = P ]]; then + type=postpattern + elif [[ "$opt" = K ]]; then + type=widgetkey else type=key fi @@ -131,12 +196,17 @@ compdef() { done shift OPTIND-1 + if [[ $#* -eq 0 ]]; then + echo "compdef needs parameters" + return 1 + fi + if [[ -z "$delete" ]]; then # Adding definitions, first get the name of the function name # and probably do autoloading. func="$1" - [[ -n "$autol" ]] && autoload "$func" + [[ -n "$autol" ]] && autoload -U "$func" shift case "$type" in @@ -145,11 +215,33 @@ compdef() { echo "$0: only one pattern allowed" return 1 fi - # Patterns are stored in strings like `c* foo', with a space - # between the pattern and the function name. - - _patcomps=("$_patcomps[@]" "$1 $func") + _patcomps[$1]="$func" ;; + postpattern) + if [[ $# -gt 1 ]]; then + echo "$0: only one pattern allowed" + return 1 + fi + _postpatcomps[$1]="$func" + ;; + widgetkey) + while [[ -n $1 ]]; do + if [[ $# -lt 3 ]]; then + echo "$0: compdef -K requires <widget> <comp-widget> <key>" + return 1 + fi + [[ $1 = _* ]] || 1="_$1" + [[ $2 = .* ]] || 2=".$2" + zle -C "$1" "$2" "$func" + if [[ -n $new ]]; then + bindkey "$3" | read -A opt + [[ $opt[-1] = undefined-key ]] && bindkey "$3" "$1" + else + bindkey "$3" "$1" + fi + shift 3 + done + ;; key) if [[ $# -lt 2 ]]; then echo "$0: missing keys" @@ -157,30 +249,44 @@ compdef() { fi # Define the widget. - zle -C "$func" "$1" "$func" + if [[ $1 = .* ]]; then + zle -C "$func" "$1" "$func" + else + zle -C "$func" ".$1" "$func" + fi shift # And bind the keys... for i; do + if [[ -n $new ]]; then + bindkey "$i" | read -A opt + [[ $opt[-1] = undefined-key ]] || continue + fi bindkey "$i" "$func" done ;; *) # For commands store the function name in the `_comps' # associative array, command names as keys. - for i; do - [[ -z "$new" || "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func" - done + if [[ -z "$new" ]]; then + for i; do + _comps[$i]="$func" + done + else + for i; do + [[ "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func" + done + fi ;; esac else # Handle the `-d' option, deleting. case "$type" in pattern) - # Note the space. - for i; do - _patcomps=("${(@)patcomps:#$i *}") - done + unset "_patcomps[$^@]" + ;; + postpattern) + unset "_postpatcomps[$^@]" ;; key) # Oops, cannot do that yet. @@ -189,81 +295,210 @@ compdef() { return 1 ;; *) - # Deleting definitons for command is even simpler. - for i; do - unset "_comps[$i]" - done + unset "_comps[$^@]" esac fi } -# Now we automatically make the definition files autoloaded. +# Do *not* use this... -# First we get the name of a dump file if this will be used. +compconf() { -: ${COMPDUMP:=$0.dump} + local style name val i tmp cmt -if [[ ! -o extendedglob ]]; then - _i_noextglob=yes - setopt extendedglob -fi + if [[ -z "$_compconf_warn" ]]; then + _compconf_warn=yep + + print " + +Hello + +\`compconf' will be removed in the near future, we now use a more +general (and powerful) mechanism using the \`zstyle' builtin. An +approximation to your old setup using \`zstyle' should be available +in the file: + + \`${HOME}/.zsh-styles' + +Note that the values for the styles may be partly incorrect. Please +read the manual to find out how to configure the completion system +with styles. + +Have fun + + Sven +" 1>&2 + command rm -f ${HOME}/.zsh-styles + fi + + for i; do + name="${i%%\=*}" + val="${i#*\=}" + + tmp='' + cmt='' + + case "$name" in + urls_path) + tmp="'*:urls' path ${(qq)val}" + ;; + urls_localhttp) + tmp="'*:urls' local ${${(qqs.:.)val}}" + ;; + describe_options) + tmp="'*:options' verbose 'yes'" + ;; + describe_values) + tmp="'*:values' verbose 'yes'" + ;; + autodescribe_options) + tmp="'*:options' auto-description ${(qq)val}" + ;; + description_format) + tmp="'*:descriptions' format ${(qq)val}" + ;; + message_format) + tmp="'*:messages' format ${(qq)val}" + ;; + warning_format) + tmp="'*:warnings' format ${(qq)val}" + ;; + option_prefix) + tmp="'*:options' prefix-needed yes" + [[ "$val" = hide* ]] && + tmp="$tmp +zstyle ':completion:*:options' prefix-hidden yes" + ;; + group_matches) + tmp="'*' group-name ''" + ;; + colors_path) + tmp="'*:colors' path ${(qq)val}" + ;; + path_expand) + tmp="'*:paths' expand ${(qq)val}" + ;; + path_cursor) + tmp="'*:paths' cursor ${(qq)val}" + ;; + (approximate|incremental|predict|list|oldlist|match)_*) + tmp="'*${name%%_*}:*' ${${name#*_}//_/-} ${(qq)val}" + ;; + correct_*) + cmt="# This one is a bit ugly. You may want to use only \`*:correct' +# if you also have the \`correctword_*' or \`approximate_*' keys. +" + tmp="'*(correct(|-word)|approximate):*' ${name#*_} ${(qq)val}" + ;; + correctword_*) + tmp="'*:correct-word' ${name#correctword_} ${(qq)val}" + ;; + expand_*) + cmt="# This one is a bit ugly. You may want to use only \`*:expand' +# if you also have the \`expandword_*' keys. +" + tmp="'*expand(|expand-word):*' ${name#*_} ${(qq)val}" + ;; + expandword_*) + tmp="'expand-word:*' ${name#expandword_} ${(qq)val}" + ;; + history_*) + tmp="'history-words:*' ${name#history_} ${(qq)val}" + ;; + completer) + tmp="'*' completer ${${(qqs.:.)val}}" + ;; + last_prompt) + tmp="'*' last-prompt 'yes'" + ;; + esac + [[ -n "$tmp" ]] && style="${style}${cmt}zstyle :completion:${tmp} +" + done + + eval "${style}" + + print "$style" >>! ${HOME}/.zsh-styles +} + +# Now we automatically make the definition files autoloaded. typeset -U _i_files -_i_files=( ${^~fpath}/_*~*~(N:t) ) -_i_initname=$0 +_i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) ) +if [[ $#_i_files -lt 20 || $_compdir = */Core || -d $_compdir/Core ]]; then + # Too few files: we need some more directories, + # or we need to check that all directories (not just Core) are present. + if [[ -n $_compdir ]]; then + _i_addfiles=() + if [[ $_compdir = */Core ]]; then + # Add all the Completion subdirectories + _i_addfiles=(${_compdir:h}/*(/)) + elif [[ -d $_compdir/Core ]]; then + # Likewise + _i_addfiles=(${_compdir}/*(/)) + fi + for _i_line in {1..$#i_addfiles}; do + _i_file=${_i_addfiles[$_i_line]} + [[ -d $_i_file && -z ${fpath[(r)$_i_file]} ]] || + _i_addfiles[$_i_line]= + done + fpath=($fpath $_i_addfiles) + _i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) ) + fi +fi + + +# Rebind the standard widgets +for _i_line in complete-word delete-char-or-list expand-or-complete \ + expand-or-complete-prefix list-choices menu-complete \ + menu-expand-or-complete reverse-menu-complete; do + zle -C $_i_line .$_i_line _main_complete +done +zle -la menu-select && zle -C menu-select .menu-select _main_complete + _i_done='' +# Make sure compdump is available, even if we aren't going to use it. +autoload -U compdump compinstall + # If we have a dump file, load it. -if [[ -f "$COMPDUMP" ]]; then - read -rA _i_line < "$COMPDUMP" +if [[ -f "$_comp_dumpfile" ]]; then + read -rA _i_line < "$_comp_dumpfile" if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then - builtin . "$COMPDUMP" + builtin . "$_comp_dumpfile" _i_done=yes fi - unset _i_line fi if [[ -z "$_i_done" ]]; then for _i_dir in $fpath; do [[ $_i_dir = . ]] && continue - for _i_file in $_i_dir/_*~*~(N); do + for _i_file in $_i_dir/^([^_]*|*~|*.zwc)(N); do read -rA _i_line < $_i_file _i_tag=$_i_line[1] shift _i_line - if [[ $_i_tag = '#defcomp' ]]; then - compdef -na "${_i_file:t}" "${_i_line[@]}" - elif [[ $_i_tag = '#defpatcomp' ]]; then - compdef -pa "${_i_file:t}" "${_i_line[@]}" - elif [[ $_i_tag = '#defkeycomp' ]]; then - compdef -ka "${_i_file:t}" "${_i_line[@]}" - elif [[ $_i_tag = '#autoload' ]]; then - autoload ${_i_file:t} - fi + case $_i_tag in + (\#compdef) + if [[ $_i_line[1] = -[pPkK](n|) ]]; then + compdef ${_i_line[1]}na "${_i_file:t}" "${(@)_i_line[2,-1]}" + else + compdef -na "${_i_file:t}" "${_i_line[@]}" + fi + ;; + (\#autoload) + autoload -U "$_i_line[@]" ${_i_file:t} + [[ "$_i_line" != \ # ]] && _compautos[${_i_file:t}]="$_i_line" + ;; + esac done done - bindkey | - while read -rA _i_line; do - if [[ "$_i_line[2]" = complete-word || - "$_i_line[2]" = delete-char-or-list || - "$_i_line[2]" = expand-or-complete || - "$_i_line[2]" = expand-or-complete-prefix || - "$_i_line[2]" = list-choices || - "$_i_line[2]" = menu-complete || - "$_i_line[2]" = menu-expand-or-complete || - "$_i_line[2]" = reverse-menu-complete ]]; then - zle -C _complete_$_i_line[2] $_i_line[2] _main_complete - bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2] - fi - done - - unset _i_dir _i_line _i_file _i_tag - # If autodumping was requested, do it now. - (( _i_autodump )) && builtin . ${_i_initname:h}/compdump + if [[ $_i_autodump = 1 ]]; then + compdump + fi fi -[[ -z "$_i_noextglob" ]] || unsetopt extendedglob - -unset _i_files _i_initname _i_done _i_autodump _i_noextglob +unfunction compinit +autoload -U compinit diff --git a/Completion/Core/compinstall b/Completion/Core/compinstall index d96121cf2..ad05cb5a1 100644 --- a/Completion/Core/compinstall +++ b/Completion/Core/compinstall @@ -1,72 +1,149 @@ -# This script is to be run by a user to setup the new function based +# This script is to be run by a user to set up the new function based # completion system. The functions themselves are assumed to be already # available in some directory; they should have been installed with the -# the shell (except we haven't written that yet). +# the shell. If they have been, the commands `autoload -U compinit; compinit' +# in the shell startup file should be enough, although you can run +# compinstall for more configuration choices. # -# Run it as a script under zsh and answer the questions. -# You can run it as `zsh compinstall $FPATH' and it will be able to check -# your function path for the completion functions. -# -# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it), -# but you can make that unwritable and it will leave the lines in a -# temporary file instead. -# -# You can use this script to modify what compinstall previously -# added to ~/.zshrc. +# Simply run this script as a function and answer the questions. +# Normally it will alter ~/.zshrc (or wherever ZDOTDIR puts it), but you +# can make that unwritable and it will leave the lines in a temporary file +# instead. It doesn't matter if .zshrc didn't exist before. If your +# .zshrc usually exits before the end, then you should take the code added +# by compinstall and put it (including the comment lines at the start and +# end) at the point you want it to be executed. If you run compinstall +# again it will find and replace those lines, so you can use this script to +# modify what compinstall previously added to ~/.zshrc. # # It is safe to abort with ^C any time you are being prompted for # information; your .zshrc will not be altered. # # To do: -# - Maybe this should be sourced, then it can check the user's current -# setup better. But then there is a potentially horrendous option -# setting/resetting problem. (Maybe we need another way of doing that.) # - Should probably offer to set different options for _approximate than # for _complete if both are used. # - Could add code for setting other completers and options. # - Could add keys for context-sensitive help. -# - Probably should allow a set of directories to be added to $fpath, -# like Core, Base, etc. -# In case a startup script changed options -emulate zsh -[[ -n $1 ]] && FPATH=$1 +emulate -L zsh -for f in $fpath; do - if [[ $f != . && -f $f/compinit && -f $f/compdump ]]; then - fdir=$f - break - fi -done +typeset _ci_options _ci_f _ci_fdir _ci_files _ci_dumpfile _ci_lines +typeset _ci_type _ci_completer _ci_accept _ci_cprompt _ci_startline +typeset _ci_endline _ci_ifile _ci_tmpf _ci_compstyle _ci_warn +typeset _ci_dtype _ci_existing _ci_line _ci_end -if [[ -z $fdir ]]; then - print "Trying to find where the completion functions are..." - if [[ $0 = */* && -f $0:h/compinit && -f $0:h/compdump ]]; then - fdir=$0:h - else - # more guesses? - print \ +# Look for the defaults. +_ci_startline='# The following lines were added by compinstall' +_ci_endline='# End of lines added by compinstall' + +_ci_ifile=${ZDOTDIR:-~}/.zshrc +_ci_lines='' +_ci_existing='' + +typeset -A _ci_defaults + +if [[ -f $_ci_ifile ]]; then + # This assumes the lines haven't been altered by the user too much + # after they were added. + _ci_compstyle=0 + sed -n "/^$_ci_startline/,/^$_ci_endline/p" $_ci_ifile | + while read -rA _ci_line; do + if (( $_ci_compstyle )); then + # parse a compstyle component as first argument + if [[ $_ci_line[-1] != \\ ]]; then + _ci_end=-1 + _ci_compstyle=0 + else + _ci_end=-2 + fi + if [[ $_ci_line[1] = *=* ]]; then + _ci_f="${${_ci_line[1,$_ci_end]}#*=}" + if [[ $_ci_f = \'*\' ]]; then + # strip quotes + _ci_f=${_ci_f[2,-2]//\'\\\'\'/\'} + fi + _ci_defaults[${_ci_line[1]%%\=*}]=$_ci_f + fi + _ci_existing="${_ci_existing} $_ci_line +" + elif [[ $_ci_line[1] = compinit ]]; then + # parse the line running compinit + [[ $_ci_line[2] = -f ]] && _ci_fdir=$_ci_line[3] + [[ $_ci_line[-2] = -d ]] && _ci_dumpfile=$_ci_line[-1] + elif [[ $_ci_line[1] = _compdir=* ]]; then + _ci_fdir=${_ci_line[1]##_compdir=} + elif [[ $_ci_line[1] = compstyle ]]; then + # parse a compstyle component as second argument (should be completer) + [[ $_ci_line[3] = completer ]] && + _ci_completer=${_ci_line[3,-1]} + [[ $_ci_line[-1] == \\ ]] && _ci_compstyle=1 + _ci_existing="${_ci_existing}$_ci_line +" + elif [[ $_ci_line[1] != \#* && $_ci_line[1] != (autoload|\[\[) ]]; then + if [[ -z $_ci_warn ]]; then + _ci_warn=1 + print "Warning: existing lines in compinstall setup not understood:" + fi + print - $_ci_line + _ci_existing="${_ci_existing}$_ci_line +" + fi + done +fi + + +# Find out where the completion functions are kept. + +if [[ -z $_ci_fdir || ! -f ${~_ci_fdir}/compinit || + ! -f ${~_ci_fdir}/compdump ]]; then + for _ci_f in $fpath; do + if [[ $_ci_f != . && -f $_ci_f/compinit && -f $_ci_f/compdump ]]; then + _ci_fdir=$_ci_f + break + elif [[ $_ci_f != . && -f $_ci_f/Core/compinit && + -f $_ci_f/Core/compdump ]] + then + _ci_fdir=$_ci_f/Core + break + fi + done +fi + +if [[ -z $_ci_fdir || ! -d ${~_ci_fdir} ]]; then + print \ "Please edit the name of the directory where the completion functions are installed. If they are not installed, you will need to find them in the Completion/* directories of the zsh distribution and install them yourself, or insult your system manager for incompetence." - vared -c fdir - while [[ ! -d ${~fdir} || ! -f ${~fdir}/compinit || - ! -f ${~fdir}/compdump ]]; do - print "I can't find them in that directory. Try again or abort." - vared fdir - done + vared -c _ci_fdir + while [[ ! -d ${~_ci_fdir} || + ((! -f ${~_ci_fdir}/compinit || ! -f ${~_ci_fdir}/compdump) && + (! -f ${~_ci_fdir}/Core/compinit || ! -f ${~_ci_fdir}/Core/compdump)) ]] + do + print "I can't find them in that directory. Try again or abort." + vared _ci_fdir + done + if [[ -f ${~_ci_fdir}/Core/compinit && ! -f ${~_ci_fdir}/compinit ]]; then + _ci_fdir=$_ci_fdir/Core fi - eval "fpath=($fdir \$fpath)" - fdir=${fdir/#$HOME/\~} - lines="fpath=($fdir \$fpath)\n" else - print "Found completion functions in your fpath, will not alter it." + print "Keeping existing completion directiory $_ci_fdir" +fi + +if [[ ${~_ci_fdir} != /* ]]; then + _ci_fdir=$(cd $_ci_fdir;builtin pwd) fi -files=( ${^~fpath:/.}/_(|*[^~])(N:t) ) -if [[ $#files -lt 20 ]]; then +# Check if this is in fpath already, else put it there (with ~'s expanded). +_ci_f=${~_ci_fdir} +[[ -z ${fpath[(r)$_ci_f]} ]] && fpath=($fpath $_ci_f) + +# Contract $HOME to ~ in the parameter to be used for writing. +_ci_fdir=${_ci_fdir/#$HOME/\~} + +# Now check the fpath, ignoring the directory . +_ci_files=( ${^~fpath:/.}/_(|*[^~])(N:t) ) +if [[ $#_ci_files -lt 20 ]]; then print " Hmmm, completion functions seem a bit thin on the ground. There should be lots of files with names beginning with an underscore (_). You should @@ -75,12 +152,20 @@ look and see what's happened to these. read fi -if [[ -w ${~fdir} && ( ! -f ${~fdir}/compinit.dump || - -w ${~fdir}/compinit.dump ) ]] + +# Set up the dumpfile +_ci_dtype=existing +if [[ -z $_ci_dumpfile ]]; then + _ci_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump" + _ci_dtype=standard +fi + +if [[ -w ${~_ci_dumpfile:h} && ( ! -f ${~_ci_dumpfile} || + -w ${~_ci_dumpfile} ) ]] then print " -Using standard dumpfile - ${~fdir}/compinit.dump +Using $_ci_dtype dumpfile + ${_ci_dumpfile} to speed up initialisation. [Hit return to continue]" read @@ -88,23 +173,32 @@ else print " I will force completion to dump its status, which will speed up the shell's start-up considerably. However, I can't write the file I'd like to, namely -$fdir/compinit.dump. Please edit a replacement." - dumpfile='~/.compinit.dump' - vared dumpfile - while ! touch ${~dumpfile} >& /dev/null; do +${_ci_dumpfile}. Please edit a replacement." + vared _ci_dumpfile + while ! touch ${~_ci_dumpfile} >& /dev/null; do print "Sorry, I can't write that either. Try again." - vared dumpfile + vared _ci_dumpfile done - [[ -s $dumpfile ]] || rm -f $dumpfile - dumpfile=" $dumpfile" + [[ -s $_ci_dumpfile ]] || rm -f $_ci_dumpfile fi -fdir=${fdir/#$HOME/\~} - -lines="${lines}. $fdir/compinit -d$dumpfile\n" +_ci_lines="${_ci_lines}_compdir=$_ci_fdir +[[ -z \$fpath[(r)\$_compdir] ]] && fpath=(\$fpath \$_compdir) +autoload -U compinit +compinit" +[[ $_ci_dtype != standard ]] && _ci_lines="${_ci_lines} $_ci_dumpfile" +_ci_lines="${_ci_lines} +" print " +Would you like to set some more advanced options? Otherwise, you +can re-run compinstall later to set these. [n]" + +# The whole of the next part should be indented, but I can't be bothered. +if read -q; then + + print " In addition to completion, zsh can also perform correction of the current word, or approximate completion, i.e. completion where the part of the word typed so far can be corrected; or it can try correction, then @@ -112,105 +206,156 @@ approximate completion if that fails. Would you like: 0: Just ordinary completion C: Correction A: Approximate completion - B: Both? -Please type one of the keys above:" -while read -k type; do - print - case $type in - 0*) completer=_complete - break - ;; - [cC]*) completer=_complete:_correct - break - ;; - [aA]*) completer=_complete:_approximate - break; - ;; - [bB]*) completer=_complete:_correct:_approximate - break - ;; - *) print Try again - ;; - esac -done - -lines="${lines}compconf completer=$completer" - - -if [[ $completer = *(correct|approx)* ]]; then - print " -Correction and approximation will normally allow up to two errors, -and you will be able to use a numeric prefix (e.g. <Esc>4) to allow -more. The standard prompt is \`correct to:'. Do you want to change -any of this? [n]" - if read -q; then - print "Number of errors to accept normally (0 is OK):" - read accept - while [[ $accept != <-> ]]; do - read accept"?Please enter a number: " - done - print \ + B: Both" + if [[ -n $_ci_completer ]]; then + print " Default: use the current completers:\n$_ci_completer" + else + print "Please type one of the keys above." + fi + while read -k _ci_type; do + print + case $_ci_type in + 0*) _ci_completer=_complete + break + ;; + [cC]*) _ci_completer='_complete _correct' + break + ;; + [aA]*) _ci_completer='_complete _approximate' + break; + ;; + [bB]*) _ci_completer='_complete _correct _approximate' + break + ;; + *) [[ -n $_ci_completer ]] && break + print Try again + ;; + esac + done + + _ci_lines="${_ci_lines}zstyle ':completion*' completer $_ci_completer" + + + if [[ $_ci_completer = *(correct|approx)* ]]; then + _ci_accept=${_ci_defaults[correct_accept]} + _ci_cprompt=${_ci_defaults[correct_prompt]} + print " +Correction and approximation will allow up to ${${_ci_accept:-2}%%[^0-9]*} \ +errors. " + case $_ci_accept in + *n*!*|*!*n) print "A numeric prefix, if not 1, will cause correction \ +not to be done." + ;; + *n*) print "A numeric prefix gives the maximum number of errors which \ +will be accepted." + ;; + *) print "The numeric prefix will not be used." + esac +print "The correction prompt is \`${_ci_cprompt:-correct to:}'. +Do you want to change any of this? [n]" + if read -q; then + print "Number of errors to accept normally (0 is OK):" + _ci_accept=${_ci_accept%%[^0-9]*} + vared _ci_accept + while [[ $_ci_accept != <-> ]]; do + print "Please enter a number:" + vared _ci_accept + done + print \ "How would you like the numeric prefix to be treated: 0: Not used by correction - U: Used to given the number of errors + U: The number gives the largest number of errors which will be + accepted when correcting I: If present, and not 1, do not perform correction? Please type one of the keys above:" - while read -k type; do - print - case $type in - 0*) break - ;; - [uU]*) accept="${accept}n" - break - ;; - [Ii]*) accept="${accept}!n" - break - ;; - *) print Try again - ;; - esac - done - lines="$lines \\\\ - correct_accept='$accept'" - print " + while read -k _ci_type; do + print + case $_ci_type in + 0*) break + ;; + [uU]*) _ci_accept="${_ci_accept}n" + break + ;; + [Ii]*) _ci_accept="${_ci_accept}!n" + break + ;; + *) print Try again + ;; + esac + done + print " Instead of the prompt \`correct to:', you can have no prompt, or a prompt of your choosing which can display the number of errors found by containing the string \`%e'. Do you wish to change the correction prompt? [n]" - if read -q; then - cprompt='' - print "Edit a new prompt (may be empty):" - vared cprompt - lines="$lines \\\\ - correct_prompt='${cprompt//\'/\'\\\'\'}'" + if read -q; then + print "Edit a new prompt (may be empty):" + vared _ci_cprompt + [[ -z $_ci_cprompt ]] && _ci_cprompt=':empty:' + fi + fi + if [[ -n $_ci_accept ]]; then + _ci_lines="$_ci_lines \\ + correct_accept='$_ci_accept'" + unset '_ci_defaults[correct_accept]' + fi + if [[ -n $_ci_cprompt ]]; then + _ci_cprompt=${_ci_cprompt##:empty:} + _ci_lines="$_ci_lines \\ + correct_prompt='${_ci_cprompt//\'/\'\\\'\'}'" + unset '_ci_defaults[correct_prompt]' fi fi -fi -lines="$lines\n" + _ci_warn='' + for _ci_f in ${(k)_ci_defaults}; do + if [[ -z $_ci_warn ]]; then + print " +(Keeping other existing configuration settings...)" + _ci_warn=1 + fi + _ci_lines="$_ci_lines \\ + ${_ci_f}='${_ci_defaults[$_ci_f]//\'/\'\\\'\'}'" + done + _ci_lines="$_ci_lines +" -startline='# The following lines were added by compinstall' -endline='# End of lines added by compinstall' +else -ifile=${ZDOTDIR:-~}/.zshrc -[[ -f $ifile ]] || touch $ifile -tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$ + if [[ -n $_ci_existing ]]; then + print -nr " +I will retain the following lines from the existing completion setup: +$_ci_existing" + _ci_lines="$_ci_lines${_ci_existing}" + fi + +fi # End of advanced options -if [[ ! -w $ifile ]]; then - print "\nI can't write to $ifile. I will leave the lines to add in -\`$tmpf' and you must add them by hand." - print "\n$startline\n$lines\n$endline" >$tmpf - return 0 -fi -if grep $endline $ifile >& /dev/null; then - print -- "$startline\n$lines$endline" >$tmpf - sed -e "/^$endline/r $tmpf -/^$startline/,/^$endline/d" $ifile >${tmpf}2 && mv ${tmpf}2 $ifile && - print "\nSuccesfully modified old compinstall lines in $ifile." - rm -f $tmpf ${tmpf}2 +[[ -f $_ci_ifile ]] || touch $_ci_ifile +_ci_tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$ + +if [[ ! -w $_ci_ifile ]]; then + print "\nI can't write to $_ci_ifile. I will leave the lines to add in +\`$_ci_tmpf' and you must add them by hand." + print -r - "$_ci_startline +$_ci_lines$_ci_endline" >$_ci_tmpf +elif grep $_ci_endline $_ci_ifile >& /dev/null; then + print -r - "$_ci_startline +$_ci_lines$_ci_endline" >$_ci_tmpf + sed -e "/^$_ci_endline/r $_ci_tmpf +/^$_ci_startline/,/^$_ci_endline/d" $_ci_ifile >${_ci_tmpf}2 && + mv ${_ci_tmpf}2 $_ci_ifile && + print "\nSuccesfully modified old compinstall lines in $_ci_ifile." + rm -f $_ci_tmpf ${_ci_tmpf}2 else - print "\n$startline\n$lines\n$endline" >>$ifile && - print "\nSuccessfully appended lines to $ifile." + print -r - "$_ci_startline +$_ci_lines$_ci_endline" >>$_ci_ifile && + print "\nSuccessfully appended lines to $_ci_ifile." fi + +unfunction compinstall +autoload -U compinstall + +return 0 |