From 04a89199d02a3ee6c4b3d89a6c782bdb0a4f1bc8 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 15 Apr 1999 18:20:19 +0000 Subject: zsh-3.1.5-pws-12 --- Completion/Core/.distfiles | 5 ++ Completion/Core/_compalso | 6 +- Completion/Core/_files | 11 ++- Completion/Core/_main_complete | 118 +++++++++++++++++----------- Completion/Core/_normal | 16 ++-- Completion/Core/_path_files | 141 +++++++++++++++++++++++++-------- Completion/Core/_sep_parts | 171 +++++++++++++++++++++++++++++++++++++++++ Completion/Core/compdump | 2 +- Completion/Core/compinit | 48 ++++++++++-- 9 files changed, 419 insertions(+), 99 deletions(-) create mode 100644 Completion/Core/.distfiles create mode 100644 Completion/Core/_sep_parts (limited to 'Completion/Core') diff --git a/Completion/Core/.distfiles b/Completion/Core/.distfiles new file mode 100644 index 000000000..ddf2a707e --- /dev/null +++ b/Completion/Core/.distfiles @@ -0,0 +1,5 @@ +DISTFILES_SRC=' + .distfiles + _compalso _files _main_complete _multi_parts _normal _path_files + _sep_parts compdump compinit +' diff --git a/Completion/Core/_compalso b/Completion/Core/_compalso index 6ff6cf0bf..52fb08f05 100644 --- a/Completion/Core/_compalso +++ b/Completion/Core/_compalso @@ -7,7 +7,9 @@ # `_compalso -math-' to get the completions that would be generated for a # mathematical context. -local tmp +local tmp ret=1 tmp="$_comps[$1]" -[[ -z "$tmp" ]] || "$tmp" +[[ -z "$tmp" ]] || "$tmp" && ret=0 + +return ret diff --git a/Completion/Core/_files b/Completion/Core/_files index 471824bfe..506ddbc8e 100644 --- a/Completion/Core/_files +++ b/Completion/Core/_files @@ -3,10 +3,9 @@ # 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 nm=$compstate[nmatches] ret +local nm=$compstate[nmatches] ret=1 -_path_files "$@" -ret=$? +_path_files "$@" && ret=0 if [[ $# -ne 0 && compstate[nmatches] -eq nm ]]; then local opt opts @@ -23,7 +22,7 @@ if [[ $# -ne 0 && compstate[nmatches] -eq nm ]]; then [[ "$opt" = [PSWFJVX] ]] && opts=("$opts[@]" "-$opt" "$OPTARG") done - _path_files "$opts[@]" -else - return $ret + _path_files "$opts[@]" && ret=0 fi + +return ret diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete index 34c5a3d3c..3571b712c 100644 --- a/Completion/Core/_main_complete +++ b/Completion/Core/_main_complete @@ -3,36 +3,47 @@ # The main loop of the completion code. This is what is called when # completion is attempted from the command line. # -# This code will automatically try to correct the string on the -# line based on the strings generated for the context if the -# parameter `COMPCORRECT' is set and normal completion didn't yield -# any matches. These corrected strings will be shown in a list and -# one can cycle through them as in a menucompletion. To use this -# feature, `COMPCORRECT' should be set to a number, specifying the +# This code will automatically try to correct the string on the line +# based on the strings generated for the context if +# `compconfig[correct]' is set and normal completion didn't yield any +# matches. These corrected strings will be shown in a list and one can +#cycle through them as in a menucompletion. To use this feature, +#`compconfig[correct]' 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 -# `COMPCORRECT' will be used. E.g. with `COMPCORRECT=2n' two errors -# will be accepted, but if the user gives another number with the -# numeric argument, this will be prefered. Also, with `COMPCORRECT=0n', -# normally no automatic correction will be tried, but if a numeric -# argument is given, automatic correction will be used. 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. -# If the parameter `CCORIG' is set (independent of the value), the -# line will first be left unchanged and consecutive TABs cycle through -# the list. -# When using automatic correction, one can also set the parameter -# `CCPROMPT' to a string that will be shown when multiple -# correction results are displayed and the code starts cycling -# through them (this string is used with the `-X' option and thus may -# contain the control sequences `%n', `%B',...). - -local comp name _comp_correct comax - -setopt localoptions nullglob rcexpandparam globdots +# `compconfig[correct]' will be used. E.g. with `compconfig[correct]=2n' +# two errors will be accepted, but if the user gives another number +# with the numeric argument, this will be prefered. Also, with +# `compconfig[correct]=0n',normally no automatic correction will be +# tried, but if a numeric argument is given, automatic correction will +# be used. 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. +# The value of `compconfig[correct_orig]' 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 apear 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 immediatly). Also, if the value of +# `compconfig[correct_orig]' 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. +# Finally, `compconfig[correct_prompt]' may 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. + +local comp name _comp_correct _correct_prompt comax + +setopt localoptions nullglob rcexpandparam unsetopt markdirs globsubst shwordsplit nounset ksharrays # Special completion contexts after `~' and `='. @@ -91,25 +102,30 @@ while true; do # Use automatic correction? - if (( $+COMPCORRECT )); then + if (( $+compconfig[correct] )); then # Do we have matches? if (( compstate[nmatches] )); then # Yes, were they added using correction? (More than one match?) - if [[ -n "$_comp_correct" && compstate[nmatches] -gt 1 ]]; then + if [[ -n "$_comp_correct" && + ( "$compconfig[correct_orig]" = *always* || + compstate[nmatches] -gt 1 ) ]]; then - # If we got more than one string from correction, we add the - # original string as a possible match, let it not be shown in - # the list, and probably display the `CCPROMPT'. - - (( $+CCORIG )) && builtin compadd -nQ - "$PREFIX$SUFFIX" + if [[ "$compconfig[correct_orig]" = *last* ]]; then + builtin compadd -V _correct_orig -nQ - "$PREFIX$SUFFIX" + elif [[ -n "$compconfig[correct_orig]" ]]; then + builtin compadd -nQ - "$PREFIX$SUFFIX" + fi # If you always want to see the list of possible corrections, # set `compstate[list]=list' here. + + compstate[force_list]=list fi # Since we have matches, we don't want to try again. + break fi @@ -117,25 +133,33 @@ while true; do if [[ -n "$_comp_correct" ]]; then - # Yes, give up if we reached the maximum number of tries, - # otherwise increment our counter. + # Yes, give up if we reached the maximum number of tries or the + # string from the line is too short, otherwise increment our + # counter. - [[ _comp_correct -eq comax ]] && break + [[ _comp_correct -eq comax || + "${#${:-$PREFIX$SUFFIX}}" -le _comp_correct+1 ]] && break (( _comp_correct++ )) + _correct_prompt="${compconfig[correct_prompt]//\%e/$_comp_correct}" + elif [[ compstate[matcher] -eq compstate[total_matchers] ]]; then + # We don't try correction if the string is too short. + + [[ "${#${:-$PREFIX$SUFFIX}}" -le 1 ]] && return + # No matches and no correction tried yet, but we just tried the # last global match specification, so let's see if we should use # correction now. First, get the maximum number of errors. - if [[ "$COMPCORRECT" = *[nN]* && NUMERIC -ne 1 ]]; then + if [[ "$compconfig[correct]" = *[nN]* && NUMERIC -ne 1 ]]; then # Prefer the numeric argument if that has a sensible value. comax="$NUMERIC" else - comax="${COMPCORRECT//[^0-9]}" + comax="${compconfig[correct]//[^0-9]}" fi - # If the number of errors to accept is to small, give up. + # If the number of errors to accept is too small, give up. [[ "$comax" -lt 1 ]] && break @@ -145,25 +169,31 @@ while true; do # ignored prefix). compadd() { + [[ "$*" != *-([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 (( $+CCPROMPT )); then - builtin compadd -X "$CCPROMPT" -J _correct "$@" + if [[ -n "$_correct_prompt" ]]; then + builtin compadd -X "$_correct_prompt" -J _correct "$@" else builtin compadd -J _correct "$@" fi } 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 (( $+CCPROMPT )); then - builtin compgen "$@" -X "$CCPROMPT" -J _correct + if [[ -n "$_correct_prompt" ]]; then + builtin compgen "$@" -X "$_correct_prompt" -J _correct else builtin compgen "$@" -J _correct fi @@ -179,6 +209,8 @@ while true; do _comp_correct=1 compstate[matcher]=-1 + _correct_prompt="${compconfig[correct_prompt]//\%e/$_comp_correct}" + # We also need to set `extendedglob' and to make the completion # code behave as if globcomplete were set. diff --git a/Completion/Core/_normal b/Completion/Core/_normal index f56849194..98337eae5 100644 --- a/Completion/Core/_normal +++ b/Completion/Core/_normal @@ -1,6 +1,6 @@ #autoload -local comp command cmd1 cmd2 pat val name i ret +local comp command cmd1 cmd2 pat val name i ret=1 # Completing in command position? If not we set up `cmd1' and `cmd2' as # two strings we have search in the completion definition arrays (e.g. @@ -9,8 +9,9 @@ local comp command cmd1 cmd2 pat val name i ret command="$words[1]" if [[ CURRENT -eq 1 ]]; then comp="$_comps[-command-]" - [[ -z "$comp" ]] || "$comp" - return + [[ -z "$comp" ]] || "$comp" && ret=0 + + return ret elif [[ "$command[1]" == '=' ]]; then eval cmd1\=$command cmd2="$command[2,-1]" @@ -28,11 +29,10 @@ for i in "$_patcomps[@]"; do pat="${i% *}" val="${i#* }" if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]]; then - "$val" - ret=$? + "$val" && ret=0 if (( $+_compskip )); then unset _compskip - return $ret + return ret fi fi done @@ -53,4 +53,6 @@ if [[ -z "$comp" ]]; then name=-default- comp="$_comps[-default-]" fi -[[ -z "$comp" ]] || "$comp" +[[ -z "$comp" ]] || "$comp" && ret=0 + +return ret diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 3c03c0c61..535ba537c 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -2,13 +2,15 @@ # Utility function for in-path completion. # Supported arguments are: `-f', `-/', `-g ', `-J ', -# `-V ', `-W paths', `-X explanation', and `-F '. All but -# the last have the same syntax and meaning as for `compgen'. The -# `-F ' option may be used to give a list of suffixes either by -# giving the name of an array or literally by giving them in a string -# surrounded by parentheses. Files with one of the suffixes thus given -# are treated like files with one of the suffixes in the `fignore' array -# in normal completion. +# `-V ', `-W paths', `-X explanation', `-P prefix', `-S suffix', +# `-q', `-r remove-chars', `-R remove-func', and `-F '. All but +# the last have the same syntax and meaning as for `compgen' or +# `compadd', respectively. The `-F ' option may be used to give +# a list of suffixes either by giving the name of an array or +# literally by giving them in a string surrounded by +# parentheses. Files with one of the suffixes thus given are treated +# like files with one of the suffixes in the `fignore' array in normal +# completion. # # This function uses the helper functions `_match_test' and `_match_pattern'. @@ -20,9 +22,10 @@ _match_test _path_files || return 1 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 orig ostr nm=$compstate[nmatches] +local addpfx addsfx expl orig ostr nm=$compstate[nmatches] menu remsfx patlast +local origflags mflags -setopt localoptions nullglob rcexpandparam globdots extendedglob +setopt localoptions nullglob rcexpandparam extendedglob unsetopt markdirs globsubst shwordsplit nounset prepaths=('') @@ -33,16 +36,21 @@ gopt='' pats=() addpfx=() addsfx=() +remsfx=() expl=() # Get the options. -while getopts "P:S:W:F:J:V:X:f/g:" opt; do +while getopts "P:S:qr:R:W:F:J:V:X:f/g:" opt; do case "$opt" in P) addpfx=(-P "$OPTARG") ;; S) addsfx=(-S "$OPTARG") ;; + q) tmp1=yes + ;; + [rR]) remsfx=("-$opt" "$OPTARG") + ;; W) tmp1="$OPTARG" if [[ "$tmp1[1]" = '(' ]]; then prepaths=( ${^=tmp1[2,-2]}/ ) @@ -76,6 +84,8 @@ while getopts "P:S:W:F:J:V:X:f/g:" opt; do esac done +[[ -n "$tmp1" && $#addsfx -ne 0 ]] && addsfx[1]=-qS + # If we were given no file selection option, we behave as if we were given # a `-f'. @@ -89,19 +99,25 @@ if [[ "$sopt" = - ]]; then fi # str holds the whole string from the command line with a `*' between -# the prefix and the suffix. +# the prefix and the suffix. Then we see if we will do menucompletion. -if [[ -o globcomplete ]]; then +if [[ $#compstate[pattern_match] -ne 0 ]]; then str="${PREFIX}*${SUFFIX}" else str="${PREFIX:q}*${SUFFIX:q}" + [[ "$str" = \\\~* ]] && str="$str[2,-1]" fi orig="${PREFIX}${SUFFIX}" +[[ $compstate[insert] = *menu || -n "$_comp_correct" || + ( $#compstate[pattern_match] -ne 0 && + "$orig" != "${orig:q}" ) ]] && menu=yes + + # We will first try normal completion called with `compgen', but only if we -# weren't given a `-F' option. +# weren't given a `-F', `-r', or `-R' option. -if (( ! $#ignore )); then +if [[ $#ignore -eq 0 && $#remsfx -eq 0 && -z "$_comp_correct" ]]; 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. @@ -124,11 +140,11 @@ if (( ! $#ignore )); then # If this generated any matches, we don't want to do in-path completion. [[ compstate[nmatches] -eq nm ]] || return 0 +fi - # No `-F' option, so we want to use `fignore'. +# No `-F' option, so we want to use `fignore'. - ignore=(-F fignore) -fi +(( $#ignore )) || ignore=(-F fignore) # Now let's have a closer look at the string to complete. @@ -176,6 +192,7 @@ fi patstr="$str" matchflags="" _match_pattern _path_files patstr matchflags +origflags="$matchflags" [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" # We almost expect the pattern to have changed `..' into `*.*.', `/.' into @@ -185,13 +202,40 @@ _match_pattern _path_files patstr matchflags patstr="$patstr:gs-/-*/-:gs/*.*./../:gs-/*.-/.-:gs/**/*/:gs-.*/-./-" +# We take the last pathname component from the pattern and store it in +# `patlast', replacing `*'s in it with patterns that match any character +# but not slashes. Later we will generate matches using `patstr' with the +# patterns we were given (like `*.c') appended to it, producing all matching +# files. These filenames are then compared to `patlast' and all names not +# matching that will be removed. All this is needed to be able to correctly +# support `completeinword' as otherwise we would have something like `a*x' +# from the line (the `*' was inserted above) and appending the `-g' pattern +# `*.tex' would yield `a*x*.tex' which is not what we want. + +if [[ "$patstr" = */* ]]; then + if [[ -n "$_comp_correct" && "${#orig##*/}" -le _comp_correct ]]; then + patlast="*/${origflags}${${patstr##*/}//\*/[^/]#}" + else + patlast="*/${matchflags}${${patstr##*/}//\*/[^/]#}" + fi + patstr="${patstr%/*}/" +else + if [[ -n "$_comp_correct" && "$#orig" -le _comp_correct ]]; then + patlast="${origflags}${patstr//\*/[^/]#}" + else + patlast="${matchflags}${patstr//\*/[^/]#}" + fi + patstr="" +fi + # First we skip over all pathname components in `str' which really exist in # the file-system, so that `/usr/lib/l' doesn't offer you `lib' and # `lib5'. Pathname components skipped this way are taken from `orig' and added # to `donepath'. while [[ "$orig" = */* ]] do - tmp1=( ${~matchflags}$realpath$donepath${orig%%/*}/${~patstr#*/}$^pats ) + tmp1=( $realpath$donepath${orig%%/*}/${~matchflags}${~patstr#*/}$^pats ) + tmp1=("${(@M)tmp1:#$~patlast}") [[ $#tmp1 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break donepath="$donepath${orig%%/*}/" orig="${orig#*/}" @@ -217,8 +261,13 @@ for prepath in "$prepaths[@]"; do # we get the globbing matches for the pathname component currently # handled. + if [[ -n "$_comp_correct" && "${#ostr%%/*}" -le _comp_correct ]]; then + mflags="$origflags" + else + mflags="$matchflags" + fi rest="${str#*/}" - tmp1="${prepath}${realpath}${testpath}${~matchflags}${str%%/*}(-/)" + tmp1="${prepath}${realpath}${testpath}${~mflags}${str%%/*}(-/)" tmp1=( $~tmp1 ) if [[ $#tmp1 -eq 0 ]]; then @@ -240,12 +289,19 @@ for prepath in "$prepaths[@]"; do suffixes=( $rest$^pats ) suffixes=( "${(@)suffixes:gs.**.*.}" ) + if [[ -n "$_comp_correct" && "${#ostr#*/}" -le _comp_correct ]]; then + mflags="$origflags" + else + mflags="$matchflags" + fi + # 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=( ${~i}/${~mflags}${~suffixes} ) + tmp2=("${(@M)tmp2:#$~patlast}") [[ $#tmp2 -ne 0 ]] && collect=( $collect $i ) done @@ -255,9 +311,6 @@ for prepath in "$prepaths[@]"; do # next `-W' path. if [[ $#collect -eq 0 ]]; then - compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \ - -W "$tmp1" -f "$ignore[@]" - "${(@)tmp1:q}" continue 2 elif [[ $#collect -ne 1 ]]; then # If we have more than one possible match, this means that the @@ -270,6 +323,7 @@ for prepath in "$prepaths[@]"; do # Now produce all matching pathnames in `collect'. collect=( ${~collect}/${~matchflags}${~suffixes} ) + collect=("${(@M)collect:#$~patlast}") # And then remove the common path prefix from all these matches. @@ -282,15 +336,16 @@ for prepath in "$prepaths[@]"; do # these are file names and that `fignore' should be used as usual # (the `-f' and `-F' options). - if [[ $compstate[insert] = *menu ]]; then + if [[ -n "$menu" ]]; then compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \ + -i "$IPREFIX" -p "$linepath${testpath:q}" \ + -s "/${ostr#*/}" \ -W "$tmp1" -f "$ignore[@]" - "${(@)${(@)collect%%/*}:q}" else for i in $collect; do - compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -p "$linepath$testpath" -s "/${i#*/}" \ - -M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${i%%/*}" + compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "$linepath${testpath:q}" -s "/${${i#*/}:q}" \ + -M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${${i%%/*}:q}" done fi @@ -299,12 +354,27 @@ for prepath in "$prepaths[@]"; do continue 2 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. tmp1=( "$collect[1]" ) + elif [[ -n "$_comp_correct" && "$mflags" = "$matchflags" ]]; then + + # If we got only one match with auto-correction and if we get none + # without correction, stop now. + + tmp2="${prepath}${realpath}${testpath}${~origflags}${str%%/*}(-/)" + tmp2=( $~tmp2 ) + + if [[ $#tmp1 -ne $#tmp2 ]]; then + compadd -QU "$addpfx[@]" -S '' "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "$linepath${testpath:q}" -s "/${ostr#*/}" \ + - "${${tmp1#${prepath}${realpath}${testpath}}:q}" + continue 2 + fi 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. @@ -320,10 +390,17 @@ for prepath in "$prepaths[@]"; do # no path suffix, the `-W' we are currently handling, all the matches we # can produce in this directory, if any. + if [[ -n "$_comp_correct" && "${#ostr#*/}" -le _comp_correct ]]; then + mflags="$origflags" + else + mflags="$matchflags" + fi tmp1="$prepath$realpath$testpath" suffixes=( $str$^pats ) suffixes=( "${(@)suffixes:gs.**.*.}" ) tmp2=( ${~tmp1}${~matchflags}${~suffixes} ) + tmp2=("${(@M)tmp2:#$~patlast}") + if [[ $#tmp2 -eq 0 ]]; then # No match, insert the expanded path and add the original tail. @@ -334,11 +411,11 @@ for prepath in "$prepaths[@]"; do [[ "$linepath$testpath$ostr" = "$PREFIX$SUFFIX" ]] && return 1 compadd -QU -S '' "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -f - "${linepath:q}${testpath:q}$ostr" + -i "$IPREFIX" -f - "$linepath${testpath:q}$ostr" else - compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -p "$linepath$testpath" -f "$ignore[@]" \ - -W "$prepath$realpath$testpath" - "${(@)tmp2#$tmp1}" + compadd -QU "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "$linepath${testpath:q}" -f "$ignore[@]" \ + -W "$prepath$realpath$testpath" - "${(@)${(@)tmp2#$tmp1}:q}" fi done diff --git a/Completion/Core/_sep_parts b/Completion/Core/_sep_parts new file mode 100644 index 000000000..c1cda2b9a --- /dev/null +++ b/Completion/Core/_sep_parts @@ -0,0 +1,171 @@ +#autoload + +# This function can be used to separately complete parts of strings +# where each part may be one of a set of matches and different parts +# have different sets. +# Arguments are alternatingly arrays and separator strings. Arrays may +# be given by name or literally as words separated by white space in +# parentheses, e.g.: +# +# _sep_parts '(foo bar)' @ hosts +# +# This will make this function complete the strings in the array +# `friends'. If the string on the line contains a `@', the substring +# after it will be completed from the array `hosts'. Of course more +# arrays may be given, each preceded by another separator string. +# +# This function understands the `-J group', `-V group', and +# `-X explanation' options. +# +# This function does part of the matching itself and calls the functions +# `_match_test' and `_match_pattern' for this. + +local str arr sep test testarr tmparr prefix suffixes matchers autosuffix +local matchflags opt group expl nm=$compstate[nmatches] + +# Test if we should use this function for the global matcher in use. + +_match_test _sep_parts || return 1 + +# Get the options. + +group=() +expl=() +while getopts "J:V:X:" opt; do + case "$opt" in + [JV]) group=("-$opt" "$OPTARG");; + X) expl=(-X "$OPTARG");; + esac +done +shift OPTIND-1 + +# Get the string from the line. + +str="$PREFIX$SUFFIX" +[[ $#compstate[pattern_match] -ne 0 ]] || str="$str:q" +prefix="" + +# Walk through the arguments to find the longest unambiguous prefix. + +while [[ $# -gt 1 ]]; do + # Get the next array and separator. + arr="$1" + sep="$2" + + if [[ "$arr[1]" == '(' ]]; then + tmparr=( ${=arr[2,-2]} ) + arr=tmparr + fi + # Is the separator on the line? + [[ "$str" != *${sep}* ]] && break + + # Build a pattern matching the possible matches and get all these + # matches in an array. + + test="${str%%${sep}*}" + [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1 + + matchflags="" + _match_pattern _sep_parts test matchflags + [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" + + test="${matchflags}${test}" + testarr=( "${(@M)${(@P)arr}:#${~test}*}" ) + testarr=( "${(@)testarr:#}" ) + + # If there are no matches we give up. If there is more than one + # match, this is the part we will complete. + (( $#testarr )) || return 1 + [[ $#testarr -gt 1 ]] && break + + # Only one match, add it to the prefix and skip over it in `str', + # continuing with the next array and separator. + prefix="${prefix}${testarr[1]}${sep}" + str="${str#*${sep}}" + shift 2 +done + +# Get the array to work upon. +arr="$1" +if [[ "$arr[1]" == '(' ]]; then + tmparr=( ${=arr[2,-2]} ) + arr=tmparr +fi +if [[ $# -le 1 || "$str" != *${2}* ]]; then + # No more separators, build the matches. + + test="$str" + [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1 + + matchflags="" + _match_pattern _sep_parts test matchflags + [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" + + test="${matchflags}${test}" + testarr=( "${(@M)${(@P)arr}:#${~test}*}" ) + testarr=( "${(@)testarr:#}" ) +fi + +[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return 1 + +# Now we build the suffixes to give to the completion code. +shift +matchers=() +suffixes=("") +autosuffix=() + +while [[ $# -gt 0 && "$str" == *${1}* ]]; do + # Remove anything up to the the suffix. + str="${str#*${1}}" + + # Again, we get the string from the line up to the next separator + # and build a pattern from it. + if [[ $# -gt 2 ]]; then + test="${str%%${3}*}" + else + test="$str" + fi + + [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1 + + matchflags="" + _match_pattern _sep_parts test matchflags + [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" + test="${matchflags}${test}" + + # We incrementally add suffixes by appending to them the seperators + # and the strings from the next array that match the pattern we built. + + arr="$2" + if [[ "$arr[1]" == '(' ]]; then + tmparr=( ${=arr[2,-2]} ) + arr=tmparr + fi + tmparr=( "${(@M)${(@P)arr}:#${~test}*}" ) + tmparr=( "${(@)tmparr:#}" ) + suffixes=("${(@)^suffixes[@]}${1}${(@)^tmparr}") + + # We want the completion code to generate the most specific suffix + # for us, so we collect matching specifications that allow partial + # word matching before the separators on the fly. + matchers=("$matchers[@]" "r:|${1:q}=*") + shift 2 +done + +# If we were given at least one more separator we make the completion +# code offer it by appending it as a autoremovable suffix. +(( $# )) && autosuffix=(-qS "$1") + +# If we have collected matching specifications, we build an array +# from it that can be used as arguments to `compadd'. +[[ $#matchers -gt 0 ]] && matchers=(-M "$matchers") + +# Add the matches for each of the suffixes. +for i in "$suffixes[@]"; do + compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \ + -i "$IPREFIX" -p "$prefix" -s "$i" - "$testarr[@]" +done + +# This sets the return value to indicate that we added matches (or not). + +[[ nm -ne compstate[nmatches] ]] diff --git a/Completion/Core/compdump b/Completion/Core/compdump index 8be096f50..5fdee8c7a 100644 --- a/Completion/Core/compdump +++ b/Completion/Core/compdump @@ -15,7 +15,7 @@ # 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} +_d_file=${compconfig[dump_file]-${0:h}/compinit.dump} typeset -U _d_files _d_files=( ${^~fpath}/_*~*~(N:t) ) diff --git a/Completion/Core/compinit b/Completion/Core/compinit index ec5867838..31d011565 100644 --- a/Completion/Core/compinit +++ b/Completion/Core/compinit @@ -37,18 +37,24 @@ # 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. +# 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 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. -# + # If we got the `-d'-flag, we will automatically dump the new state (at # the end). +# If we were given an argument, this will be taken as the name of the +# file in which to store the dump. if [[ "$1" = -d ]]; then _i_autodump=1 + shift else _i_autodump=0 fi @@ -59,6 +65,18 @@ fi typeset -A _comps _patcomps=() +# This is the associative array used for configuration. + +typeset -A compconfig + +# Standard initialisation for `compconfig'. + +(( $# )) && compconfig[dump_file]="$1" +[[ -z "$compconfig[dump_file]" ]] && compconfig[dump_file]="$0.dump" + +compconfig[correct_prompt]='correct to:' + + # This function is used to register or delete completion functions. For # registering completion functions, it is invoked with the name of the # function as it's first argument (after the options). The other @@ -197,11 +215,25 @@ compdef() { fi } -# Now we automatically make the definition files autoloaded. +# Functional interface to configuration. This takes its arguments +# and sets the according values in `compconfig'. +# Arguments may be `foo=bar' to set key `foo' to `bar' or `baz' to +# set key `baz' to the empty string. -# First we get the name of a dump file if this will be used. +compconf() { + local i name -: ${COMPDUMP:=$0.dump} + for i; do + if [[ "$i" = *\=* ]]; then + name="${i%%\=*}" + compconfig[$name]="${i#*\=}" + else + compconfig[$i]='' + fi + done +} + +# Now we automatically make the definition files autoloaded. if [[ ! -o extendedglob ]]; then _i_noextglob=yes @@ -215,10 +247,10 @@ _i_done='' # If we have a dump file, load it. -if [[ -f "$COMPDUMP" ]]; then - read -rA _i_line < "$COMPDUMP" +if [[ -f "$compconfig[dump_file]" ]]; then + read -rA _i_line < "$compconfig[dump_file]" if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then - builtin . "$COMPDUMP" + builtin . "$compconfig[dump_file]" _i_done=yes fi unset _i_line -- cgit 1.4.1