From e74702b467171dbdafb56dfe354794a212e020d9 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 15 Apr 1999 18:05:38 +0000 Subject: Initial revision --- Completion/Core/_multi_parts | 201 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 Completion/Core/_multi_parts (limited to 'Completion/Core/_multi_parts') 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] ]] -- cgit 1.4.1