1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-12-06 17:51:18 +01:00

zsh-workers/9635

This commit is contained in:
Tanaka Akira 2000-02-09 16:29:22 +00:00
parent 06cd60e1cf
commit 74ccd8d5a3
8 changed files with 378 additions and 242 deletions

View file

@ -1,14 +1,11 @@
#autoload #autoload
local name gropt format gname hidden hide match ign local name gropt=-J format gname hidden hide match opts
gropt=(-J) opts=()
hide=()
match=()
ign=()
if [[ "$1" = -([12]|)[VJ] ]]; then if [[ "$1" = -([12]|)[VJ] ]]; then
gropt=("$1") gropt="$1"
shift shift
fi fi
@ -24,14 +21,14 @@ zstyle -s ":completion:${curcontext}:$1" format format ||
zstyle -s ":completion:${curcontext}:$1" hidden hidden zstyle -s ":completion:${curcontext}:$1" hidden hidden
if [[ "$hidden" = (all|yes|true|1|on) ]]; then if [[ "$hidden" = (all|yes|true|1|on) ]]; then
[[ "$hidden" = all ]] && format='' [[ "$hidden" = all ]] && format=''
hide=(-n) opts=(-n)
fi fi
zstyle -s ":completion:${curcontext}:$1" group-name gname && zstyle -s ":completion:${curcontext}:$1" group-name gname &&
[[ -z "$gname" ]] && gname="$1" [[ -z "$gname" ]] && gname="$1"
zstyle -s ":completion:${curcontext}:$1" matcher match && zstyle -s ":completion:${curcontext}:$1" matcher match &&
match=(-M "${(q)match}") opts=($opts -M "${(q)match}")
if zstyle -a ":completion:${curcontext}:$1" ignored-patterns _comp_ignore; then if zstyle -a ":completion:${curcontext}:$1" ignored-patterns _comp_ignore; then
ign=(-F _comp_ignore) opts=( $opts -F _comp_ignore)
else else
_comp_ignore=() _comp_ignore=()
fi fi
@ -41,15 +38,15 @@ shift 2
if [[ -n "$gname" ]]; then if [[ -n "$gname" ]]; then
if [[ -n "$format" ]]; then if [[ -n "$format" ]]; then
eval "${name}=($hide $match $ign $gropt ${(q)gname} -X \"${format}\")" eval "${name}=($opts $gropt ${(q)gname} -X \"${format}\")"
else else
eval "${name}=($hide $match $ign $gropt ${(q)gname})" eval "${name}=($opts $gropt ${(q)gname})"
fi fi
else else
if [[ -n "$format" ]]; then if [[ -n "$format" ]]; then
eval "${name}=($hide $match $ign $gropt -default- -X \"${format}\")" eval "${name}=($opts $gropt -default- -X \"${format}\")"
else else
eval "${name}=($hide $match $ign $gropt -default-)" eval "${name}=($opts $gropt -default-)"
fi fi
fi fi

View file

