mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 06:00:54 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			160 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| #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.:
 | |
| #
 | |
| #  _comp_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 _comp_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"
 | |
| [[ -o globcomplete ]] && 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}*}"
 | |
|   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 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.
 | |
|   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 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
 | |
|   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
 | |
|   # 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=( "${(@)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
 | |
|   # word matching before the separators on the fly.
 | |
|   matchers=("$matchers[@]" "r:|${1}=*")
 | |
|   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] ]]
 |