mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-19 21:44:11 +01:00
172 lines
4.9 KiB
Plaintext
172 lines
4.9 KiB
Plaintext
|
#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] ]]
|