1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2026-01-04 09:01:06 +01:00

zsh-3.1.5-pws-15

This commit is contained in:
Tanaka Akira 1999-04-15 18:25:40 +00:00
parent 6c1fb551ba
commit 8ceb54fbc2
101 changed files with 1931 additions and 1149 deletions

View file

@ -1,4 +1,4 @@
#defcomp -brace-parameter-
#compdef -brace-parameter-
if [[ "$SUFFIX" = *\}* ]]; then
ISUFFIX="${SUFFIX#*\}}$ISUFFIX"

View file

@ -1,4 +1,4 @@
#defcomp -command-
#compdef -command-
local nm=$compstate[nmatches] ret=1

View file

@ -1,4 +1,4 @@
#defcomp -condition-
#compdef -condition-
local prev="$words[CURRENT-1]"

View file

@ -1,4 +1,4 @@
#defcomp -default-
#compdef -default-
# We first try the `compctl's. This is without first (-T) and default (-D)
# completion. If you want them add `-T' and/or `-D' to this command.

View file

@ -1,3 +1,3 @@
#defcomp -equal-
#compdef -equal-
compgen -am

View file

@ -32,12 +32,25 @@
# for option descriptions containing `=FILE' and paths for option
# descriptions that contain `=DIR' or `=PATH'. These builtin patterns
# can be overridden by patterns given as arguments, though.
#
# This function accepts following options:
#
# -t do completion only on words starting with two hyphens
#
# -i list of patterns. Options, matching these patterns, are ignored.
# The list may be given as array name or as literal list in braces.
# E.g. _long_options -i '(--(enable|disable)-FEATURE*)' will ignore
# --enable-FEATURE, that is listed in configure help output
#
# -s list of pattern/replacement pairs. The argument is the same as above.
# E.g. configure often lists only --enable but accepts both
# --enable and --disable options.
# _long_options -s '(#--enable- --disable)' will accept both forms.
#
# This function also accepts the `-X', `-J', and `-V' options which
# are given to `compadd'. Finally, it accepts the option `-t'. If this
# is given, completion is only done on words starting with two hyphens.
# are given to `compadd'.
local opt expl group test i name action ret=1 tmp suffix
local opt expl group test i name action ret=1 tmp suffix iopts sopts
setopt extendedglob
@ -46,11 +59,23 @@ setopt extendedglob
group=()
expl=()
if [[ $1 = -*~--* ]]; then
while getopts "J:V:X:t" opt; do
while getopts "J:V:X:ti:s:" opt; do
case "$opt" in
[JV]) group=("-$opt" "$OPTARG");;
X) expl=(-X "$OPTARG");;
t) test=yes;;
i) if [[ "$OPTARG[1]" = '(' ]]; then
iopts=( ${=OPTARG[2,-2]} )
else
iopts=( ${(P)${OPTARG}} )
fi
;;
s) if [[ "$OPTARG[1]" = '(' ]]; then
sopts=( ${=OPTARG[2,-2]} )
else
sopts=( ${(P)${OPTARG}} )
fi
;;
esac
done
shift OPTIND-1
@ -77,6 +102,7 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
(( $+_lo_cache_actions )) && unset "$_lo_cache_names[@]" _lo_cache_actions _lo_cache_names
local opts pattern anum=1 tmpo str
typeset -U opts
# Now get the long option names by calling the command with `--help'.
# The parameter expansion trickery first gets the lines as separate
@ -87,11 +113,24 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
# the old array elements with newlines between them. Then we select
# those elements that start with two hyphens, remove anything up to
# those hyphens and anything from the space or comma after the
# option up to the end. Finally all elements with option strings
# that contain uppercase letters are removed.
# option up to the end.
opts=("--${(@)^${(@)${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$("$words[1]" --help)}:#[ ]#-*}//,/
}}:#[ ]#--*}#*--}%%[, ]*}:#(*-[A-Z]*|)}")
opts=("--${(@)^${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$("$words[1]" --help)}:#[ ]#-*}//,/
}}:#[ ]#--*}#*--}%%[, ]*}")
# Now remove all ignored options ...
while (($#iopts)) ; do
opts=( ${opts:#$~iopts[1]} )
shift iopts
done
# ... and add "same" options
while (($#sopts)) ; do
opts=( $opts ${opts/$sopts[1]/$sopts[2]} )
shift 2 sopts
done
# The interpretation of the options is completely table driven. We
# use the positional parameters we were given and a few standard
@ -173,7 +212,7 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
# Now filter out any option strings we don't like and stuff them
# in an array, if there are still some.
tmp=("${(@)${(@)tmp%%\=*}//[^a-z0-9-]}")
tmp=("${(@)${(@)tmp%%\=*}//[^a-zA-Z0-9-]}")
if (( $#tmp )); then
_lo_cache_names[anum]="$name"
_lo_cache_actions[anum]="$action"
@ -200,20 +239,6 @@ if [[ "$str" = *\=* ]]; then
osuf="$SUFFIX"
pre="${str%%\=*}"
IPREFIX="${IPREFIX}${pre}="
PREFIX="${str#*\=}"
SUFFIX=""
# We will check if the arrays contain an option matching what's on
# the line. To do this good, we build a pattern.
[[ -n "$_comp_correct" && $#pre -le _comp_correct ]] && return 1
pat="${pre}*"
patflags=''
_match_pattern _long_options pat patflags
[[ -n "$_comp_correct" ]] && patflags="$patflags(#a$_comp_correct)"
# Then we walk through the array names. For each array we test if it
# contains the option string. If so, we `invoke' the action stored
@ -223,6 +248,9 @@ if [[ "$str" = *\=* ]]; then
for name in "$_lo_cache_names[@]"; do
action="$_lo_cache_actions[anum]"
if (( ${(@)${(@P)name}[(I)$pre]} )); then
IPREFIX="${oipre}${pre}="
PREFIX="${str#*\=}"
SUFFIX=""
if [[ "$action[1]" = (\[|\() ]]; then
compadd - ${=action[2,-2]}
elif (( $#action )); then
@ -240,7 +268,10 @@ if [[ "$str" = *\=* ]]; then
# element from `_lo_actions' in `parta'. If we find more than one
# such option or if we already had one, we set `parto' to `-'.
tmp=("${(@M)${(@P)name}:#${~pat}}")
PREFIX="${str%%\=*}"
SUFFIX=""
compadd -O tmp -M 'r:|-=* r:|=*' - "${(@P)name}"
if [[ $#tmp -eq 1 ]]; then
if [[ -z "$parto" ]]; then
parto="$tmp[1]"
@ -258,8 +289,9 @@ if [[ "$str" = *\=* ]]; then
# try to complete the string after the `='.
if [[ -n "$parto" && "$parto" != - ]]; then
IPREFIX="${parto}="
IPREFIX="${oipre}${parto}="
PREFIX="${str#*\=}"
SUFFIX=""
if (( $#parta )); then
if [[ "$parta[1]" = (\[|\() ]]; then
compadd - ${=parta[2,-2]}
@ -281,7 +313,7 @@ fi
# The string on the line did not contain a `=', or we couldn't
# complete the option string since there were more than one matching
# what's on the line. So we just ad the option string as possible
# what's on the line. So we just add the option strings as possible
# matches, giving the string from the `=' on as a suffix.
if [[ "$str" = *\=* ]]; then

View file

@ -1,4 +1,4 @@
#defcomp -math-
#compdef -math-
if [[ "$PREFIX" = *[^a-zA-Z0-9_]* ]]; then
IPREFIX="$IPREFIX${PREFIX%%[a-zA-Z0-9_]#}"
@ -10,7 +10,7 @@ if [[ "$SUFFIX" = *[^a-zA-Z0-9_]* ]]; then
fi
compgen -v
#defcomp -math-
#compdef -math-
IPREFIX="$IPREFIX${PREFIX%[a-zA-Z0-9_]*}"
PREFIX="${PREFIX##*[^a-zA-Z0-9_]}"

View file

@ -1,3 +1,3 @@
#defcomp -parameter-
#compdef -parameter-
compgen -v

View file

@ -1,4 +1,4 @@
#defcomp - nohup nice eval time rusage noglob nocorrect exec
#compdef - nohup nice eval time rusage noglob nocorrect exec
shift words
(( CURRENT-- ))

View file

@ -1,3 +1,3 @@
#defcomp -redirect-
#compdef -redirect-
_files

View file

@ -1,4 +1,4 @@
#defcomp -subscript-
#compdef -subscript-
if [[ ${(Pt)${compstate[parameter]}} = assoc* ]]; then
compgen -S ']' -k "( ${(kP)${compstate[parameter]}} )"

View file

@ -1,4 +1,4 @@
#defcomp -tilde-
#compdef -tilde-
# We use all named directories and user names here. If this is too slow
# for you or if there are too many of them, you may want to use

View file

@ -1,3 +1,3 @@
#defcomp getopts read unset vared
#compdef getopts read unset vared
compgen -v

View file

@ -1,3 +1,3 @@
#defcomp unalias
#compdef unalias
compgen -a

View file

@ -1,3 +1,3 @@
#defcomp shift
#compdef shift
compgen -A

View file

@ -1,3 +1,3 @@
#defcomp autoload
#compdef autoload
compgen -s '${^fpath}/*(N:t)'

View file

@ -1,3 +1,3 @@
#defcomp bg
#compdef bg
compgen -z -P '%'

View file

@ -1,4 +1,4 @@
#defcomp bindkey
#compdef bindkey
# Normally, this completes names of zle widgets, whether the builtin ones
# or ones defined by the user. Note that a - allows a wildcard before it,

View file

@ -1,4 +1,4 @@
#defcomp builtin
#compdef builtin
if (( $CURRENT > 2 )); then
shift words

View file

@ -1,4 +1,4 @@
#defcomp cd pushd
#compdef cd pushd
# Handling of cd.
# - Normally just completes directories. Uses cdpath if that's set
@ -55,7 +55,7 @@ elif [[ $words[1] = pu* && $PREFIX = [-+]* ]]; then
list=(${list%%[ ]*})
compgen -y '$lines' -Q -k list && ret=0
[[ -z $compstate[list] ]] && compstate[list]=list && ret=0
[[ -n $compstate[insert] ]] && compstat[insert]=menu && ret=0
[[ -n $compstate[insert] ]] && compstate[insert]=menu && ret=0
return ret
elif [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then

View file

@ -1,4 +1,4 @@
#defcomp command
#compdef command
if [[ CURRENT -ge 3 ]]; then
compset -n 2

View file

@ -1,3 +1,3 @@
#defcomp rmdir df du dircmp
#compdef rmdir df du dircmp
_files -/

View file

@ -1,4 +1,4 @@
#defcomp disable
#compdef disable
local prev="$words[CURRENT-1]" ret=1

View file

@ -1,3 +1,3 @@
#defcomp echotc
#compdef echotc
compgen -k '(al dc dl do le up al bl cd ce cl cr dc dl do ho is le ma nd nl se so up)'

View file

@ -1,4 +1,4 @@
#defcomp enable
#compdef enable
local prev="$words[CURRENT-1]" ret=1

View file

@ -1,4 +1,4 @@
#defcomp fc
#compdef fc
local prev="$words[CURRENT-1]"

View file

@ -1,3 +1,3 @@
#defcomp unfunction
#compdef unfunction
compgen -F

View file

@ -1,4 +1,4 @@
#defcomp hash
#compdef hash
if [[ "$words[2]" = -*d* ]]; then
if compset -P 1 '*\='; then

View file

@ -1,3 +1,3 @@
#defcomp fg jobs
#compdef fg jobs
compgen -j -P '%'

View file

@ -1,4 +1,4 @@
#defcomp kill
#compdef kill
local list

View file

@ -1,3 +1,3 @@
#defcomp limit unlimit
#compdef limit unlimit
compgen -k "(${(j: :)${(f)$(limit)}%% *})"

View file

@ -1,3 +1,3 @@
#defcomp sched
#compdef sched
compset -n 3 && _normal

View file

@ -1,4 +1,4 @@
#defcomp set
#compdef set
local prev="$words[CURRENT-1]"

View file

@ -1,4 +1,4 @@
#defcomp setopt
#compdef setopt
# If you first want to complete only unset options, un-comment the lines
# setting the _unset_options array and then use:

View file

@ -1,4 +1,4 @@
#defcomp source
#compdef source
if [[ CURRENT -ge 3 ]]; then
compset -n 2

View file

@ -1,4 +1,4 @@
#defcomp trap
#compdef trap
if [[ CURRENT -eq 2 ]]; then
compgen -c

View file

@ -1,4 +1,4 @@
#defcomp unhash
#compdef unhash
local fl="$words[2]" ret=1

View file

@ -1,4 +1,4 @@
#defcomp unsetopt
#compdef unsetopt
# If you first want to complete only unset options, uncomment the lines
# setting the _set_options array and then use:

View file

@ -1,3 +1,3 @@
#defcomp declare export integer local readonly typeset
#compdef declare export integer local readonly typeset
compgen -v -q -S '='

View file

@ -1,4 +1,4 @@
#defcomp wait
#compdef wait
local list ret=1

View file

@ -1,3 +1,3 @@
#defcomp which whence where type
#compdef which whence where type
compgen -caF

View file

@ -1,4 +1,4 @@
#defpatcomp zf*
#compdef -p zf*
# Don't try any more completion after this.
_compskip=1
@ -10,7 +10,7 @@ _compskip=1
local subcom
if [[ $words[1] = zftp ]]; then
if [[ $CURRENT -eq 1 ]]; then
if [[ $CURRENT -eq 2 ]]; then
compadd open params user login type ascii binary mode put \
putat get getat append appendat ls dir local remote mkdir rmdir
return

View file

@ -1,4 +1,4 @@
#defcomp zle
#compdef zle
if [[ "$words[2]" = -N && CURRENT -eq 3 ]]; then
compgen -F

View file

@ -1,4 +1,4 @@
#defcomp zmodload
#compdef zmodload
local fl="$words[2]"

View file

@ -1,4 +1,4 @@
#defkeycomp complete-word \C-xc
#compdef -k complete-word \C-xc
# Function to correct a filename. Can be used as a completion widget,
# or as a function in its own right, in which case it will print the

View file

@ -0,0 +1,12 @@
#compdef -k complete-word \C-xc
# Simple completion front-end implementing spelling correction.
# The maximum number of errors is set quite high, and
# the numeric prefix can be used to specify a different value.
local oca="$compconfig[correct_accept]"
compconfig[correct_accept]=6n
_main_complete _correct
compconfig[correct_accept]=$oca

View file

@ -1,4 +1,4 @@
#defkeycomp complete-word \C-xm
#compdef -k complete-word \C-xm
# Complete the most recent file matching the pattern on the line so
# far: globbing is active, i.e. *.txt will be expanded to the most recent

View file

@ -1,15 +1,17 @@
#autoload
# This searches $1 in the array for normal completions and calls the result.
# This searches $* in the array for normal completions and calls the result.
# It is used to include completions for another command or special context
# into the list generated by the calling function.
# For example the function for `-subscript-' could call this as in
# `_compalso -math-' to get the completions that would be generated for a
# mathematical context.
local tmp ret=1
local i tmp
tmp="$_comps[$1]"
[[ -z "$tmp" ]] || "$tmp" && ret=0
for i; do
tmp="$_comps[$1]"
[[ -z "$tmp" ]] || "$tmp" && return 0
done
return ret
return 1

View file

@ -7,15 +7,8 @@
# 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 menu origflags mflags
_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
typeset -U tmp2
# Get the options.
@ -41,193 +34,159 @@ else
matches=( "${(@P)2}" )
fi
# Now build the pattern from what we have on the line. We also save
# the original string in `orig'.
# 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 [[ $#compstate[pattern_match] -ne 0 ]]; then
if [[ "${compstate[pattern_match]-*}" = \** ]]; then
str="${PREFIX}*${SUFFIX}*"
else
str="${PREFIX}${SUFFIX}"
fi
else
patstr="${PREFIX:q}*${SUFFIX:q}*"
fi
orig="${PREFIX}${SUFFIX}"
pre="$PREFIX"
suf="$SUFFIX"
orig="$PREFIX$SUFFIX"
[[ $compstate[insert] = *menu || -n "$_comp_correct" ||
# Special handling for menucompletion?
[[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
( $#compstate[pattern_match] -ne 0 &&
"$orig" != "${orig:q}" ) ]] && menu=yes
matchflags=""
_match_pattern _path_files patstr matchflags
origflags="$matchflags"
[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
patstr="${${patstr//$sep/*$sep}//\*##/*}"
# 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.
if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then
mflags="$origflags"
compadd -O tmp1 -M "r:|${sep}=* r:|=*" - "$matches[@]"
(( $#tmp1 )) && matches=( "$tmp1[@]" )
while true; do
# Get the prefix and suffix for matching.
if [[ "$pre" = *${sep}* ]]; then
PREFIX="${pre%%${sep}*}"
SUFFIX=""
else
mflags="$matchflags"
PREFIX="${pre}"
SUFFIX="${suf%%${sep}*}"
fi
pat="${${${patstr#*${sep}}%${sep}*}//\*/[^${sep}]#}"
tmp1=( "${(@M)matches:#${~mflags}${orig%%${sep}*}${sep}${~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 there are no words matching the exact substring, stop.
tmp1=( "${(@M)matches:#${PREFIX}${SUFFIX}${sep}*}" )
(( $#tmp1 )) || break
# Otherwise add the part to the prefix, remove it from the matches
# (and also remove all words not matching the string at all), and
# set `patstr' and `orig' to the next component.
tmp1="${orig%%${sep}*}${sep}"
pref="$pref$tmp1"
matches=("${(@)${(@)${(@M)matches:#${tmp1}*}#$tmp1}:#}")
orig="${orig#*${sep}}"
patstr="${patstr#*${sep}}"
done
# Now we get all the words that still match in `tmp1'.
if [[ "$patstr" = *${sep}* ]]; then
tmp1="${patstr%${sep}*}${sep}"
pat="${tmp1//\*/[^${sep}]#}${patstr##*${sep}}"
else
pat="$patstr"
fi
if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then
mflags="$origflags"
else
mflags="$matchflags"
fi
tmp1=( "${(@M)matches:#${~mflags}${~pat}}" )
if (( $#tmp1 )); then
# There are words that are matched, put them into `matches' and then
# move all unambiguous components from the beginning into `pref'.
matches=( "$tmp1[@]" )
while [[ "$matches[1]" = *${sep}* ]]; do
# 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="${matches[1]%%${sep}*}${sep}"
tmp2=( "${(@)matches:#${tmp1}*}" )
(( $#tmp2 )) && break
# All matches have the same prefix, put it into `pref' and remove
# it from the matches.
pref="$pref$tmp1"
matches=( "${(@)${(@)matches#$tmp1}:#}" )
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" -I "$ISUFFIX" -S '' - \
"${pref}${orig}"
elif [[ -n "$menu" ]]; then
if [[ "$orig" = *${sep}* ]]; then
orig="${sep}${orig#*${sep}}"
else
orig=''
fi
for i in "$matches[@]" ; do
if [[ "$i" = *${sep}* ]]; then
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" -s "$orig" - "${i%%${sep}*}${sep}"
else
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" -s "$orig" - "${i%%${sep}*}"
fi
done
if (( $#tmp1 )); then
npref="${PREFIX}${SUFFIX}${sep}"
else
for i in "$matches[@]" ; do
if [[ "$i" = *${sep}* ]]; then
compadd -U -i "$IPREFIX" -I "$ISUFFIX" -p "$pref" -s "${i#*${sep}}" \
"$group[@]" "$expl[@]" -M "r:|${sep:q}=*" - "${i%%${sep}*}${sep}"
# No exact match, see how many strings match what's on the line.
tmp2=( "${(@)matches%%${sep}*}" )
compadd -O tmp1 - "$tmp2[@]"
if [[ $#tmp1 -eq 1 ]]; then
# 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 [[ "$pre$suf" = *${sep}* ]]; then
npref="${tmp1[1]}${sep}"
else
matches=( "${(@M)matches:#${tmp1[1]}*}" )
tmp2=( "${(@M)matches:#${tmp1[1]}${sep}*}" )
if (( $#tmp2 )); then
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" -qS "$sep" - "$tmp1[1]"
else
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" - "$tmp1[1]"
fi
return 1
fi
elif (( $#tmp1 )); then
# More than one match. First we get all strings that match the
# rest from the line.
PREFIX="$pre"
SUFFIX="$suf"
compadd -O matches -M "r:|${sep}=* r:|=*" - "$matches[@]"
if [[ -n "$menu" ]]; then
# With menucompletion we just add matches for the matching
# components with the prefix we collected and the rest from the
# line as a suffix.
tmp2="$pre$suf"
if [[ "$tmp2" = *${sep}* ]]; then
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" -s "${sep}${tmp2#*${sep}}" - "$tmp1[@]"
else
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" - "$tmp1[@]"
fi
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 -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-S '' -p "$pref" -s "${i#*${sep}}" - "${i%%${sep}*}${sep}"
else
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-S '' -p "$pref" - "$i"
fi
done
fi
return 0
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.
[[ "$orig" = "$pref$pre$suf" ]] && return 1
if [[ -n "$suf" ]]; then
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-s "$suf" - "$pref$pre"
else
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" - "$i"
-S '' - "$pref$pre$suf"
fi
done
fi
elif [[ "$patstr" = *${sep}* ]]; then
# 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.
while [[ "$patstr" = *${sep}* ]]; do
# First we get all words matching at least this component in
# `tmp1'. If there are none, we give up.
if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then
mflags="$origflags"
else
mflags="$matchflags"
fi
tmp1=( "${(@M)matches:#${~mflags}${~patstr%%${sep}*}${sep}*}" )
(( $#tmp1 )) || break
# Then we check if there are words that have a different prefix.
tmp2=( "${(@)tmp1:#${tmp1[1]%%${sep}*}${sep}*}" )
if (( $#tmp2 )); then
# 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.
compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}"
return 0
fi
fi
# All words have the same prefix, so add it to `pref' again and
# try the next component.
# 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'.
pref="$pref${tmp1[1]%%${sep}*}${sep}"
matches=( "${(@)matches#${tmp1[1]%%${sep}*}${sep}}" )
orig="${orig#*${sep}}"
patstr="${patstr#*${sep}}"
done
matches=( "${(@)${(@)${(@M)matches:#${npref}*}#*${sep}}:#}" )
pref="$pref$npref"
# Finally, add the unambiguous prefix and the rest of the string
# from the line.
# Now we set `pre' and `suf' to their new values.
compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -I "$ISUFFIX" \
-p "$pref" - "$orig"
fi
if [[ "$pre" = *${sep}* ]]; then
pre="${pre#*${sep}}"
elif [[ "$suf" = *${sep}* ]]; then
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.
# This sets the return value to indicate that we added matches (or not).
[[ -n "$pref" && "$orig" != "$pref" ]] &&
compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-S '' - "$pref"
[[ nm -ne compstate[nmatches] ]]
return
fi
done

View file

@ -7,10 +7,9 @@
# the last have the same syntax and meaning as for `compgen' or
# `compadd', respectively. The `-F <ignore>' option may be used to give
# a list of suffixes either by giving the name of an array or
# literally by giving them in a string surrounded by
# parentheses. Files with one of the suffixes thus given are treated
# like files with one of the suffixes in the `fignore' array in normal
# completion.
# literally by giving them in a string surrounded by parentheses. Files
# with one of the suffixes thus given are treated like files with one
# of the suffixes in the `fignore' array in normal completion.
#
# This function supports one configuration key:
#
@ -18,22 +17,13 @@
# If this is set to a non-empty string, the partially typed path
# from the line will be expanded as far as possible even if trailing
# pathname components can not be completed.
#
#
# This function uses the helper functions `_match_test' and `_match_pattern'.
# First see if we should generate matches for the global matcher in use.
local linepath realpath donepath prepath testpath exppath
local tmp1 tmp2 tmp3 tmp4 i orig pre suf tpre tsuf
local pats ignore group expl addpfx addsfx remsfx
local nm=$compstate[nmatches] menu
_match_test _path_files || return 1
# Yes, so...
local nm str linepath realpath donepath patstr prepath testpath rest
local tmp1 collect tmp2 suffixes i ignore matchflags opt group sopt pats gopt
local addpfx addsfx expl orig ostr nm=$compstate[nmatches] menu remsfx patlast
local origflags mflags tmp3 tmp4 exppaths
typeset -U prepaths
typeset -U prepaths exppaths
setopt localoptions nullglob rcexpandparam extendedglob
unsetopt markdirs globsubst shwordsplit nounset
@ -109,35 +99,27 @@ if [[ "$sopt" = - ]]; then
fi
fi
# str holds the whole string from the command line with a `*' between
# the prefix and the suffix. Then we see if we will do menucompletion.
# We get the prefix and the suffix from the line and save the whole
# original string. Then we see if we will do menucompletion.
if [[ $#compstate[pattern_match] -ne 0 ]]; then
if [[ "${compstate[pattern_match]-*}" = \** ]]; then
str="${PREFIX}*${SUFFIX}"
else
str="${PREFIX}${SUFFIX}"
fi
else
str="${PREFIX:q}*${SUFFIX:q}"
[[ "$str" = \\\~* ]] && str="$str[2,-1]"
fi
pre="$PREFIX"
suf="$SUFFIX"
orig="${PREFIX}${SUFFIX}"
[[ $compstate[insert] = *menu || -n "$_comp_correct" ||
[[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
( $#compstate[pattern_match] -ne 0 &&
"${orig#\~}" != "${${orig#\~}:q}" ) ]] && menu=yes
# We will first try normal completion called with `compgen', but only if we
# weren't given a `-F', `-r', or `-R' option.
# weren't given a `-F', `-r', or `-R' option or we are in the string.
if [[ $#ignore -eq 0 && $#remsfx -eq 0 && -z "$_comp_correct" ]]; then
if [[ -z "$suf" && $#ignore -eq 0 && $#remsfx -eq 0 &&
-z "$_comp_correct" ]]; then
# First build an array containing the `-W' option, if there is any and we
# want to use it. We don't want to use it if the string from the command line
# is a absolute path or relative to the current directory.
if [[ -z "$tmp1[1]" || "$str[1]" = [~/] || "$str" = (.|..)/* ]]; then
if [[ -z "$prepaths[1]" || "$pre[1]" = [~/] || "$pre" = (.|..)/* ]]; then
tmp1=()
else
tmp1=(-W "( $prepaths )")
@ -145,7 +127,6 @@ if [[ $#ignore -eq 0 && $#remsfx -eq 0 && -z "$_comp_correct" ]]; then
# Now call compgen.
nm=$compstate[nmatches]
if [[ -z "$gopt" ]]; then
compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
else
@ -157,13 +138,13 @@ if [[ $#ignore -eq 0 && $#remsfx -eq 0 && -z "$_comp_correct" ]]; then
[[ compstate[nmatches] -eq nm ]] || return 0
fi
# No `-F' option, so we want to use `fignore'.
# If given no `-F' option, we want to use `fignore'.
(( $#ignore )) || ignore=(-F fignore)
# Now let's have a closer look at the string to complete.
if [[ "$str[1]" = \~ ]]; then
if [[ "$pre[1]" = \~ ]]; then
# It begins with `~', so remember anything before the first slash to be able
# to report it to the completion code. Also get an expanded version of it
# (in `realpath'), so that we can generate the matches. Then remove that
@ -171,10 +152,10 @@ if [[ "$str[1]" = \~ ]]; then
# paths and make sure that the loop below is run only once with an empty
# prefix path by setting `prepaths'.
linepath="${str%%/*}/"
linepath="${pre%%/*}/"
eval realpath\=$linepath
[[ "$realpath" = "$linepath" ]] && return 1
str="${str#*/}"
pre="${pre#*/}"
orig="${orig#*/}"
donepath=''
prepaths=( '' )
@ -185,12 +166,12 @@ else
linepath=''
realpath=''
if [[ "$str[1]" = / ]]; then
if [[ "$pre[1]" = / ]]; then
# If it is a absolut path name, we remove the first slash and put it in
# `donepath' meaning that we treat it as the path that was already handled.
# Also, we don't use the paths from `-W'.
str="$str[2,-1]"
pre="$pre[2,-1]"
orig="$orig[2,-1]"
donepath='/'
prepaths=( '' )
@ -198,278 +179,204 @@ else
# The common case, we just use the string as it is, unless it begins with
# `./' or `../' in which case we don't use the paths from `-W'.
[[ "$str" = (.|..)/* ]] && prepaths=( '' )
[[ "$pre" = (.|..)/* ]] && prepaths=( '' )
donepath=''
fi
fi
# Now build the glob pattern by calling `_match_pattern'.
patstr="$str"
matchflags=""
_match_pattern _path_files patstr matchflags
origflags="$matchflags"
[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
# We almost expect the pattern to have changed `..' into `*.*.', `/.' into
# `/*.', and probably to contain two or more consecutive `*'s. Since these
# have special meaning for globbing, we remove them. But before that, we
# add the pattern for matching any characters before a slash.
patstr="$patstr:gs-/-*/-:gs/*.*./../:gs/**/*/:gs-.*/-./-"
# We take the last pathname component from the pattern and store it in
# `patlast', replacing `*'s in it with patterns that match any character
# but not slashes. Later we will generate matches using `patstr' with the
# patterns we were given (like `*.c') appended to it, producing all matching
# files. These filenames are then compared to `patlast' and all names not
# matching that will be removed. All this is needed to be able to correctly
# support `completeinword' as otherwise we would have something like `a*x'
# from the line (the `*' was inserted above) and appending the `-g' pattern
# `*.tex' would yield `a*x*.tex' which is not what we want.
if [[ "$patstr" = */* ]]; then
if [[ -n "$_comp_correct" && "${#orig##*/}" -le _comp_correct ]]; then
patlast="*/${origflags}${${${patstr##*/}//\*/[^/]#}:gs.\[^/]#.\\\*.}"
else
patlast="*/${matchflags}${${${patstr##*/}//\*/[^/]#}:gs.\[^/]#.\\\*.}"
fi
patstr="${patstr%/*}/"
else
if [[ -n "$_comp_correct" && "$#orig" -le _comp_correct ]]; then
patlast="${origflags}${${patstr//\*/[^/]#}:gs.\[^/]#.\\\*.}"
else
patlast="${matchflags}${${patstr//\*/[^/]#}:gs.\[^/]#.\\\*.}"
fi
patstr=""
fi
# First we skip over all pathname components in `str' which really exist in
# the file-system, so that `/usr/lib/l<TAB>' doesn't offer you `lib' and
# `lib5'. Pathname components skipped this way are taken from `orig' and added
# to `donepath'.
while [[ "$orig" = */* ]] do
tmp1=( $realpath$donepath${orig%%/*}/${~matchflags}${~patstr#*/}${^~pats} )
tmp1=("${(@M)tmp1:#$~patlast}")
[[ $#tmp1 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break
donepath="$donepath${orig%%/*}/"
orig="${orig#*/}"
patstr="${patstr#*/}"
done
# Finally, generate the matches. First we loop over all the paths from `-W'.
# Note that in this loop `str' is used as a modifyable version of `patstr'
# and `testpath' is a modifyable version of `donepath'.
# Now we generate the matches. First we loop over all prefix paths given
# with the `-W' option.
for prepath in "$prepaths[@]"; do
str="$patstr"
# Get local copies of the prefix, suffix, and the prefix path to use
# in the following loop, which walks through the pathname components
# in the string from the line.
tpre="$pre"
tsuf="$suf"
testpath="$donepath"
ostr="$orig"
[[ -z "$prepath" || "$prepath[-1]" = / ]] || prepath="${prepath}/"
tmp1=( "$prepath$realpath$donepath" )
# The second loop tests the components of the path in `str' to get the
# possible matches.
while true; do
while [[ "$str" = */* ]] do
# `rest' is the pathname after the first slash that is left. In `tmp1'
# we get the globbing matches for the pathname component currently
# handled.
# Skip over `./' and `../'.
if [[ -n "$_comp_correct" && "${#ostr%%/*}" -le _comp_correct ]]; then
mflags="$origflags"
if [[ "$tpre" = (.|..)/* ]]; then
tmp1=( ${^tmp1}${tpre%%/*}/ )
tpre="${tpre#*/}"
continue
fi
# Get the prefix and suffix for matching.
if [[ "$tpre" = */* ]]; then
PREFIX="${tpre%%/*}"
SUFFIX=""
else
mflags="$matchflags"
PREFIX="${tpre}"
SUFFIX="${tsuf%%/*}"
fi
rest="${str#*/}"
tmp1="${prepath}${realpath}${testpath}${~mflags}${str%%/*}(-/)"
tmp1=( $~tmp1 )
if [[ $#tmp1 -eq 0 ]]; then
# If this didn't produce any matches, we don't need to test this path
# any further, so continue with the next `-W' path, if any.
# Get the matching files by globbing.
continue 2
elif [[ $#tmp1 -gt 1 ]]; then
# If it produced more than one match, we want to remove those which
# don't have possible following pathname components matching the
# rest of the string we are completing. (The case with only one
# match is handled below.)
# In `collect' we will collect those of the produced pathnames that
# have a matching possible path-suffix. In `suffixes' we build an
# array containing strings build from the rest of the string to
# complete and the glob patterns we were given as arguments.
if [[ "$tpre$tsuf" = */* ]]; then
tmp1=( ${^tmp1}*(D/) )
else
tmp1=( ${^tmp1}${^~pats} )
fi
collect=()
suffixes=( $rest$^pats )
suffixes=( "${(@)suffixes:gs.**.*.}" )
if [[ -n "$PREFIX$SUFFIX" ]]; then
# See which of them match what's on the line.
if [[ -n "$_comp_correct" && "${#ostr#*/}" -le _comp_correct ]]; then
mflags="$origflags"
compadd -O tmp2 "$ignore[@]" - "${(@)tmp1##*/}"
# If no file matches, save the expanded path and continue with
# the outer loop.
if [[ $#tmp2 -eq 0 ]]; then
[[ "$tmp1[1]" = */* ]] &&
exppaths=( "$exppaths[@]" ${^tmp1%/*}/${tpre}${tsuf} )
continue 2
fi
# Remove all files that weren't matched.
if [[ "$tmp1[1]" = */* ]]; then
tmp1=( "${(@M)tmp1:#*/(${(j:|:)~${(@)tmp2:q}})}" )
else
mflags="$matchflags"
fi
# In the loop the prefixes from the `tmp1' array produced above and
# the suffixes we just built are used to produce possible matches
# via globbing.
for i in "$tmp1[@]" ; do
tmp2=( ${~i}/${~mflags}${~suffixes} )
tmp2=("${(@M)tmp2:#$~patlast}")
[[ $#tmp2 -ne 0 ]] && collect=( $collect $i )
done
# If this test showed that none of the matches from the glob in `tmp1'
# has a possible sub-path matching what's on the line, we add the
# matches found in `tmp1' and otherwise give up and continue with the
# next `-W' path.
if [[ $#collect -eq 0 ]]; then
# Before giving, we first try to get the longest expandable path-
# prefix, though. The result is stored in `exppaths'
tmp2=()
tmp3="$rest"
tmp4="${ostr##*/}"
ostr="${ostr%/*}"
while [[ "$tmp3" = */* ]]; do
tmp2=( ${^tmp1}/${~mflags}${~tmp3} )
if [[ $#tmp2 -eq 1 ]]; then
exppaths=( "$exppaths[@]" "${tmp2[1]}${tmp4}" )
exppaths=( "${(@)exppaths#${prepath}${realpath}}" )
break;
fi
tmp3="${tmp3%/*}"
tmp4="${ostr##*/}/${tmp4}"
ostr="${ostr%/*}"
done
continue 2
elif [[ $#collect -ne 1 ]]; then
# If we have more than one possible match, this means that the
# pathname component currently handled is ambiguous, so we give
# it to the completion code.
# First we build the full path prefix in `tmp1'.
tmp1="$prepath$realpath$testpath"
# Now produce all matching pathnames in `collect'.
collect=( ${~collect}/${~matchflags}${~suffixes} )
collect=("${(@M)collect:#$~patlast}")
# And then remove the common path prefix from all these matches.
collect=( ${collect#$tmp1} )
# Finally, we add all these matches with the common (unexpanded)
# pathprefix (the `-p' option), the path-prefix (the `-W' option)
# to allow the completion code to test file type, and the path-
# suffix (the `-s' option). We also tell the completion code that
# these are file names and that `fignore' should be used as usual
# (the `-f' and `-F' options).
if [[ -n "$menu" ]]; then
compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
-i "$IPREFIX" -I "$ISUFFIX" -p "$linepath${testpath:q}" \
-s "/${ostr#*/}" \
-W "$tmp1" -f "$ignore[@]" - "${(@)${(@)collect%%/*}:q}"
else
for i in $collect; do
compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
-i "$IPREFIX" -I "$ISUFFIX" \
-p "$linepath${testpath:q}" -s "/${${i#*/}:q}" \
-M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${${i%%/*}:q}"
done
fi
# We have just finished handling all the matches from above, so we
# can continue with the next `-W' path.
continue 2
fi
# We reach this point if only one of the path prefixes in `tmp1'
# has a existing path-suffix matching the string from the line.
# In this case we accept this match and continue with the next
# path-name component.
tmp1=( "$collect[1]" )
elif [[ -n "$_comp_correct" && "$mflags" = "$matchflags" ]]; then
# If we got only one match with auto-correction and if we get none
# without correction, stop now.
tmp2="${prepath}${realpath}${testpath}${~origflags}${str%%/*}(-/)"
tmp2=( $~tmp2 )
if [[ $#tmp1 -ne $#tmp2 ]]; then
compadd -QU "$addpfx[@]" -S '' "$group[@]" "$expl[@]" \
-i "$IPREFIX" -I "$ISUFFIX" \
-p "$linepath${testpath:q}" -s "/${ostr#*/}" \
- "${${tmp1#${prepath}${realpath}${testpath}}:q}"
continue 2
tmp1=( "${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}" )
fi
elif (( ! $#tmp1 )); then
[[ "$tmp1[1]" = */* ]] &&
exppaths=( "$exppaths[@]" ${^tmp1%/*}/${tpre}${tsuf} )
continue 2
fi
# This is also reached if the first globbing produced only one match
# in this case we just continue with the next pathname component, too.
tmp1="$tmp1[1]"
testpath="$testpath${tmp1##*/}/"
str="$rest"
ostr="${ostr#*/}"
# Step over to the next component, if any.
if [[ "$tpre" = */* ]]; then
tpre="${tpre#*/}"
elif [[ "$tsuf" = */* ]]; then
tpre="${tsuf#*/}"
tsuf=""
else
break
fi
# There are more components, so add a slash to the files we are
# collecting.
tmp1=( ${^tmp1}/ )
done
# We are here if all pathname components except the last one (which is still
# not tested) are unambiguous. So we add matches with the full path prefix,
# no path suffix, the `-W' we are currently handling, all the matches we
# can produce in this directory, if any.
# The next loop searches the first ambiguous component.
if [[ -n "$_comp_correct" && "${#ostr#*/}" -le _comp_correct ]]; then
mflags="$origflags"
else
mflags="$matchflags"
fi
tmp1="$prepath$realpath$testpath"
suffixes=( $str$^pats )
suffixes=( "${(@)suffixes:gs.**.*.}" )
tmp2=( ${~tmp1}${~matchflags}${~suffixes} )
if [[ "$tmp1" = */* && "$patlast" != \*/* ]]; then
tmp2=("${(@M)tmp2:#*${~patlast}}")
else
tmp2=("${(@M)tmp2:#$~patlast}")
fi
if [[ $#tmp2 -eq 0 ]]; then
# No match, insert the expanded path and add the original tail.
tmp3="$pre$suf"
tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" )
[[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]"
[[ -z "$testpath" && "$linepath[-1]" = / ]] && linepath="$linepath[1,-2]"
[[ -n "$ostr" && -n "$linepath$testpath" ]] && ostr="/$ostr"
while true; do
# But only if something changed.
[[ "${PREFIX}${SUFFIX}" = $linepath$testpath$ostr(|/) ]] && return 1
# First we check if some of the files match the original string
# for this component. If there are some we remove all other
# names. This avoid having `foo' complete to `foo' and `foobar'.
compadd -QU -S '' "$group[@]" "$expl[@]" \
-i "$IPREFIX" -I "$ISUFFIX" -f - "$linepath${testpath:q}$ostr"
else
compadd -QU "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" "$group[@]" "$expl[@]" \
-i "$IPREFIX" -I "$ISUFFIX" \
-p "$linepath${testpath:q}" -f "$ignore[@]" \
-W "$prepath$realpath$testpath" - "${(@)${(@)tmp2#$tmp1}:q}"
if [[ "$tmp3" = */* ]]; then
tmp4=( "${(@M)tmp1:#${tmp3%%/*}/*}" )
if (( $#tmp4 )); then
tmp1=( "$tmp4[@]" )
fi
fi
# Next we see if this component is ambiguous.
if [[ "$tmp3" = */* ]]; then
tmp4=( "${(@)tmp1:#${tmp1[1]%%/*}/*}" )
else
tmp4=( "${(@)tmp1:#${tmp1[1]}}" )
fi
if (( $#tmp4 )); then
# It is. For menucompletion we now add the possible completions
# for this component with the unambigous prefix we have built
# and the rest of the string from the line as the suffix.
# For normal completion we add the rests of the filenames
# collected as the suffixes to make the completion code expand
# it as far as possible.
if [[ -n $menu ]]; then
if [[ "$tmp3" = */* ]]; then
compadd -Uf -p "$linepath$testpath" -s "/${tmp3#*/}" \
-W "$prepath$realpath$testpath" "$ignore[@]" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
"$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
- "${(@)tmp1%%/*}"
else
compadd -Uf -p "$linepath$testpath" \
-W "$prepath$realpath$testpath" "$ignore[@]" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
"$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
- "$tmp1[@]"
fi
else
if [[ "$tmp3" = */* ]]; then
for i in "$tmp1[@]"; do
compadd -Uf -p "$linepath$testpath" -s "/${i#*/}" \
-W "$prepath$realpath$testpath" "$ignore[@]" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" -M 'r:|/=* r:|=*' \
"$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
- "${i%%/*}"
done
else
compadd -Uf -p "$linepath$testpath" \
-W "$prepath$realpath$testpath" "$ignore[@]" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
"$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
- "$tmp1[@]"
fi
fi
tmp4=-
break
fi
# If we have checked all components, we stop now and add the
# strings collected after the loop.
if [[ "$tmp3" != */* ]]; then
tmp4=""
break
fi
# Otherwise we add the unambiguous component to `testpath' and
# take it from the filenames.
testpath="${testpath}${tmp1[1]%%/*}/"
tmp1=( "${(@)tmp1#*/}" )
tmp3="${tmp3#*/}"
done
if [[ -z "$tmp4" ]]; then
compadd -Uf -p "$linepath$testpath" \
-W "$prepath$realpath$testpath" "$ignore[@]" \
"$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
"$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
- "$tmp1[@]"
fi
done
# If no matches were found but we have expanded paths which are different
# from the original string, use them.
# If we are configured to expand paths as far as possible and we collected
# expanded paths that are different from the string on the line, we add
# them as possible matches.
exppaths=( "${(@)exppaths:#$orig}" )
if [[ -n "$compconfig[path_expand]" &&
nm -eq compstate[nmatches] && $#exppaths -ne 0 ]]; then
compadd -UQ -S '' "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" - \
"${linepath}${(@)^exppaths}"
$#exppaths -ne 0 && nm -eq compstate[nmatches] ]]; then
compadd -U -S '' "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" - \
"${(@)exppaths}"
fi
# This sets the return value to indicate that we added matches (or not).
[[ nm -ne compstate[nmatches] ]]
[[ nm -eq compstate[nmatches] ]]

View file

@ -9,24 +9,17 @@
#
# _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
# Get the options.
group=()
@ -42,7 +35,7 @@ shift OPTIND-1
# Get the string from the line.
str="$PREFIX$SUFFIX"
[[ $#compstate[pattern_match] -ne 0 ]] || str="$str:q"
SUFFIX=""
prefix=""
# Walk through the arguments to find the longest unambiguous prefix.
@ -56,61 +49,49 @@ 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.
# Get the matching array elements.
test="${str%%${sep}*}"
[[ -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%%${sep}*}"
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)"
[[ "${compstate[pattern_match]-*}" != \** ]] && test="$test:gs/*//"
test="${matchflags}${test}"
testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
testarr=( "${(@)testarr:#}" )
PREFIX="$str"
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=("")
@ -118,26 +99,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)"
[[ "${compstate[pattern_match]-*}" != \** ]] && test="$test:gs/*//"
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.
@ -146,26 +119,31 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do
tmparr=( ${=arr[2,-2]} )
arr=tmparr
fi
tmparr=( "${(@M)${(@P)arr}:#${~test}*}" )
tmparr=( "${(@)tmparr:#}" )
compadd -O tmparr - "${(@P)arr}"
suffixes=("${(@)^suffixes[@]}${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")
# If we have collected matching specifications, we build an array
# from it that can be used as arguments to `compadd'.
[[ $#matchers -gt 0 ]] && matchers=(-M "$matchers")
# Add the matches for each of the suffixes.
for i in "$suffixes[@]"; do
compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \
-i "$IPREFIX" -I "$ISUFFIX" -p "$prefix" -s "$i" - "$testarr[@]"

View file

@ -1,25 +1,23 @@
# Initialisation for new style completion. This mainly contains some helper
# function and aliases. Everything else is split into different files in this
# directory that will automatically be made autoloaded (see the end of this
# file).
# functions and aliases. Everything else is split into different files that
# will automatically be made autoloaded (see the end of this file).
# The names of the files that will be considered for autoloading have to
# start with a underscores (like `_setopt).
# start with an underscores (like `_setopt).
# The first line of these files will be read and has to say what should be
# done with its contents:
#
# `#defcomp <names ...>'
# if the first line looks like this, the file is
# autoloaded as a function and that function will
# be called to generate the matches when completing
# for one of the commands whose <name> is given
# `#compdef <names ...>'
# If the first line looks like this, the file is autoloaded as a
# function and that function will be called to generate the matches
# when completing for one of the commands whose <names> are given.
#
# `#defpatcomp <pattern>'
# this defines a function that should be called to generate
# matches for commands whose name matches <pattern>; note
# that only one pattern may be given
# `#compdef -p <pattern>'
# This defines a function that should be called to generate matches
# for commands whose name matches <pattern>. Note that only one pattern
# may be given.
#
# `#defkeycomp <style> [ <key-sequence> ... ]
# this is used to bind special completions to all the given
# `#compdef -k <style> [ <key-sequence> ... ]
# This is used to bind special completions to all the given
# <key-sequence>(s). The <style> is the name of one of the built-in
# completion widgets (complete-word, delete-char-or-list,
# expand-or-complete, expand-or-complete-prefix, list-choices,
@ -41,11 +39,6 @@
# were able to add matches and non-zero otherwise.
#
# See the file `compdump' for how to speed up initialisation.
#
# If you are using global matching specifications with `compctl -M ...'
# have a look at the files `_match_test' and `_match_pattern'. To make
# all the example functions use matching as specified with `-M' these
# need some editing.
# If we got the `-d'-flag, we will automatically dump the new state (at
# the end).
@ -220,17 +213,34 @@ compdef() {
# and sets the according values in `compconfig'.
# Arguments may be `foo=bar' to set key `foo' to `bar' or `baz' to
# set key `baz' to the empty string.
# If no arguments are given, all configurations keys set are displayed.
# With the option `-l' as the first argument, the other arguments are
# taken to be key names and the values for theses keys are printed, one
# per line.
compconf() {
local i
for i; do
if [[ "$i" = *\=* ]]; then
compconfig[${i%%\=*}]="${i#*\=}"
if (( $# )); then
if [[ "$1" = -l ]]; then
shift
for i; do
print $compconfig[$i]
done
else
compconfig[$i]=''
for i; do
if [[ "$i" = *\=* ]]; then
compconfig[${i%%\=*}]="${i#*\=}"
else
compconfig[$i]=''
fi
done
fi
done
else
for i in ${(k)compconfig}; do
print ${(r:25:)i} $compconfig[$i]
done
fi
}
# Now we automatically make the definition files autoloaded.
@ -262,12 +272,12 @@ if [[ -z "$_i_done" ]]; then
read -rA _i_line < $_i_file
_i_tag=$_i_line[1]
shift _i_line
if [[ $_i_tag = '#defcomp' ]]; then
compdef -na "${_i_file:t}" "${_i_line[@]}"
elif [[ $_i_tag = '#defpatcomp' ]]; then
compdef -pa "${_i_file:t}" "${_i_line[@]}"
elif [[ $_i_tag = '#defkeycomp' ]]; then
compdef -ka "${_i_file:t}" "${_i_line[@]}"
if [[ $_i_tag = '#compdef' ]]; then
if [[ $_i_line[1] = -[pk] ]]; then
compdef ${_i_line[1]}a "${_i_file:t}" "${(@)_i_line[2,-1]}"
else
compdef -na "${_i_file:t}" "${_i_line[@]}"
fi
elif [[ $_i_tag = '#autoload' ]]; then
autoload ${_i_file:t}
fi

View file

@ -1,356 +1,3 @@
The subdirectories contain code for the new function-based completion
system. Broadly speaking, this uses shell functions defined for each
command to determine how the arguments of a command should be completed.
You should copy all the files you need or want to a directory of your own,
which should be included in your autoload path as defined by $fpath. Then
in your .zshrc you should source the file which appears here in
Core/compinit. It is recommnded that you use the -d option, which outputs
a file containing the necessary variables, bindkeys etc., making later
loading much faster. For example,
[[ -f ~/completion/compinit ]] && . ~/completion/compinit -d
The name of the file to use may be given as an extra argument.
This will rebind any keys which do completion to use the new system.
For more detailed instructions, including how to add new completions, see
the top of Core/compinit. For information about how to configure the code,
see the section below.
The subdirectories contain:
Core:
The basic functions and files to be sourced. You will certainly need
these, and will most likely not want to alter them --- if you do, it
would probably help to give your version a different name. The files
are:
compinit
As already described, this is not a function, but is sourced once
(with the `source' or `.' commands) to set up the completion system.
compdump
This dumps the completions status for faster initialisation. The
easiest way of doing this is to use the -d option to compinit rather
than calling compdump directly.
_approximate
A completer function that does correcting completion.
_compalso
Utility for calling a function to add additional completions to an
already existing set.
_complete
The main completer function that generates the completions by calling
the context and command specific functions.
_correct
A completer function that attempts correction on the word from the
line. Unlike _approximate this does only correction, not completion.
_expand
A completer function for expanding the word on the line.
_files
A frontend to _path_files which will default to any old file if the
specified file was not found.
_list
A completer function that allows showing only a list on the first
TAB and insert completions on the second one.
_match
A completer function that temporarily swicthes on pattern matching
when comparing the string from the line with possible completions.
_main_complete
The main entry point called by the key bindings which compinit sets
up (the main `completion widget' in zsh jargon). This mainly calls
completer functions like _complete, either those given as arguments
or (if it is called without arguments) those from the completer
configuration key (see below).
_multi_parts
Utility for completion parts of words given a separator character and
a list of words.
_normal
The function called by _main_complete to handle the most common
cases, such as completing a command name or its arguments. This
function dispatches to the various other functions for individual
commands. (Actually, the system is fairly context-sensitive, so
it is wider than just command+argument.)
_options
Utility to complete option names, allowing the optional `no' prefix
and correctly handling upper case letters and underscores.
_parameters
This can be used to complete parameter names if you need some of the
options of compadd not supported by compgen.
_path_files
The function usually called to complete filenames and directories. It
replaces the standard -f, -g and -/ options for the basic completion
commands: it can do various extra tricks, such as expanding a whole
path at once, e.g. F/C/C/_p<TAB> -> Functions/Completion/Core/_path_files
_sep_parts
Utility used for completing words with multiple separate parts, such as
`<user>@<host>'
_set_options
_unset_options
These can be used to complete only set or unset options. For this to
work, you'll have to un-comment a few lines in _main_complete.
Base:
You will almost certainly want these files, too, which handle standard
tasks like completing files. However, you may want to edit them for
your own particular setup. Files are:
_command_names
This handles completion of the command word, i.e. the first thing
on the command line. You may want to alter this, for example,
to complete parameters to assign to.
_condition
This handles completing inside [[ ... ]] .
_default
This handles completion of command arguments when no special function
exists. Usually this means completing files, but you can modify this
as you wish.
_long_options
This handles options beginning with `--', as in many GNU commands.
The command must accept the --help option to list the possible options.
__long_options can also take arguments to help it decide what to
complete as the value of the option. Note that this is potentially
dangerous because the command from the line will be called with the
--help option and hence could cause damage if used with a command
that does not support it.
_match_pattern
_match_test
These are used by Base/_path_files (and hence also Base/_files)
and Base/_sep_parts for file completion with control over
matching (whether to complete case-insensitively, or to allow
insertion before `.', etc.) See _match_test for instructions.
Note _path_files expects these files to be present.
_precommand
Allows completion when the first word on the line has to be ignored,
for example `noglob ...' should ignore the noglob and just complete
as if it wasn't there. Add other such commands to the top line.
_redirect
Completes after `<' or `>': this version calls _files.
_subscript
For completion in subscripts of parameters, e.g $foo[...].
_vars
Completion for commands which need variables (so this could also be in
the Builtins directory), but also in math environments such as ((...)).
_tilde
Completion after `~', defaults to user names and named directories.
_equal
Completion after `=', normally command and alias names are used.
_parameter
_brace_parameter
For completion inside parameter expansions ($... and ${...).
Builtins:
Define completions for various shell builtins. The top line of each file
says which builtins they apply to; in many cases you can guess from the
name. Note in particular that _zftp defines completions for all commands
beginning `zf', not just for the module command zftp. This is only
really useful if you use zftp with the zf* function suite (zfopen, zfget,
...).
User:
This contains a pot pourri of completions for various external commands.
Not all will work unmodified on your system.
Commands:
These functions define separate completion commands which do not use
the usual context information, and hence have to be bound separately
to keys. As they appear, they have bindings which you can change or
delete by altering the top line of the file. To bind a function
(strictly speaking, the corresponding completion widget) yourself
after completion is loaded, use `bindkey '<key-string>' <_function_name>'.
The files are:
_correct_filename, bound to \C-xc
Correct the word under the cursor as a filename. This is significantly
more powerful than the standard \e$ (spell-word) binding.
_most_recent_file, bound to \C-xm
Insert the name of the most recent file matching the pattern
so far on the command line.
Configuration
You can configure several aspects of the completion functions and the
overall completion behavior using the compconf shell function defined
in compinit. This function gets any number of arguments of the form
`key=value', where `key' is one of the keys described below and `value'
is any string. Most configuration keys are defined by the completer
functions.
The completion widget function _main_complete currently understands
one configuration key:
completer
This should be set to the names of the functions to generate the
matches separated by colons. E.g. with
compconf completer=_complete:_correct:_approximate
the code will first try normal completion. If that doesn't yield
any matches, correction is tried and if that doesn't yield
anything either, correcting completion is attempted.
The keys understood by the _approximate completer function are:
approximate_accept
This should be set to a number, specifying the maximum number
of errors that should be accepted. If the string also contains
a `n' or `N', the code will use the numeric argument as the
maximum number of errors if a numeric argument was given. If no
numeric argument was given, the number from the value of this
key will be used. E.g. with `compconf approximate_accept=2n' two
errors will be accepted, but if the user gives another number
with the numeric argument, this will be prefered. Also, with
`compconf approximate_accept=0n', normally no correction will be
tried, but if a numeric argument is given, automatic correction
will be used. On the other hand, if the string contains an `!'
and a `n' or `N', correction is not attempted if a numeric
argument is given. Once the number of errors to accept is
determined, the code will repeatedly try to generate matches by
allowing one error, two errors, and so on. Independent of the
number of errors the user wants to accept, the code will allow
only fewer errors than there are characters in the string from
the line.
approximate_original
This value is used to determine if the original string should
be included in the list (and thus be presented to the user when
cycling through the corrections). If it is set to any non-empty
value, the original string will be offered. If it contains the
sub-string `last', the original string will appear as the last
string when cycling through the corrections, otherwise it will
appear as the first one (so that the command line does not
change immediately). Also, if the value contains the sub-string
`always', the original string will always be included, whereas
normally it is included only if more than one possible
correction was generated.
approximate_prompt
This can be set to a string that should be printed before the
list of corrected strings when cycling through them. This string
may contain the control sequences `%n', `%B', etc. known from
the `-X' option of `compctl'. Also, the sequence `%e' will be
replaced by the number of errors accepted to generate the
corrected strings.
approximate_insert
If this is set to a string starting with `unambig', the code
will try to insert a usable unambiguous string in the command
line instead of always cycling through the corrected strings.
If such a unambiguous string could be found, the original
string is not used, independent of the setting of
`approximate_original'. If no sensible string could be found,
one can cycle through the corrected strings as usual.
If any of these keys is not set, but the the same key with the
prefix `correct' instead of `approximate' is set, that value will
be used. The forms beginning with `correct' are also used by the
_correct completer function, and this function uses only them, not
the ones starting with `approximate'. This allows one to give
different value to be used with correction and correcting
completion. For example, with:
compconf completer=_complete:_correct:_approximate
compconf correct_accept='2n!' approximate_accept=3n
correction will accept up to two errors. If a numeric argument is
given, correction will not be used, but correcting completion will
and it will accept as many errors as given by the numeric argument.
Without a numeric argument first correction and then correcting
completion will be tried, with the first one accepting two errors
and the second one accepting three errors.
The _match completer function, which allows to give patterns on the
command line and complete all strings matching it from the set of
possible completions, understands the following key:
match_original
If this is set to a `only', pattern matching will only be tried
with the string from the line. If it is set to any other non-empty
string, the original pattern will be tried first and if that yields
no completions, matching will be tried again with a `*' inserted
at the cursor position. If this key is not set or set to an empty
string, matching will only be attempted with the `*' inserted.
The _expand completer allows one to do expansion on the word from the
line. Note that you may either want to use the configuration keys or
not use this completer at all if you also use the _match completer
because the _expand completer will otherwise expand patterns before
they are seen by the _match completer.
Configuration keys supported are:
expand_substitute
If this is unset or set to the empty string, the code will first
try to expand all substitutions in the string (such as $(...) and
${...}). If this is set to an non-empty string it should be
an expression usable inside a $[...] arithmetical expression.
In this case, expansion of substitutions will be done if the
expression evaluates to `1'. For example, with
compconf expand_substitute='NUMERIC != 1'
substitution will be performed only if given an explicit numeric
argument other than `1', as by typing ESC 2 TAB.
expand_glob
If this is unset or set to an empty string, globbing will be
attempted on the word resulting from substitution or the
original string. The values accepted for this key are the same
as for expand_substitute.
expand_menu
If this is unset or set to the empty string, the words resulting
from expansion (if any) will simply be inserted in the ommand line,
replacing the original string. However, if this key is set to an
non-empty string, the user can cycle through the expansion as in
a menucompletion. Unless the value contains the sub-string `only',
the user will still be offered all expansions at once as one of
the strings to insert in the command line. Also, if the value
contains the sub-string `last', the string with all expansion will
be offered first, whereas normally it is offered as the last string
to insert. Finally, if the value contains the sub-string `sort',
the expansions will be sorted alphabetically, normally they are
kept in the order the expansion produced them in.
expand_original
If this is set to an non-empty string, the original string from the
line will be included in the list of strings the user can cycle
through as in a menucompletion. If the value contains the sub-string
`last', the original string will appear as the last string, with
other values it is inserted as the first one (so that the command
line does not change immediatly).
expand_prompt
This may be set to a string that should be displayed before the
possible expansions. This is given to the -X option and thus may
contain the control sequences `%n', `%B', etc. Also, the sequence
`%o' in this string will be replaced by the original string.
The _list completer allows one to delay the insertion of matches until
completion is attempted a second time without the word on the line
being changed. On the first attempt, only the list of matches will
be shown. Configuration keys understood are:
list_condition
If this key is unset or set to the empty string, this completer
will delay the insertion of matches unconditionally. However,
if this value is set, it should be set to an expression usable
inside a $[...] arithmetical expression. In this case, delaying
will be done if the expression evaluates to `1'.
For example, with
compconf list_condition='NUMERIC != 1'
delaying will be done only if given an explicit numeric argument
other than `1'.
list_word
To find out if only listing should be done, the code normally
compares the contents of the line with the contents the line
had at the time of the last invocation. If this key is set to
an non-empty string comparison is done using only the current
word. So if it is set, attempting completion on a word equal
to the one completion was called on the last time will not
delay the generation of matches.
For more information about what the completers do, see the files
containing them (_complete, _correct, _approximate, _match, and
_expand in the Core directory).
The _path_files function used to complete filenames has one
configuration key:
path_expand
If this is set to a non-empty string, the partially typed path
from the line will be expanded as far as possible even if trailing
pathname components can not be completed.
The subdirectories contain code for a shell-based system of command-line
completion. This is considerably more powerful than the old `compctl'
method. For details, see the compsys(1) manual page (`man zshcompsys').

View file

@ -1,4 +1,4 @@
#defcomp a2ps
#compdef a2ps
# This is for the GNU version of a2ps.

View file

@ -1,3 +1,3 @@
#defcomp compress
#compdef compress
_files -g '*~*.Z'

View file

@ -1,4 +1,9 @@
#defcomp configure
#compdef configure
_long_options '*=(E|)PREFIX*' '_files -/' \
_long_options -i '(--(disable|enable)-FEATURE* --(with|without)-PACKAGE*)' \
-s '(#--disable- --enable-
#--enable- --disable-
#--with- --without-
#--without- --with-)' \
'*=(E|)PREFIX*' '_files -/' \
'*=PROGRAM*' '_command_names'

View file

@ -1,4 +1,4 @@
#defcomp dd
#compdef dd
if compset -P 1 'conv\='; then
# If there's a comma present, ignore up to the last one. The

View file

@ -1,3 +1,3 @@
#defcomp xdvi dvips dvibook dviconcat dvicopy dvidvi dviselect dvitodvi dvitype
#compdef xdvi dvips dvibook dviconcat dvicopy dvidvi dviselect dvitodvi dvitype
_files -g '*.(dvi|DVI)'

View file

@ -1,4 +1,4 @@
#defcomp find
#compdef find
local prev="$words[CURRENT-1]"

View file

@ -1,3 +1,3 @@
#defcomp gunzip zcat
#compdef gunzip zcat
_files -g '*.[gG][z]'

View file

@ -1,3 +1,3 @@
#defcomp gzip
#compdef gzip
_files -g '*~*.[gG][zZ]'

View file

@ -1,3 +1,3 @@
#defcomp ftp ncftp ping rwho rup xping traceroute nslookup
#compdef ftp ncftp ping rwho rup xping traceroute nslookup
compgen -k hosts

View file

@ -1,3 +1,3 @@
#defcomp make gmake pmake
#compdef make gmake pmake
compgen -s "\$(awk '/^[a-zA-Z0-9][^/ ]+:/ {print \$1}' FS=: [mM]akefile)"
compgen -s "\$(awk '/^[a-zA-Z0-9][^\/ ]+:/ {print \$1}' FS=: [mM]akefile)"

View file

@ -1,4 +1,4 @@
#defcomp man
#compdef man
setopt localoptions rcexpandparam

View file

@ -1,4 +1,4 @@
#defcomp folder folders comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath
#compdef folder folders comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath
# Completion for all possible MH commands.
# Alter the following two to your own mh directory and the directory

View file

@ -1,3 +1,3 @@
#defcomp acroread
#compdef acroread
_files -g '*.(pdf|PDF)'

View file

@ -1,3 +1,3 @@
#defcomp gs ghostview gview psnup psselect pswrap pstops pstruct lpr
#compdef gs ghostview gview psnup psselect pswrap pstops pstruct lpr
_files -g '*([pP][sS]|eps)'

View file

@ -1,4 +1,4 @@
#defcomp co ci rcs
#compdef co ci rcs
local nm=$compstate[nmatches]

View file

@ -1,4 +1,4 @@
#defcomp rlogin rsh ssh
#compdef rlogin rsh ssh
if [[ CURRENT -eq 2 ]]; then
compgen -k hosts

View file

@ -1,3 +1,3 @@
#defcomp strip
#compdef strip
_files -g '*(*)'

View file

@ -1,4 +1,4 @@
#defcomp stty
#compdef stty
if [[ "$words[CURRENT-1]" = \
(*erase|discard|status|dsusp|intr|kill|lnext|quit|reprint|start|s*p) ]]

View file

@ -1,4 +1,4 @@
#defcomp tar
#compdef tar
# Tar completion. Features:
# - Tries to collect tar commands from second position, single letter

View file

@ -1,3 +1,3 @@
#defcomp tex latex slitex
#compdef tex latex slitex
_files -g '*.(tex|TEX|texinfo|texi)'

View file

@ -1,3 +1,3 @@
#defcomp uncompress zmore
#compdef uncompress zmore
_files -g '*.Z'

View file

@ -1,4 +1,4 @@
#defpatcomp */X11/*
#compdef -p */X11/*
# A simple pattern completion, just as an example.

View file

@ -1,3 +1,3 @@
#defcomp xfig
#compdef xfig
_files -g '*.fig'

View file

@ -27,5 +27,5 @@
# This must also serve as a shell script, so do not add spaces around the
# `=' signs.
VERSION=3.1.5-pws-14
VERSION_DATE='March 26, 1999'
VERSION=3.1.5-pws-15
VERSION_DATE='April 13, 1999'

View file

@ -38,7 +38,7 @@ TEXI2HTML = texi2html -expandinfo -split_chapter
.SUFFIXES: .yo .1
# man pages to install
MAN = zsh.1 zshbuiltins.1 zshcompctl.1 zshcompwid.1 \
MAN = zsh.1 zshbuiltins.1 zshcompctl.1 zshcompwid.1 zshcompsys.1 \
zshexpn.1 zshmisc.1 zshmodules.1 \
zshoptions.1 zshparam.1 zshzle.1 zshall.1
@ -48,7 +48,7 @@ YODLSRC = zmacros.yo zman.yo ztexi.yo Zsh/arith.yo Zsh/builtins.yo \
Zsh/compat.yo Zsh/compctl.yo Zsh/cond.yo Zsh/exec.yo Zsh/expn.yo \
Zsh/filelist.yo Zsh/files.yo Zsh/func.yo Zsh/grammar.yo Zsh/guide.yo \
Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/metafaq.yo \
Zsh/modules.yo Zsh/mod_cap.yo Zsh/compwid.yo \
Zsh/modules.yo Zsh/mod_cap.yo Zsh/compwid.yo Zsh/compsys.yo \
Zsh/mod_clone.yo Zsh/mod_comp1.yo Zsh/mod_compctl.yo Zsh/mod_deltochar.yo \
Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_stat.yo \
Zsh/mod_zle.yo Zsh/options.yo \
@ -115,6 +115,8 @@ zshcompctl.1: Zsh/compctl.yo
zshcompwid.1: Zsh/compwid.yo
zshcompsys.1: Zsh/compsys.yo
zshexpn.1: Zsh/expn.yo
zshmisc.1: Zsh/grammar.yo Zsh/redirect.yo Zsh/exec.yo Zsh/func.yo \

View file

@ -449,7 +449,8 @@ be shown if there was at least one match added for the explanation
string.
The sequences tt(%B), tt(%b), tt(%S), tt(%s), tt(%U), and tt(%u) specify
output attributes (bold, standout, and underline) as in prompts.
output attributes (bold, standout, and underline) and tt(%{...%}) can
be used to include literal escape sequences as in prompts.
)
item(tt(-Y) var(explanation))(
Identical to tt(-X), except that the var(explanation) first undergoes

691
Doc/Zsh/compsys.yo Normal file
View file

@ -0,0 +1,691 @@
texinode(Completion System)()(Zsh Modules)(Top)
chapter(Completion System)
cindex(completion, system)
cindex(completion, programmable)
cindex(completion, controlling)
sect(Description)
This describes the shell code for the new completion system. It consists
of two scripts and a few other files that define shell functions.
The shell functions which implement completion behaviour and which may
be bound to keystrokes, are referred to as `widgets'. All are contained
in the following subdirectories of the tt(Completion) directory of the main
distribution directory.
startitem()
item(tt(Core))(
The core scripts and functions. You will certainly need these, though will
probably not need to alter them. The contents of this directory is
described in more detail below.
)
item(tt(Base))(
Other functions you will almost certainly want if you are going to use
any of the standard completion functions. You may want to edit some of
these files.
)
item(tt(Builtins))(
Functions for completing arguments of shell builtin commands.
)
item(tt(User))(
Functions for completing arguments of external commands and suites of
commands. They may need modifying for your system.
)
item(tt(Commands))(
Functions which implement special types of completion to be bound to
keystrokes rather than called by context.
)
enditem()
You should decide which files you will be using and copy them to a
directory (or multiple directories) of your own which should appear in your
tt($fpath) variable so that the functions can be autoloaded.
startmenu()
menu(Initialisation)
menu(Control Functions)
menu(Completion Functions)
endmenu()
texinode(Initialisation)(Control Functions)()(Completion System)
sect(Initialisation)
To initialise the system, the script tt(compinit) should be sourced with
`tt(source )var(<path>)tt(/compinit)' or
`tt(. )var(<path>)tt(/compinit)'. This will define a few utility functions,
arrange for all the necessary shell functions to be autoloaded, and will
then re-bind all keys that do completion to use the new system.
subsect(Arguments)
To speed up the running of tt(compinit), it can be made to produce a dumped
configuration which will be read in on future invocations. The easiest way
to do this is by adding the option tt(-d) whenever tt(compinit) is sourced.
In this case the dumped file will have the same name as the sourced file,
but with tt(.dump) appended to the end; alternatively, an explicit file
name can be given following the tt(-d). On the next call to tt(compinit
-d), the dumped file will be read instead.
If the number of completion files changes, tt(compinit) will recognise this
and produce a new dump file. However, if the name of a function or the
arguments in the first line of a tt(#compdef) funcion (as described below)
change, it is easiest to delete the dump file by hand so that the next time
tt(compinit) will re-create it.
The dumping is actually done by another script, tt(compdump), but you will
only need to source this yourself if you change the configuration
(e.g. using tt(compdef)) and then want to dump the new one. The name of
the old dumped file will be remembered for this.
subsect(Autoloaded files)
The convention for autoloaded functions used in completion is that they
start with an underscore; as already mentioned, the tt(fpath/FPATH)
parameter must contain the directory in which they are stored. When
tt(compinit) is sourced, it searches all such files accessible via
tt(fpath/FPATH) and reads the first line of each of them. This line should
contain one of the tags described below. Files whose first line does not
start with one of these tags are not considered to be part of the
completion system and will not be treated specially.
The tags are:
startitem()
item(tt(#compdef) var(names...))(
The file will be made autoloadable and the function defined
in it will be called when completing var(names), each of which is
either the name of a command whose arguments are to be completed or one of
a number of special contexts in the form tt(-)var(context)tt(-) described
below for the tt(_complete) function.
)
item(tt(#compdef -p) var(pattern))(
The file will be made autoloadable and the function defined in it will be
called when completing for a command whose name matches the given
var(pattern) (a standard globbing pattern). Note that only one
var(pattern) may be given.
)
item(tt(#compdef -k) var(style key-sequences...))(
This can be used bind special completion functions to the
var(key-sequences). It creates a widget behaving like the builtin widget
var(style), which must be one of those that perform completion, namely
tt(complete-word), tt(delete-char-or-list), tt(expand-or-complete),
tt(expand-or-complete-prefix), tt(list-choices), tt(menu-complete),
tt(menu-expand-or-complete), or tt(reverse-menu-complete).
The widget is then bound to all the var(key-sequences) given, if any: when
one of the var(key-sequences) is typed, the function in the file will
be invoked to generate the matches. The widget created has the same
name as the file and can also be bound to other keys using tt(bindkey)
as usual.
)
item(tt(#autoload))(
This is used for files defining utility function that are not to be
called directly as completion functions but should be loaded automatically
when invoked. Typically they are to be called from within one of the
completion functions.
)
enditem()
Note that the tt(#) is part of the tag name and no white space is allowed
after it. The tt(#compdef) tags use the tt(compdef) function defined
below; the main difference is that the name of the function is supplied
implicitly.
subsect(Functions)
The tt(compinit) file defines the following functions, which may
also be called directly by the user.
startitem()
xitem(tt(compdef) [ tt(-an) ] var(function names...))
xitem(tt(compdef -d) var(names...))
xitem(tt(compdef -p) [ tt(-a) ] var(function pattern))
item(tt(compdef -k) [ tt(-a) ] var(function style key-sequences...))(
The first form tells the completion system to call the given
var(function) when completing for the contexts or commands
whose var(names) are given: this is like the tt(#compdef) tag. If the
tt(-n) option is given, any existing completion behaviour for particular
contexts or commands will not be altered. These definitions can be deleted
by giving the tt(-d) option as in the second form.
The third form is similar to the first, but var(function) will be called
for all commands whose name matches the var(pattern); this is like the
tt(#compdef -p) function tag.
The fourth form defines a widget with the same name as the var(function)
which will be called for each of the var(key-sequences); this is like the
tt(#compdef -k) tag. The function should generate the completions needed
and will otherwise behave like the builtin widget whose name is given as
the var(style) argument. The widgets usable for this are:
tt(complete-word), tt(delete-char-or-list), tt(expand-or-complete),
tt(expand-or-complete-prefix), tt(list-choices), tt(menu-complete),
tt(menu-expand-or-complete), and tt(reverse-menu-complete).
In each of the forms supporting it the tt(-a) option makes the
var(function) autoloadable (exactly equivalent to
tt(autoload )var(function)).
)
xitem(tt(compconf) var(definitions...))
xitem(tt(compconf))
item(tt(compconf) [ tt(-l) ] var(keys...))(
Several aspects of the completion system can be configured by the
user. The configuration values are stored under the keys described
below in the associative array `tt(compconfig)'. After sourcing
tt(compinit), configuration values can either be set directly as in
`tt(compconfig[completer]=_complete)' or by calling this utility function.
Each var(definition) may be either a simple `var(key)', which sets this
key in the tt(compconfig) array to an empty string, or of the form
`var(key=value)' which stores the `var(value)' under key `var(key)'.
Since the completion system also uses the array for internal purposes,
you should not set all values at once by doing `tt(compconfig=(...))'.
In the second form (without arguments), this function lists all keys
and their values. If given the tt(-l) option as its first argument, as
in the last form, the other arguments are taken as names of keys and
the values of these keys are printed one per line.
)
enditem()
texinode(Control Functions)(Completion Functions)(Initialisation)(Completion System)
sect(Control Functions)
The initialisation script tt(compinit) re-binds all the keys which perform
completion to newly created widgets that all call the supplied widget
function tt(_main_complete). This function acts as a wrapper calling
the so-called `completer' functions that generate matches. If
tt(_main_complete) is
called with arguments, these are taken as the names of completer
functions to be called in the order given. If no arguments are given, the
set of functions to try is taken from the colon-separated list in the
configuration key tt(completer). For example, to use normal
completion and correction if that doesn't generate any matches:
indent(
nofill(tt(compconf completer=_complete:_correct))
)
after sourcing tt(compinit). The default value for this configuration key
set up in tt(compinit) is `tt(_complete)', i.e. normally only ordinary
completion is tried. The tt(_main_complete) function uses the return value
of the completer functions to decide if other completers should be
called. If the return value is zero, no other completers are tried and the
tt(_main_complete) function returns.
The following completer functions are contained in the distribution (users
may write their own):
startitem()
item(tt(_complete))(
This completer generates all possible completions in a context-sensitive
manner, i.e. using the tt(compdef) function
explained above and the current settings of all special parameters.
To complete arguments of commands, tt(_complete) uses the utility function
tt(_normal), which is in turn responsible for finding the particular
function; it is described below. Various contexts of the form
tt(-)var(context)tt(-), as mentioned above for the tt(#compdef) tag, are
handled specially. These are:
startitem()
item(tt(-equal-))(
for completion after an equal sign, other than one occurring in a
shell-variable assignment.
)
item(tt(-tilde-))(
for completion after a tilde (`tt(~)') character, but before a slash.
)
item(tt(-redirect-))(
for completion after a redirection operator.
)
item(tt(-math-))(
for completion inside mathematical contexts, such as
`tt(LPAR()LPAR())...tt(RPAR()RPAR())'.
)
item(tt(-subscript-))(
for completion inside subscripts.
)
item(tt(-value-))(
for completion on the right hand side of an assignment.
)
item(tt(-array-value-))(
for completion on the right hand side of an array-assignment
(`tt(foo=LPAR()...RPAR())').
)
item(tt(-condition-))(
for completion inside conditions (`tt([[...]])').
)
item(tt(-parameter-))(
for completing the name of a parameter expansion (`tt($...)').
)
item(tt(-brace-parameter-))(
for completing the name of a parameter expansion within braces
(`tt(${...})').
)
item(tt(-first-))(
for adding completions before any other other completion functions are
tried (similar to the `tt(-T)' flag of tt(compctl)); if this
function sets the tt(_compskip) parameter to any value, the completion
system will not call any other function to generate matches.
)
item(tt(-default-))(
for generating completions when no special completion function is used
(similar to the `tt(-D)' option of tt(compctl)).
)
item(tt(-command-))(
for completing in a command position (as with the `tt(-C)' option of
tt(compctl)).
)
enditem()
Default implementations are supplied for each of these
contexts, in most cases named after the context itself
(e.g. completion for the `tt(-tilde-)' context is done by the function
named `tt(_tilde)').
)
item(tt(_approximate))(
This completer function uses the tt(_complete) completer to generate
a list of strings for the context the cursor is currently in, allowing
you to specify a maximum number of errors: see the description of
approximate matching in
ifzman(\
zmanref(zshexpn)
)\
ifnzman(\
noderef(Filename Generation)
)\
for how errors are
counted. The resulting list of corrected and completed strings is then
presented to the user. The intended use of this completer function is to
try after the normal tt(_complete) completer by setting:
indent(
nofill(tt(compconf completer=_complete:_approximate))
)
This will give correcting completion if and only if
normal completion doesn't yield any possible completions. When
corrected completions are found, the completer will normally start
menucompletion allowing you to cycle through these strings.
The exact behavior of this completer can be changed by using the
following configuration keys:
startitem()
item(tt(approximate_accept))(
This should be set to the number of errors the correction code should
accept. The completer will try to generate completions by first allowing
one error, then two errors, and so on, until either a match
was found or the maximum number of errors given by this key has
been reached.
If the value for this key contains a lower- or upper-case `tt(n)', the
completer function will take any numeric argument as the
maximum number of errors allowed. For example, with
indent(
nofill(tt(compconf approximate_accept=2n))
)
two errors will be allowed if no numeric argument is given. However,
with a numeric argument of six (as in `tt(ESC-6 TAB)'), up to six
errors are accepted. Hence with a value of `tt(0n)', no correcting
completion will be attempted unless a numeric argument is given.
If the value contains `tt(n)' or `tt(N)' and a exclamation mark
(`tt(!)'), tt(_approximate) will var(not) try to generate corrected
completions when given a numeric argument, so in this case the number given
should be greater than zero. For example, `tt(2n!)' specifies that
correcting completion with two errors will usually be performed, but if a
numeric argument is given, correcting completion will not be performed.
)
item(tt(approximate_original))(
This key is used to specify whether the original string on which correcting
completion was attempted is to be included in the list of possible
corrections. If it is set to any non-empty string, the original string
will be offered when cycling through the completions. Normally it will
appear as the first string, so that the command line does not change
immediately; consecutive completion attempts will cycle through the
corrected strings. If the value for this key contains the substring
`tt(last)', the original string will be the last one in the list, so
that it appears just before wrapping around to the first corrected
string again. Also, if the value contains the substring `tt(always)',
the original string will always be included; normally it is
included only if more than one possible correction was generated.
)
item(tt(approximate_prompt))(
This can be set to a string to be displayed on top of the
corrected strings generated when cycling through them. This string
may contain the control sequences `tt(%n)', `tt(%B)', etc. known from
the `tt(-X)' option of tt(compctl). Also, the sequence `tt(%e)' will
be replaced by the number of errors accepted to generate the corrected
strings.
)
item(tt(approximate_insert))(
If this is set to a string starting with `tt(unambig)', the code will try
to insert a usable unambiguous string in the command line instead of
always cycling through the corrected strings. If such a unambiguous
string could be found, the original string is not used, independent of
the setting of tt(approximate_original). If no sensible string could be
found, one can cycle through the corrected strings as usual.
)
enditem()
If any of these keys is not set, but the the same key with the prefix
`tt(correct)' instead of `tt(approximate)' is set, that value will be
used. The forms beginning with `tt(correct)' are also used by the
tt(_correct) completer function.
The keys with the `tt(approximate)' prefix have no default values, but
tt(compinit) defines default values for tt(correct_accept) (which
is set to `tt(2n)'), and tt(correct_prompt).
)
item(tt(_correct))(
Generate corrections (but not completions) for the current word; this is
similar to spell-checking. This calls tt(_approximate), but only the
configuration parameters beginning tt(correct_) are used.
For example, with:
indent(tt(
nofill(compconf completer=_complete:_correct:_approximate)
nofill(compconf correct_accept='2n!' approximate_accept=3n))
)
correction will accept up to two errors. If a numeric argument is
given, correction will not be performed, but correcting completion will be,
and will accept as many errors as given by the numeric argument.
Without a numeric argument, first correction and then correcting
completion will be tried, with the first one accepting two errors
and the second one accepting three errors.
This completer function is intended to be used without the
tt(_approximate) completer or, as in the example, just before
it. Using it after the tt(_approximate) completer is useless since
tt(_approximate) will at least generate the corrected strings
generated by the tt(_correct) completer -- and probably more.
)
item(tt(_match))(
This completer is intended to be used after the tt(_complete)
completer. It allows one to give patterns on the command line and
to complete all strings metching these patterns from the set of possible
completions for the context the cursor is in, without having to set
the tt(GLOB_COMPLETE) option.
Normally this will be done by taking the pattern from the line,
inserting a `tt(*)' at the cursor position and comparing the resulting
pattern with the possible completions generated. However, if the
configuration key tt(match_original) has a value of `tt(only)', no
`tt(*)' will be inserted. If tt(match_original) has any other non-empty
string as its value, this completer will first try to generate matches
without, then with a `tt(*)' inserted at the cursor position.
)
item(tt(_expand))(
This completer function does not really do completion, but instead
checks if the word on the command line is eligible for expansion and,
if it is, gives detailed control over how this expansion is done. When
using this, one should not use the tt(expand-or-complete) widget, but
instead use tt(complete-word), as otherwise tt(expand-or-complete)
will expand the string on the line before the completion widget is
called. Also, this completer should be called before the tt(_complete)
completer function.
Control over how the expanded string will be treated is possible with the
following configuration keys:
startitem()
item(tt(expand_substitute))(
If this is unset or set to the empty string, the code will first try
to expand all substitutions in the string (such as
`tt($LPAR()...RPAR())' and `tt(${...})'). If this is set to an
non-empty string it should be an expression usable inside a `tt($((...)))'
arithmetical expression. In this case, expansion of substitutions will
be done if the expression evaluates to `tt(1)'. For example, with
indent(
nofill(tt(compconf expand_substitute='NUMERIC != 1'))
)
substitution will be performed only if given an explicit numeric
argument other than `tt(1)', as by typing `tt(ESC 2 TAB)'.
)
item(tt(expand_glob))(
If this is unset or set to an empty string, globbing will be attempted
on the word resulting from substitution or the original string. The
values accepted for this key are the same as for tt(expand_substitute).
)
item(tt(expand_menu))(
If this is unset or set to the empty string, the words resulting from
expansion (if any) will simply be inserted in the command line,
replacing the original string. However, if this key is set to a
non-empty string, the user can cycle through the expansion as in
menucompletion. Unless the value contains the substring `tt(only)',
the user will still be offered all expansions at once as one of the
strings to insert in the command line; normally, this possibility is
offered first, but if the value contains the
substring `tt(last)', it is offered last. Finally, if the value contains
the substring `tt(sort)', the expansions will be sorted alphabetically,
normally they are kept in the order the expansion produced them in.
)
item(tt(expand_original))(
If this is set to an non-empty string, the original string from the
line will be included in the list of strings the user can cycle
through as in a menucompletion. If the value contains the substring
`tt(last)', the original string will appear as the last string, with
other values it is inserted as the first one (so that the command line
does not change immediately).
)
item(tt(expand_prompt))(
This may be set to a string that should be displayed before the
possible expansions. This is passed to the `tt(-X)' option of
tt(compadd) and thus may contain the control sequences `tt(%n)',
`tt(%B)', etc. Also, the sequence `tt(%o)' in this string will be
replaced by the original string.
)
enditem()
None of these configuration keys has a default value.
)
item(tt(_list))(
This completer allows one to delay the insertion of matches until
completion is attempted a second time without the word on the line
being changed. On the first attempt, only the list of matches will be
shown. Configuration keys understood are:
startitem()
item(tt(list_condition))(
If this key is unset or set to the empty string, the insertion of
matches will be delayed unconditionally. If this value is set, it
should be set to an expression usable inside a `tt($((...)))'
arithmetical expression. In this case, delaying will be done if the
expression evaluates to `tt(1)'. For example, with
indent(
nofill(tt(compconf list_condition='NUMERIC != 1'))
)
delaying will be done only if given an explicit numeric argument
other than `tt(1)'.
)
item(tt(list_word))(
To find out if listing should be performed on its own, the code normally
compares the contents of the line with the contents the line had at the
time of the last invocation. If this key is set to an non-empty string,
comparison is done using only the current word. So if it is set,
attempting completion on a word equal to the one when completion was called
the last time will not delay the generation of matches.
)
enditem()
)
item(tt(_menu))(
This completer is a simple example function implemented to show how
menucompletion can be done in shell code. It should be used as the
first completer and has the effect of making the code perform
menucompletion. Note that this is independent of the setting of the
tt(MENU_COMPLETE) option and does not work with the other
menucompletion widgets such as tt(reverse-menu-complete), or
tt(accept-and-menu-complete).
)
enditem()
texinode(Completion Functions)()(Control Functions)(Completion System)
sect(Utility Functions)
Descriptions follow for utility functions that may be
useful when writing completion functions. Most of these reside in the
tt(Core) subdirectory except where noted. Like the example
functions for commands in the distribution, the utility functions
generating matches all follow the convention of returning zero if they
generated completions and non-zero if no matching completions could be
added.
startitem()
item(tt(_compalso))(
This function looks up the definitions for the context and command
names given as arguments and calls the handler functions for them if
there is a definition (given with the tt(compdef) function). For
example, the function completing inside subscripts might use
`tt(_compalso -math-)' to include the completions generated for
mathematical environments.
)
item(tt(_normal))(
This function is used for normal command completion. If
completion is attempted on the first word, command names are
completed. Otherwise, the arguments are completed by calling the
functions defined for this command, including those functions defined
for patterns matching the command name. This function can also be
called by other completion functions if they have to complete a range
of words as a separate command. For example, the function to complete after
the pre-command specifiers such as tt(nohup) removes the first word from
the tt(words) array, decrements the tt(CURRENT) parameter, then calls this
function.
When calling a function defined for a pattern, this function also
checks if the parameter tt(_compskip) is set. If it was set by the
function called, no further completion functions are called. With this
one can write a pattern completion function that keeps other functions
from being tried simply by setting this parameter to any value.
)
item(tt(_multi_parts))(
This functions gets two arguments: a separator character and an
array. As usual, the array may be either the
name of an array parameter or a literal array in the form
`tt(LPAR()foo bar)tt(RPAR())' (i.e. a list of words separated by white
space in parentheses). With these arguments, this function will
complete to strings from the array where the parts separated by the
separator character are completed independently. For example, the
tt(_tar) function from the distribution caches the pathnames from the
tar file in an array and then calls this function to complete these
names in the way normal filenames are completed by the
tt(_path_files) function.
Like other utility functions, this function accepts the `tt(-V)',
`tt(-J)', and `tt(-X)' options with an argument and passes them to the
tt(compadd) builtin.
)
item(tt(_sep_parts))(
This function gets as arguments alternating arrays and separators.
The arrays specify completions for parts of strings to be separated by the
separators. The arrays may be the names of array parameters or
a quoted list of words in parentheses. For example, with the array
`tt(hosts=(ftp news))' the call `tt(_sep_parts '(foo bar)' @ hosts)' will
complete the string `tt(f)' to `tt(foo)' and the string `tt(b@n)' to
`tt(bar@news)'.
This function passes the `tt(-V)', `tt(-J)', and `tt(-X)' options and
their arguments to the tt(compadd) builtin used to add the matches.
)
item(tt(_path_files) and tt(_files))(
The function tt(_path_files) is used throughout the shell code
to complete filenames. The advantage over the builtin
completion functions is that it allows completion of partial paths. For
example, the string `tt(/u/i/s/sig)' may be completed to
`tt(/usr/include/sys/signal.h)'. The options `tt(-/)', `tt(-f)', `tt(-g)',
and `tt(-W)' are available as for the tt(compctl)
and tt(compgen) builtins; tt(-f) is the default. Additionally, the `tt(-F)'
option from the tt(compadd) builtin is supported, giving direct control
over which filenames should be ignored as done by the tt(fignore)
parameter in normal completion.
The function tt(_files) calls tt(_path_files) with all the arguments
it was passed and, if that generated no matches, call tt(_path_files) again
without any tt(-g) or tt(-/) option, thus generating all filenames.
These functions also accept the `tt(-J)', `tt(-V)', `tt(-X)', `tt(-P)',
`tt(-S)', `tt(-q)', `tt(-r)', and `tt(-R)' options from the
tt(compadd) builtin.
Finally, the tt(_path_files) function supports one configuration key:
tt(path_expand). If this is set to any non-empty string, the partially
typed path from the line will be expanded as far as possible even if
trailing pathname components can not be completed.
)
item(tt(_parameters))(
This should be used to complete parameter names if you need some of the
extra options of tt(compadd). It first tries to complete only non-local
parameters. All arguments are passed unchanged to the tt(compadd) builtin.
)
item(tt(_options))(
This can be used to complete option names. The difference to the
`tt(-o)' option of tt(compgen) is that this function uses a matching
specification that ignores a leading `tt(no)', ignores underscores and
allows the user to type upper-case letters, making them match their
lower-case counterparts. All arguments passed to this function are
propagated unchanged to the tt(compgen) builtin.
)
item(tt(_set_options) and tt(_unset_options))(
These functions complete only set or unset options, with the same
matching specification used in the tt(_options) function.
Note that you need to uncomment a few lines in the tt(_main_complete)
function for these functions to work properly. The lines in question
are used to store the option settings in effect before the completion
widget locally sets the options it needs.
)
item(tt(_long_options))(
This function resides in the tt(Base) subdirectory of the example
completion system because it is not used by the core system.
This function is used to complete long options for commands that
support the `tt(--help)' option as, for example, most of the GNU
commands do. For this it invokes the command from the line with the
`tt(--help)' option and then parses the output to find possible option
names. Note that this means that you should be careful to make sure
that this function is not called for a command that does not support
this option.
For options that get an argument after a `tt(=)', the function also
automatically tries to find out what should be completed as the argument.
The possible completions for option-arguments can be described with
the arguments to this function. This is done by giving pairs of
patterns and actions as consecutive arguments. The actions specify
what should be done to complete arguments of those options whose
description match the pattern. The action may be a list of words in
brackets or in parentheses, separated by spaces. A list in square brackets
denotes possible values for an optional argument, a list in parentheses
gives words to complete for mandatory arguments. If the action does
not start with a square bracket or parenthesis, it should be the name of a
command (probably with arguments) that should be invoked to complete
after the equal sign. Example:
indent(
nofill(tt(_long_options '*\*' '(yes no)' \))
nofill(tt( '*=FILE*' '_files' \))
nofill(tt( '*=DIR*' '_files -/'))
)
Here, `tt(yes)' and `tt(no)' will be completed as the argument of
options whose description ends in a star, file names for options that
contain the substring `tt(=FILE)' in the description, and paths for
options whose description contains `tt(=DIR)'. In fact, the last two
patterns are not needed since this function always completes files
for option descriptions containing `tt(=FILE)' and paths for option
descriptions that contain `tt(=DIR)' or `tt(=PATH)'. These builtin
patterns can be overridden by patterns given as arguments, however.
This function also accepts the `tt(-X)', `tt(-J)', and `tt(-V)'
options which are passed unchanged to `tt(compadd)'. Finally, it
accepts the option `tt(-t)'; if this is given, completion is only done
on words starting with two hyphens.
)
enditem()

View file

@ -186,6 +186,18 @@ normally be shown only if there are at least two matches in the
list. Setting tt(force_list) to an non-empty string makes the list be
shown even if there is only one match.
)
item(tt(list_max))(
Initially this is set to the value of the tt(LISTMAX) parameter.
Completion widgets may set it to any other numeric value and the value
stored at when the widget finishes will be used in the same way the
value of tt(LISTMAX) is used.
)
item(tt(last_prompt))(
If this is set to an non-empty string, the completion code will move
the cursor back to the previous prompt after the list of completions
has been displayed. Initially this is set depending on the setting of
the tt(ALWAYS_LAST_PROMPT) option.
)
item(tt(insert))(
This will be unset by the completon code if the contents of the
command line will not be changed. It is set to tt(unambiguous),
@ -193,6 +205,62 @@ tt(menu), or tt(automenu) if a common unambiguous string will be
inserted or if the first match will be inserted and menu completion
will be started (due to tt(MENU_COMPLETE) or tt(AUTO_MENU) being set),
respectively.
On exit it may be set to any of the values above with the obvious
result or to a number or a string of the form
`var(group):var(match)'. If it is set to a number the match whose
number is given will be inserted in the command line. A string like
`tt(2:4)' specifies which match from which group should be
inserted. In this example the fourth match of the second group is
inserted. All groups and matches are number from one upwards. In the
value of this key, negative numbers count backward from the last match
or group (with `tt(-1)' selecting the last match or group) and values
out of the range from one to the number of matches or groups are
wrapped around (so that a value of zero selects the last match and a
value equal to the number of matches or groups plus one selects the
first one).
)
item(tt(to_end))(
On entry to the completion widget this is set to tt(single) if the
cursor would be moved to the end of the word only if completion
generated only one match and that is inserted into the line. Depending
on the original position of the cursor and the setting of the option
tt(ALWAYS_TO_END) this may also be set to the string tt(match) if the
cursor would be moved to the end if a whole match would be inserted
(either if there is only one match or if menucompletion is used).
The value of this key after the completion widget exits will be used
to determin when the cursor will be moved to the end of the string
inserted into the line. If it is unset or set to the empty string, the
cursor will never be moved to the end. If it is set to tt(single), it
will be moved to the end only if completion generated only one
match. A value of tt(always) says to move the cursor always to the end
(even with normal completion when an unambiguous string is inserted),
and any other value says to move the cursor to the end when a full
match is inserted (a single match or the first match when using
menucompletion).
)
item(tt(old_list))(
This is set to tt(yes) if there is still a valid list of completions
from a previous completion at the time the widget is invoked. Such a
list exists if it was generated by the previous key press. If the list
is also shown on the screen, the value of this key is tt(shown).
After the widget has exited the value of this key is only used if it
was set to tt(keep). In this case, the completion code will continue
to use this old list. If the widget generated new matches, they will
not be used.
)
item(tt(old_insert))(
On entry to the widget this will be set to the number of the match of
an old list of completions that is currently inserted in the command
line. If no match has been inserted, this is unset.
As with tt(old_list), the value of this key will only be used if it is
the string tt(keep). If it was set to this value by the widget and
there was an old match inserted in the line, this match will be kept
and if the value of the tt(insert) key says that another match should
be inserted, this will be inserted after the old one.
)
item(tt(exact))(
This is set to tt(accept) if an exact match would be accepted by the
@ -268,7 +336,8 @@ xitem([ tt(-i) var(ignored-prefix) ] [ tt(-I) var(ignored-suffix) ])
xitem([ tt(-W) var(file-prefix) ])
xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ])
xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ])
item([ tt(-M) var(match-spec) ] [ tt(--) ] [ var(words) ... ])(
xitem([ tt(-M) var(match-spec) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ])
item([ tt(--) ] [ var(words) ... ])(
This builtin command can be used to add matches and directly control
all the information the completion code stores with each possible
@ -437,6 +506,23 @@ Note that with tt(compadd) this option does not automatically turn on
menu completion if tt(AUTO_LIST) is set as the same options for the
tt(compctl) and tt(compgen) builtin command do.
)
item(tt(-O) var(array))(
If this option is given, the var(words) are em(not) added to the set of
possible completions. Instead, matching is done as usual and all
var(words) given as arguments that are matched will be stored in the
array parameter whose name is given as var(array).
)
item(tt(-A) var(array))(
Like the tt(-O) option this keeps the var(words) from being stored as
possible completions. The matching words are instead stored in the array
parameter given as var(array). In difference to the tt(-O) option this
does not store the unchanged var(words) given as arguments, but instead
the strings the completion code generated while matching. For example,
with a matching specification of `tt(-M "L:|no=")', the string `tt(nof)'
on the line and the string `tt(foo)' as one of the var(words), this option
will make the string `tt(nofoo)' be stored in the array, whereas the tt(-O)
option stores the `tt(foo)' originally given.
)
item(tt(-), tt(--))(
This flag ends the list of flags and options. All arguments after it
will be taken as the words to use as matches even if they begin with
@ -596,3 +682,9 @@ tt(complete-history LPAR()RPAR() { compgen -H 0 '' })))
In this the function will complete words from the history matching the
current word.
For a description of the example completion system from the
distributions, see
ifzman(zmanref(zshcompsys))\
ifnzman(noderef(Completion System))\
.

View file

@ -31,6 +31,7 @@ menu(Zsh Line Editor)
menu(Programmable Completion)
menu(Completion Widgets)
menu(Zsh Modules)
menu(Completion System)
--- Indices ---

View file

@ -23,6 +23,7 @@ list(em(zshzle) Zsh command line editing)
list(em(zshcompctl) Zsh completion control)
list(em(zshcompwid) Zsh completion widgets)
list(em(zshmodules) Zsh loadable modules)
list(em(zshcompsys) Zsh completion system)
ifzshone(\
list(em(zshall) Meta-man page containing all of the above)
)\

View file

@ -1,4 +1,4 @@
texinode(Zsh Modules)()(Completion Widgets)(Top)
texinode(Zsh Modules)(Completion System)(Completion Widgets)(Top)
chapter(Zsh Modules)
cindex(modules)
sect(Description)

View file

@ -11,6 +11,7 @@ ifzshone(\
zmanref(zshbuiltins),
zmanref(zshcompctl),
zmanref(zshcompwid),
zmanref(zshcompsys),
zmanref(zshexpn),
zmanref(zshmisc),
zmanref(zshmodules),

View file

@ -139,6 +139,12 @@ The part of the buffer that lies to the right of the cursor position.
If it is assigned to, only that part of the buffer is replaced, and the
cursor remains between the old tt($LBUFFER) and the new tt($RBUFFER).
)
vindex(PREBUFFER)
item(tt(PREBUFFER) (scalar))(
In a multi-line input at the secondary prompt, this read-only parameter
contains the contents of the lines before the one the cursor is
currently in.
)
vindex(WIDGET)
item(tt(WIDGET) (scalar))(
The name of the widget currently being executed.

View file

@ -66,6 +66,7 @@ ifnzman(includefile(Zsh/zle.yo))
ifnzman(includefile(Zsh/compctl.yo))
ifnzman(includefile(Zsh/compwid.yo))
ifnzman(includefile(Zsh/modules.yo))
ifnzman(includefile(Zsh/compsys.yo))
ifzshall(\
def(source)(1)(NOTRANS(.so )man1/ARG1NOTRANS(.)1)\
CMT()
@ -78,6 +79,7 @@ source(zshzle)
source(zshcompctl)
source(zshcompwid)
source(zshmodules)
source(zshcompsys)
manpage(ZSHALL)(1)(date())(zsh version())
)\
ifzman(includefile(Zsh/filelist.yo))

3
Doc/zshcompsys.yo Normal file
View file

@ -0,0 +1,3 @@
manpage(ZSHCOMPSYS)(1)(date())(zsh version())
manpagename(zshcompsys)(zsh completion system)
includefile(Zsh/compsys.yo)

View file

@ -11,15 +11,15 @@
# page.
#
#------------------------------------------------------------------------------
hosts=("${${(s: :)${(s: :)${${(f)$(</etc/hosts)}%%\#*}#*[ ]*}}:#}")
ports=( "${${${(f)$(</etc/services)}:#\#*}%%[ ]*}" )
hosts=("${(@)${(@s: :)${(@s: :)${(@)${(@f)$(</etc/hosts)}%%\#*}#*[ ]*}}:#}")
ports=( "${(@)${(@)${(@f)$(</etc/services)}:#\#*}%%[ ]*}" )
# groups=( $(cut -d: -f1 /etc/group) )
# groups=( $(ypcat group.byname | cut -d: -f1) ) # if you use NIS
# It can be done without forking, but it used too much memory in old zsh's:
groups=( "${${(f)$(</etc/group)}%%:*}" )
#groups=( "${${(f)$(ypcat groups)}%%:*}" ) # if you use NIS
groups=( "${(@)${(@f)$(</etc/group)}%%:*}" )
#groups=( "${(@)${(@f)$(ypcat groups)}%%:*}" ) # if you use NIS
# Completion for zsh builtins.
compctl -z -P '%' bg
@ -251,7 +251,7 @@ compctl -k ftphosts ftp
# Note that 'r[-exec,;]' must come first
if [[ -r /proc/filesystems ]]; then
# Linux
filesystems='"${${(f)$(</proc/filesystems)}#* }"'
filesystems='"${(@)${(@f)$(</proc/filesystems)}#* }"'
else
filesystems='ufs 4.2 4.3 nfs tmp mfs S51K S52K'
fi
@ -563,7 +563,7 @@ cvsprefix() {
cvsentries() {
setopt localoptions nullglob unset
if [[ -f ${pref}CVS/Entries ]]; then
reply=( "${pref}${^${${${(f@)$(<${pref}CVS/Entries)}:#D*}#/}%%/*}" )
reply=( "${pref}${^${(@)${(@)${(f@)$(<${pref}CVS/Entries)}:#D*}#/}%%/*}" )
fi
}
@ -574,7 +574,7 @@ cvstargets() {
}
cvsrevisions() {
reply=( "${${${(M)${(f)$(cvs -q status -vl .)}:# *}##[ ]##}%%[ ]*}" )
reply=( "${(@)${(@)${(@M)${(@f)$(cvs -q status -vl .)}:# *}##[ ]##}%%[ ]*}" )
}
cvsrepositories() {
@ -582,7 +582,7 @@ cvsrepositories() {
[[ -f CVS/Root ]] && root=$(<CVS/Root)
reply=(
$root/^CVSROOT(:t)
"${${(M)${(f)$(<$root/CVSROOT/modules)}:#[^#]*}%%[ ]*}"
"${(@)${(@M)${(@f)$(<$root/CVSROOT/modules)}:#[^#]*}%%[ ]*}"
)
}
@ -622,7 +622,7 @@ compctl -s '$(rpm -qa)' \
'c[-1,--rcfile]' -f - \
'p[1] s[-b]' -k '(p l c i b a)' - \
'c[-1,--queryformat] N[-1,{]' \
-s '"${${(f)$(rpm --querytags)}#RPMTAG_}"' -S '}' - \
-s '"${(@)${(@f)$(rpm --querytags)}#RPMTAG_}"' -S '}' - \
'W[1,-q*] C[-1,-([^-]*|)f*]' -f - \
'W[1,-i*], W[1,-q*] C[-1,-([^-]*|)p*]' \
-/g '*.rpm' + -f -- rpm
@ -635,7 +635,7 @@ compctl -K talkmatch talk ytalk ytalk3
function talkmatch {
local u
reply=($(users))
for u in "${${(f)$(rwho 2>/dev/null)}%%:*}"; do
for u in "${(@)${(@f)$(rwho 2>/dev/null)}%%:*}"; do
reply=($reply ${u%% *}@${u##* })
done
}

View file

@ -190,6 +190,7 @@ struct cmgroup {
LinkList lmatches; /* list of matches */
LinkList lfmatches; /* list of matches without fignore */
LinkList lallccs; /* list of used compctls */
int num; /* number of this group */
};
@ -213,6 +214,8 @@ struct cmatch {
int brsl; /* ...and the suffix */
char *rems; /* when to remove the suffix */
char *remf; /* shell function to call for suffix-removal */
int rnum; /* group relative number */
int gnum; /* global number */
};
#define CMF_FILE 1 /* this is a file */
@ -298,7 +301,12 @@ struct cpattern {
#define CP_PATINSERT (1 << 23)
#define CP_UNAMBIG (1 << 24)
#define CP_UNAMBIGC (1 << 25)
#define CP_LISTMAX (1 << 26)
#define CP_LASTPROMPT (1 << 27)
#define CP_TOEND (1 << 28)
#define CP_OLDLIST (1 << 29)
#define CP_OLDINS (1 << 30)
#define CP_NUM 26
#define CP_NUM 31
#define CP_ALLMASK ((1 << CP_NUM) - 1)
#define CP_ALLMASK ((int) ((((unsigned int) 1) << CP_NUM) - 1))

View file

@ -52,7 +52,7 @@ void (*comp_setunsetptr) _((int, int));
/* pointers to functions required by compctl and defined by zle */
/**/
int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **));
int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char *, char *, char **));
/**/
char *(*comp_strptr) _((int *, int *, int));
@ -103,7 +103,8 @@ int incompfunc;
long compcurrent,
compnmatches,
compmatcher,
compmatchertot;
compmatchertot,
complistmax;
/**/
char **compwords,
@ -124,7 +125,11 @@ char **compwords,
*compexact,
*compexactstr,
*comppatmatch,
*comppatinsert;
*comppatinsert,
*complastprompt,
*comptoend,
*compoldlist,
*compoldins;
/**/
Param *comppms;
@ -439,7 +444,8 @@ setup_comp1(Module m)
compcontext = compparameter = compredirect = compquote =
compquoting = comprestore = complist = compinsert =
compexact = compexactstr = comppatmatch = comppatinsert =
compforcelist = NULL;
compforcelist = complastprompt = comptoend =
compoldlist = compoldins = NULL;
makecompparamsptr = NULL;
comp_setunsetptr = NULL;
return 0;
@ -487,6 +493,10 @@ finish_comp1(Module m)
zsfree(compexactstr);
zsfree(comppatmatch);
zsfree(comppatinsert);
zsfree(complastprompt);
zsfree(comptoend);
zsfree(compoldlist);
zsfree(compoldins);
return 0;
}

View file

@ -19,11 +19,15 @@ compforcelist
compinsert
compiprefix
compisuffix
complastprompt
complist
complistmax
compmatcher
compmatcherstr
compmatchertot
compnmatches
compoldlist
compoldins
compparameter
comppatinsert
comppatmatch
@ -36,6 +40,7 @@ comprestore
comp_setunsetptr
comp_strptr
compsuffix
comptoend
compwords
freecmatcher
freecmlist

View file

@ -1694,7 +1694,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
char *p, **sp, *e;
char *ipre = NULL, *isuf = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL;
char *ign = NULL, *rf = NULL, *expl = NULL;
char *ign = NULL, *rf = NULL, *expl = NULL, *apar = NULL, *opar = NULL;
int f = 0, a = CAF_MATCH, dm;
Cmatcher match = NULL;
@ -1791,6 +1791,14 @@ bin_compadd(char *name, char **argv, char *ops, int func)
sp = &rf;
e = "function name expected after -%c";
break;
case 'A':
sp = &apar;
e = "parameter name expected after -%c";
break;
case 'O':
sp = &opar;
e = "parameter name expected after -%c";
break;
case '-':
argv++;
goto ca_args;
@ -1799,15 +1807,13 @@ bin_compadd(char *name, char **argv, char *ops, int func)
return 1;
}
if (sp) {
if (*sp) {
zerrnam(name, "doubled option: -%c", NULL, *p);
return 1;
}
if (p[1]) {
*sp = p + 1;
if (!*sp)
*sp = p + 1;
p = "" - 1;
} else if (argv[1]) {
*sp = *++argv;
if (!*sp)
*sp = *++argv;
p = "" - 1;
} else {
zerrnam(name, e, NULL, *p);
@ -1826,7 +1832,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
match = cpcmatcher(match);
a = addmatchesptr(ipre, isuf, ppre, psuf, prpre, pre, suf, group,
rs, rf, ign, f, a, match, expl, argv);
rs, rf, ign, f, a, match, expl, apar, opar, argv);
freecmatcher(match);
return a;
@ -2152,7 +2158,13 @@ static struct compparam {
{ "pattern_match", PM_SCALAR, VAL(comppatmatch), NULL, NULL },
{ "pattern_insert", PM_SCALAR, VAL(comppatinsert), NULL, NULL },
{ "unambiguous", PM_SCALAR | PM_READONLY, NULL, NULL, VAL(get_unambig) },
{ "unambiguous_cursor", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_unambig_curs) },
{ "unambiguous_cursor", PM_INTEGER | PM_READONLY, NULL, NULL,
VAL(get_unambig_curs) },
{ "list_max", PM_INTEGER, VAL(complistmax), NULL, NULL },
{ "last_prompt", PM_SCALAR, VAL(complastprompt), NULL, NULL },
{ "to_end", PM_SCALAR, VAL(comptoend), NULL, NULL },
{ "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL },
{ "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL },
{ NULL, 0, NULL, NULL, NULL }
};

View file

@ -883,7 +883,7 @@ trashzle(void)
moveto(nlnct, 0);
if (clearflag && tccan(TCCLEAREOD)) {
tcout(TCCLEAREOD);
clearflag = 0;
clearflag = listshown = 0;
}
if (postedit)
fprintf(shout, "%s", postedit);
@ -927,6 +927,7 @@ setup_zle(Module m)
/* miscellaneous initialisations */
stackhist = stackcs = -1;
kungetbuf = (char *) zalloc(kungetsz = 32);
hasperm = 0;
/* initialise the keymap system */
init_keymaps();

View file

@ -61,6 +61,8 @@ static struct zleparam {
zleunsetfn, NULL },
{ "RBUFFER", PM_SCALAR, FN(set_rbuffer), FN(get_rbuffer),
zleunsetfn, NULL },
{ "PREBUFFER", PM_SCALAR | PM_READONLY, NULL, FN(get_prebuffer),
zleunsetfn, NULL },
{ "WIDGET", PM_SCALAR | PM_READONLY, NULL, FN(get_widget),
zleunsetfn, NULL },
{ "LASTWIDGET", PM_SCALAR | PM_READONLY, NULL, FN(get_lwidget),
@ -210,6 +212,16 @@ get_rbuffer(Param pm)
return metafy((char *)line + cs, ll - cs, META_HEAPDUP);
}
/**/
static char *
get_prebuffer(Param pm)
{
if (chline)
return dupstrpfx(chline, hptr - chline);
else
return dupstring("");
}
/**/
static char *
get_widget(Param pm)

View file

@ -53,6 +53,11 @@ int nlnct;
/**/
int showinglist;
/* Non-zero if a completion list was displayed. */
/**/
int listshown;
/* Non-zero if ALWAYS_LAST_PROMPT has been used, meaning that the *
* screen below the buffer display should not be cleared by *
* zrefresh(), but should be by trashzle(). */
@ -253,13 +258,23 @@ zrefresh(void)
if (inlist)
return;
if (clearlist) {
invalidatelist();
moveto(0, 0);
clearflag = 0;
resetneeded = 1;
clearlist = 0;
if (clearlist && listshown) {
if (tccan(TCCLEAREOD)) {
int ovln = vln, ovcs = vcs;
moveto(nlnct, 0);
tcout(TCCLEAREOD);
moveto(ovln, ovcs);
} else {
invalidatelist();
moveto(0, 0);
clearflag = 0;
resetneeded = 1;
}
listshown = 0;
}
clearlist = 0;
#ifdef HAVE_SELECT
cost = 0; /* reset */
#endif
@ -287,6 +302,7 @@ zrefresh(void)
moveto(0, 0);
t0 = olnct; /* this is to clear extra lines even when */
winchanged = 0; /* the terminal cannot TCCLEAREOD */
listshown = 0;
}
#endif
resetvideo();
@ -303,6 +319,7 @@ zrefresh(void)
tcout(TCCLEAREOD);
else
cleareol = 1; /* request: clear to end of line */
listshown = 0;
}
if (t0 > -1)
olnct = t0;

View file

@ -72,12 +72,27 @@ static int wb, we;
static int offs;
/* These control the type of completion that will be done. They are *
* affected by the choice of ZLE command and by relevant shell options. *
* usemenu is set to 2 if we have to start automenu. */
/* These control the type of completion that will be done. They are *
* affected by the choice of ZLE command and by relevant shell options. *
* usemenu is set to 2 if we have to start automenu and 3 if we have to *
* insert a match as if for menucompletion but without really stating it. */
static int usemenu, useglob, useexact, useline, uselist;
/* Non-zero if we should keep an old list. */
static int oldlist, oldins;
/* The match and group number to insert when starting menucompletion. */
static int insmnum, insgnum, insgroup;
/* This is used to decide when the cursor should be moved to the end of *
* the inserted word: 0 - never, 1 - only when a single match is inserted, *
* 2 - when a full match is inserted (single or menu), 3 - always. */
static int movetoend;
/* != 0 if we are in the middle of a menu completion */
static int menucmp;
@ -99,12 +114,12 @@ static int menupos, menulen, menuend, menuwe, menuinsc;
/* This is for completion inside a brace expansion. brbeg and brend hold *
* strings that were temporarily removed from the string to complete. *
* brpl and brsl, brbsl hold the offset of these strings. *
* brpl and brsl, hold the offset of these strings. *
* brpcs and brscs hold the positions of the re-inserted string in the *
* line. */
static char *brbeg = NULL, *brend = NULL;
static int brpl, brsl, brbsl, brpcs, brscs;
static int brpl, brsl, brpcs, brscs, qbrpl, qbrsl, hasunqu;
/* The list of matches. fmatches contains the matches we first ignore *
* because of fignore. */
@ -114,7 +129,16 @@ static LinkList matches, fmatches;
/* This holds the list of matches-groups. lmatches is a pointer to the *
* last element in this list. */
static Cmgroup amatches, lmatches;
static Cmgroup pmatches, amatches, lmatches;
/* Non-zero if we have permanently allocated matches. */
/**/
int hasperm;
/* Number of permanently allocated matches and groups. */
static int permmnum, permgnum;
/* The total number of matches and the number of matches to be listed. */
@ -155,6 +179,7 @@ static char *ppre, *psuf, *lppre, *lpsuf, *prpre;
static char *fpre, *fsuf;
static char *ipre, *ripre;
static char *isuf;
static char *qfpre, *qfsuf, *qrpre, *qrsuf, *qlpre, *qlsuf;
static int lpl, lsl, rpl, rsl, fpl, fsl, lppl, lpsl;
static int noreal;
@ -485,14 +510,9 @@ reversemenucomplete(void)
* with the next completions. This gives you a way to *
* accept several selections from the list of matches. */
/**/
void
acceptandmenucomplete(void)
static void
acceptlast(void)
{
if (!menucmp) {
feep();
return;
}
if (brbeg && *brbeg) {
int l;
@ -514,6 +534,17 @@ acceptandmenucomplete(void)
menupos = cs;
menuwe = 1;
}
}
/**/
void
acceptandmenucomplete(void)
{
if (!menucmp) {
feep();
return;
}
acceptlast();
menucomplete();
}
@ -650,7 +681,13 @@ check_param(char *s, int set)
int n = 0, br = 1;
if (*b == Inbrace) {
/* If this is a ${...}, ignore the possible (...) flags. */
char *tb = b;
/* If this is a ${...}, see if we are before the '}'. */
if (!skipparens(Inbrace, Outbrace, &tb))
return NULL;
/* Ignore the possible (...) flags. */
b++, br++;
n = skipparens(Inpar, Outpar, &b);
}
@ -1494,11 +1531,13 @@ get_comp_string(void)
if (tt && tt < s + myoffs) {
/* Braces are go: delete opening brace */
char *com = NULL;
char *com = NULL, *tmp;
int pl, sl;
brbeg = dupstring(tt);
brpl = tt - s;
tmp = dupstrpfx(s, tt - s);
qbrpl = strlen(quotename(tmp, NULL));
pl = 1;
sl = 0;
chuck(tt);
@ -1531,8 +1570,8 @@ get_comp_string(void)
if (*p == Outbrace)
chuck(p);
brsl = strlen(s) - (p - s);
brbsl = p - s;
brend[sl] = '\0';
qbrsl = strlen(quotename(p, NULL));
}
/* we are still waiting for an outbrace and maybe commas */
if (brbeg)
@ -2040,7 +2079,7 @@ static int
match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
{
int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw;
int il = 0, iw = 0, t, ind, add, bc;
int il = 0, iw = 0, t, ind, add, bc = (bp ? *bp : 0);
VARARR(unsigned char, ea, ll + 1);
char *ow;
Cmlist ms;
@ -2054,9 +2093,9 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
if (sfx) {
l += ll; w += lw;
ind = -1; add = -1; bc = brsl;
ind = -1; add = -1;
} else {
ind = 0; add = 1; bc = brpl;
ind = 0; add = 1;
}
/* ow will always point to the beginning (or end) of that sub-string
* in w that wasn't put in the match-variables yet. */
@ -2406,17 +2445,19 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp,
wl = strlen(w);
*clp = bld_parts(w, wl, wl, NULL);
*exact = 0;
*bpl = (qu ? qbrpl : brpl);
*bsl = (qu ? qbrsl : brsl);
} else {
Cline pli, plil;
int mpl, rpl, wl;
if (qu)
w = quotename(w, NULL);
w = (qu ? quotename(w, NULL) : dupstring(w));
wl = strlen(w);
/* Always try to match the prefix. */
*bpl = (qu ? qbrpl : brpl);
if ((mpl = match_str(pfx, w, bpl, &rpl, 0, 0)) < 0)
return NULL;
@ -2441,6 +2482,7 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp,
plil = matchlastpart;
/* The try to match the suffix. */
*bsl = (qu ? qbrsl : brsl);
if ((msl = match_str(sfx, w + mpl, bsl, &rsl, 1, 0)) < 0) {
free_cline(pli);
@ -2479,6 +2521,7 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp,
pli = matchparts;
}
r = dupstring(matchbuf);
*clp = pli;
/* Test if the string built is equal to the one from the line. */
@ -2489,6 +2532,9 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp,
} else
*exact = !strcmp(pfx, w);
}
if (!qu)
hasunqu = 1;
return r;
}
@ -3398,6 +3444,22 @@ add_match_data(int alt, char *str, Cline line,
return cm;
}
/* This stores the strings from the list in an array. */
static void
set_param(char *name, LinkList l)
{
char **a, **p;
LinkNode n;
a = (char **) zalloc((countlinknodes(l) + 1) * sizeof(char *));
for (p = a, n = firstnode(l); n; incnode(n))
*p++ = ztrdup((char *) getdata(n));
*p = NULL;
setaparam(name, a);
}
/* This is used by compadd to add a couple of matches. The arguments are
* the strings given via options. The last argument is the array with
* the matches. */
@ -3407,22 +3469,29 @@ int
addmatches(char *ipre, char *isuf,
char *ppre, char *psuf, char *prpre, char *pre,
char *suf, char *group, char *rems, char *remf, char *ign,
int flags, int aflags, Cmatcher match, char *exp, char **argv)
int flags, int aflags, Cmatcher match, char *exp,
char *apar, char *opar, char **argv)
{
char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
char **aign = NULL;
int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
int oisalt = 0, isalt, isexact;
int oisalt = 0, isalt, isexact, doadd;
Cline lc = NULL;
Cmatch cm;
struct cmlist mst;
Cmlist oms = mstack;
Comp cp = NULL;
LinkList aparl = NULL, oparl = NULL;
/* Switch back to the heap that was used when the completion widget
* was invoked. */
SWITCHHEAPS(compheap) {
HEAPALLOC {
doadd = (!apar && !opar);
if (apar)
aparl = newlinklist();
if (opar)
oparl = newlinklist();
if (exp) {
expl = (Cexpl) zhalloc(sizeof(struct cexpl));
expl->count = expl->fcount = 0;
@ -3548,9 +3617,17 @@ addmatches(char *ipre, char *isuf,
rems = NULL;
} else if (rems)
rems = dupstring(rems);
/* Probably quote the prefix and suffix for testing. */
if (!cp && (aflags & CAF_MATCH) && !(aflags & CAF_QUOTE)) {
lpre = quotename(lpre, NULL);
lsuf = quotename(lsuf, NULL);
llpl = strlen(lpre);
llsl = strlen(lsuf);
}
}
/* Walk through the matches given. */
for (; (s = dupstring(*argv)); argv++) {
for (; (s = *argv); argv++) {
sl = strlen(s);
bpl = brpl;
bsl = brsl;
@ -3565,25 +3642,40 @@ addmatches(char *ipre, char *isuf,
if ((filell = strlen(*pt)) < sl
&& !strcmp(*pt, s + sl - filell))
isalt = 1;
if (isalt && !doadd)
continue;
}
if (!(aflags & CAF_MATCH)) {
ms = s;
lc = bld_parts(s, sl, -1, NULL);
ms = dupstring(s);
lc = bld_parts(ms, sl, -1, NULL);
isexact = 0;
} else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc,
(aflags & CAF_QUOTE),
!(aflags & CAF_QUOTE),
&bpl, &bsl, &isexact)))
continue;
cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, prpre,
ppre, psuf, suf, bpl, bsl,
flags, isexact);
cm->rems = rems;
cm->remf = remf;
if (doadd) {
cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre,
prpre, ppre, psuf, suf, bpl, bsl,
flags, isexact);
cm->rems = rems;
cm->remf = remf;
} else {
if (apar)
addlinknode(aparl, ms);
if (opar)
addlinknode(oparl, s);
free_cline(lc);
}
}
compnmatches = mnum;
if (exp)
addexpl();
if (apar)
set_param(apar, aparl);
if (opar)
set_param(opar, oparl);
} LASTALLOC;
} SWITCHBACKHEAPS;
@ -3629,9 +3721,6 @@ addmatch(char *s, char *t)
hn = (HashNode) t;
pm = (Param) t;
if (incompfunc)
s = dupstring(s);
if (addwhat == -1 || addwhat == -5 || addwhat == -6 ||
addwhat == CC_FILES || addwhat == -7 || addwhat == -8) {
if ((addwhat == CC_FILES ||
@ -3645,10 +3734,13 @@ addmatch(char *s, char *t)
!strcmp(*pt, s + sl - filell))
isalt = 1;
}
if (!(ms = comp_match(fpre, fsuf, s, filecomp, &lc,
(addwhat == CC_FILES || addwhat == -6 ||
addwhat == -5 || addwhat == -8),
&bpl, &bsl, &isexact)))
ms = ((addwhat == CC_FILES || addwhat == -6 ||
addwhat == -5 || addwhat == -8) ?
comp_match(qfpre, qfsuf, s, filecomp, &lc, 1,
&bpl, &bsl, &isexact) :
comp_match(fpre, fsuf, s, filecomp, &lc, 0,
&bpl, &bsl, &isexact));
if (!ms)
return;
if (addwhat == -7 && !findcmd(s, 0))
@ -3678,10 +3770,19 @@ addmatch(char *s, char *t)
(((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) ||
((addwhat & CC_EXCMDS) && !(hn->flags & DISABLED)))) ||
((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) {
if (!(ms = comp_match(rpre, rsuf, s, patcomp, &lc,
char *p1, *s1, *p2, *s2;
if (addwhat == CC_QUOTEFLAG) {
p1 = qrpre; s1 = qrsuf;
p2 = rpre; s2 = rsuf;
} else {
p1 = qlpre; s1 = qlsuf;
p2 = lpre; s2 = lsuf;
}
if (!(ms = comp_match(p1, s1, s, patcomp, &lc,
(addwhat == CC_QUOTEFLAG),
&bpl, &bsl, &isexact)) &&
!(ms = comp_match(lpre, lsuf, s, NULL, &lc,
!(ms = comp_match(p2, s2, s, NULL, &lc,
(addwhat == CC_QUOTEFLAG),
&bpl, &bsl, &isexact)))
return;
@ -4002,6 +4103,7 @@ docompletion(char *s, int lst, int incmd)
ainfo = fainfo = NULL;
matchers = newlinklist();
hasunqu = 0;
useline = (lst != COMP_LIST_COMPLETE);
useexact = (isset(RECEXACT) && usemenu != 1);
uselist = (useline ?
@ -4014,6 +4116,12 @@ docompletion(char *s, int lst, int incmd)
zsfree(compforcelist);
compforcelist = ztrdup("");
haspattern = 0;
complistmax = getiparam("LISTMAX");
zsfree(complastprompt);
complastprompt = ztrdup(((isset(ALWAYSLASTPROMPT) && zmult == 1) ||
(unset(ALWAYSLASTPROMPT) && zmult != 1)) ?
"yes" : "");
movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1);
/* Make sure we have the completion list and compctl. */
if (makecomplist(s, incmd, lst)) {
@ -4031,7 +4139,7 @@ docompletion(char *s, int lst, int incmd)
/* We have matches. */
if (nmatches > 1)
/* There is more than one match. */
do_ambiguous();
do_ambiguous();
else if (nmatches == 1) {
/* Only one match. */
@ -4039,6 +4147,7 @@ docompletion(char *s, int lst, int incmd)
while (!m->mcount)
m = m->next;
menucur = NULL;
do_single(m->matches[0]);
invalidatelist();
}
@ -4069,9 +4178,8 @@ docompletion(char *s, int lst, int incmd)
g = g->next;
}
if (!tr) {
clearflag = ((isset(USEZLE) && !termflags &&
(isset(ALWAYSLASTPROMPT) && zmult == 1)) ||
(unset(ALWAYSLASTPROMPT) && zmult != 1));
clearflag = (isset(USEZLE) && !termflags &&
complastprompt && *complastprompt);
if (clearflag && up + nlnct < lines)
tcmultout(TCUP, TCMULTUP, up + nlnct);
@ -4099,7 +4207,8 @@ callcompfunc(char *s, char *fn)
{
List list;
int lv = lastval;
char buf[20];
if ((list = getshfunc(fn)) != &dummy_list) {
char **p, *tmp;
int set, aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
@ -4108,7 +4217,10 @@ callcompfunc(char *s, char *fn)
comppms = (Param *) zalloc(CP_NUM * sizeof(Param));
set = -1 & ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING |
CP_EXACTSTR | CP_FORCELIST | (useglob ? 0 : CP_PATMATCH));
CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS |
(useglob ? 0 : CP_PATMATCH));
if (!*complastprompt)
set &= ~CP_LASTPROMPT;
zsfree(compcontext);
zsfree(compparameter);
zsfree(compredirect);
@ -4205,20 +4317,17 @@ callcompfunc(char *s, char *fn)
zsfree(compprefix);
zsfree(compsuffix);
if (unset(COMPLETEINWORD)) {
if (linwhat == IN_MATH)
tmp = s;
else
tmp = quotename(s, NULL);
/* Maybe we'll have to do quoting here some time. */
tmp = dupstring(s);
untokenize(tmp);
compprefix = ztrdup(tmp);
compsuffix = ztrdup("");
} else {
char *ss = s + offs, sav;
char *ss, sav;
if (linwhat == IN_MATH)
tmp = s;
else
tmp = quotename(s, &ss);
tmp = dupstring(s);
ss = tmp + offs;
sav = *ss;
*ss = '\0';
untokenize(tmp);
@ -4260,6 +4369,30 @@ callcompfunc(char *s, char *fn)
compexact = ztrdup("");
set &= ~CP_EXACT;
}
zsfree(comptoend);
if (movetoend == 1)
comptoend = ztrdup("single");
else
comptoend = ztrdup("match");
zsfree(compoldlist);
zsfree(compoldins);
if (hasperm && permmnum) {
if (listshown)
compoldlist = "shown";
else
compoldlist = "yes";
set |= CP_OLDLIST;
if (menucur) {
sprintf(buf, "%d", (*menucur)->gnum);
compoldins = buf;
set |= CP_OLDINS;
} else
compoldins = "";
} else
compoldlist = compoldins = "";
compoldlist = ztrdup(compoldlist);
compoldins = ztrdup(compoldins);
incompfunc = 1;
startparamscope();
makecompparamsptr();
@ -4294,10 +4427,32 @@ callcompfunc(char *s, char *fn)
else if (!strcmp(compinsert, "auto") ||
!strcmp(compinsert, "automenu"))
useline = 1, usemenu = 2;
else
else if (idigit(*compinsert)) {
char *m;
useline = 1; usemenu = 3;
insmnum = atoi(compinsert);
if ((m = strchr(compinsert, ':'))) {
insgroup = 1;
insgnum = atoi(m + 1);
}
} else
useline = usemenu = 0;
useexact = (compexact && !strcmp(compexact, "accept"));
if (!comptoend || !*comptoend)
movetoend = 0;
else if (!strcmp(comptoend, "single"))
movetoend = 1;
else if (!strcmp(comptoend, "always"))
movetoend = 3;
else
movetoend = 2;
oldlist = (hasperm && compoldlist && !strcmp(compoldlist, "keep"));
oldins = (hasperm && menucur &&
compoldins && !strcmp(compoldins, "keep"));
zfree(comppms, CP_NUM * sizeof(Param));
comppms = ocpms;
}
@ -4327,6 +4482,7 @@ makecomplist(char *s, int incmd, int lst)
struct cmlist ms;
Cmlist m;
char *p, *os = s;
int onm = nmatches;
/* Inside $... ? */
if (compfunc && (p = check_param(s, 0)))
@ -4382,10 +4538,12 @@ makecomplist(char *s, int incmd, int lst)
if (!validlist)
lastambig = 0;
amatches = 0;
amatches = NULL;
mnum = 0;
unambig_mnum = -1;
isuf = NULL;
insmnum = insgnum = 1;
insgroup = oldlist = oldins = 0;
begcmgroup("default", 0);
ccused = newlinklist();
@ -4399,7 +4557,7 @@ makecomplist(char *s, int incmd, int lst)
endcmgroup(NULL);
if (amatches)
if (amatches && !oldlist)
amatches->ccs = (Compctl *) makearray(ccused, 0,
&(amatches->ccount), NULL);
else {
@ -4408,7 +4566,13 @@ makecomplist(char *s, int incmd, int lst)
for (n = firstnode(ccused); n; incnode(n))
freecompctl((Compctl) getdata(n));
}
if (oldlist) {
nmatches = onm;
validlist = 1;
amatches = pmatches;
return 0;
}
PERMALLOC {
permmatches();
} LASTALLOC;
@ -4996,9 +5160,9 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
delit = ispattern = 0;
usemenu = um;
patcomp = filecomp = NULL;
menucur = NULL;
rpre = rsuf = lpre = lsuf = ppre = psuf = lppre = lpsuf = prpre =
fpre = fsuf = ipre = ripre = prpre = NULL;
rpre = rsuf = lpre = lsuf = ppre = psuf = lppre = lpsuf =
fpre = fsuf = ipre = ripre = prpre =
qfpre = qfsuf = qrpre = qrsuf = qlpre = qlsuf = NULL;
curcc = cc;
@ -5106,8 +5270,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
lpre = zhalloc(lpl + 1);
memcpy(lpre, s, lpl);
lpre[lpl] = '\0';
qlpre = quotename(lpre, NULL);
lsuf = dupstring(s + offs);
lsl = strlen(lsuf);
qlsuf = quotename(lsuf, NULL);
/* First check for ~.../... */
if (ic == Tilde) {
@ -5126,9 +5292,11 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
rpre = (*p || *lpre == Tilde || *lpre == Equals) ?
(noreal = 0, getreal(tt)) :
dupstring(tt);
qrpre = quotename(rpre, NULL);
for (p = lsuf; *p && *p != String && *p != Tick; p++);
rsuf = *p ? (noreal = 0, getreal(lsuf)) : dupstring(lsuf);
qrsuf = quotename(rsuf, NULL);
/* Check if word is a pattern. */
@ -5204,7 +5372,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
lppre = dupstring((char *) (line + wb));
line[cs] = save;
if (brbeg && *brbeg)
strcpy(lppre + brpl, lppre + brpl + strlen(brbeg));
strcpy(lppre + qbrpl, lppre + qbrpl + strlen(brbeg));
if ((p = strrchr(lppre, '/'))) {
p[1] = '\0';
lppl = strlen(lppre);
@ -5226,7 +5394,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
lpsuf = dupstring((char *) (line + cs));
line[we] = save;
if (brend && *brend) {
char *p = lpsuf + brsl - (cs - wb);
char *p = lpsuf + qbrsl - (cs - wb);
strcpy(p, p + strlen(brend));
}
@ -5241,8 +5409,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
/* And get the file prefix. */
fpre = dupstring(((s1 == s || s1 == rpre || ic) &&
(*s != '/' || cs == wb)) ? s1 : s1 + 1);
qfpre = quotename(fpre, NULL);
/* And the suffix. */
fsuf = dupstrpfx(rsuf, s2 - rsuf);
qfsuf = quotename(fsuf, NULL);
if (comppatmatch && *comppatmatch && (ispattern & 2)) {
int t2;
@ -5506,6 +5676,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
* that things starting with these characters will be added. */
rpre = dyncat((ic == Tilde) ? "~" : "=", rpre);
rpl++;
qrpre = dyncat((ic == Tilde) ? "~" : "=", qrpre);
}
if (!ic && (cc->mask & CC_COMMPATH) && !*ppre && !*psuf) {
/* If we have to complete commands, add alias names, *
@ -6137,7 +6308,10 @@ permmatches(void)
Cmatch *p, *q;
Cexpl *ep, *eq, e, o;
Compctl *cp, *cq;
int nn, nl, fi = 0;
int nn, nl, fi = 0, gn = 1, mn = 1, rn;
if (hasperm)
freematches();
amatches = lmatches = NULL;
nmatches = smatches = 0;
@ -6179,13 +6353,17 @@ permmatches(void)
n->next = amatches;
amatches = n;
n->prev = 0;
n->num = gn++;
n->flags = g->flags;
n->mcount = g->mcount;
n->matches = p = (Cmatch *) ncalloc((n->mcount + 1) *
sizeof(Cmatch));
for (q = g->matches; *q; q++, p++)
for (rn = 1, q = g->matches; *q; q++, p++, rn) {
*p = dupmatch(*q);
(*p)->rnum = rn++;
(*p)->gnum = mn++;
}
*p = NULL;
n->lcount = g->lcount;
@ -6216,6 +6394,10 @@ permmatches(void)
n->ccs = NULL;
g = g->next;
}
pmatches = amatches;
hasperm = 1;
permmnum = mn - 1;
permgnum = gn - 1;
}
/* This frees one match. */
@ -6247,7 +6429,7 @@ freematch(Cmatch m)
static void
freematches(void)
{
Cmgroup g = amatches, n;
Cmgroup g = pmatches, n;
Cmatch *m;
Cexpl *e;
Compctl *c;
@ -6281,24 +6463,27 @@ freematches(void)
g = n;
}
hasperm = 0;
}
/* Insert the given string into the command line. If move is non-zero, *
* the cursor position is changed and len is the length of the string *
* to insert (if it is -1, the length is calculated here). */
* to insert (if it is -1, the length is calculated here). *
* The last argument says if we should quote the string. */
/**/
static void
static int
inststrlen(char *str, int move, int len)
{
if (!len || !str)
return;
return 0;
if (len == -1)
len = strlen(str);
spaceinline(len);
strncpy((char *)(line + cs), str, len);
if (move)
cs += len;
return len;
}
/* This builds the unambiguous string. If ins is non-zero, it is
@ -6319,10 +6504,11 @@ cline_str(Cline l, int ins, int *csp)
* to re-insert. */
if (ins) {
if ((hasp = (brbeg && *brbeg))) {
plen = strlen(brbeg); pl = brpl;
plen = strlen(brbeg); pl = (hasunqu ? brpl : qbrpl);
}
if ((hass = (brend && *brend))) {
slen = strlen(brend); sl = we - wb - brsl - plen - slen + 1;
slen = strlen(brend);
sl = we - wb - (hasunqu ? brsl : qbrsl) - plen - slen + 1;
}
if (!pl) {
inststrlen(brbeg, 1, -1);
@ -6606,6 +6792,7 @@ do_ambiguous(void)
* how REC_EXACT takes effect. We effectively turn the ambiguous *
* completion into an unambiguous one. */
if (ainfo && ainfo->exact == 1 && useexact && !(fromcomp & FC_LINE)) {
menucur = NULL;
do_single(ainfo->exactm);
invalidatelist();
return;
@ -6628,6 +6815,8 @@ do_ambiguous(void)
int atend = (cs == we), oll = ll, la;
VARARR(char, oline, ll);
menucur = NULL;
/* Copy the line buffer to be able to easily test if it changed. */
memcpy(oline, line, ll);
@ -6653,6 +6842,10 @@ do_ambiguous(void)
fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) |
((atend && cs != lastend) ? FC_INWORD : 0));
/* Probably move the cursor to then end. */
if (movetoend == 3)
cs = lastend;
/* If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
* if the completion is completely ambiguous') is set, and some *
* prefix was inserted, return now, bypassing the list-displaying *
@ -6674,7 +6867,8 @@ do_ambiguous(void)
* if it is needed. */
if (isset(LISTBEEP))
feep();
if (uselist && usemenu != 2 && !showinglist &&
if (uselist && usemenu != 2 &&
(!showinglist || (usemenu == 3 && !oldlist)) &&
(smatches >= 2 || (compforcelist && *compforcelist)))
showinglist = -2;
}
@ -6721,7 +6915,7 @@ do_single(Cmatch m)
/* We are currently not in a menu-completion, *
* so set the position variables. */
menupos = wb;
menuwe = (cs == we) || isset(ALWAYSTOEND);
menuwe = (movetoend >= 2 || (movetoend == 1 && !menucmp));
menuend = we;
}
/* If we are already in a menu-completion or if we have done a *
@ -6770,14 +6964,20 @@ do_single(Cmatch m)
* If it is, we append a slash. */
struct stat buf;
char *p;
int t = 0;
/* Build the path name. */
p = (char *) zhalloc(strlen(prpre) + strlen(str) +
if (m->ipre && m->ipre[0] == '~' && !m->ipre[1])
t = 1;
else {
/* Build the path name. */
p = (char *) zhalloc(strlen(prpre) + strlen(str) +
strlen(psuf) + 3);
sprintf(p, "%s%s%s", (prpre && *prpre) ? prpre : "./", str, psuf);
sprintf(p, "%s%s%s", (prpre && *prpre) ? prpre : "./", str, psuf);
/* And do the stat. */
if (!(sr = ztat(p, &buf, 0)) && S_ISDIR(buf.st_mode)) {
/* And do the stat. */
t = (!(sr = ztat(p, &buf, 0)) && S_ISDIR(buf.st_mode));
}
if (t) {
/* It is a directory, so add the slash. */
havesuff = 1;
inststrlen("/", 1, 1);
@ -6822,23 +7022,71 @@ do_single(Cmatch m)
if (menuwe && m->ripre && isset(AUTOPARAMKEYS))
makeparamsuffix(((m->flags & CMF_PARBR) ? 1 : 0), menuinsc);
if (menucmp && !menuwe)
if ((menucmp && !menuwe) || !movetoend)
cs = menuend;
}
/* This maps the value in v into the range [0,m-1], decrementing v
* if it is non-negative and making negative values cound backwards. */
static int
comp_mod(int v, int m)
{
if (v >= 0)
v--;
if (v >= 0)
return v % m;
else {
while (v < 0)
v += m;
return v;
}
}
/* This handles the beginning of menu-completion. */
/**/
static void
do_ambig_menu(void)
{
menucmp = 1;
menucur = NULL;
menugrp = amatches;
while (!menugrp->mcount)
menugrp = menugrp->next;
do_single(menugrp->matches[0]);
menucur = menugrp->matches;
Cmatch *mc;
if (usemenu != 3) {
menucmp = 1;
menucur = NULL;
} else {
if (oldlist) {
if (oldins)
acceptlast();
} else
menucur = NULL;
}
if (insgroup) {
insgnum = comp_mod(insgnum, permgnum);
for (menugrp = amatches;
menugrp && menugrp->num != insgnum + 1;
menugrp = menugrp->next);
if (!menugrp || !menugrp->mcount) {
menucur = NULL;
return;
}
insmnum = comp_mod(insmnum, menugrp->mcount);
} else {
int c = 0;
insmnum = comp_mod(insmnum, permmnum);
for (menugrp = amatches;
menugrp && (c += menugrp->mcount) <= insmnum;
menugrp = menugrp->next)
insmnum -= menugrp->mcount;
if (!menugrp) {
menucur = NULL;
return;
}
}
mc = menugrp->matches + insmnum;
do_single(*mc);
menucur = mc;
}
/* Return the length of the common prefix of s and t. */
@ -6924,6 +7172,15 @@ printfmt(char *fmt, int n, int dopr)
u = 0; m = 1;
tcout(TCUNDERLINEEND);
break;
case '{':
for (p++; *p && (*p != '%' || p[1] != '}'); p++, cc++)
if (dopr)
putc(*p, shout);
if (*p)
p++;
else
p--;
break;
}
if (m) {
if (b)
@ -6971,7 +7228,6 @@ listmatches(void)
Cexpl *e;
int nlines = 0, ncols, nlist = 0, longest = 1, pnl = 0;
int of = isset(LISTTYPES), opl = 0;
int listmax = getiparam("LISTMAX");
#ifdef DEBUG
/* Sanity check */
@ -6983,11 +7239,10 @@ listmatches(void)
/* Set the cursor below the prompt. */
trashzle();
showinglist = 0;
showinglist = listshown = 0;
clearflag = (isset(USEZLE) && !termflags &&
(isset(ALWAYSLASTPROMPT) && zmult == 1)) ||
(unset(ALWAYSLASTPROMPT) && zmult != 1);
complastprompt && *complastprompt);
for (g = amatches; g; g = g->next) {
char **pp = g->ylist;
@ -7066,7 +7321,8 @@ listmatches(void)
}
/* Maybe we have to ask if the user wants to see the list. */
if ((listmax && nlist > listmax) || (!listmax && nlines >= lines)) {
if ((complistmax && nlist > complistmax) ||
(!complistmax && nlines >= lines)) {
int qup;
zsetterm();
qup = printfmt("zsh: do you wish to see all %n possibilities? ", nlist, 1);
@ -7204,6 +7460,7 @@ listmatches(void)
if ((nlines += nlnct - 1) < lines) {
tcmultout(TCUP, TCMULTUP, nlines);
showinglist = -1;
listshown = 1;
} else
clearflag = 0, putc('\n', shout);
} else

View file

@ -397,6 +397,7 @@ scanner(Complist q)
int pbcwdsav = pathbufcwd;
int errssofar = errsfound;
struct dirsav ds;
char *str;
ds.ino = ds.dev = 0;
ds.dirname = NULL;
@ -412,17 +413,18 @@ scanner(Complist q)
scanner(q->next);
}
c = q->comp;
str = c->str;
/* Now the actual matching for the current path section. */
if (!(c->next || c->left) && !haswilds(c->str)
if (!(c->next || c->left) && !haswilds(str)
&& (!((c->stat & (C_LCMATCHUC|C_IGNCASE)) || c->errsmax)
|| !strcmp(".", c->str) || !strcmp("..", c->str))) {
|| !*str || !strcmp(".", str) || !strcmp("..", str))) {
/*
* We always need to match . and .. explicitly, even if we're
* checking other strings for case-insensitive matches.
*
* It's a straight string to the end of the path section.
*/
int l = strlen(c->str);
int l = strlen(str);
if (l + !l + pathpos - pathbufcwd >= PATH_MAX) {
int err;
@ -442,14 +444,14 @@ scanner(Complist q)
/* Not the last path section. Just add it to the path. */
int oppos = pathpos;
if (!errflag && !(q->closure && !strcmp(c->str, "."))) {
addpath(c->str);
if (!errflag && !(q->closure && !strcmp(str, "."))) {
addpath(str);
if (!closure || statfullpath("", NULL, 1))
scanner((q->closure) ? q : q->next);
pathbuf[pathpos = oppos] = '\0';
}
} else
insert(c->str, 0);
insert(str, 0);
} else {
/* Do pattern matching on current path section. */
char *fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : ".";
@ -2282,16 +2284,45 @@ int
getmatch(char **sp, char *pat, int fl, int n, char *replstr)
{
Comp c;
char *s = *sp, *t, *start, sav;
int i, l = strlen(*sp), matched;
MUSTUSEHEAP("getmatch"); /* presumably covered by prefork() test */
repllist = NULL;
c = parsereg(pat);
if (!c) {
zerr("bad pattern: %s", pat, 0);
return 1;
}
return igetmatch(sp, c, fl, n, replstr);
}
/**/
void
getmatcharr(char ***ap, char *pat, int fl, int n, char *replstr)
{
char **arr = *ap, **pp;
Comp c;
MUSTUSEHEAP("getmatch"); /* presumably covered by prefork() test */
c = parsereg(pat);
if (!c) {
zerr("bad pattern: %s", pat, 0);
return 1;
return;
}
*ap = pp = ncalloc(sizeof(char *) * (arrlen(arr) + 1));
while ((*pp = *arr++))
if (igetmatch(pp, c, fl, n, replstr))
pp++;
}
/**/
static int
igetmatch(char **sp, Comp c, int fl, int n, char *replstr)
{
char *s = *sp, *t, *start, sav;
int i, l = strlen(*sp), matched;
repllist = NULL;
if (fl & SUB_ALL) {
i = domatch(s, c, 0);
*sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0);

View file

@ -1361,16 +1361,24 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
NULL, s[-1]);
return NULL;
}
singsub(&s);
{
char t = s[-1];
singsub(&s);
if (t == '/' && (flags & SUB_SUBSTR)) {
if (*s == '#' || *s == '%') {
flags &= ~SUB_SUBSTR;
if (*s == '%')
flags |= SUB_END;
s++;
} else if (*s == '\\') {
s++;
}
}
}
if (!vunset && isarr) {
char **ap = aval;
char **pp = aval = (char **)ncalloc(sizeof(char *) * (arrlen(aval) + 1));
while ((*pp = *ap++)) {
if (getmatch(pp, s, flags, flnum, replstr))
pp++;
}
getmatcharr(&aval, s, flags, flnum, replstr);
copied = 1;
} else {
if (vunset)

View file

@ -3177,10 +3177,7 @@ bslashquote(const char *s, char **e, int instring)
*v++ = *u;
}
*v = '\0';
if (strcmp(buf, s))
tt = dupstring(buf);
else
tt = s;
tt = dupstring(buf);
v += tt - buf;
if (e && (sf & 1))
*e += tt - buf;

Some files were not shown because too many files have changed in this diff Show more