@ -3,24 +3,21 @@
local opts opt type=file glob group gopts dopts aopts tmp _file_pat_checked=yes local opts opt type=file glob group gopts dopts aopts tmp _file_pat_checked=yes
local hasign ign local hasign ign
opts=() zparseopts \
group=() /tmp ftmp g+tmp \
gopts=() qopts nopts 1opts 2opts P:opts S:opts r:opts R:opts W:opts X:opts M:opts \
dopts=(-/) F:opts J:group V:group
aopts=(-f)
ign=()
while getopts "P:S:qr:R:W:F:J:V:X:f/g:M:12n" opt; do
case "$opt" in
/) type="${type}dir" ;;
g) type="${type}glob"; gopts=(-g "$OPTARG") ;;
[qn12]) opts=("$opts[@]" "-$opt" ) ;;
[JV]) group=( "-$opt" "$OPTARG") ;;
F) opts=("$opts[@]" "-$opt" "$OPTARG"); hasign=yes ;;
[^f]) opts=("$opts[@]" "-$opt" "$OPTARG") ;;
esac
done
if [[ "$group[2]" = files ]]; then type="${(@j::M)${(@)tmp#-}#?}"
[[ -n "$type" ]] || type=f
if (( $tmp[(I)-g*] )); then
gopts=( -g ${(j: :)${(M)tmp:#-g*}#-g} )
else
gopts=()
fi
(( $opts[(I)-F*] )) && hasign=yes
if [[ "$group[1]" = -?files ]]; then
opts=("$opts[@]" "$group[@]") opts=("$opts[@]" "$group[@]")
group=() group=()
fi fi
@ -32,36 +29,36 @@ fi
if zstyle -s ":completion:${curcontext}:directories" file-patterns tmp && if zstyle -s ":completion:${curcontext}:directories" file-patterns tmp &&
[[ -n "$tmp" ]]; then [[ -n "$tmp" ]]; then
dopts=(-g "$tmp") dopts=(-g "$tmp")
if [[ "$type" = (*dir*glob*|*glob*dir*) ]]; then if [[ "$type" = (*/*g*|*g*/*) ]]; then
type=glob type=g
elif [[ "$type" != *(dir|glob)* ]]; then elif [[ "$type" != *[/g]* ]]; then
type="${type}dir" type="${type}/"
fi fi
fi fi
if zstyle -s ":completion:${curcontext}:globbed-files" file-patterns tmp && if zstyle -s ":completion:${curcontext}:globbed-files" file-patterns tmp &&
[[ -n "$tmp" ]]; then [[ -n "$tmp" ]]; then
gopts=(-g "$tmp") gopts=(-g "$tmp")
if [[ "$type" != (*dir*glob*|*glob*dir*) ]]; then if [[ "$type" != (*/*g*|*g*/*) ]]; then
if [[ "$type" = *(dir|glob)* ]]; then if [[ "$type" = *[g/]* ]]; then
type=glob type=g
else else
type=globall type=ga
fi fi
fi fi
fi fi
case "$type" in case "$type" in
*dir*glob*|*glob*dir*) _tags globbed-files all-files ;; */*g*|*g*/*) _tags globbed-files all-files ;;
*all*glob*|*glob*all*) _tags globbed-files all-files ;; *a*g*|*g*a*) _tags globbed-files all-files ;;
*glob*) _tags globbed-files directories all-files ;; *g*) _tags globbed-files directories all-files ;;
*dir*) _tags directories all-files ;; */*) _tags directories all-files ;;
*) _tags all-files ;; *) _tags all-files ;;
esac esac
while _tags; do while _tags; do
if _requested all-files; then if _requested all-files; then
if (( $#group )); then if (( $#group )); then
group[2]=all-files group[1]="${group[1][1,2]}all-files"
_setup all-files _setup all-files
[[ -z "$hasign" ]] && [[ -z "$hasign" ]] &&
zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore && zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@ -72,7 +69,7 @@ while _tags; do
elif _requested directories; then elif _requested directories; then
if _requested globbed-files; then if _requested globbed-files; then
if (( $#group )); then if (( $#group )); then
group[2]=globbed-files group[1]="${group[1][1,2]}globbed-files"
_setup globbed-files _setup globbed-files
[[ -z "$hasign" ]] && [[ -z "$hasign" ]] &&
zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore && zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@ -81,7 +78,7 @@ while _tags; do
_path_files "$opts[@]" "$ign[@]" "$dopts[@]" "$gopts[@]" && return 0 _path_files "$opts[@]" "$ign[@]" "$dopts[@]" "$gopts[@]" && return 0
else else
if (( $#group )); then if (( $#group )); then
group[2]=directories group[1]="${group[1][1,2]}directories"
_setup directories _setup directories
[[ -z "$hasign" ]] && [[ -z "$hasign" ]] &&
zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore && zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@ -91,13 +88,13 @@ while _tags; do
fi fi
elif _requested globbed-files; then elif _requested globbed-files; then
if (( $#group )); then if (( $#group )); then
group[2]=globbed-files group[1]="${group[1][1,2]}globbed-files"
_setup globbed-files _setup globbed-files
[[ -z "$hasign" ]] && [[ -z "$hasign" ]] &&
zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore && zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
ign=(-F _comp_ignore) ign=(-F _comp_ignore)
fi fi
if [[ "$type" = (*dir*glob*|*glob*dir*) ]]; then if [[ "$type" = (*/*g*|*g*/*) ]]; then
_path_files "$opts[@]" "$ign[@]" "$dopts[@]" "$gopts[@]" && return 0 _path_files "$opts[@]" "$ign[@]" "$dopts[@]" "$gopts[@]" && return 0
else else
_path_files "$opts[@]" "$ign[@]" "$gopts[@]" && return 0 _path_files "$opts[@]" "$ign[@]" "$gopts[@]" && return 0

View file

@ -13,22 +13,18 @@ typeset -U tmp2
# Get the options. # Get the options.
group=() zparseopts -D \
expl=() J:group V:group X:expl \
opts=() P:opts F:opts \
sopts=() S:sopts r:sopts R:sopts qsopts 1sopts 2sopts nsopts \
while getopts "J:V:X:P:F:S:r:R:qM:12n" opt; do M:match
case "$opt" in
[JV]) group=("-$opt" "$OPTARG");; sopts=( "$sopts[@]" "$opts[@]" )
X) expl=(-X "$OPTARG");; if (( $#match )); then
[PF]) opts=( "$opts[@]" "-$opt" "$OPTARG") match="${match[1][3,-1]}"
sopts=( "$sopts[@]" "-$opt" "$OPTARG");; else
[SrR]) sopts=( "$sopts[@]" -P "$OPTARG");; match=''
[q12n]) sopts=( "$sopts[@]" "-$opt");; fi
M) match="$OPTARG";;
esac
done
shift OPTIND-1
# Get the arguments, first the separator, then the array. The array is # Get the arguments, first the separator, then the array. The array is
# stored in `matches'. Further on this array will always contain those # stored in `matches'. Further on this array will always contain those

View file

@ -3,9 +3,9 @@
# Utility function for in-path completion. This allows `/u/l/b<TAB>' # Utility function for in-path completion. This allows `/u/l/b<TAB>'
# to complete to `/usr/local/bin'. # to complete to `/usr/local/bin'.
local linepath realpath donepath prepath testpath exppath skips local linepath realpath donepath prepath testpath exppath skips skipped
local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre
local pats haspats=no ignore group expl addpfx addsfx remsfx rem remt local pats haspats=no ignore pfxsfx rem remt sopt gopt opt
local nm=$compstate[nmatches] menu mspec matcher mopts atmp sort match local nm=$compstate[nmatches] menu mspec matcher mopts atmp sort match
typeset -U prepaths exppaths typeset -U prepaths exppaths
@ -13,73 +13,50 @@ typeset -U prepaths exppaths
setopt localoptions nullglob rcexpandparam setopt localoptions nullglob rcexpandparam
unsetopt markdirs globsubst shwordsplit nounset unsetopt markdirs globsubst shwordsplit nounset
local sopt='-' gopt='' opt
exppaths=() exppaths=()
prepaths=('')
ignore=()
group=()
pats=()
addpfx=()
addsfx=()
remsfx=()
expl=()
matcher=()
mopts=()
# Get the options. # Get the options.
while getopts "P:S:qr:R:W:F:J:V:X:f/g:M:12n" opt; do zparseopts \
case "$opt" in P:pfxsfx S:pfxsfx qpfxsfx r:pfxsfx R:pfxsfx \
[12n]) mopts=( "$mopts[@]" "-$opt" ) W:prepaths F:ignore M+matcher \
;; J:mopts V:mopts X:mopts 1:mopts 2:mopts n:mopts \
P) addpfx=(-P "$OPTARG") ftmp1 /tmp1 g+tmp1
;;
S) addsfx=(-S "$OPTARG") sopt="-${(@j::M)${(@)tmp1#-}#?}"
;; (( $tmp1[(I)-[/g]*] )) && haspats=yes
q) tmp1=yes (( $tmp1[(I)-g*] )) && gopt=yes
;; if (( $tmp1[(I)-/] )); then
[rR]) remsfx=("-$opt" "$OPTARG") pats=( '*(-/)' ${=${(M)tmp1:#-g*}#-g} )
;; else
W) tmp1="$OPTARG" pats=( "${(@)=${(@M)tmp1:#-g*}#-g}" )
if [[ "$tmp1[1]" = '(' ]]; then fi
prepaths=( ${^=tmp1[2,-2]%/}/ )
elif [[ "$tmp1[1]" = '/' ]]; then if (( $#prepaths )); then
prepaths=( "$tmp1/" ) tmp1="${prepaths[1][3,-1]}"
else if [[ "$tmp1[1]" = '(' ]]; then
# In this case the variable should be an array, so prepaths=( ${^=tmp1[2,-2]%/}/ )
# don't use an extra ${=...}. elif [[ "$tmp1[1]" = '/' ]]; then
prepaths=( ${(P)^tmp1%/}/ ) prepaths=( "$tmp1/" )
(( ! $#prepaths )) && prepaths=( ${tmp1%/}/ ) else
fi prepaths=( ${(P)^tmp1%/}/ )
(( ! $#prepaths )) && prepaths=( '' ) (( ! $#prepaths )) && prepaths=( ${tmp1%/}/ )
;; fi
F) tmp1="$OPTARG" (( ! $#prepaths )) && prepaths=( '' )
if [[ "$tmp1[1]" = '(' ]]; then else
ignore=( ${=tmp1[2,-2]} ) prepaths=( '' )
else fi
ignore=( ${(P)tmp1} )
fi if (( $#ignore )); then
;; tmp1="${ignore[1][3,-1]}"
[JV]) group=("-$opt" "$OPTARG") if [[ "$tmp1[1]" = '(' ]]; then
;; ignore=( ${=tmp1[2,-2]} )
X) expl=(-X "$OPTARG") else
;; ignore=( ${(P)tmp1} )
f) sopt="${sopt}f" fi
pats=("$pats[@]" '*') fi
;;
/) sopt="${sopt}/" (( $#matcher )) && mspec="${matcher[1][3,-1]}"
pats=("$pats[@]" '*(-/)')
haspats=yes
;;
g) gopt='-g'
pats=("$pats[@]" ${=OPTARG})
haspats=yes
;;
M) mspec="$OPTARG"
matcher=(-M "$OPTARG")
;;
esac
done
if [[ -z "$_file_pat_checked" ]] && if [[ -z "$_file_pat_checked" ]] &&
zstyle -s ":completion:${curcontext}:files" file-patterns tmp1 && zstyle -s ":completion:${curcontext}:files" file-patterns tmp1 &&
@ -88,20 +65,34 @@ if [[ -z "$_file_pat_checked" ]] &&
gopt='' gopt=''
sopt=-/ sopt=-/
else else
gopt='-g' gopt=yes
sopt=- sopt=-
fi fi
pats=( $=tmp1 ) pats=( $=tmp1 )
haspats=yes haspats=yes
fi fi
if (( ! ( $#group + $#expl ) )); then # If we were given no file selection option, we behave as if we were given
# a `-f'.
if [[ "$sopt" = -(f|) ]]; then
if [[ -z "$gopt" ]]; then
sopt='-f'
pats=('*')
else
unset sopt
fi
fi
if (( ! $mopts[(I)-[JVX]*] )); then
local expl
if [[ -z "$gopt" && "$sopt" = -/ ]]; then if [[ -z "$gopt" && "$sopt" = -/ ]]; then
_description directories expl directory _description directories expl directory
else else
_description files expl file _description files expl file
fi fi
tmp1=$expl[(I)-M] tmp1=$expl[(I)-M*]
if (( tmp1 )); then if (( tmp1 )); then
mspec="$mspec $expl[1+tmp1]" mspec="$mspec $expl[1+tmp1]"
if (( $#matcher )); then if (( $#matcher )); then
@ -110,20 +101,7 @@ if (( ! ( $#group + $#expl ) )); then
matcher=(-M "$expl[1+tmp1]") matcher=(-M "$expl[1+tmp1]")
fi fi
fi fi
fi mopts=( "$mopts[@]" "$expl[@]" )
[[ -n "$tmp1" && $#addsfx -ne 0 ]] && addsfx[1]=-qS
# If we were given no file selection option, we behave as if we were given
# a `-f'.
if [[ "$sopt" = - ]]; then
if [[ -z "$gopt" ]]; then
sopt='-f'
pats=('*')
else
unset sopt
fi
fi fi
if zstyle -s ":completion:${curcontext}:files" sort tmp1; then if zstyle -s ":completion:${curcontext}:files" sort tmp1; then
@ -140,8 +118,7 @@ if zstyle -s ":completion:${curcontext}:files" sort tmp1; then
if [[ "$sort" = on ]]; then if [[ "$sort" = on ]]; then
sort='' sort=''
else else
group=( "${(@)group/#-J/-V}" ) mopts=( "${(@)mopts/#-J/-V}" )
expl=( "${(@)expl/#-J/-V}" )
tmp2=() tmp2=()
for tmp1 in "$pats[@]"; do for tmp1 in "$pats[@]"; do
@ -157,9 +134,15 @@ if zstyle -s ":completion:${curcontext}:files" sort tmp1; then
fi fi
fi fi
# Skip over sequences of slashes. # Check if we have to skip over sequences of slashes. The value of $skips
# is used below to match the pathname components we always have to accept
# immediatly.
zstyle -t ":completion:${curcontext}:paths" squeeze-slashes && skips=yes if zstyle -t ":completion:${curcontext}:paths" squeeze-slashes; then
skips='((.|..|)/)##'
else
skips='((.|..)/)##'
fi
# We get the prefix and the suffix from the line and save the whole # We get the prefix and the suffix from the line and save the whole
# original string. Then we see if we will do menucompletion. # original string. Then we see if we will do menucompletion.
@ -182,7 +165,7 @@ eorig="$orig"
if (( $#ignore )); then if (( $#ignore )); then
_comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" ) _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" )
(( $expl[(I)-F] )) || expl=( "$expl[@]" -F _comp_ignore ) (( $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore )
fi fi
# Now let's have a closer look at the string to complete. # Now let's have a closer look at the string to complete.
@ -256,26 +239,13 @@ for prepath in "$prepaths[@]"; do
tsuf="$suf" tsuf="$suf"
testpath="$donepath" testpath="$donepath"
tmp1=( "$prepath$realpath$donepath" ) tmp2="${(M)tpre##${~skips}}"
tpre="${tpre#$tmp2}"
tmp1=( "$prepath$realpath$donepath$tmp2" )
while true; do while true; do
# Skip over `./' and `../'.
if [[ "$tpre" = (.|..)/* ]]; then
tmp1=( ${^tmp1}${tpre%%/*}/ )
tpre="${tpre#*/}"
continue
fi
# Skip over multiple slashes?
if [[ -n "$skips" && "$tpre" = /* ]]; then
tmp1=( ${^tmp1}/ )
tpre="${tpre#/}"
continue
fi
# Get the prefix and suffix for matching. # Get the prefix and suffix for matching.
if [[ "$tpre" = */* ]]; then if [[ "$tpre" = */* ]]; then
@ -289,45 +259,24 @@ for prepath in "$prepaths[@]"; do
# Get the matching files by globbing. # Get the matching files by globbing.
if [[ "$tpre$tsuf" = */* ]]; then if [[ "$tpre$tsuf" = */* ]]; then
tmp2=( ${^tmp1}*(-/) ) if [[ ! -o globdots && "$PREFIX" = .* ]]; then
[[ ! -o globdots && "$PREFIX" = .* ]] && tmp1=( ${^tmp1}${skipped}*(-/) ${^tmp1}${slash}.*(-/) )
tmp2=( "$tmp2[@]" ${^tmp1}.*(-/) ) else
tmp1=( ${^tmp1}${skipped}*(-/) )
fi
if [[ -o globdots || "$PREFIX" = .* ]] && if [[ -o globdots || "$PREFIX" = .* ]] &&
zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
if [[ "$atmp" = (yes|true|1|on) ]]; then if [[ "$atmp" = (yes|true|1|on) ]]; then
tmp2=( "$tmp2[@]" . .. ) tmp1=( "$tmp1[@]" . .. )
elif [[ "$atmp" = .. ]]; then elif [[ "$atmp" = .. ]]; then
tmp2=( "$tmp2[@]" .. ) tmp1=( "$tmp1[@]" .. )
fi fi
fi fi
else else
tmp2=( ${^tmp1}${^~pats} ) if [[ ! -o globdots && "$PREFIX" = .* ]]; then
[[ ! -o globdots && "$PREFIX" = .* ]] && tmp1=( ${^tmp1}${skipped}${^~pats} ${^tmp1}${slash}.${^~pats} )
tmp2=( "$tmp2[@]" ${^tmp1}.${^~pats} ) else
if (( $#tmp2 )) && tmp1=( ${^tmp1}${skipped}${^~pats} )
zstyle -s ":completion:${curcontext}:files" ignore-parents rem &&
[[ ( "$rem" != *dir* || "$pats" = '*(-/)' ) &&
( "$rem" != *..* || "$tmp1" = *../* ) ]]; then
if [[ "$rem" = *parent* ]]; then
for i in "$tmp2[@]"; do
if [[ -d "$i" && "$i" = */* ]]; then
remt="${i%/*}"
while [[ "$remt" = */* ]]; do
[[ "$remt" -ef "$i" ]] && break
remt="${remt%/*}"
done
[[ "$remt" = */* || "$remt" -ef "$i" ]] &&
_comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
fi
done
fi
if [[ "$rem" = *pwd* ]]; then
for i in "$tmp2[@]"; do
[[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
done
fi
(( $#_comp_ignore )) && (( $expl[(I)-F] )) ||
expl=( "$expl[@]" -F _comp_ignore )
fi fi
if [[ "$sopt" = *[/f]* && ( -o globdots || "$PREFIX" = .* ) ]] && if [[ "$sopt" = *[/f]* && ( -o globdots || "$PREFIX" = .* ) ]] &&
zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
@ -338,22 +287,28 @@ for prepath in "$prepaths[@]"; do
fi fi
fi fi
fi fi
tmp1=( "$tmp2[@]" )
if [[ -n "$PREFIX$SUFFIX" ]]; then if [[ -n "$PREFIX$SUFFIX" ]]; then
# See which of them match what's on the line. # See which of them match what's on the line.
builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}" if [[ -n "$_comp_correct" ]]; then
tmp2=( "$tmp1[@]" )
builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
if [[ $#tmp1 -eq 0 && -n "$_comp_correct" ]]; then if [[ $#tmp1 -eq 0 && -n "$_comp_correct" ]]; then
tmp1=( "$tmp2[@]" ) tmp1=( "$tmp2[@]" )
compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}" compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
fi
else
[[ "$tmp1[1]" = */* ]] && tmp2=( "$tmp1[@]" )
builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
fi fi
# If no file matches, save the expanded path and continue with # If no file matches, save the expanded path and continue with
# the outer loop. # the outer loop.
if [[ $#tmp1 -eq 0 ]]; then if (( ! $#tmp1 )); then
if [[ "$tmp2[1]" = */* ]]; then if [[ "$tmp2[1]" = */* ]]; then
tmp2=( "${(@)tmp2#${prepath}${realpath}}" ) tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
if [[ "$tmp2[1]" = */* ]]; then if [[ "$tmp2[1]" = */* ]]; then
@ -384,8 +339,7 @@ for prepath in "$prepaths[@]"; do
if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then
tmp1=( "$tmp2[@]" ) tmp1=( "$tmp2[@]" )
addsfx=(-S '') pfxsfx=(-S '' "$pfxsfx[@]")
remsfx=()
break; break;
elif [[ "$haspats" = no && -z "$tpre$tsuf" && elif [[ "$haspats" = no && -z "$tpre$tsuf" &&
"$pre" = */ && -z "$suf" ]]; then "$pre" = */ && -z "$suf" ]]; then
@ -397,6 +351,29 @@ for prepath in "$prepaths[@]"; do
continue 2 continue 2
fi fi
if [[ "$tpre$tsuf" != */* && $#tmp1 -ne 0 ]] &&
zstyle -s ":completion:${curcontext}:files" ignore-parents rem &&
[[ ( "$rem" != *dir* || "$pats" = '*(-/)' ) &&
( "$rem" != *..* || "$tmp1" = *../* ) ]]; then
if [[ "$rem" = *parent* ]]; then
for i in ${(M)^tmp1:#*/*}(-/); do
remt="${${i#$prepath$realpath$donepath}%/*}"
while [[ "$remt" = */* ]]; do
[[ "$prepath$realpath$donepath$remt" -ef "$i" ]] && break
remt="${remt%/*}"
done
[[ "$remt" = */* || "$remt" -ef "$i" ]] &&
_comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
done
fi
if [[ "$rem" = *pwd* ]]; then
for i in ${^tmp1}(-/); do
[[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
done
fi
(( $#_comp_ignore && $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore )
fi
# Step over to the next component, if any. # Step over to the next component, if any.
if [[ "$tpre" = */* ]]; then if [[ "$tpre" = */* ]]; then
@ -408,10 +385,16 @@ for prepath in "$prepaths[@]"; do
break break
fi fi
# There are more components, so add a slash to the files we are # There are more components, so skip over the next components and make a
# collecting. # slash be added.
tmp1=( ${^tmp1}/ ) tmp2="${(M)tpre##((.|..|)/)##}" ###
if [[ -n "$tmp2" ]]; then
skipped="/$tmp2"
tpre="${tpre#$tmp2}"
else
skipped=/
fi
done done
# The next loop searches the first ambiguous component. # The next loop searches the first ambiguous component.
@ -471,30 +454,30 @@ for prepath in "$prepaths[@]"; do
if [[ "$tmp3" = */* ]]; then if [[ "$tmp3" = */* ]]; then
compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \ compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \
-W "$prepath$realpath$testpath" \ -W "$prepath$realpath$testpath" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ "$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \ -M "r:|/=* r:|=* $mspec" \
- "${(@)tmp1%%/*}" - "${(@)tmp1%%/*}"
else else
compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
-W "$prepath$realpath$testpath" \ -W "$prepath$realpath$testpath" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ "$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \ -M "r:|/=* r:|=* $mspec" \
- "$tmp1[@]" - "$tmp1[@]"
fi fi
else else
if [[ "$tmp3" = */* ]]; then if [[ "$tmp3" = */* ]]; then
atmp=( -Qf "$mopts[@]" -p "$linepath$tmp2" atmp=( -Qf "$mopts[@]" -p "$linepath$tmp2"
-W "$prepath$realpath$testpath" -W "$prepath$realpath$testpath"
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" "$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" ) -M "r:|/=* r:|=* $mspec" )
for i in "$tmp1[@]"; do for i in "$tmp1[@]"; do
compadd "$atmp[@]" -s "/${i#*/}" - "${i%%/*}" compadd "$atmp[@]" -s "/${i#*/}" - "${i%%/*}"
done done
else else
compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
-W "$prepath$realpath$testpath" \ -W "$prepath$realpath$testpath" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ "$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \ -M "r:|/=* r:|=* $mspec" \
- "$tmp1[@]" - "$tmp1[@]"
fi fi
fi fi
@ -543,8 +526,8 @@ for prepath in "$prepaths[@]"; do
compquote tmp4 tmp1 compquote tmp4 tmp1
compadd -Qf "$mopts[@]" -p "$linepath$tmp4" \ compadd -Qf "$mopts[@]" -p "$linepath$tmp4" \
-W "$prepath$realpath$testpath" \ -W "$prepath$realpath$testpath" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ "$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \ -M "r:|/=* r:|=* $mspec" \
- "$tmp1[@]" - "$tmp1[@]"
fi fi
done done
@ -553,14 +536,17 @@ done
# expanded paths that are different from the string on the line, we add # expanded paths that are different from the string on the line, we add
# them as possible matches. # them as possible matches.
exppaths=( "${(@)exppaths:#$eorig}" )
if zstyle -t ":completion:${curcontext}:paths" expand prefix && if zstyle -t ":completion:${curcontext}:paths" expand prefix &&
[[ $#exppaths -gt 0 && nm -eq compstate[nmatches] ]]; then [[ nm -eq compstate[nmatches] ]]; then
PREFIX="${opre}"
SUFFIX="${osuf}" exppaths=( "${(@)exppaths:#$eorig}" )
compadd -Q "$mopts[@]" -S '' "$group[@]" "$expl[@]" \
-M "r:|/=* r:|=* $mspec" -p "$linepath" - "$exppaths[@]" if (( $#exppaths )); then
PREFIX="${opre}"
SUFFIX="${osuf}"
compadd -Q "$mopts[@]" -S '' \
-M "r:|/=* r:|=* $mspec" -p "$linepath" - "$exppaths[@]"
fi
fi fi
[[ nm -ne compstate[nmatches] ]] [[ nm -ne compstate[nmatches] ]]

View file

@ -22,19 +22,16 @@ local matchflags opt group expl nm=$compstate[nmatches] opre osuf opts match
# Get the options. # Get the options.
group=() zparseopts -D \
expl=() J:group V:group \
opts=() P:opts F:opts S:opts r:opts R:opts qopts 1opts 2opts nopts \
while getopts "J:V:X:P:F:S:r:R:qM:12n" opt; do X:expl M:match
case "$opt" in
[JV]) group=("-$opt" "$OPTARG");; if (( $#match )); then
X) expl=(-X "$OPTARG");; match="${match[1][3,-1]}"
[q12n]) opts=( "$opts[@]" "-$opt" );; else
M) match="$OPTARG";; match=''
*) opts=( "$opts[@]" "-$opt" "$OPTARG" );; fi
esac
done
shift OPTIND-1
# Get the string from the line. # Get the string from the line.

View file

@ -111,4 +111,28 @@ The resulting strings are stored in the var(array).
item(tt(zregexparse))( item(tt(zregexparse))(
This implements the internals of the `tt(_regex_arguments)'. This implements the internals of the `tt(_regex_arguments)'.
) )
item(tt(zparseopts) [ tt(-D) ] var(specs))(
This builtin can be used to parse the positional arguments and put
options found in them into separate arrays. Each var(spec) describes
one option which is given as its first character. If the second
character is either `tt(:)' or `tt(+)', the option takes an argument
(either directly following the option in the same word or in the next
word). After the option character or the `tt(:)' or `tt(+)' follows
the name of the array in which the option should be stored. The only
difference between the form with a `t(:)' and the one with a `tt(+)'
is that in the first case the option and its argument will be put in
the array only once (later occurrences overwriting earlier ones),
whereas with `tt(+)' all occurrences are moved to the array.
If the tt(-D) option is given, all options found are removed from the
positional parameters leaving only those strings that did not match
any of the var(specs).
For example, calling `tt(zparseopts afoo b:bar c+bar)' with the
strings `tt(-a)', `tt(-bx)', `tt(-c)', `tt(y)', `tt(-cz)', `tt(baz)'
and `tt(-cend)' as positional arguments will set the array tt(foo) to
contain the element `tt(-a)' and the array tt(bar) to the strings
`tt(-bx)', `tt(-cy)' and `tt(-cz)'. The `tt(baz)' and any strings
after it will not be used.
)
enditem() enditem()

View file

@ -1155,10 +1155,149 @@ bin_zregexparse(char *nam, char **args, char *ops, int func)
return ret; return ret;
} }
typedef struct zoptdesc *Zoptdesc;
typedef struct zoptarr *Zoptarr;
typedef struct zoptval *Zoptval;
struct zoptdesc {
int arg;
Zoptarr arr;
};
struct zoptarr {
char *name;
Zoptval vals, last;
Zoptarr next;
int num;
};
#define ZOF_ARG 1
#define ZOF_ADD 2
struct zoptval {
char *str;
Zoptval next;
};
static Zoptarr opt_arrs;
static Zoptarr
get_opt_arr(char *name)
{
Zoptarr p;
for (p = opt_arrs; p; p = p->next)
if (!strcmp(name, p->name))
return p;
return NULL;
}
static int
bin_zparseopts(char *nam, char **args, char *ops, int func)
{
char *o, *n, **pp, *str, **aval;
Zoptdesc opts[256], d;
Zoptarr a;
Zoptval v;
memset(opts, 0, 256 * sizeof(Zoptdesc));
opt_arrs = NULL;
while ((o = *args++)) {
if (opts[STOUC(*o)]) {
zerrnam(nam, "option described more than once: %s", o, 0);
return 1;
}
d = (Zoptdesc) zhalloc(sizeof(*d));
d->arg = (o[1] == ':' ? ZOF_ARG : (o[1] == '+' ? ZOF_ADD : 0));
if (!(a = get_opt_arr((n = o + (d->arg ? 2 : 1))))) {
a = (Zoptarr) zhalloc(sizeof(*a));
a->name = n;
a->num = 0;
a->vals = a->last = NULL;
a->next = opt_arrs;
opt_arrs = a;
}
d->arr = a;
opts[STOUC(*o)] = d;
}
for (pp = pparams; (o = *pp); pp++) {
if (*o != '-')
break;
while (*++o) {
if (!(d = opts[STOUC(*o)]))
break;
if (d->arg) {
if (o[1]) {
str = (char *) zhalloc(strlen(o) + 2);
str[0] = '-';
strcpy(str + 1, o);
} else if (!pp[1]) {
zerrnam(nam, "missing argument for option: -%c", NULL, *o);
return 1;
} else {
str = (char *) zhalloc(strlen(pp[1]) + 3);
str[0] = '-';
str[1] = *o;
strcpy(str + 2, pp[1]);
pp++;
}
o = "" - 1;
} else {
str = (char *) zhalloc(3);
str[0] = '-';
str[1] = *o;
str[2] = '\0';
}
if (d->arg != ZOF_ADD) {
for (v = d->arr->vals; v; v = v->next) {
if (str[1] == v->str[1]) {
v->str = str;
str = NULL;
break;
}
}
}
if (str) {
v = (Zoptval) zhalloc(sizeof(*v));
v->str = str;
v->next = NULL;
if (d->arr->last)
d->arr->last->next = v;
else
d->arr->vals = v;
d->arr->last = v;
d->arr->num++;
}
}
if (*o)
break;
}
if (ops['D']) {
PERMALLOC {
pp = arrdup(pp);
} LASTALLOC;
freearray(pparams);
pparams = pp;
}
for (a = opt_arrs; a; a = a->next) {
aval = (char **) zalloc((a->num + 1) * sizeof(char *));
for (pp = aval, v = a->vals; v; pp++, v = v->next)
*pp = ztrdup(v->str);
*pp = NULL;
setaparam(a->name, aval);
}
return 0;
}
static struct builtin bintab[] = { static struct builtin bintab[] = {
BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL), BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL),
BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL), BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL),
BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL), BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL),
BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, "D", NULL),
}; };

View file

@ -4,4 +4,4 @@ moddeps="zsh/complete"
objects="zutil.o" objects="zutil.o"
autobins="zformat zstyle" autobins="zformat zstyle zregexparse zparseopts"