1
0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-11-19 21:44:11 +01:00
zsh/Completion/Core/_multi_parts
1999-04-15 18:05:38 +00:00

202 lines
6.1 KiB
Plaintext

#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 `*<sep>'.
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] ]]