26763: fix problem on failed cd -s to relative path
[zsh.git] / Completion / Unix / Type / _path_files
blob63713eff79faf9e7f6ea9e703db8df7938a1b170
1 #autoload
3 local -a match mbegin mend
5 # Look for glob qualifiers.  Do this first:  if we're really
6 # in a glob qualifier, we don't actually want to expand
7 # the earlier part of the path.  We can't expand inside
8 # parentheses otherwise, so as we test that successfully
9 # we should be able to commit to glob qualifiers here.
11 # Extra nastiness to be careful about a quoted parenthesis.
12 # The initial tests look for parentheses with zero or an
13 # even number of backslashes in front.  We also require that
14 # there was at least one character before the parenthesis for
15 # a bare glob qualifier.
16 # The later test looks for an outstanding quote.
17 if _have_glob_qual $PREFIX; then
18    compset -p ${#match[1]}
19    if [[ -o extendedglob ]] && compset -P '\#'; then
20      _globflags
21    else
22      _globquals
23    fi
24    return
27 # Utility function for in-path completion. This allows `/u/l/b<TAB>'
28 # to complete to `/usr/local/bin'.
30 local linepath realpath donepath prepath testpath exppath skips skipped
31 local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre
32 local pats haspats ignore pfx pfxsfx sopt gopt opt sdirs ignpar cfopt listsfx
33 local nm=$compstate[nmatches] menu matcher mopts sort mid accex fake
34 local listfiles listopts tmpdisp origtmp1 Uopt
35 integer npathcheck
36 local -a Mopts
38 typeset -U prepaths exppaths
40 exppaths=()
42 # Get the options.
44 zparseopts -a mopts \
45     'P:=pfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \
46     'W:=prepaths' 'F:=ignore' 'M+:=matcher' \
47     J+: V+: X+: 1 2 n 'f=tmp1' '/=tmp1' 'g+:-=tmp1'
49 sopt="-${(@j::M)${(@)tmp1#-}#?}"
50 (( $tmp1[(I)-[/g]*] )) && haspats=yes
51 (( $tmp1[(I)-g*] )) && gopt=yes
52 if (( $tmp1[(I)-/] )); then
53   pats="${(@)${(@M)tmp1:#-g*}#-g}"
54   pats=( '*(-/)' ${${(z):-x $pats}[2,-1]} )
55 else
56   pats="${(@)${(@M)tmp1:#-g*}#-g}"
57   pats=( ${${(z):-x $pats}[2,-1]} )
59 pats=( "${(@)pats:# #}" )
61 if (( $#pfx )); then
62   compset -P "$pfx[2]" || pfxsfx=( "$pfx[@]" "$pfxsfx[@]" )
65 if (( $#prepaths )); then
66   tmp1="${prepaths[2]}"
67   if [[ "$tmp1[1]" = '(' ]]; then
68     prepaths=( ${^=tmp1[2,-2]%/}/ )
69   elif [[ "$tmp1[1]" = '/' ]]; then
70     prepaths=( "${tmp1%/}/" )
71   else
72     prepaths=( ${(P)^tmp1%/}/ )
73     (( ! $#prepaths )) && prepaths=( ${tmp1%/}/ )
74   fi
75   (( ! $#prepaths )) && prepaths=( '' )
76 else
77   prepaths=( '' )
80 if (( $#ignore )); then
81   if [[ "${ignore[2]}" = \(* ]]; then
82     ignore=( ${=ignore[2][2,-2]} )
83   else
84     ignore=( ${(P)ignore[2]} )
85   fi
88 # If we were given no file selection option, we behave as if we were given
89 # a `-f'.
91 if [[ "$sopt" = -(f|) ]]; then
92   if [[ -z "$gopt" ]]; then
93     sopt='-f'
94     pats=('*')
95   else
96     unset sopt
97   fi
100 if (( ! $mopts[(I)-[JVX]] )); then
101   local expl
103   if [[ -z "$gopt" && "$sopt" = -/ ]]; then
104     _description directories expl directory
105   else
106     _description files expl file
107   fi
108   tmp1=$expl[(I)-M*]
109   if (( tmp1 )); then
110     if (( $#matcher )); then
111       matcher[2]="$matcher[2] $expl[1+tmp1]"
112     else
113       matcher=(-M "$expl[1+tmp1]")
114     fi
115   fi
116   mopts=( "$mopts[@]" "$expl[@]" )
119 # If given no `-F' option, we may want to use $fignore, turned into patterns.
121 [[ -z "$_comp_no_ignore" && $#ignore -eq 0 &&
122    ( -z $gopt || "$pats" = \ #\*\ # ) && -n $FIGNORE ]] && 
123     ignore=( "?*${^fignore[@]}" )
125 if (( $#ignore )); then
126   _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" )
127   (( $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore )
130 if [[ $#matcher -eq 0 && -o nocaseglob ]]; then
131   # If globbing is case insensitive and there's no matcher,
132   # do case-insensitive matching.
133   matcher=( -M 'm:{a-zA-Z}={A-Za-z}' )
136 if (( $#matcher )); then
137   # Add the current matcher to the options to compadd.
138   mopts=( "$mopts[@]" "$matcher[@]" )
141 if zstyle -s ":completion:${curcontext}:" file-sort tmp1; then
142   case "$tmp1" in
143   *size*)             sort=oL;;
144   *links*)            sort=ol;;
145   *(time|date|modi)*) sort=om;;
146   *access*)           sort=oa;;
147   *(inode|change)*)   sort=oc;;
148   *)                  sort=on;;
149   esac
150   [[ "$tmp1" = *rev* ]] && sort[1]=O
151   [[ "$tmp1" = *follow* ]] && sort="-${sort}-"
153   if [[ "$sort" = on ]]; then
154     sort=
155   else
156     mopts=( "${(@)mopts/#-J/-V}" )
158     tmp2=()
159     for tmp1 in "$pats[@]"; do
160       if _have_glob_qual "$tmp1" complete; then
161         # unbalanced parenthesis is correct: match[1] contains the start,
162         # match[5] doesn't contain the end.
163         tmp2+=( "${match[1]}${sort}${match[5]})" )
164       else
165         tmp2+=( "${tmp1}(${sort})" )
166       fi
167     done
168     pats=( "$tmp2[@]" )
169   fi
172 # Check if we have to skip over sequences of slashes. The value of $skips
173 # is used below to match the pathname components we always have to accept
174 # immediately.
176 if zstyle -t ":completion:${curcontext}:paths" squeeze-slashes; then
177   skips='((.|..|)/)##'
178 else
179   skips='((.|..)/)##'
182 zstyle -s ":completion:${curcontext}:paths" special-dirs sdirs
183 zstyle -t ":completion:${curcontext}:paths" list-suffixes &&
184     listsfx=yes
186 [[ "$pats" = ((|*[[:blank:]])\*(|[[:blank:]]*|\([^[:blank:]]##\))|*\([^[:blank:]]#/[^[:blank:]]#\)*) ]] &&
187     sopt=$sopt/
189 zstyle -a ":completion:${curcontext}:paths" accept-exact accex
190 zstyle -a ":completion:${curcontext}:" fake-files fake
192 zstyle -s ":completion:${curcontext}:" ignore-parents ignpar
194 if [[ -n "$compstate[pattern_match]" ]]; then
195   if { [[ -z "$SUFFIX" ]] && _have_glob_qual "$PREFIX" complete } ||
196     _have_glob_qual "$SUFFIX" complete; then
197     # Copy all glob qualifiers from the line to
198     # the patterns used when generating matches
199     tmp3=${match[5]}
200     if [[ -n "$SUFFIX" ]]; then
201       SUFFIX=${match[2]}
202     else
203       PREFIX=${match[2]}
204     fi
205     tmp2=()
206     for tmp1 in "$pats[@]"; do
207       if _have_glob_qual "$tmp1" complete; then
208         # unbalanced parenthesis is correct: match[1] contains the start,
209         # match[5] doesn't contain the end.
210         tmp2+=( "${match[1]}${tmp3}${match[5]})")
211       else
212         tmp2+=( "${tmp1}(${tmp3})" )
213       fi
214     done
215     pats=( "$tmp2[@]" )
216   fi
219 # We get the prefix and the suffix from the line and save the whole
220 # original string. Then we see if we will do menu completion.
222 pre="$PREFIX"
223 suf="$SUFFIX"
224 opre="$PREFIX"
225 osuf="$SUFFIX"
226 orig="${PREFIX}${SUFFIX}"
227 eorig="$orig"
229 [[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
230    ( -n "$compstate[pattern_match]" &&
231      "${orig#\~}" != (|*[^\\])[][*?#~^\|\<\>]* ) ]] && menu=yes
232 if [[ -n "$_comp_correct" ]]; then
233     cfopt=-
234     Uopt=-U
235 else
236     Mopts=(-M "r:|/=* r:|=*")
239 # Now let's have a closer look at the string to complete.
241 if [[ "$pre" = [^][*?#^\|\<\>\\]#(\`[^\`]#\`|\$)*/* && "$compstate[quote]" != \' ]]; then
243   # If there is a parameter expansion in the word from the line, we try
244   # to complete the beast by expanding the prefix and completing anything
245   # after the first slash after the parameter expansion.
246   # This fails for things like `f/$foo/b/<TAB>' where the first `f' is
247   # meant as a partial path.
249   linepath="${(M)pre##*\$[^/]##/}"
250   eval 'realpath=${(e)~linepath}' 2>/dev/null
251   [[ -z "$realpath" || "$realpath" = "$linepath" ]] && return 1
252   pre="${pre#${linepath}}"
253   i='[^/]'
254   i="${#linepath//$i}"
255   orig="${orig[1,(in:i:)/][1,-2]}"
256   donepath=
257   prepaths=( '' )
258 elif [[ "$pre[1]" = \~ && -z "$compstate[quote]" ]]; then
260   # It begins with `~', so remember anything before the first slash to be able
261   # to report it to the completion code. Also get an expanded version of it
262   # (in `realpath'), so that we can generate the matches. Then remove that
263   # prefix from the string to complete, set `donepath' to build the correct
264   # paths and make sure that the loop below is run only once with an empty
265   # prefix path by setting `prepaths'.
267   linepath="${pre[2,-1]%%/*}"
268   if [[ -z "$linepath" ]]; then
269     realpath="${HOME%/}/"
270   elif [[ "$linepath" = ([-+]|)[0-9]## ]]; then
271     if [[ "$linepath" != [-+]* ]]; then
272       tmp1="$linepath"
273     else
274       if [[ "$linepath" = -* ]]; then
275         tmp1=$(( $#dirstack $linepath ))
276       else
277         tmp1=$linepath[2,-1]
278       fi
279       [[ -o pushdminus ]] && tmp1=$(( $#dirstack - $tmp1 ))
280     fi
281     if (( ! tmp1 )); then
282       realpath=$PWD/
283     elif [[ tmp1 -le $#dirstack ]]; then
284       realpath=$dirstack[tmp1]/
285     else
286       _message 'not enough directory stack entries'
287       return 1
288     fi
289   elif [[ "$linepath" = [-+] ]]; then
290     realpath=${~:-\~$linepath}/
291   else
292     eval "realpath=~${linepath}/" 2>/dev/null
293     if [[ -z "$realpath" ]]; then
294       _message "unknown user \`$linepath'"
295       return 1
296     fi
297   fi
298   linepath="~${linepath}/"
299   [[ "$realpath" = "$linepath" ]] && return 1
300   pre="${pre#*/}"
301   orig="${orig#*/}"
302   donepath=
303   prepaths=( '' )
304 else
305   # If the string does not start with a `~' we don't remove a prefix from the
306   # string.
308   linepath=
309   realpath=
311   if zstyle -s ":completion:${curcontext}:" preserve-prefix tmp1 &&
312      [[ -n "$tmp1" && "$pre" = (#b)(${~tmp1})* ]]; then
314     pre="$pre[${#match[1]}+1,-1]"
315     orig="$orig[${#match[1]}+1,-1]"
316     donepath="$match[1]"
317     prepaths=( '' )
319   elif [[ "$pre[1]" = / ]]; then
320     # If it is a absolute path name, we remove the first slash and put it in
321     # `donepath' meaning that we treat it as the path that was already handled.
322     # Also, we don't use the paths from `-W'.
324     pre="$pre[2,-1]"
325     orig="$orig[2,-1]"
326     donepath='/'
327     prepaths=( '' )
328   else
329     # The common case, we just use the string as it is, unless it begins with
330     # `./' or `../' in which case we don't use the paths from `-W'.
331     
332     [[ "$pre" = (.|..)/* ]] && prepaths=( '' )
333     donepath=
334   fi
337 # Now we generate the matches. First we loop over all prefix paths given
338 # with the `-W' option.
340 for prepath in "$prepaths[@]"; do
342   # Get local copies of the prefix, suffix, and the prefix path to use
343   # in the following loop, which walks through the pathname components
344   # in the string from the line.
346   skipped=
347   cpre=
349   if zstyle -t ":completion:${curcontext}:paths" accept-exact-dirs &&
350     [[ $pre = (#b)(*)/([^/]#) ]]; then
351     # We've been told that we can accept an exact directory
352     # prefix immediately.  Try this with the longest path prefix
353     # first:  this saves stats in the simple case and may get around
354     # automount behaviour if early components don't yet exist.
355     tmp1=$match[1]
356     tpre=$match[2]
357     while true; do
358       if [[ -d $donepath$tmp1 ]]; then
359         donepath=$donepath$tmp1/
360         pre=$tpre
361         break
362       elif [[ $tmp1 = (#b)(*)/([^/]#) ]]; then
363         tmp1=$match[1]
364         tpre=$match[2]/$tpre
365       else
366         break
367       fi
368     done
369   fi
371   tpre="$pre"
372   tsuf="$suf"
373   testpath="$donepath"
375   tmp2="${(M)tpre##${~skips}}"
376   tpre="${tpre#$tmp2}"
378   tmp1=( "$prepath$realpath$donepath$tmp2" )
380   # count of attemps for pws non-canonical hack
381   (( npathcheck = 0 ))
382   while true; do
384     origtmp1=("${tmp1[@]}")
385     # Get the prefix and suffix for matching.
387     if [[ "$tpre" = */* ]]; then
388       PREFIX="${tpre%%/*}"
389       SUFFIX=
390     else
391       PREFIX="${tpre}"
392       SUFFIX="${tsuf%%/*}"
393     fi
395     # Force auto-mounting. There might be a better way...
396     # Commented out in the hope that `pws non-canonical hack'
397     # down below does this for us.  Can be uncommented if it
398     # doesn't.
400     # : ${^tmp1}/${PREFIX}${SUFFIX}/.(/)
402     # Get the matching files by globbing.
404     tmp2=( "$tmp1[@]" )
406     if [[ "$tpre$tsuf" = */* ]]; then
407       compfiles -P$cfopt tmp1 accex "$skipped" "$_matcher $matcher[2]" "$sdirs" fake
408     elif [[ "$sopt" = *[/f]* ]]; then
409       compfiles -p$cfopt tmp1 accex "$skipped" "$_matcher $matcher[2]" "$sdirs" fake "$pats[@]"
410     else
411       compfiles -p$cfopt tmp1 accex "$skipped" "$_matcher $matcher[2]" '' fake "$pats[@]"
412     fi
413     tmp1=( $~tmp1 ) 2> /dev/null
415     if [[ -n "$PREFIX$SUFFIX" ]]; then
416       # See which of them match what's on the line.
418       # pws non-canonical hack which seems to work so far...
419       # if we didn't match by globbing, check that there is
420       # something to match by explicit name.  This is for
421       # `clever' filing systems where names pop into existence
422       # when referenced.
423       #
424       # As suggested by Bart, to make sure the "compfiles" checks
425       # still work we repeat the tests above if we successfully
426       # find something that might need adding, but we make sure
427       # we only do this once for completion of each path segment.
428       if (( ! $#tmp1 && npathcheck == 0 )); then
429         (( npathcheck = 1 ))
430         for tmp3 in "$tmp2[@]"; do
431           if [[ -n $tmp3 && $tmp3 != */ ]]; then
432             tmp3+=/
433           fi
434           if [[ -e "$tmp3${(Q)PREFIX}${(Q)SUFFIX}" ]] then
435             (( npathcheck = 2 ))
436           fi
437         done
438         if (( npathcheck == 2 )); then
439           # repeat loop with same arguments
440           tmp1=("$origtmp1[@]")
441           continue
442         fi
443       fi
445       if (( ! $#tmp1 )); then
446         tmp2=( ${^${tmp2:#/}}/$PREFIX$SUFFIX )
447       elif [[ "$tmp1[1]" = */* ]]; then
448         if [[ -n "$_comp_correct" ]]; then
449           tmp2=( "$tmp1[@]" )
450           builtin compadd -D tmp1 "$matcher[@]" - "${(@)tmp1:t}"
452           if [[ $#tmp1 -eq 0 ]]; then
453             tmp1=( "$tmp2[@]" )
454             compadd -D tmp1 "$matcher[@]" - "${(@)tmp2:t}"
455           fi
456         else
457           tmp2=( "$tmp1[@]" )
458           compadd -D tmp1 "$matcher[@]" - "${(@)tmp1:t}"
459         fi
460       else
461         tmp2=( '' )
462         compadd -D tmp1 "$matcher[@]" -a tmp1
463       fi
465       # If no file matches, save the expanded path and continue with
466       # the outer loop.
468       if (( ! $#tmp1 )); then
469         if [[ "$tmp2[1]" = */* ]]; then
470           tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
471           if [[ "$tmp2[1]" = */* ]]; then
472             tmp2=( "${(@)tmp2:h}" )
473             compquote tmp2
474             if [[ "$tmp2" = */ ]]; then
475               exppaths=( "$exppaths[@]" ${^tmp2}${tpre}${tsuf} )
476             else
477               exppaths=( "$exppaths[@]" ${^tmp2}/${tpre}${tsuf} )
478             fi
479           elif [[ ${tpre}${tsuf} = */* ]]; then
480             exppaths=( "$exppaths[@]" ${tpre}${tsuf} )
482             ### this once was in an `else' (not `elif')
483           fi
484         fi
485         continue 2
486       fi
487     elif (( ! $#tmp1 )); then
488       # A little extra hack: if we were completing `foo/<TAB>' and `foo'
489       # contains no files, this will normally produce no matches and other
490       # completers might think that's it's their time now. But if the next
491       # completer is _correct or something like that, this will result in
492       # an attempt to correct a valid directory name. So we just add the
493       # original string in such a case so that the command line doesn't 
494       # change but other completers still think there are matches.
495       # We do this only if we weren't given a `-g' or `-/' option because
496       # otherwise this would keep `_files' from completing all filenames
497       # if none of the patterns match.
499       if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then
500         pfxsfx=(-S '' "$pfxsfx[@]")
501         ### Don't remember what the break was good for. We explicitly
502         ### execute this only when there are no matches in the directory,
503         ### so why continue?
504         ###
505         ### tmp1=( "$tmp2[@]" )
506         ### break
507       elif [[ -n "$haspats" && -z "$tpre$tsuf$suf" && "$pre" = */ ]]; then
508         PREFIX="${opre}"
509         SUFFIX="${osuf}"
510         compadd -nQS '' - "$linepath$donepath$orig"
511         tmp4=-
512       fi
513       continue 2
514     fi
516     if [[ -n "$ignpar" && -z "$_comp_no_ignore" &&
517           "$tpre$tsuf" != */* && $#tmp1 -ne 0 &&
518           ( "$ignpar" != *dir* || "$pats" = '*(-/)' ) &&
519           ( "$ignpar" != *..* || "$tmp1[1]" = *../* ) ]]; then
521       compfiles -i tmp1 _comp_ignore "$ignpar" "$prepath$realpath$donepath"
523       (( $#_comp_ignore && $mopts[(I)-F] )) ||
524           mopts=( "$mopts[@]" -F _comp_ignore )
525     fi
527     # Step over to the next component, if any.
529     if [[ "$tpre" = */* ]]; then
530       tpre="${tpre#*/}"
531     elif [[ "$tsuf" = */* ]]; then
532       tpre="${tsuf#*/}"
533       tsuf=
534     else
535       break
536     fi
538     # There are more components, so skip over the next components and make a
539     # slash be added.
541     tmp1=( ${tmp1//(#b)([][()|*?^#~<>\\=])/\\${match[1]}} )
542     tmp2="${(M)tpre##((.|..|)/)##}"
543     if [[ -n "$tmp2" ]]; then
544       skipped="/$tmp2"
545       tpre="${tpre#$tmp2}"
546     else
547       skipped=/
548     fi
549     (( npathcheck = 0 ))
550   done
552   # The next loop searches the first ambiguous component.
554   tmp3="$pre$suf"
555   tpre="$pre"
556   tsuf="$suf"
557   [[ -n "${prepath}${realpath}${testpath}" ]] &&
558       tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" )
560   while true; do
562     # First we check if some of the files match the original string
563     # for this component. If there are some we remove all other
564     # names. This avoids having `foo' complete to `foo' and `foobar'.
565     # The return value is non-zero if the component is ambiguous.
567     compfiles -r tmp1 "${(Q)tmp3}"
568     tmp4=$?
570     if [[ "$tpre" = */* ]]; then
571       tmp2="${cpre}${tpre%%/*}"
572       PREFIX="${linepath}${donepath}${tmp2}"
573       SUFFIX="/${tpre#*/}${tsuf#*/}"
574     else
575       tmp2="${cpre}${tpre}"
576       PREFIX="${linepath}${donepath}${tmp2}"
577       SUFFIX="${tsuf}"
578     fi
580     # This once tested `|| [[ -n "$compstate[pattern_match]" &&
581     # "$tmp2" = (|*[^\\])[][*?#~^\|\<\>]* ]]' but it should now be smart
582     # enough to handle multiple components with patterns.
584     if (( tmp4 )); then
585       # It is. For menu completion we now add the possible completions
586       # for this component with the unambiguous prefix we have built
587       # and the rest of the string from the line as the suffix.
588       # For normal completion we add the rests of the filenames
589       # collected as the suffixes to make the completion code expand
590       # it as far as possible.
592       tmp2="$testpath"
593       if [[ -n "$linepath" ]]; then
594         compquote -p tmp2 tmp1
595       elif [[ -n "$tmp2" ]]; then
596         compquote -p tmp1
597         compquote tmp2
598       else
599         compquote tmp1 tmp2
600       fi
602       if [[ -z "$_comp_correct" &&
603             "$compstate[pattern_match]" = \*  && -n "$listsfx" &&
604             "$tmp2" = (|*[^\\])[][*?#~^\|\<\>]* ]]; then
605         PREFIX="$opre"
606         SUFFIX="$osuf"
607       fi
609       # This once tested `-n $menu ||' but our menu-completion expert says
610       # that's not what we want.
612       if [[ -z "$compstate[insert]" ]] ||
613          { ! zstyle -t ":completion:${curcontext}:paths" expand suffix &&
614            [[ -z "$listsfx" &&
615               ( -n "$_comp_correct" ||
616                 -z "$compstate[pattern_match]" || "$SUFFIX" != */* ||
617                 "${SUFFIX#*/}" = (|*[^\\])[][*?#~^\|\<\>]* ) ]] }; then
618         # We have not been told to insert the match, so we are
619         # listing, or something.
620         (( tmp4 )) && zstyle -t ":completion:${curcontext}:paths" ambiguous &&
621             compstate[to_end]=
622         if [[ "$tmp3" = */* ]]; then
623           if [[ -z "$listsfx" || "$tmp3" != */?* ]]; then
624             # I think this means we are expanding some directory
625             # back up the path.
626             tmp1=("${(@)tmp1%%/*}")
627             _list_files tmp1 "$prepath$realpath$testpath"
628             compadd $Uopt -Qf "$mopts[@]" \
629                     -p "${Uopt:+$IPREFIX}$linepath$tmp2" \
630                     -s "/${tmp3#*/}${Uopt:+$ISUFFIX}" \
631                     -W "$prepath$realpath$testpath" \
632                     "$pfxsfx[@]" $Mopts \
633                     $listopts \
634                     -a tmp1
635           else
636             # Same with a non-empty suffix
637             tmp1=("${(@)^tmp1%%/*}/${tmp3#*/}")
638             _list_files tmp1 "$prepath$realpath$testpath"
639             compadd $Uopt -Qf "$mopts[@]" \
640                     -p "${Uopt:+$IPREFIX}$linepath$tmp2" \
641                     -s "${Uopt:+$ISUFFIX}" \
642                     -W "$prepath$realpath$testpath" \
643                     "$pfxsfx[@]" $Mopts \
644                     $listopts \
645                     -a tmp1
646           fi
647         else
648           _list_files tmp1 "$prepath$realpath$testpath"
649           compadd $Uopt -Qf "$mopts[@]" -p "${Uopt:+$IPREFIX}$linepath$tmp2" \
650                   -s "${Uopt:+$ISUFFIX}" \
651                   -W "$prepath$realpath$testpath" \
652                    "$pfxsfx[@]" $Mopts \
653                    $listopts \
654                    -a tmp1
655         fi
656       else
657         # We are inserting the match into the command line.
658         if [[ "$tmp3" = */* ]]; then
659           tmp4=( $Uopt -Qf "$mopts[@]" -p "${Uopt:+$IPREFIX}$linepath$tmp2"
660                  -W "$prepath$realpath$testpath"
661                  "$pfxsfx[@]" $Mopts )
662           if [[ -z "$listsfx" ]]; then
663             for i in "$tmp1[@]"; do
664               tmpdisp=("$i")
665               _list_files tmpdisp "$prepath$realpath$testpath"
666               compadd "$tmp4[@]" -s "${Uopt:+$ISUFFIX}" $listopts - "$tmpdisp"
667             done
668           else
669             [[ -n "$compstate[pattern_match]" ]] && SUFFIX="${SUFFIX:s./.*/}*"
671             for i in "$tmp1[@]"; do
672               _list_files i "$prepath$realpath$testpath"
673               compadd "$tmp4[@]" $listopts - "$i"
674             done
675           fi
676         else
677           _list_files tmp1 "$prepath$realpath$testpath"
678           compadd $Uopt -Qf "$mopts[@]" -p "${Uopt:+$IPREFIX}$linepath$tmp2" \
679                   -s "${Uopt:+$ISUFFIX}" \
680                   -W "$prepath$realpath$testpath" \
681                   "$pfxsfx[@]" $Mopts \
682                   $listopts \
683                   -a tmp1
684         fi
685       fi
686       tmp4=-
687       break
688     fi
690     # If we have checked all components, we stop now and add the 
691     # strings collected after the loop.
693     if [[ "$tmp3" != */* ]]; then
694       tmp4=
695       break
696     fi
698     # Otherwise we add the unambiguous component to `testpath' and
699     # take it from the filenames.
701     testpath="${testpath}${tmp1[1]%%/*}/"
703     tmp3="${tmp3#*/}"
705     if [[ "$tpre" = */* ]]; then
706       if [[ -z "$_comp_correct" && -n "$compstate[pattern_match]" &&
707             "$tmp2" = (|*[^\\])[][*?#~^\|\<\>]* ]]; then
708         cpre="${cpre}${tmp1[1]%%/*}/"
709       else
710         cpre="${cpre}${tpre%%/*}/"
711       fi
712       tpre="${tpre#*/}"
713     elif [[ "$tsuf" = */* ]]; then
714       [[ "$tsuf" != /* ]] && mid="$testpath"
715       if [[ -z "$_comp_correct" && -n "$compstate[pattern_match]" &&
716             "$tmp2" = (|*[^\\])[][*?#~^\|\<\>]* ]]; then
717         cpre="${cpre}${tmp1[1]%%/*}/"
718       else
719         cpre="${cpre}${tpre}/"
720       fi
721       tpre="${tsuf#*/}"
722       tsuf=
723     else
724       tpre=
725       tsuf=
726     fi
728     tmp1=( "${(@)tmp1#*/}" )
729   done
731   if [[ -z "$tmp4" ]]; then
732     if [[ "$mid" = */ ]]; then
733       PREFIX="${opre}"
734       SUFFIX="${osuf}"
736       tmp4="${testpath#${mid}}"
737       tmp3="${mid%/*/}"
738       tmp2="${${mid%/}##*/}"
739       if [[ -n "$linepath" ]]; then
740         compquote -p tmp3
741       else
742         compquote tmp3
743       fi
744       compquote tmp4 tmp2 tmp1
745       for i in "$tmp1[@]"; do
746         _list_files tmp2 "$prepath$realpath${mid%/*/}"
747         compadd $Uopt -Qf "$mopts[@]" -p "${Uopt:+$IPREFIX}$linepath$tmp3/" \
748                 -s "/$tmp4$i${Uopt:+$ISUFFIX}" \
749                 -W "$prepath$realpath${mid%/*/}/" \
750                 "$pfxsfx[@]" $Mopts $listopts - "$tmp2"
751       done
752     else
753       if [[ "$osuf" = */* ]]; then
754         PREFIX="${opre}${osuf}"
755         SUFFIX=
756       else
757         PREFIX="${opre}"
758         SUFFIX="${osuf}"
759       fi
760       tmp4="$testpath"
761       if [[ -n "$linepath" ]]; then
762         compquote -p tmp4 tmp1
763       elif [[ -n "$tmp4" ]]; then
764         compquote -p tmp1
765         compquote tmp4
766       else
767         compquote tmp4 tmp1
768       fi
769       if [[ -z "$_comp_correct" && -n "$compstate[pattern_match]" &&
770             "${PREFIX#\~}$SUFFIX" = (|*[^\\])[][*?#~^\|\<\>]* ]]; then
771         tmp1=("$linepath$tmp4${(@)^tmp1}")
772         _list_files tmp1 "$prepath$realpath"
773         compadd -Qf -W "$prepath$realpath" "$pfxsfx[@]" "$mopts[@]" \
774                 -M "r:|/=* r:|=*" $listopts -a tmp1
775       else
776         # Not a pattern match
777         _list_files tmp1 "$prepath$realpath$testpath"
778         compadd $Uopt -Qf -p "${Uopt:+$IPREFIX}$linepath$tmp4" \
779                 -s "${Uopt:+$ISUFFIX}" \
780                 -W "$prepath$realpath$testpath" \
781                 "$pfxsfx[@]" "$mopts[@]" $Mopts $listopts -a tmp1
782       fi
783     fi
784   fi
785 done
787 # If we are configured to expand paths as far as possible and we collected
788 # expanded paths that are different from the string on the line, we add
789 # them as possible matches. Do that only if we are currently trying the
790 # last entry in the matcher-list style, otherwise other match specs might
791 # make the suffix that didn't match this time match in one of the following
792 # attempts.
794 if [[ _matcher_num -eq ${#_matchers} ]] &&
795    zstyle -t ":completion:${curcontext}:paths" expand prefix &&
796    [[ nm -eq compstate[nmatches] && $#exppaths -ne 0 &&
797       "$linepath$exppaths" != "$eorig" ]]; then
798   PREFIX="${opre}"
799   SUFFIX="${osuf}"
800   compadd -Q "$mopts[@]" -S '' -M "r:|/=* r:|=*" -p "$linepath" -a exppaths
803 [[ nm -ne compstate[nmatches] ]]