about summary refs log tree commit diff
path: root/Completion/Core/_comp_parts
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Core/_comp_parts')
-rw-r--r--Completion/Core/_comp_parts147
1 files changed, 147 insertions, 0 deletions
diff --git a/Completion/Core/_comp_parts b/Completion/Core/_comp_parts
new file mode 100644
index 000000000..7c24fd19d
--- /dev/null
+++ b/Completion/Core/_comp_parts
@@ -0,0 +1,147 @@
+#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
+
+# Test if we should use this function for the global matcher in use.
+
+_match_test _comp_parts || return
+
+# 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"
+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
+  test="${matchflags}${test}"
+  testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
+
+  # If there are no matches we give up. If there is more than one
+  # match, this is the part we will complete.
+  (( $#testarr )) || return
+  [[ $#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
+  test="${matchflags}${test}"
+  testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
+fi
+
+[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return
+
+# 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
+  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
+  suffixes=("${^suffixes[@]}${1}${(@M)^${(@P)arr}:#${~test}*}")
+
+  # 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 "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" -p "$prefix" -s "$i" - "$testarr[@]"
+done