From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27228 invoked from network); 15 Mar 1999 11:51:52 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 15 Mar 1999 11:51:52 -0000 Received: (qmail 18216 invoked by alias); 15 Mar 1999 11:51:30 -0000 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 5811 Received: (qmail 18208 invoked from network); 15 Mar 1999 11:51:29 -0000 Date: Mon, 15 Mar 1999 12:51:22 +0100 (MET) Message-Id: <199903151151.MAA21911@beta.informatik.hu-berlin.de> From: Sven Wischnowsky To: zsh-workers@sunsite.auc.dk In-reply-to: Bruce Stephens's message of 15 Mar 1999 11:42:32 +0000 Subject: Re: _tar uses _multi_parts Bruce Stephens wrote: > Presumably the fix is: > ! _multi_parts / _tar_cache_list > ! _sep_parts / _tar_cache_list Nay! It was just that `_multi_parts' somehow got omitted from the distribution. Bye Sven diff -u Completion/Core/_multi_parts Completion/Core/_multi_parts --- Completion/Core/_multi_parts Mon Mar 15 12:49:22 1999 +++ Completion/Core/_multi_parts Mon Mar 15 12:49:41 1999 @@ -0,0 +1,226 @@ +#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 menu origflags mflags + +_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'. + +if [[ $#compstate[pattern_match] -ne 0 ]]; then + patstr="${PREFIX}*${SUFFIX}*" +else + patstr="${PREFIX:q}*${SUFFIX:q}*" +fi +orig="${PREFIX}${SUFFIX}" + +[[ $compstate[insert] = *menu || -n "$_comp_correct" || + ( $#compstate[pattern_match] -ne 0 && + "$orig" != "${orig:q}" ) ]] && menu=yes + +matchflags="" +_match_pattern _path_files patstr matchflags +origflags="$matchflags" +[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" + +patstr="${${patstr//$sep/*$sep}//\*##/*}" + +# 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'. + + if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then + mflags="$origflags" + else + mflags="$matchflags" + fi + + pat="${${${patstr#*${sep}}%${sep}*}//\*/[^${sep}]#}" + tmp1=( "${(@M)matches:#${~mflags}${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 + # (and also remove all words not matching the string at all), and + # set `patstr' and `orig' to the next component. + + tmp1="${orig%%${sep}*}${sep}" + pref="$pref$tmp1" + matches=("${(@)${(@)${(@M)matches:#${tmp1}*}#$tmp1}:#}") + 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 +if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then + mflags="$origflags" +else + mflags="$matchflags" +fi +tmp1=( "${(@M)matches:#${~mflags}${~pat}}" ) + +if (( $#tmp1 )); then + + # There are words that are matched, put them into `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, put 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 [[ -n "$menu" ]]; then + if [[ "$orig" = *${sep}* ]]; then + orig="${sep}${orig#*${sep}}" + else + orig='' + fi + for i in "$matches[@]" ; do + if [[ "$i" = *${sep}* ]]; then + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \ + -p "$pref" -s "$orig" - "${i%%${sep}*}${sep}" + else + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \ + -p "$pref" -s "$orig" - "${i%%${sep}*}" + fi + done + else + for i in "$matches[@]" ; do + if [[ "$i" = *${sep}* ]]; then + compadd -U -i "$IPREFIX" -p "$pref" -s "${i#*${sep}}" \ + "$group[@]" "$expl[@]" -M "r:|${sep:q}=*" - "${i%%${sep}*}${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. + + if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then + mflags="$origflags" + else + mflags="$matchflags" + fi + tmp1=( "${(@M)matches:#${~mflags}${~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] ]] -- Sven Wischnowsky wischnow@informatik.hu-berlin.de