1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-12-07 06:02:21 +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
local name gropt format gname hidden hide match ign
local name gropt=-J format gname hidden hide match opts
gropt=(-J)
hide=()
match=()
ign=()
opts=()
if [[ "$1" = -([12]|)[VJ] ]]; then
gropt=("$1")
gropt="$1"
shift
fi
@ -24,14 +21,14 @@ zstyle -s ":completion:${curcontext}:$1" format format ||
zstyle -s ":completion:${curcontext}:$1" hidden hidden
if [[ "$hidden" = (all|yes|true|1|on) ]]; then
[[ "$hidden" = all ]] && format=''
hide=(-n)
opts=(-n)
fi
zstyle -s ":completion:${curcontext}:$1" group-name gname &&
[[ -z "$gname" ]] && gname="$1"
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
ign=(-F _comp_ignore)
opts=( $opts -F _comp_ignore)
else
_comp_ignore=()
fi
@ -41,15 +38,15 @@ shift 2
if [[ -n "$gname" ]]; then
if [[ -n "$format" ]]; then
eval "${name}=($hide $match $ign $gropt ${(q)gname} -X \"${format}\")"
eval "${name}=($opts $gropt ${(q)gname} -X \"${format}\")"
else
eval "${name}=($hide $match $ign $gropt ${(q)gname})"
eval "${name}=($opts $gropt ${(q)gname})"
fi
else
if [[ -n "$format" ]]; then
eval "${name}=($hide $match $ign $gropt -default- -X \"${format}\")"
eval "${name}=($opts $gropt -default- -X \"${format}\")"
else
eval "${name}=($hide $match $ign $gropt -default-)"
eval "${name}=($opts $gropt -default-)"
fi
fi

View file

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

View file

