From 7a0415cfd70a02b2280d27556c6c54cef1c86e1a Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 15 Apr 1999 18:18:42 +0000 Subject: zsh-3.1.5-pws-11 --- Completion/Core/_comp_parts | 25 +++-- Completion/Core/_compalso | 6 +- Completion/Core/_files | 7 +- Completion/Core/_main_complete | 219 ++++++++++++++++++++++++++++++++++------- Completion/Core/_multi_parts | 201 +++++++++++++++++++++++++++++++++++++ Completion/Core/_normal | 30 +++--- Completion/Core/_path_files | 110 ++++++++++++++------- 7 files changed, 502 insertions(+), 96 deletions(-) create mode 100644 Completion/Core/_multi_parts (limited to 'Completion/Core') diff --git a/Completion/Core/_comp_parts b/Completion/Core/_comp_parts index 7c24fd19d..d58669f29 100644 --- a/Completion/Core/_comp_parts +++ b/Completion/Core/_comp_parts @@ -21,11 +21,11 @@ # `_match_test' and `_match_pattern' for this. local str arr sep test testarr tmparr prefix suffixes matchers autosuffix -local matchflags opt group expl +local matchflags opt group expl nm=$compstate[nmatches] # Test if we should use this function for the global matcher in use. -_match_test _comp_parts || return +_match_test _comp_parts || return 1 # Get the options. @@ -42,6 +42,7 @@ shift OPTIND-1 # Get the string from the line. str="$PREFIX$SUFFIX" +[[ -o globcomplete ]] && str="$str:q" prefix="" # Walk through the arguments to find the longest unambiguous prefix. @@ -63,12 +64,14 @@ while [[ $# -gt 1 ]]; do test="${str%%${sep}*}" matchflags="" _match_pattern _comp_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 + (( $#testarr )) || return 1 [[ $#testarr -gt 1 ]] && break # Only one match, add it to the prefix and skip over it in `str', @@ -89,11 +92,13 @@ if [[ $# -le 1 || "$str" != *${2}* ]]; then matchflags="" test="$str" _match_pattern _comp_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 +[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return 1 # Now we build the suffixes to give to the completion code. shift @@ -114,6 +119,7 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do fi matchflags="" _match_pattern _comp_parts test matchflags + [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" test="${matchflags}${test}" # We incrementally add suffixes by appending to them the seperators @@ -124,7 +130,9 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do tmparr=( ${=arr[2,-2]} ) arr=tmparr fi - suffixes=("${^suffixes[@]}${1}${(@M)^${(@P)arr}:#${~test}*}") + tmparr=( "${(@M)${(@P)arr}:#${~test}*}" ) + tmparr=( "${(@)testarr:#}" ) + 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 @@ -143,5 +151,10 @@ done # Add the matches for each of the suffixes. for i in "$suffixes[@]"; do - compadd "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" -p "$prefix" -s "$i" - "$testarr[@]" + 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/_compalso b/Completion/Core/_compalso index 23a40e2d0..6ff6cf0bf 100644 --- a/Completion/Core/_compalso +++ b/Completion/Core/_compalso @@ -4,10 +4,10 @@ # It is used to include completions for another command or special context # into the list generated by the calling function. # For example the function for `-subscript-' could call this as in -# `_compalso -math- "$@"' to get the completions that would be generated -# for a mathematical context. +# `_compalso -math-' to get the completions that would be generated for a +# mathematical context. local tmp tmp="$_comps[$1]" -[[ -z "$tmp" ]] || "$tmp" "$@" +[[ -z "$tmp" ]] || "$tmp" diff --git a/Completion/Core/_files b/Completion/Core/_files index d2cce35e7..471824bfe 100644 --- a/Completion/Core/_files +++ b/Completion/Core/_files @@ -3,11 +3,12 @@ # 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=$NMATCHES +local nm=$compstate[nmatches] ret _path_files "$@" +ret=$? -if [[ $# -ne 0 && -nmatches nm ]]; then +if [[ $# -ne 0 && compstate[nmatches] -eq nm ]]; then local opt opts # We didn't get any matches for those types of files described by @@ -23,4 +24,6 @@ if [[ $# -ne 0 && -nmatches nm ]]; then done _path_files "$opts[@]" +else + return $ret fi diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete index c7f5a5a96..34c5a3d3c 100644 --- a/Completion/Core/_main_complete +++ b/Completion/Core/_main_complete @@ -2,47 +2,198 @@ # 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. +# +# 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 +# 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 +local comp name _comp_correct comax setopt localoptions nullglob rcexpandparam globdots -unsetopt markdirs globsubst shwordsplit nounset - -# 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 - "$comp" "$@" - if (( $+_compskip )); then - unset _compskip - return - fi +unsetopt markdirs globsubst shwordsplit nounset ksharrays + +# Special completion contexts after `~' and `='. + +if [[ -iprefix '=' ]]; then + compstate[context]=equal +elif [[ "$PREFIX$SUFFIX" != */* && -iprefix '~' ]]; then + compstate[context]=tilde fi -# For arguments we use the `_normal function. +# This is not an endless loop. -if [[ $CONTEXT == argument || $CONTEXT == command ]]; then - _normal "$@" -else - # Let's see if we have a special completion definition for the other - # possible contexts. +while true; do - comp='' + # 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. - case $CONTEXT in - redirect) comp="$_comps[-redirect-]";; - math) comp="$_comps[-math-]";; - subscript) comp="$_comps[-subscript-]";; - value) comp="$_comps[-value-]";; - condition) comp="$_comps[-condition-]";; - esac + comp="$_comps[-first-]" + if [[ ! -z "$comp" ]]; then + "$comp" + if (( $+_compskip )); then + unset _compskip + return + fi + fi - # If not, we use default completion, if any. + # For arguments and command names we use the `_normal' function. - [[ -z "$comp" ]] && comp="$_comps[-default-]" - [[ -z "$comp" ]] || "$comp" "$@" -fi + if [[ "$compstate[context]" = command ]]; then + _normal + 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 + + # If not, we use default completion, if any. + + [[ -z "$comp" ]] && comp="$_comps[-default-]" + [[ -z "$comp" ]] || "$comp" + fi + + # Use automatic correction? + + if (( $+COMPCORRECT )); 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 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 you always want to see the list of possible corrections, + # set `compstate[list]=list' here. + fi + # Since we have matches, we don't want to try again. + break + fi + + # No matches, so let's see if we already tried correction. + + if [[ -n "$_comp_correct" ]]; then + + # Yes, give up if we reached the maximum number of tries, + # otherwise increment our counter. + + [[ _comp_correct -eq comax ]] && break + (( _comp_correct++ )) + + elif [[ compstate[matcher] -eq compstate[total_matchers] ]]; then + + # 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 + # Prefer the numeric argument if that has a sensible value. + comax="$NUMERIC" + else + comax="${COMPCORRECT//[^0-9]}" + fi + # If the number of errors to accept is to small, give up. + + [[ "$comax" -lt 1 ]] && break + + # 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 + # ignored prefix). + + compadd() { + 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 "$@" + else + builtin compadd -J _correct "$@" + fi + } + compgen() { + 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 + 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 + + # We also need to set `extendedglob' and to make the completion + # code behave as if globcomplete were set. + + setopt extendedglob + compstate[pattern_match]=yes + else + # We are still trying global match specifications... + break + fi + else + # No automatic correction to try, just give up. + break + fi +done + +# If we added wrapper functions, remove them. + +[[ -n "$_comp_correct" ]] && unfunction compadd compgen diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts new file mode 100644 index 000000000..1f51d2f6d --- /dev/null +++ b/Completion/Core/_multi_parts @@ -0,0 +1,201 @@ +#autoload + +# This gets two arguments, a separator (which should be only one +# character) and an array. As usual, the array may be given by it's +# name or literal as in `(foo bar baz)' (words separated by spaces in +# parentheses). +# The parts of words from the array that are separated by the +# separator character are then completed independently. + +local sep matches patstr orig matchflags pref i tmp1 tmp2 nm +local group expl + +_match_test _multi_parts || return 1 + +# Save the current number of matches to be able to return if we added +# matches or not. + +nm=$compstate[nmatches] + +# 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 arguments, first the separator, then the array. The array is +# stored in `matches'. Further on this array will always contain those +# words from the original array that still match everything we have +# tried to match while we walk through the string from the line. + +sep="$1" +if [[ "${2[1]}" = '(' ]]; then + matches=( ${2[2,-2]} ) +else + matches=( "${(@P)2}" ) +fi + +# Now build the pattern from what we have on the line. We also save +# the original string in `orig'. The `eval' is used to replace our +# separator character by `*'. + +if [[ -o globcomplete ]]; then + patstr="${PREFIX}*${SUFFIX}*" +else + patstr="${PREFIX:q}*${SUFFIX:q}*" +fi +orig="${PREFIX}${SUFFIX}" + +matchflags="" +_match_pattern _path_files patstr matchflags +[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" + +patstr="${${patstr//$sep/*$sep}//\*##/*}" +#eval patstr\="\$patstr:gs-${sep}-\*${sep}-:gs/\*\*/\*/" + +# First we will skip over those parts of the matches for which we have +# exact substrings on the line. In `pref' we will build the +# unambiguous prefix string. + +pref='' +while [[ "$orig" = *${sep}* ]] do + + # First build the pattern to use, then collect all strings from + # `matches' that match the prefix we have and the exact substring in + # the array `tmp1'. + + pat="${${${patstr#*${sep}}%${sep}*}//\*/[^${sep}]#}${patstr##*${sep}}" + tmp1=( "${(@M)matches:#${~matchflags}${orig%%${sep}*}${sep}${~pat}}" ) + + # If there are no words matching the exact substring, stop. + + (( $#tmp1 )) || break + + # Otherwise add the part to the prefix, remove it from the matches + # (which will also remove all words not matching the string at all), + # and set `patstr' and `orig' to the next component. + + pref="$pref${orig%%${sep}*}${sep}" + matches=( "${(@)${(@)matches#${orig%%${sep}*}${sep}}:#}" ) + orig="${orig#*${sep}}" + patstr="${patstr#*${sep}}" +done + +# Now we get all the words that still match in `tmp1'. + +if [[ "$patstr" = *${sep}* ]]; then + tmp1="${patstr%${sep}*}${sep}" + pat="${tmp1//\*/[^${sep}]#}${patstr##*${sep}}" +else + pat="$patstr" +fi +tmp1=( "${(@M)matches:#${~matchflags}${~pat}}" ) + +if (( $#tmp1 )); then + + # There are words that are matched, put them int `matches' and then + # move all unambiguous components from the beginning into `pref'. + + matches=( "$tmp1[@]" ) + while [[ "$matches[1]" = *${sep}* ]]; do + + # We just take the first component of the first match and see if + # there are other matches with a different prefix (these are + # collected in `tmp2'). If there are any, we give up. + + tmp1="${matches[1]%%${sep}*}${sep}" + tmp2=( "${(@)matches:#${tmp1}*}" ) + (( $#tmp2 )) && break + + # All matches have the same prefix, but it into `pref' and remove + # it from the matches. + + pref="$pref$tmp1" + matches=( "${(@)${(@)matches#$tmp1}:#}" ) + + if [[ "$orig" = *${sep}* ]]; then + orig="${orig#*${sep}}" + else + orig='' + fi + done + + # Now we can tell the completion code about the things we + # found. Strings that have a separator will be added with a suffix. + + if [[ -z "$orig" && "$PREFIX$SUFFIX" != "$pref$orig" ]]; then + compadd -QU "$group[@]" "$expl[@]" -i "$IPREFIX" -S '' - "${pref}${orig}" + elif [[ $compstate[insert] = *menu ]]; then + for i in "$matches[@]" ; do + if [[ "$i" = *${sep}* ]]; then + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \ + -p "$pref" -qS "$sep" - "${i%%${sep}*}" + else + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \ + -p "$pref" - "${i%%${sep}*}" + fi + done + else + for i in "$matches[@]" ; do + if [[ "$i" = *${sep}* ]]; then + compadd -U -i "$IPREFIX" -p "$pref" -s "${sep}${i#*${sep}}" \ + "$group[@]" "$expl[@]" -M "r:|${sep}=*" - "${i%%${sep}*}" + else + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -p "$pref" - "$i" + fi + done + fi +elif [[ "$patstr" = *${sep}* ]]; then + + # We had no words matching the string from the line. But we want to + # be friendly and at least expand the prefix as far as we can. So we + # will loop through the rest of the string from the line and test + # the components one by one. + + while [[ "$patstr" = *${sep}* ]]; do + + # First we get all words matching at least this component in + # `tmp1'. If there are none, we give up. + + tmp1=( "${(@M)matches:#${~matchflags}${~patstr%%${sep}*}${sep}*}" ) + (( $#tmp1 )) || break + + # Then we check if there are words that have a different prefix. + + tmp2=( "${(@)tmp1:#${tmp1[1]%%${sep}*}${sep}*}" ) + if (( $#tmp2 )); then + + # There are words with another prefix, so we have found an + # ambiguous component. So we just give all possible prefixes to + # the completion code together with our prefix and the rest of + # the string from the line as the suffix. + + compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" \ + -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}" + return 0 + fi + + # All words have the same prefix, so add it to `pref' again and + # try the next component. + + pref="$pref${tmp1[1]%%${sep}*}${sep}" + matches=( "${(@)matches#${tmp1[1]%%${sep}*}${sep}}" ) + orig="${orig#*${sep}}" + patstr="${patstr#*${sep}}" + done + + # Finally, add the unambiguous prefix and the rest of the string + # from the line. + + compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" - "$orig" +fi + +# This sets the return value to indicate that we added matches (or not). + +[[ nm -ne compstate[nmatches] ]] diff --git a/Completion/Core/_normal b/Completion/Core/_normal index 19da6d79b..f56849194 100644 --- a/Completion/Core/_normal +++ b/Completion/Core/_normal @@ -1,24 +1,25 @@ #autoload -local comp cmd1 cmd2 pat val name +local comp command cmd1 cmd2 pat val name i ret # 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. # a path and the last path name component). -if [[ $CONTEXT == command ]]; then +command="$words[1]" +if [[ CURRENT -eq 1 ]]; then comp="$_comps[-command-]" - [[ -z "$comp" ]] || "$comp" "$@" + [[ -z "$comp" ]] || "$comp" return -elif [[ "$COMMAND[1]" == '=' ]]; then - eval cmd1\=$COMMAND - cmd2="$COMMAND[2,-1]" -elif [[ "$COMMAND" == */* ]]; then - cmd1="$COMMAND" - cmd2="${COMMAND:t}" +elif [[ "$command[1]" == '=' ]]; then + eval cmd1\=$command + cmd2="$command[2,-1]" +elif [[ "$command" == */* ]]; then + cmd1="$command" + cmd2="${command:t}" else - cmd1="$COMMAND" - eval cmd2=$(whence -p $COMMAND) + cmd1="$command" + eval cmd2=$(whence -p $command) fi # See if there are any matching pattern completions. @@ -27,10 +28,11 @@ for i in "$_patcomps[@]"; do pat="${i% *}" val="${i#* }" if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]]; then - "$val" "$@" + "$val" + ret=$? if (( $+_compskip )); then unset _compskip - return + return $ret fi fi done @@ -51,4 +53,4 @@ if [[ -z "$comp" ]]; then name=-default- comp="$_comps[-default-]" fi -[[ -z "$comp" ]] || "$comp" "$@" +[[ -z "$comp" ]] || "$comp" diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 83b6e8a09..3c03c0c61 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -3,7 +3,7 @@ # Utility function for in-path completion. # Supported arguments are: `-f', `-/', `-g ', `-J ', # `-V ', `-W paths', `-X explanation', and `-F '. All but -# the last have the same syntax and meaning as for `complist'. The +# 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 @@ -14,13 +14,13 @@ # First see if we should generate matches for the global matcher in use. -_match_test _path_files || return +_match_test _path_files || return 1 # 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 +local addpfx addsfx expl orig ostr nm=$compstate[nmatches] setopt localoptions nullglob rcexpandparam globdots extendedglob unsetopt markdirs globsubst shwordsplit nounset @@ -91,14 +91,14 @@ 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. - -[[ "$str" = \\\~* ]] && str="$str[2,-1]" +if [[ -o globcomplete ]]; then + str="${PREFIX}*${SUFFIX}" +else + str="${PREFIX:q}*${SUFFIX:q}" +fi +orig="${PREFIX}${SUFFIX}" -# We will first try normal completion called with `complist', but only if we +# We will first try normal completion called with `compgen', but only if we # weren't given a `-F' option. if (( ! $#ignore )); then @@ -112,18 +112,18 @@ if (( ! $#ignore )); then tmp1=(-W "( $prepaths )") fi - # Now call complist. + # Now call compgen. - nm=$NMATCHES + nm=$compstate[nmatches] if [[ -z "$gopt" ]]; then - complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt + compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt else - complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats" + compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats" fi # If this generated any matches, we don't want to do in-path completion. - [[ -nmatches nm ]] || return + [[ compstate[nmatches] -eq nm ]] || return 0 # No `-F' option, so we want to use `fignore'. @@ -142,14 +142,16 @@ if [[ "$str[1]" = \~ ]]; then linepath="${str%%/*}/" eval realpath\=$linepath + [[ "$realpath" = "$linepath" ]] && return 1 str="${str#*/}" + orig="${orig#*/}" 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 @@ -158,6 +160,7 @@ else # Also, we don't use the paths from `-W'. str="$str[2,-1]" + orig="$orig[2,-1]" donepath='/' prepaths=( '' ) else @@ -169,28 +172,31 @@ else fi fi -# First we skip over all pathname components in `str' which really exist in -# the file-system, so that `/usr/lib/l' doesn't offer you `lib' and -# `lib5'. Pathname components skipped this way are taken from `str' and added -# to `donepath'. - -while [[ "$str" = */* ]] do - [[ -e "$realpath$donepath${str%%/*}" ]] || break - donepath="$donepath${str%%/*}/" - str="${str#*/}" -done - # Now build the glob pattern by calling `_match_pattern'. patstr="$str" matchflags="" _match_pattern _path_files patstr matchflags +[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" # 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. -patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/" +patstr="$patstr:gs-/-*/-:gs/*.*./../:gs-/*.-/.-:gs/**/*/:gs-.*/-./-" + +# 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 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break + donepath="$donepath${orig%%/*}/" + orig="${orig#*/}" + patstr="${patstr#*/}" +done # 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' @@ -199,6 +205,9 @@ patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/" for prepath in "$prepaths[@]"; do str="$patstr" testpath="$donepath" + ostr="$orig" + + [[ -z "$prepath" || "$prepath[-1]" = / ]] || prepath="${prepath}/" # The second loop tests the components of the path in `str' to get the # possible matches. @@ -235,16 +244,20 @@ for prepath in "$prepaths[@]"; do # the suffixes we just built are used to produce possible matches # via globbing. - for i in $tmp1; do + 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. + # has a possible sub-path matching what's on the line, we add the + # matches found in `tmp1' and otherwise give up and continue with the + # 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 @@ -269,9 +282,17 @@ for prepath in "$prepaths[@]"; do # these are file names and that `fignore' should be used as usual # (the `-f' and `-F' options). - for i in $collect; do - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}" - done + if [[ $compstate[insert] = *menu ]]; then + compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "${linepath:q}${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%%/*}" + done + fi # We have just finished handling all the matches from above, so we # can continue with the next `-W' path. @@ -291,6 +312,7 @@ for prepath in "$prepaths[@]"; do tmp1="$tmp1[1]" testpath="$testpath${tmp1##*/}/" str="$rest" + ostr="${ostr#*/}" done # We are here if all pathname components except the last one (which is still @@ -302,10 +324,24 @@ for prepath in "$prepaths[@]"; do suffixes=( $str$^pats ) suffixes=( "${(@)suffixes:gs.**.*.}" ) tmp2=( ${~tmp1}${~matchflags}${~suffixes} ) - if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then + if [[ $#tmp2 -eq 0 ]]; then + # No match, insert the expanded path and add the original tail. + [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]" - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath" + [[ -n "$ostr" && -n "$linepath$testpath" ]] && ostr="/$ostr" + + # But only if something changed. + [[ "$linepath$testpath$ostr" = "$PREFIX$SUFFIX" ]] && return 1 + + compadd -QU -S '' "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -f - "${linepath:q}${testpath:q}$ostr" else - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1} + compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "$linepath$testpath" -f "$ignore[@]" \ + -W "$prepath$realpath$testpath" - "${(@)tmp2#$tmp1}" fi done + +# This sets the return value to indicate that we added matches (or not). + +[[ nm -ne compstate[nmatches] ]] -- cgit 1.4.1