about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSven Wischnowsky <wischnow@users.sourceforge.net>2000-05-19 08:24:16 +0000
committerSven Wischnowsky <wischnow@users.sourceforge.net>2000-05-19 08:24:16 +0000
commitf9e65c2b1f448cd27c597ec727b63bebde2fbdff (patch)
tree816fd81472f634d8b19cc8aff9400c7644b22f77
parentaa86df8d1c3daeb0b267ad16cdca647247530696 (diff)
downloadzsh-f9e65c2b1f448cd27c597ec727b63bebde2fbdff.tar.gz
zsh-f9e65c2b1f448cd27c597ec727b63bebde2fbdff.tar.xz
zsh-f9e65c2b1f448cd27c597ec727b63bebde2fbdff.zip
don't use $match for something different than (#b)ackrefs (11464)
-rw-r--r--ChangeLog9
-rw-r--r--Completion/Base/_arguments19
-rw-r--r--Completion/Core/_approximate2
-rw-r--r--Completion/Core/_files2
-rw-r--r--Completion/Core/_multi_parts350
-rw-r--r--Completion/Core/_sep_parts112
-rw-r--r--Completion/Debian/_apt2
-rw-r--r--Completion/User/_enscript2
-rw-r--r--Completion/User/_finger2
-rw-r--r--Completion/User/_urls2
-rw-r--r--Completion/X/_xutils2
11 files changed, 286 insertions, 218 deletions
diff --git a/ChangeLog b/ChangeLog
index ec82f9d37..098a120a3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2000-05-19  Sven Wischnowsky  <wischnow@zsh.org>
+
+	* 11464: Completion/Base/_arguments, Completion/Core/_approximate,
+ 	Completion/Core/_files, Completion/Core/_multi_parts,
+ 	Completion/Core/_sep_parts, Completion/Debian/_apt,
+ 	Completion/User/_enscript, Completion/User/_finger,
+ 	Completion/User/_urls, Completion/X/_xutils:don't use $match for
+ 	something different than (#b)ackrefs
+	
 2000-05-18  Sven Wischnowsky  <wischnow@zsh.org>
 
 	* 11460: Completion/User/_netscape: fix for completion of
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
index 8aad10852..f819f69c9 100644
--- a/Completion/Base/_arguments
+++ b/Completion/Base/_arguments
@@ -164,7 +164,7 @@ zstyle -s ":completion:${curcontext}:options" auto-description autod
 
 if (( $# )) && comparguments "$multi[@]" "$autod" "$@"; then
   local action noargs aret expl local tried
-  local next direct odirect equal single match matched ws tmp1 tmp2 tmp3
+  local next direct odirect equal single matcher matched ws tmp1 tmp2 tmp3
   local opts subc tc prefix suffix descrs actions subcs
   local origpre="$PREFIX" origipre="$IPREFIX"
 
@@ -196,6 +196,8 @@ if (( $# )) && comparguments "$multi[@]" "$autod" "$@"; then
     fi
   fi
 
+  comparguments -M matcher
+
   context=()
   state=()
 
@@ -252,7 +254,7 @@ if (( $# )) && comparguments "$multi[@]" "$autod" "$@"; then
 
               eval ws\=\( "${action[3,-3]}" \)
 
-              _describe -t "$subc" "$descr" ws -M "$match" "$subopts[@]"
+              _describe -t "$subc" "$descr" ws -M "$matcher" "$subopts[@]"
 	      tried=yes
 
             elif [[ "$action" = \(*\) ]]; then
@@ -307,8 +309,6 @@ if (( $# )) && comparguments "$multi[@]" "$autod" "$@"; then
 	PREFIX="$origpre"
 	IPREFIX="$origipre"
 
-        comparguments -M match
-	
         if comparguments -s single; then
 
           if [[ "$single" = direct ]]; then
@@ -342,15 +342,15 @@ if (( $# )) && comparguments "$multi[@]" "$autod" "$@"; then
           next=( "$next[@]" "$odirect[@]" )
 	  if [[ -n "$ismulti" ]]; then
 	    _ms_opt=yes
-	    _ms_match="$_ms_match $match"
+	    _ms_match="$_ms_match $matcher"
 	    _ms_optnext=( "$_ms_optnext[@]" "$next[@]" )
 	    _ms_optdirect=( "$_ms_optdirect[@]" "$direct[@]" )
 	    _ms_optequal=( "$_ms_optequal[@]" "$equal[@]" )
 	  else
             _describe -o option \
-                      next -Q -M "$match" -- \
-                      direct -QS '' -M "$match" -- \
-                      equal -QqS= -M "$match"
+                      next -Q -M "$matcher" -- \
+                      direct -QS '' -M "$matcher" -- \
+                      equal -QqS= -M "$matcher"
           fi
         fi
 	PREFIX="$prevpre"
@@ -368,7 +368,8 @@ if (( $# )) && comparguments "$multi[@]" "$autod" "$@"; then
       suffix="$SUFFIX"
       PREFIX="${PREFIX%%\=*}"
       SUFFIX=''
-      compadd -M "$match" -D equal - "${(@)equal%%:*}"
+
+      compadd -M "$matcher" -D equal - "${(@)equal%%:*}"
 
       if [[ $#equal -eq 1 ]]; then
         PREFIX="$prefix"
diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate
index 47fc9ce23..9d294e8c4 100644
--- a/Completion/Core/_approximate
+++ b/Completion/Core/_approximate
@@ -10,7 +10,7 @@
 
 [[ _matcher_num -gt 1 || "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1
 
-local _comp_correct _correct_expl comax cfgacc redef
+local _comp_correct _correct_expl comax cfgacc redef match
 local oldcontext="${curcontext}" opm="$compstate[pattern_match]"
 
 if [[ "$1" = -a* ]]; then
diff --git a/Completion/Core/_files b/Completion/Core/_files
index b1d06e23a..391d570a5 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -1,6 +1,6 @@
 #autoload
 
-local opts tmp glob pat pats expl tag i def descr end ign ret=1
+local opts tmp glob pat pats expl tag i def descr end ign ret=1 match
 
 zparseopts -a opts \
     '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X+: M+: F: J+: V+:
diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts
index 1f51d2f6d..bdfa26fc3 100644
--- a/Completion/Core/_multi_parts
+++ b/Completion/Core/_multi_parts
@@ -7,27 +7,22 @@
 # 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]
+local sep matches pref npref i tmp1 group expl menu pre suf opre osuf cpre
+local opts sopts matcher imm
+typeset -U tmp2
 
 # 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
+zparseopts -D -a sopts \
+    'J+:=group' 'V+:=group' 'X+:=expl' 'P:=opts' 'F:=opts' \
+    S: r: R: q 1 2 n f 'M+:=matcher' 'i=imm'
+
+sopts=( "$sopts[@]" "$opts[@]" )
+if (( $#matcher )); then
+  matcher="${matcher[2]}"
+else
+  matcher=
+fi
 
 # Get the arguments, first the separator, then the array. The array is 
 # stored in `matches'. Further on this array will always contain those 
@@ -36,166 +31,237 @@ shift OPTIND-1
 
 sep="$1"
 if [[ "${2[1]}" = '(' ]]; then
-  matches=( ${2[2,-2]} )
+  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>'.
+# In `pre' and `suf' we will hold the prefix and the suffix from the
+# line while we walk through them. The original string are used 
+# temporarily for matching.
 
-if [[ -o globcomplete ]]; then
-  patstr="${PREFIX}*${SUFFIX}*"
-else
-  patstr="${PREFIX:q}*${SUFFIX:q}*"
-fi
-orig="${PREFIX}${SUFFIX}"
+pre="$PREFIX"
+suf="$SUFFIX"
+opre="$PREFIX"
+osuf="$SUFFIX"
+orig="$PREFIX$SUFFIX"
 
-matchflags=""
-_match_pattern _path_files patstr matchflags
-[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
+# Special handling for menucompletion?
 
-patstr="${${patstr//$sep/*$sep}//\*##/*}"
-#eval patstr\="\$patstr:gs-${sep}-\*${sep}-:gs/\*\*/\*/"
+[[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
+   ( $#compstate[pattern_match] -ne 0 &&
+     "$orig" != "${orig:q}" ) ]] && menu=yes
 
-# 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.
+# In `pref' we collect the unambiguous prefix path.
 
 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'.
+# If the string from the line matches at least one of the strings,
+# we use only the matching strings.
 
-  pat="${${${patstr#*${sep}}%${sep}*}//\*/[^${sep}]#}${patstr##*${sep}}"
-  tmp1=( "${(@M)matches:#${~matchflags}${orig%%${sep}*}${sep}${~pat}}" )
+compadd -O tmp1 -M "r:|${sep}=* r:|=* $matcher" - "$matches[@]"
 
-  # If there are no words matching the exact substring, stop.
+(( $#tmp1 )) && matches=( "$tmp1[@]" )
 
-  (( $#tmp1 )) || break
+while true; do
 
-  # 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
+  # Get the prefix and suffix for matching.
 
-# Now we get all the words that still match in `tmp1'.
+  if [[ "$pre" = *${sep}* ]]; then
+    PREFIX="${pre%%${sep}*}"
+    SUFFIX=""
+  else
+    PREFIX="${pre}"
+    SUFFIX="${suf%%${sep}*}"
+  fi
 
-if [[ "$patstr" = *${sep}* ]]; then
-  tmp1="${patstr%${sep}*}${sep}"
-  pat="${tmp1//\*/[^${sep}]#}${patstr##*${sep}}"
-else
-  pat="$patstr"
-fi
-tmp1=( "${(@M)matches:#${~matchflags}${~pat}}" )
+  # Check if the component for some of the possible matches is equal
+  # to the string from the line. If there are such strings, we directly
+  # use the stuff from the line. This avoids having `foo' complete to
+  # both `foo' and `foobar'.
 
-if (( $#tmp1 )); then
+  if [[ -n "$PREFIX$SUFFIX" || "$pre" = ${sep}* ]]; then
+    tmp1=( "${(@M)matches:#${PREFIX}${SUFFIX}${sep}*}" )
+  else
+    tmp1=()
+  fi
 
-  # There are words that are matched, put them int `matches' and then
-  # move all unambiguous components from the beginning into `pref'.
+  if (( $#tmp1 )); then
+    npref="${PREFIX}${SUFFIX}${sep}"
+  else
+    # No exact match, see how many strings match what's on the line.
 
-  matches=( "$tmp1[@]" )
-  while [[ "$matches[1]" = *${sep}* ]]; do
+    builtin compadd -O tmp1 - "${(@)matches%%${sep}*}"
 
-    # 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 -eq 0 && -n "$_comp_correct" ]] &&
+      compadd -O tmp1 - "${(@)matches%%${sep}*}"
 
-    tmp1="${matches[1]%%${sep}*}${sep}"
-    tmp2=( "${(@)matches:#${tmp1}*}" )
-    (( $#tmp2 )) && break
+    tmp2=( "$tmp1[@]" )
 
-    # All matches have the same prefix, but it into `pref' and remove
-    # it from the matches.
+    if [[ $#tmp1 -eq 1 ]]; then
 
-    pref="$pref$tmp1"
-    matches=( "${(@)${(@)matches#$tmp1}:#}" )
+      # Only one match. If there are still separators from the line
+      # we just accept this component. Otherwise we insert what we 
+      # have collected, probably giving it a separator character
+      # as a suffix.
 
-    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}*}"
+      if [[ "$pre$suf" = *${sep}* ]]; then
+        npref="${tmp1[1]}${sep}"
       else
-        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -p "$pref" - "$i"
+        matches=( "${(@M)matches:#${tmp1[1]}*}" )
+
+	PREFIX="${cpre}${pre}"
+	SUFFIX="$suf"
+
+	if [[ $#imm -ne 0 && $#matches -eq 1 ]] ||
+           zstyle -t ":completion:${curcontext}:" expand suffix; then
+	  compadd "$group[@]" "$expl[@]" "$opts[@]" \
+                  -M "r:|${sep}=* r:|=* $matcher" - "$pref$matches[1]"
+        else
+	  tmp2=( "${(@M)matches:#${tmp1[1]}${sep}*}" )
+
+	  if (( $#tmp2 )); then
+	    compadd "$group[@]" "$expl[@]" -p "$pref" -r "$sep" -S "$sep" "$opts[@]" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "$tmp1[1]"
+          else
+	    compadd "$group[@]" "$expl[@]" -p "$pref" "$sopts[@]" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "$tmp1[1]"
+          fi
+        fi
+	return
       fi
-    done
-  fi
-elif [[ "$patstr" = *${sep}* ]]; then
+    elif (( $#tmp1 )); then
+      local ret=1
 
-  # 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.
+      # More than one match. First we get all strings that match the
+      # rest from the line.
 
-  while [[ "$patstr" = *${sep}* ]]; do
+      PREFIX="$pre"
+      SUFFIX="$suf"
+      compadd -O matches -M "r:|${sep}=* r:|=* $matcher" - "$matches[@]"
 
-    # 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
+      if [[ "$pre" = *${sep}* ]]; then
+ 	PREFIX="${cpre}${pre%%${sep}*}"
+	SUFFIX="${sep}${pre#*${sep}}${suf}"
+      else
+        PREFIX="${cpre}${pre}"
+	SUFFIX="$suf"
+      fi
 
-    # Then we check if there are words that have a different prefix.
+      if ! zstyle -t ":completion:${curcontext}:" expand suffix ||
+         [[ -n "$menu" || -z "$compstate[insert]" ]]; then
+
+        # With menucompletion we add only the ambiguous component with
+        # the prefix collected and a spearator for the matches that
+        # have more components.
+
+        tmp2="$pre$suf"
+        if [[ "$tmp2" = *${sep}* ]]; then
+          tmp2=(-s "${sep}${tmp2#*${sep}}")
+        else
+	  tmp2=()
+        fi
+        for i in "${(@M)matches:#(${(j:|:)~tmp1})*}"; do
+	  case "$i" in
+	  *${sep})
+            compadd "$group[@]" "$expl[@]" -r "$sep" -S "$sep" "$opts[@]" \
+	            -p "$pref" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "${i%%${sep}*}" && ret=0
+            ;;
+	  ${sep}*)
+            compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" \
+	            -p "$pref" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "$sep" && ret=0
+            ;;
+	  *${sep}*)
+            compadd "$group[@]" "$expl[@]" -r "$sep" -S "$sep" "$opts[@]" \
+	            -p "$pref" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "${i%%${sep}*}" && ret=0
+            ;;
+          *)
+            compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" -p "$pref" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "$i" && ret=0
+            ;;
+          esac
+        done
+      else
+        # With normal completion we add all matches one-by-one with
+	# the unmatched part as a suffix. This will insert the longest
+	# unambiguous string for all matching strings.
+
+        for i in "${(@M)matches:#(${(j:|:)~tmp1})*}"; do
+	  if [[ "$i" = *${sep}* ]]; then
+            compadd "$group[@]" "$expl[@]" "$opts[@]" \
+	            -p "$pref" -s "${i#*${sep}}" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "${i%%${sep}*}" && ret=0
+          else
+            compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" -p "$pref" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "$i" && ret=0
+          fi
+        done
+      fi
+      return ret
+    else
+      # We are here if no string matched what's on the line. In this
+      # case we insert the expanded prefix we collected if it differs
+      # from the original string from the line.
 
-    tmp2=( "${(@)tmp1:#${tmp1[1]%%${sep}*}${sep}*}" )
-    if (( $#tmp2 )); then
+      { ! zstyle -t ":completion:${curcontext}:" expand prefix ||
+        [[ "$orig" = "$pref$pre$suf" ]] } && return 1
 
-      # 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.
+      PREFIX="${cpre}${pre}"
+      SUFFIX="$suf"
 
-      compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" \
-              -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}"
-      return 0
+      if [[ -n "$suf" ]]; then
+        compadd "$group[@]" "$expl[@]" -s "$suf" "$sopts[@]" \
+                -M "r:|${sep}=* r:|=* $matcher" - "$pref$pre"
+      else
+        compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" \
+                -M "r:|${sep}=* r:|=* $matcher" - "$pref$pre"
+      fi
+      return
     fi
+  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
+  # We just accepted and/or expanded a component from the line. We
+  # remove it from the matches (using only those that have a least
+  # the skipped string) and ad it the `pref'.
 
-  # Finally, add the unambiguous prefix and the rest of the string
-  # from the line.
+  matches=( "${(@)${(@)${(@M)matches:#${npref}*}#*${sep}}:#}" )
+  pref="$pref$npref"
 
-  compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" - "$orig"
-fi
+  # Now we set `pre' and `suf' to their new values.
 
-# This sets the return value to indicate that we added matches (or not).
-
-[[ nm -ne compstate[nmatches] ]]
+  if [[ "$pre" = *${sep}* ]]; then
+    cpre="${cpre}${pre%%${sep}*}${sep}"
+    pre="${pre#*${sep}}"
+  elif [[ "$suf" = *${sep}* ]]; then
+    cpre="${cpre}${pre}${suf%%${sep}*}${sep}"
+    pre="${suf#*${sep}}"
+    suf=""
+  else
+    # The string from the line is fully handled. If we collected an
+    # unambiguous prefix and that differs from the original string,
+    # we insert it.
+
+    PREFIX="${opre}${osuf}"
+    SUFFIX=""
+
+    if [[ -n "$pref" && "$orig" != "$pref" ]]; then
+      if [[ "$pref" = *${sep} ]]; then
+        compadd "$group[@]" "$expl[@]" "$opts[@]" \
+                -p "${pref%${sep}*${sep}}${sep}" -S "$sep" \
+                -M "r:|${sep}=* r:|=* $matcher" - "${${pref%${sep}}##*${sep}}"
+
+      elif [[ "$pref" = *${sep}* ]]; then
+        compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" \
+                -p "${pref%${sep}*}${sep}" \
+                -M "r:|${sep}=* r:|=* $matcher" - "${pref##*${sep}}"
+      else
+        compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" \
+                -M "r:|${sep}=* r:|=* $matcher" - "$pref"
+      fi
+    fi
+    return
+  fi
+done
diff --git a/Completion/Core/_sep_parts b/Completion/Core/_sep_parts
index c1cda2b9a..0f9ef0fc4 100644
--- a/Completion/Core/_sep_parts
+++ b/Completion/Core/_sep_parts
@@ -9,40 +9,34 @@
 #
 #  _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 will make this function complete the strings `foo' and `bar'.
+# 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
+local matchflags opt group expl nm=$compstate[nmatches] opre osuf opts matcher
 
 # 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
+zparseopts -D -a opts \
+    'J+:=group' 'V+:=group' P: F: S: r: R: q 1 2 n 'X+:=expl' 'M+:=matcher'
+
+if (( $#matcher )); then
+  matcher="${matcher[2]}"
+else
+  matcher=''
+fi
 
 # Get the string from the line.
 
+opre="$PREFIX"
+osuf="$SUFFIX"
 str="$PREFIX$SUFFIX"
-[[ $#compstate[pattern_match] -ne 0 ]] || str="$str:q"
+SUFFIX=""
 prefix=""
 
 # Walk through the arguments to find the longest unambiguous prefix.
@@ -56,59 +50,53 @@ while [[ $# -gt 1 ]]; do
     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.
+  # Is the separator on the line?
 
-  test="${str%%${sep}*}"
-  [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1
+  [[ "$str" != *${sep}* ]] && break
 
-  matchflags=""
-  _match_pattern _sep_parts test matchflags
-  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
+  # Get the matching array elements.
 
-  test="${matchflags}${test}"
-  testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
-  testarr=( "${(@)testarr:#}" )
+  PREFIX="${str%%(|\\)${sep}*}"
+  builtin compadd -O testarr - "${(@P)arr}"
+  [[ $#testarr -eq 0 && -n "$_comp_correct" ]] &&
+    compadd -O testarr - "${(@P)arr}"
 
   # 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:#}" )
+  PREFIX="$str"
+  builtin compadd -O testarr - "${(@P)arr}"
+  [[ $#testarr -eq 0 && -n "$_comp_correct" ]] &&
+    compadd -O testarr - "${(@P)arr}"
 fi
 
 [[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return 1
 
 # Now we build the suffixes to give to the completion code.
+
 shift
 matchers=()
 suffixes=("")
@@ -116,23 +104,18 @@ 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}*}"
+    PREFIX="${str%%${3}*}"
   else
-    test="$str"
+    PREFIX="$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.
 
@@ -141,29 +124,38 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do
     tmparr=( ${=arr[2,-2]} )
     arr=tmparr
   fi
-  tmparr=( "${(@M)${(@P)arr}:#${~test}*}" )
-  tmparr=( "${(@)tmparr:#}" )
-  suffixes=("${(@)^suffixes[@]}${1}${(@)^tmparr}")
+
+  builtin compadd -O tmparr - "${(@P)arr}"
+  [[ $#tmparr -eq 0 && -n "$_comp_correct" ]] &&
+    compadd -O tmparr - "${(@P)arr}"
+
+  suffixes=("${(@)^suffixes[@]}${(q)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")
+
+(( $# )) && autosuffix=(-qS "${(q)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")
+
+[[ $#matchers+$#matcher -gt 0 ]] && matchers=(-M "$matchers $matcher")
 
 # Add the matches for each of the suffixes.
+
+PREFIX="$pre"
+SUFFIX="$suf"
 for i in "$suffixes[@]"; do
-  compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \
-          -i "$IPREFIX" -p "$prefix" -s "$i" - "$testarr[@]"
+  compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" "$opts[@]" \
+          -i "$IPREFIX" -I "$ISUFFIX" -p "$prefix" -s "$i" - "$testarr[@]"
 done
 
 # This sets the return value to indicate that we added matches (or not).
diff --git a/Completion/Debian/_apt b/Completion/Debian/_apt
index f4e35fe32..cba9ebad5 100644
--- a/Completion/Debian/_apt
+++ b/Completion/Debian/_apt
@@ -53,7 +53,7 @@ _apt_arguments () {
   comp_hasarg="{case \$current_option in
   ${comp_hasarg}esac}"
 
-  local short_seq false true bool bool_prefix intlevel word word1 nul qnul
+  local short_seq false true bool bool_prefix intlevel word word1 nul qnul match
   local comp_bool comp_intlevel comp_configfile comp_arbitem comp_long comp_opt
   local regex_short regex_long regex_all
 
diff --git a/Completion/User/_enscript b/Completion/User/_enscript
index 21c388bb9..c5de3375a 100644
--- a/Completion/User/_enscript
+++ b/Completion/User/_enscript
@@ -1,6 +1,6 @@
 #compdef enscript
 
-local state context line curcontext="$curcontext"
+local state context line curcontext="$curcontext" match
 typeset -A opt_args
 
 _arguments -C -s \
diff --git a/Completion/User/_finger b/Completion/User/_finger
index c5787571c..74b97521e 100644
--- a/Completion/User/_finger
+++ b/Completion/User/_finger
@@ -1,6 +1,6 @@
 #compdef finger
 
-local curcontext="$curcontext" state line
+local curcontext="$curcontext" state line match
 typeset -A opt_args
 
 if (( ! $+_finger_args )); then
diff --git a/Completion/User/_urls b/Completion/User/_urls
index f335b16aa..691a386ec 100644
--- a/Completion/User/_urls
+++ b/Completion/User/_urls
@@ -38,7 +38,7 @@
 #    E.g.:
 #      zstyle ':completion:*:urls' local www /usr/local/apache/htdocs public_html
 
-local ipre scheme host user uhosts ret=1 expl
+local ipre scheme host user uhosts ret=1 expl match
 local urls_path localhttp
 zstyle -s ":completion:${curcontext}:urls" path urls_path ||
     urls_path="${ZDOTDIR:-$HOME}/.zsh/urls"
diff --git a/Completion/X/_xutils b/Completion/X/_xutils
index 17100c033..09fafd5d4 100644
--- a/Completion/X/_xutils
+++ b/Completion/X/_xutils
@@ -46,7 +46,7 @@ xev)
     '-rv'
   ;;
 xhost)
-  local expl type ret=1 tmp
+  local expl type ret=1 tmp match
 
   if compset -P '-'; then
     tmp=(${(f)"$(xhost)"})