@ -13,22 +13,18 @@ typeset -U tmp2
# Get the options.
group=()
expl=()
opts=()
sopts=()
while getopts "J:V:X:P:F:S:r:R:qM:12n" opt; do
case "$opt" in
[JV]) group=("-$opt" "$OPTARG");;
X) expl=(-X "$OPTARG");;
[PF]) opts=( "$opts[@]" "-$opt" "$OPTARG")
sopts=( "$sopts[@]" "-$opt" "$OPTARG");;
[SrR]) sopts=( "$sopts[@]" -P "$OPTARG");;
[q12n]) sopts=( "$sopts[@]" "-$opt");;
M) match="$OPTARG";;
esac
done
shift OPTIND-1
zparseopts -D \
J:group V:group X:expl \
P:opts F:opts \
S:sopts r:sopts R:sopts qsopts 1sopts 2sopts nsopts \
M:match
sopts=( "$sopts[@]" "$opts[@]" )
if (( $#match )); then
match="${match[1][3,-1]}"
else
match=''
fi
# Get the arguments, first the separator, then the array. The array is
# 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>'
# 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 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
typeset -U prepaths exppaths
@ -13,73 +13,50 @@ typeset -U prepaths exppaths
setopt localoptions nullglob rcexpandparam
unsetopt markdirs globsubst shwordsplit nounset
local sopt='-' gopt='' opt
exppaths=()
prepaths=('')
ignore=()
group=()
pats=()
addpfx=()
addsfx=()
remsfx=()
expl=()
matcher=()
mopts=()
# Get the options.
while getopts "P:S:qr:R:W:F:J:V:X:f/g:M:12n" opt; do
case "$opt" in
[12n]) mopts=( "$mopts[@]" "-$opt" )
;;
P) addpfx=(-P "$OPTARG")
;;
S) addsfx=(-S "$OPTARG")
;;
q) tmp1=yes
;;
[rR]) remsfx=("-$opt" "$OPTARG")
;;
W) tmp1="$OPTARG"
if [[ "$tmp1[1]" = '(' ]]; then
prepaths=( ${^=tmp1[2,-2]%/}/ )
elif [[ "$tmp1[1]" = '/' ]]; then
prepaths=( "$tmp1/" )
else
# In this case the variable should be an array, so
# don't use an extra ${=...}.
prepaths=( ${(P)^tmp1%/}/ )
(( ! $#prepaths )) && prepaths=( ${tmp1%/}/ )
fi
(( ! $#prepaths )) && prepaths=( '' )
;;
F) tmp1="$OPTARG"
if [[ "$tmp1[1]" = '(' ]]; then
ignore=( ${=tmp1[2,-2]} )
else
ignore=( ${(P)tmp1} )
fi
;;
[JV]) group=("-$opt" "$OPTARG")
;;
X) expl=(-X "$OPTARG")
;;
f) sopt="${sopt}f"
pats=("$pats[@]" '*')
;;
/) sopt="${sopt}/"
pats=("$pats[@]" '*(-/)')
haspats=yes
;;
g) gopt='-g'
pats=("$pats[@]" ${=OPTARG})
haspats=yes
;;
M) mspec="$OPTARG"
matcher=(-M "$OPTARG")
;;
esac
done
zparseopts \
P:pfxsfx S:pfxsfx qpfxsfx r:pfxsfx R:pfxsfx \
W:prepaths F:ignore M+matcher \
J:mopts V:mopts X:mopts 1:mopts 2:mopts n:mopts \
ftmp1 /tmp1 g+tmp1
sopt="-${(@j::M)${(@)tmp1#-}#?}"
(( $tmp1[(I)-[/g]*] )) && haspats=yes
(( $tmp1[(I)-g*] )) && gopt=yes
if (( $tmp1[(I)-/] )); then
pats=( '*(-/)' ${=${(M)tmp1:#-g*}#-g} )
else
pats=( "${(@)=${(@M)tmp1:#-g*}#-g}" )
fi
if (( $#prepaths )); then
tmp1="${prepaths[1][3,-1]}"
if [[ "$tmp1[1]" = '(' ]]; then
prepaths=( ${^=tmp1[2,-2]%/}/ )
elif [[ "$tmp1[1]" = '/' ]]; then
prepaths=( "$tmp1/" )
else
prepaths=( ${(P)^tmp1%/}/ )
(( ! $#prepaths )) && prepaths=( ${tmp1%/}/ )
fi
(( ! $#prepaths )) && prepaths=( '' )
else
prepaths=( '' )
fi
if (( $#ignore )); then
tmp1="${ignore[1][3,-1]}"
if [[ "$tmp1[1]" = '(' ]]; then
ignore=( ${=tmp1[2,-2]} )
else
ignore=( ${(P)tmp1} )
fi
fi
(( $#matcher )) && mspec="${matcher[1][3,-1]}"
if [[ -z "$_file_pat_checked" ]] &&
zstyle -s ":completion:${curcontext}:files" file-patterns tmp1 &&
@ -88,20 +65,34 @@ if [[ -z "$_file_pat_checked" ]] &&
gopt=''
sopt=-/
else
gopt='-g'
gopt=yes
sopt=-
fi
pats=( $=tmp1 )
haspats=yes
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
_description directories expl directory
else
_description files expl file
fi
tmp1=$expl[(I)-M]
tmp1=$expl[(I)-M*]
if (( tmp1 )); then
mspec="$mspec $expl[1+tmp1]"
if (( $#matcher )); then
@ -110,20 +101,7 @@ if (( ! ( $#group + $#expl ) )); then
matcher=(-M "$expl[1+tmp1]")
fi
fi
fi
[[ -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
mopts=( "$mopts[@]" "$expl[@]" )
fi
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
sort=''
else
group=( "${(@)group/#-J/-V}" )
expl=( "${(@)expl/#-J/-V}" )
mopts=( "${(@)mopts/#-J/-V}" )
tmp2=()
for tmp1 in "$pats[@]"; do
@ -157,9 +134,15 @@ if zstyle -s ":completion:${curcontext}:files" sort tmp1; then
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
# original string. Then we see if we will do menucompletion.
@ -182,7 +165,7 @@ eorig="$orig"
if (( $#ignore )); then
_comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" )
(( $expl[(I)-F] )) || expl=( "$expl[@]" -F _comp_ignore )
(( $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore )
fi
# Now let's have a closer look at the string to complete.
@ -256,26 +239,13 @@ for prepath in "$prepaths[@]"; do
tsuf="$suf"
testpath="$donepath"
tmp1=( "$prepath$realpath$donepath" )
tmp2="${(M)tpre##${~skips}}"
tpre="${tpre#$tmp2}"
tmp1=( "$prepath$realpath$donepath$tmp2" )
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.
if [[ "$tpre" = */* ]]; then
@ -289,45 +259,24 @@ for prepath in "$prepaths[@]"; do
# Get the matching files by globbing.
if [[ "$tpre$tsuf" = */* ]]; then
tmp2=( ${^tmp1}*(-/) )
[[ ! -o globdots && "$PREFIX" = .* ]] &&
tmp2=( "$tmp2[@]" ${^tmp1}.*(-/) )
if [[ ! -o globdots && "$PREFIX" = .* ]]; then
tmp1=( ${^tmp1}${skipped}*(-/) ${^tmp1}${slash}.*(-/) )
else
tmp1=( ${^tmp1}${skipped}*(-/) )
fi
if [[ -o globdots || "$PREFIX" = .* ]] &&
zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
if [[ "$atmp" = (yes|true|1|on) ]]; then
tmp2=( "$tmp2[@]" . .. )
tmp1=( "$tmp1[@]" . .. )
elif [[ "$atmp" = .. ]]; then
tmp2=( "$tmp2[@]" .. )
tmp1=( "$tmp1[@]" .. )
fi
fi
else
tmp2=( ${^tmp1}${^~pats} )
[[ ! -o globdots && "$PREFIX" = .* ]] &&
tmp2=( "$tmp2[@]" ${^tmp1}.${^~pats} )
if (( $#tmp2 )) &&
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 )
if [[ ! -o globdots && "$PREFIX" = .* ]]; then
tmp1=( ${^tmp1}${skipped}${^~pats} ${^tmp1}${slash}.${^~pats} )
else
tmp1=( ${^tmp1}${skipped}${^~pats} )
fi
if [[ "$sopt" = *[/f]* && ( -o globdots || "$PREFIX" = .* ) ]] &&
zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
@ -338,22 +287,28 @@ for prepath in "$prepaths[@]"; do
fi
fi
fi
tmp1=( "$tmp2[@]" )
if [[ -n "$PREFIX$SUFFIX" ]]; then
# 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
tmp1=( "$tmp2[@]" )
compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
if [[ $#tmp1 -eq 0 && -n "$_comp_correct" ]]; then
tmp1=( "$tmp2[@]" )
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
# If no file matches, save the expanded path and continue with
# the outer loop.
if [[ $#tmp1 -eq 0 ]]; then
if (( ! $#tmp1 )); then
if [[ "$tmp2[1]" = */* ]]; then
tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
if [[ "$tmp2[1]" = */* ]]; then
@ -384,8 +339,7 @@ for prepath in "$prepaths[@]"; do
if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then
tmp1=( "$tmp2[@]" )
addsfx=(-S '')
remsfx=()
pfxsfx=(-S '' "$pfxsfx[@]")
break;
elif [[ "$haspats" = no && -z "$tpre$tsuf" &&
"$pre" = */ && -z "$suf" ]]; then
@ -397,6 +351,29 @@ for prepath in "$prepaths[@]"; do
continue 2
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.
if [[ "$tpre" = */* ]]; then
@ -408,10 +385,16 @@ for prepath in "$prepaths[@]"; do
break
fi
# There are more components, so add a slash to the files we are
# collecting.
# There are more components, so skip over the next components and make a
# slash be added.
tmp1=( ${^tmp1}/ )
tmp2="${(M)tpre##((.|..|)/)##}" ###
if [[ -n "$tmp2" ]]; then
skipped="/$tmp2"
tpre="${tpre#$tmp2}"
else
skipped=/
fi
done
# The next loop searches the first ambiguous component.
@ -471,30 +454,30 @@ for prepath in "$prepaths[@]"; do
if [[ "$tmp3" = */* ]]; then
compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \
-W "$prepath$realpath$testpath" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \
"$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" \
- "${(@)tmp1%%/*}"
else
compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
-W "$prepath$realpath$testpath" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \
"$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" \
- "$tmp1[@]"
fi
else
if [[ "$tmp3" = */* ]]; then
atmp=( -Qf "$mopts[@]" -p "$linepath$tmp2"
-W "$prepath$realpath$testpath"
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]"
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" )
"$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" )
for i in "$tmp1[@]"; do
compadd "$atmp[@]" -s "/${i#*/}" - "${i%%/*}"
done
else
compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
-W "$prepath$realpath$testpath" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \
"$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" \
- "$tmp1[@]"
fi
fi
@ -543,8 +526,8 @@ for prepath in "$prepaths[@]"; do
compquote tmp4 tmp1
compadd -Qf "$mopts[@]" -p "$linepath$tmp4" \
-W "$prepath$realpath$testpath" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \
"$pfxsfx[@]" \
-M "r:|/=* r:|=* $mspec" \
- "$tmp1[@]"
fi
done
@ -553,14 +536,17 @@ done
# expanded paths that are different from the string on the line, we add
# them as possible matches.
exppaths=( "${(@)exppaths:#$eorig}" )
if zstyle -t ":completion:${curcontext}:paths" expand prefix &&
[[ $#exppaths -gt 0 && nm -eq compstate[nmatches] ]]; then
PREFIX="${opre}"
SUFFIX="${osuf}"
compadd -Q "$mopts[@]" -S '' "$group[@]" "$expl[@]" \
-M "r:|/=* r:|=* $mspec" -p "$linepath" - "$exppaths[@]"
[[ nm -eq compstate[nmatches] ]]; then
exppaths=( "${(@)exppaths:#$eorig}" )
if (( $#exppaths )); then
PREFIX="${opre}"
SUFFIX="${osuf}"
compadd -Q "$mopts[@]" -S '' \
-M "r:|/=* r:|=* $mspec" -p "$linepath" - "$exppaths[@]"
fi
fi
[[ 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.
group=()
expl=()
opts=()
while getopts "J:V:X:P:F:S:r:R:qM:12n" opt; do
case "$opt" in
[JV]) group=("-$opt" "$OPTARG");;
X) expl=(-X "$OPTARG");;
[q12n]) opts=( "$opts[@]" "-$opt" );;
M) match="$OPTARG";;
*) opts=( "$opts[@]" "-$opt" "$OPTARG" );;
esac
done
shift OPTIND-1
zparseopts -D \
J:group V:group \
P:opts F:opts S:opts r:opts R:opts qopts 1opts 2opts nopts \
X:expl M:match
if (( $#match )); then
match="${match[1][3,-1]}"
else
match=''
fi
# Get the string from the line.

View file

@ -111,4 +111,28 @@ The resulting strings are stored in the var(array).
item(tt(zregexparse))(
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()

View file

@ -1155,10 +1155,149 @@ bin_zregexparse(char *nam, char **args, char *ops, int func)
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[] = {
BUILTIN("zstyle", 0, bin_zstyle, 0, -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("zparseopts", 0, bin_zparseopts, 1, -1, 0, "D", NULL),
};

View file

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