summaryrefslogtreecommitdiff
path: root/Completion/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Core')
-rw-r--r--Completion/Core/_all_labels44
-rw-r--r--Completion/Core/_alternative45
-rw-r--r--Completion/Core/_approximate192
-rw-r--r--Completion/Core/_call2
-rw-r--r--Completion/Core/_complete58
-rw-r--r--Completion/Core/_correct4
-rw-r--r--Completion/Core/_description54
-rw-r--r--Completion/Core/_expand152
-rw-r--r--Completion/Core/_files59
-rw-r--r--Completion/Core/_ignored3
-rw-r--r--Completion/Core/_list43
-rw-r--r--Completion/Core/_main_complete221
-rw-r--r--Completion/Core/_match44
-rw-r--r--Completion/Core/_menu4
-rw-r--r--Completion/Core/_next_label24
-rw-r--r--Completion/Core/_oldlist53
-rw-r--r--Completion/Core/_path_files661
-rw-r--r--Completion/Core/_prefix4
-rw-r--r--Completion/Core/_requested21
-rw-r--r--Completion/Core/_setup68
-rw-r--r--Completion/Core/_tags144
-rw-r--r--Completion/Core/_wanted22
-rw-r--r--Completion/Core/compdump62
-rw-r--r--Completion/Core/compinit427
-rw-r--r--Completion/Core/compinstall431
25 files changed, 1866 insertions, 976 deletions
diff --git a/Completion/Core/_all_labels b/Completion/Core/_all_labels
new file mode 100644
index 000000000..fa7118ec4
--- /dev/null
+++ b/Completion/Core/_all_labels
@@ -0,0 +1,44 @@
+#autoload
+
+local gopt=-J len tmp pre suf tloop ret=1 descr
+
+if [[ "$1" = -t ]]; then
+ tloop=yes
+ shift
+fi
+if [[ "$1" = -([12]|)[VJ] ]]; then
+ gopt="$1"
+ shift
+fi
+
+tmp=${argv[(ib:4:)-]}
+len=$#
+if [[ tmp -lt len ]]; then
+ pre=$(( tmp-1 ))
+ suf=$tmp
+elif [[ tmp -eq $# ]]; then
+ pre=-2
+ suf=$(( len+1 ))
+else
+ pre=4
+ suf=5
+fi
+
+while [[ -z "$tloop" ]] || comptags -N; do
+ while comptags -A "$1" curtag; do
+ if [[ "$curtag" = *:* ]]; then
+ zformat -f descr "${curtag#*:}" "d:$3"
+ _description "$gopt" "${curtag%:*}" "$2" "$descr"
+ curtag="${curtag%:*}"
+
+ "$4" "${(P@)2}" "${(@)argv[5,-1]}"
+ else
+ _description "$gopt" "$curtag" "$2" "$3"
+
+ "${(@)argv[4,pre]}" "${(P@)2}" "${(@)argv[suf,-1]}" && ret=0
+ fi
+ done
+ [[ -z "$tloop" || ret -eq 0 ]] && break
+done
+
+return ret
diff --git a/Completion/Core/_alternative b/Completion/Core/_alternative
index 158f3a07a..b038aa8a4 100644
--- a/Completion/Core/_alternative
+++ b/Completion/Core/_alternative
@@ -1,19 +1,23 @@
#autoload
-local tags def expl descr action mesgs nm="$compstack[nmatches]"
-local context
+local tags def expl descr action mesgs nm="$compstate[nmatches]" subopts
+local opt curcontext="$curcontext"
+
+subopts=()
+while getopts 'O:C:' opt; do
+ case "$opt" in
+ O) subopts=( "${(@P)OPTARG}" ) ;;
+ C) curcontext="${curcontext%:*}:$OPTARG" ;;
+ esac
+done
+
+shift OPTIND-1
-if [[ "$1" = -C?* ]]; then
- context="${1[3,-1]}"
- shift
-elif [[ "$1" = -C ]]; then
- context="$2"
- shift 2
-fi
+[[ "$1" = -(|-) ]] && shift
mesgs=()
-_tags -C "$context" "${(@)argv%%:*}"
+_tags "${(@)argv%%:*}"
while _tags; do
for def; do
@@ -21,7 +25,7 @@ while _tags; do
descr="${${def#*:}%%:*}"
action="${def#*:*:}"
- _description expl "$descr"
+ _description "${def%%:*}" expl "$descr"
if [[ "$action" = \ # ]]; then
@@ -35,28 +39,35 @@ while _tags; do
eval ws\=\( "${action[3,-3]}" \)
- _describe "$descr" ws -M 'r:|[_-]=* r:|=*'
+ _describe "$descr" ws -M 'r:|[_-]=* r:|=*' "$subopts[@]"
elif [[ "$action" = \(*\) ]]; then
# Anything inside `(...)' is added directly.
- compadd "$expl[@]" - ${=action[2,-2]}
+ _all_labels "${def%%:*}" expl "$descr" \
+ compadd "$subopts[@]" - ${=action[2,-2]}
elif [[ "$action" = \{*\} ]]; then
# A string in braces is evaluated.
- eval "$action[2,-2]"
+ while _next_label "${def%%:*}" expl "$descr"; do
+ eval "$action[2,-2]"
+ done
elif [[ "$action" = \ * ]]; then
# If the action starts with a space, we just call it.
- ${(e)=~action}
+ eval "action=( $action )"
+ while _next_label "${def%%:*}" expl "$descr"; do
+ "$action[@]"
+ done
else
# Otherwise we call it with the description-arguments built above.
- action=( $=action )
- ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
+ eval "action=( $action )"
+ _all_labels "${def%%:*}" expl "$descr" \
+ "$action[1]" "$subopts[@]" "${(@)action[2,-1]}"
fi
fi
done
diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate
index 1b40f7cbf..0815a308e 100644
--- a/Completion/Core/_approximate
+++ b/Completion/Core/_approximate
@@ -1,102 +1,30 @@
#autoload
# This code will try to correct the string on the line based on the
-# strings generated for the context if `compconfig[correct]' is set.
-# These corrected strings will be shown in a list and one can
-# cycle through them as in a menucompletion or get the corrected prefix.
-#
-# Supported configuration keys:
-#
-# 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.
-
-local _comp_correct _correct_prompt comax
-local cfgacc cfgorig cfgps cfgins
-
-# Only if all global matchers hav been tried.
-
-[[ compstate[matcher] -ne compstate[total_matchers] ]] && return 1
-
-# We don't try correction if the string is too short.
-
-[[ "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1
-
-# Get the configuration values, using either the prefix `correct' or
-# `approximate'.
-
-if [[ "$compstate[pattern_match]" = (|\**) ]]; then
- cfgacc="${compconfig[approximate_accept]:-$compconfig[correct_accept]}"
- cfgorig="${compconfig[approximate_original]:-$compconfig[correct_original]}"
- cfgps="${compconfig[approximate_prompt]:-$compconfig[correct_prompt]}"
- cfgins="${compconfig[approximate_insert]:-$compconfig[correct_insert]}"
-else
- cfgacc="$compconfig[correct_accept]"
- cfgorig="$compconfig[correct_original]"
- cfgps="$compconfig[correct_prompt]"
- cfgins="$compconfig[correct_insert]"
-fi
+# strings generated for the context. These corrected strings will be
+# shown in a list and one can cycle through them as in a menucompletion
+# or get the corrected prefix.
+
+# We don't try correction if the string is too short or we have tried it
+# already.
+
+[[ _matcher_num -gt 1 || "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1
+
+local _comp_correct _correct_expl comax cfgacc
+local oldcontext="${curcontext}" opm="$compstate[pattern_match]"
+
+zstyle -s ":completion:${curcontext}:" max-errors cfgacc || cfgacc='2 numeric'
# Get the number of errors to accept.
-if [[ "$cfgacc" = *[nN]* && NUMERIC -ne 1 ]]; then
- # Stop if we also have a `!'.
+if [[ "$cfgacc" = *numeric* && ${NUMERIC:-1} -ne 1 ]]; then
+ # A numeric argument may mean that we should not try correction.
- [[ "$cfgacc" = *\!* ]] && return 1
+ [[ "$cfgacc" = *not-numeric* ]] && return 1
# Prefer the numeric argument if that has a sensible value.
- comax="$NUMERIC"
+ comax="${NUMERIC:-1}"
else
comax="${cfgacc//[^0-9]}"
fi
@@ -105,13 +33,15 @@ fi
[[ "$comax" -lt 1 ]] && return 1
-# Otherwise temporarily define functions to use instead of
-# the builtins that add matches. This is used to be able
-# to stick the `(#a...)' into the right place (after an
+_tags corrections original
+
+# Otherwise temporarily define a function to use instead of
+# the builtin that adds matches. This is used to be able
+# to stick the `(#a...)' in the right place (after an
# ignored prefix).
compadd() {
- [[ "$*" != *-([a-zA-Z/]#|)U* &&
+ [[ ${argv[(I)-[a-zA-Z]#U[a-zA-Z]#]} -eq 0 &&
"${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] && return
if [[ "$PREFIX" = \~*/* ]]; then
@@ -119,79 +49,49 @@ compadd() {
else
PREFIX="(#a${_comp_correct})$PREFIX"
fi
- if [[ -n "$_correct_prompt" ]]; then
- builtin compadd -X "$_correct_prompt" -J _correct "$@"
- else
- builtin compadd -J _correct "$@"
- fi
+ builtin compadd "$_correct_expl[@]" "$@"
}
-compgen() {
- [[ "$*" != *-([a-zA-Z/]#|)U* &&
- "${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] && return
-
- if [[ "$PREFIX" = \~*/* ]]; then
- PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}"
- else
- PREFIX="(#a${_comp_correct})$PREFIX"
- fi
- if [[ -n "$_correct_prompt" ]]; then
- builtin compgen "$@" -X "$_correct_prompt" -J _correct
- else
- builtin compgen "$@" -J _correct
- fi
-}
-
-# Now initialise our counter. We also set `compstate[matcher]'
-# to `-1'. This allows completion functions to use the simple
-# `[[ compstate[matcher] -gt 1 ]] && return' to avoid being
-# called for multiple global match specs and still be called
-# again when correction is done. Also, this makes it easy to
-# test if correction is attempted since `compstate[matcher]'
-# will never be set to a negative value by the completion code.
-
_comp_correct=1
-compstate[matcher]=-1
-
-_correct_prompt="${cfgps//\%e/1}"
-
-# We also need to set `extendedglob' and make the completion
-# code behave as if globcomplete were set.
-
-setopt extendedglob
[[ -z "$compstate[pattern_match]" ]] && compstate[pattern_match]='*'
while [[ _comp_correct -le comax ]]; do
+ curcontext="${oldcontext/(#b)([^:]#:[^:]#:)/${match[1][1,-2]}-${_comp_correct}:}"
+
+ _description corrections _correct_expl corrections \
+ "e:$_comp_correct" "o:$PREFIX$SUFFIX"
+
if _complete; then
- if [[ "$cfgins" = unambig* &&
- "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then
+ if zstyle -t ":completion:${curcontext}:" insert-unambiguous &&
+ [[ "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then
compstate[pattern_insert]=unambiguous
- elif [[ compstate[nmatches] -gt 1 || "$cfgorig" = *always* ]]; then
- if [[ "$cfgorig" = *last* ]]; then
- builtin compadd -U -V _correct_original -nQ - "$PREFIX$SUFFIX"
- elif [[ -n "$cfgorig" ]]; then
- builtin compadd -U -nQ - "$PREFIX$SUFFIX"
- fi
+ elif _requested original &&
+ { [[ compstate[nmatches] -gt 1 ]] ||
+ zstyle -t ":completion:${curcontext}:" original }; then
+ local expl
+
+ _description -V original expl original
+
+ builtin compadd "$expl[@]" -U -Q - "$PREFIX$SUFFIX"
# If you always want to see the list of possible corrections,
- # set `compstate[list]=list' here.
+ # set `compstate[list]=list force' here.
- compstate[force_list]=list
+ [[ "$compstate[list]" != list* ]] &&
+ compstate[list]="$compstate[list] force"
fi
- compstate[matcher]="$compstate[total_matchers]"
- unfunction compadd compgen
+ unfunction compadd
+ compstate[pattern_match]="$opm"
return 0
fi
[[ "${#:-$PREFIX$SUFFIX}" -le _comp_correct+1 ]] && break
(( _comp_correct++ ))
-
- _correct_prompt="${cfgps//\%e/$_comp_correct}"
done
-compstate[matcher]="$compstate[total_matchers]"
-unfunction compadd compgen
+unfunction compadd
+compstate[pattern_match]="$opm"
return 1
diff --git a/Completion/Core/_call b/Completion/Core/_call
index 345dae50d..b038a80bc 100644
--- a/Completion/Core/_call
+++ b/Completion/Core/_call
@@ -1,4 +1,4 @@
-#autoload
+#autoload +X
local tmp
diff --git a/Completion/Core/_complete b/Completion/Core/_complete
index 0f4d5ff4b..c2679dcb8 100644
--- a/Completion/Core/_complete
+++ b/Completion/Core/_complete
@@ -2,51 +2,65 @@
# Generate all possible completions. Note that this is not intended as
# a normal completion function, but as one possible value for the
-# compconfig[completer] parameter.
+# completer style.
-local comp name
+local comp name oldcontext
+typeset -T curcontext="$curcontext" ccarray
+
+oldcontext="$curcontext"
+
+# If we have a user-supplied context name, use only that.
+
+if [[ -n "$compcontext" ]]; then
+ ccarray[3]="$compcontext"
+
+ comp="$_comps[$compcontext]"
+ [[ -z "$comp" ]] || "$comp"
+
+ return
+fi
# An entry for `-first-' is the replacement for `compctl -T'
-# Completion functions may set `_compskip' to any value to make the
-# main loops stop calling other completion functions.
comp="$_comps[-first-]"
if [[ ! -z "$comp" ]]; then
+ ccarray[3]=-first-
"$comp"
- if (( $+_compskip )); then
- unset _compskip
+ if [[ "$_compskip" = all ]]; then
+ _compskip=''
(( compstate[nmatches] ))
return
fi
fi
+
# For arguments and command names we use the `_normal' function.
if [[ "$compstate[context]" = command ]]; then
- _normal
+ curcontext="$oldcontext"
+ _normal -s
else
# Let's see if we have a special completion definition for the other
# possible contexts.
- comp=''
-
- case $compstate[context] in
- equal) comp="$_comps[-equal-]";;
- tilde) comp="$_comps[-tilde-]";;
- redirect) comp="$_comps[-redirect-]";;
- math) comp="$_comps[-math-]";;
- subscript) comp="$_comps[-subscript-]";;
- value) comp="$_comps[-value-]";;
- array_value) comp="$_comps[-array-value-]";;
- condition) comp="$_comps[-condition-]";;
- parameter) comp="$_comps[-parameter-]";;
- brace_parameter) comp="$_comps[-brace-parameter-]";;
- esac
+ local cname="-${compstate[context]:s/_/-/}-"
+
+ ccarray[3]="$cname"
+
+ comp="$_comps[$cname]"
# If not, we use default completion, if any.
- [[ -z "$comp" ]] && comp="$_comps[-default-]"
+ if [[ -z "$comp" ]]; then
+ if [[ "$_compskip" = *default* ]]; then
+ _compskip=''
+ return 1
+ fi
+ comp="$_comps[-default-]"
+ fi
[[ -z "$comp" ]] || "$comp"
fi
+_compskip=''
+
(( compstate[nmatches] ))
diff --git a/Completion/Core/_correct b/Completion/Core/_correct
index 35ab01cf1..c9c3d999c 100644
--- a/Completion/Core/_correct
+++ b/Completion/Core/_correct
@@ -1,8 +1,8 @@
#autoload
-# This is mainly a wrapper around the more general `_approximate.
+# This is mainly a wrapper around the more general `_approximate'.
# By setting `compstate[pattern_match]' to something unequal to `*' and
-# then calling `_approximate, we get only corrections, not all strings
+# then calling `_approximate', we get only corrections, not all strings
# with the corrected prefix and something after it.
#
# Supported configuration keys are the same as for `_approximate', only
diff --git a/Completion/Core/_description b/Completion/Core/_description
index 874ba8a96..7db47228b 100644
--- a/Completion/Core/_description
+++ b/Completion/Core/_description
@@ -1,22 +1,56 @@
#autoload
-local gropt=-J
+local name gropt=-J format gname hidden hide match opts
-if [[ "$1" = -V ]]; then
- gropt=-V
+opts=()
+
+if [[ "$1" = -([12]|)[VJ] ]]; then
+ gropt="$1"
shift
fi
-if [[ -n "$compconfig[group_matches]" ]]; then
- if [[ -n "$compconfig[description_format]" ]]; then
- eval "$1=($gropt ${(q)2} -X ${(q)compconfig[description_format]//\\%d/$2})"
+_lastdescr=( "$_lastdescr[@]" "$3" )
+
+_setup "$1"
+
+name="$2"
+
+zstyle -s ":completion:${curcontext}:$1" format format ||
+ zstyle -s ":completion:${curcontext}:descriptions" format format
+
+zstyle -s ":completion:${curcontext}:$1" hidden hidden
+if [[ "$hidden" = (all|yes|true|1|on) ]]; then
+ [[ "$hidden" = all ]] && format=''
+ opts=(-n)
+fi
+zstyle -s ":completion:${curcontext}:$1" group-name gname &&
+ [[ -z "$gname" ]] && gname="$1"
+zstyle -s ":completion:${curcontext}:$1" matcher match &&
+ opts=($opts -M "${(q)match}")
+[[ -n "$_matcher" ]] && opts=($opts -M "${(q)_matcher}")
+
+if [[ -z "$_comp_no_ignore" ]] &&
+ zstyle -a ":completion:${curcontext}:$1" ignored-patterns _comp_ignore; then
+ opts=( $opts -F _comp_ignore )
+else
+ _comp_ignore=()
+fi
+
+shift 2
+[[ -n "$format" ]] && zformat -f format "$format" "d:$1" "${(@)argv[2,-1]}"
+
+if [[ -n "$gname" ]]; then
+ if [[ -n "$format" ]]; then
+ eval "${name}=($opts $gropt ${(q)gname} -X \"${format}\")"
else
- eval "$1=($gropt ${(q)2})"
+ eval "${name}=($opts $gropt ${(q)gname})"
fi
else
- if [[ -n "$compconfig[description_format]" ]]; then
- eval "$1=(-X ${(q)compconfig[description_format]//\\%d/$2})"
+ if [[ -n "$format" ]]; then
+ eval "${name}=($opts $gropt -default- -X \"${format}\")"
else
- eval "$1=()"
+ eval "${name}=($opts $gropt -default-)"
fi
fi
+
+return 0
diff --git a/Completion/Core/_expand b/Completion/Core/_expand
index 9172b6cbf..eff8d8601 100644
--- a/Completion/Core/_expand
+++ b/Completion/Core/_expand
@@ -6,61 +6,20 @@
# This function will allow other completer functions to be called if
# the expansions done produce no result or do not change the original
# word from the line.
-#
-# Configuration keys:
-#
-# 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.
-
-local exp word="$PREFIX$SUFFIX" group=-V
-
-# Do this only for the first global matcher.
-
-[[ "$compstate[matcher]" -le 1 ]] || return 1
+
+setopt localoptions nullglob
+
+[[ _matcher_num -gt 1 ]] && return 1
+
+local exp word="$PREFIX$SUFFIX" sort expr expl subd suf=" "
+
+# First, see if we should insert all *completions*.
+
+if zstyle -s ":completion:${curcontext}:" completions expr &&
+ [[ "${(e):-\$[$expr]}" -eq 1 ]]; then
+ compstate[insert]=all
+ return 1
+fi
# In exp we will collect the expansion.
@@ -69,79 +28,68 @@ exp=("$word")
# First try substitution. That weird thing spanning multiple lines
# changes quoted spaces, tabs, and newlines into spaces.
-[[ -z "$compconfig[expand_substitute]" ||
- "${(e):-\$[$compconfig[expand_substitute]]}" -eq 1 ]] &&
+zstyle -s ":completion:${curcontext}:" substitute expr &&
+ [[ "${(e):-\$[$expr]}" -eq 1 ]] &&
exp=( "${(e)exp//\\[
]/ }" )
# If the array is empty, store the original string again.
-[[ -z "$exp" ]] && exp=("$word")
+(( $#exp )) || exp=("$word")
+
+subd=("$exp[@]")
# Now try globbing.
-[[ -z "$compconfig[expand_glob]" ||
- "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ]] &&
- exp=( ${~exp}(N) )
+zstyle -s ":completion:${curcontext}:" glob expr &&
+ [[ "${(e):-\$[$expr]}" -eq 1 ]] &&
+ exp=( ${~exp} )
# If we don't have any expansions or only one and that is the same
# as the original string, we let other completers run.
-[[ $#exp -eq 0 ||
- ( $#exp -eq 1 && "$exp[1]" = "$word" ) ]] && return 1
+(( $#exp )) || exp=("$subd[@]")
-# We have expansions, should we menucomplete them?
+[[ $#exp -eq 1 && "$exp[1]" = "$word"(|\(N\)) ]] && return 1
-if [[ -z "$compconfig[expand_menu]" ]]; then
+# With subst-globs-only we bail out if there were no glob expansions,
+# regardless of any substitutions
- # No, so if the user only wants a list, we add the strings
- # separately. Otherwise we add the whole array as one string,
- # probably also adding the original string.
+zstyle -s ":completion:${curcontext}:" subst-globs-only expr &&
+ [[ "${(e):-\$[$expr]}" -eq 1 && "$subd" = "$exp"(|\(N\)) ]] && return 1
- if [[ -z "$compstate[insert]" ]]; then
- compadd -U -V _expand -Q - "$exp[@]"
- else
- [[ -n "$compconfig[expand_original]" &&
- "$compconfig[expand_original]" != *last* ]] &&
- compadd -UnQ -V _expand_original - "$word"
+# Now add as matches whatever the user requested.
- compadd -UQ -V _expand - "$exp"
+zstyle -s ":completion:${curcontext}:" sort sort
- [[ -n "$compconfig[expand_original]" &&
- "$compconfig[expand_original]" = *last* ]] &&
- compadd -UnQ -V _expand_original - "$word"
+[[ "$sort" = (yes|true|1|on) ]] && exp=( "${(@o)exp}" )
- compstate[insert]=menu
- fi
-else
- # Sorting? We just use a different group type then.
+# If there is only one expansion, add a suitable suffix
+(($#exp == 1)) && suf='' && [[ -d $exp && "$exp[1]" != */ ]] && suf='/'
- [[ "$compconfig[expand_menu]" = *sort* ]] && group=-J
+if [[ -z "$compstate[insert]" ]] ;then
+ _description all-expansions expl 'all expansions' "o:$word"
- # Now add the expansion string, probably also adding the original
- # and/or the string containing all expanded string.
+ compadd "$expl[@]" -UQ -qS "$suf" - "$exp"
+else
+ _tags all-expansions expansions original
- [[ -n "$compconfig[expand_original]" &&
- "$compconfig[expand_original]" != *last* ]] &&
- compadd -UnQ -V _expand_original - "$word"
- [[ "$compconfig[expand_menu]" = *last* &&
- "$compconfig[expand_menu]" != *only* ]] &&
- compadd -UnQ -V _expand_all - "$exp"
+ if _requested all-expansions; then
+ _description all-expansions expl 'all expansions'
+ compadd "$expl[@]" -UQ -qS "$suf" - "$exp"
+ fi
- if [[ -z "$compconfig[expand_prompt]" ]]; then
- compadd -UQ $group _expand - "$exp[@]"
- else
- compadd -UQ -X "${compconfig[expand_prompt]//\%o/$word}" \
- $group _expand - "$exp[@]"
+ if [[ $#exp -gt 1 ]] && _requested expansions; then
+ if [[ "$sort" = menu ]]; then
+ _description expansions expl expansions "o:$word"
+ else
+ _description -V expansions expl expansions "o:$word"
+ fi
+ compadd "$expl[@]" -UQ - "$exp[@]"
fi
- [[ "$compconfig[expand_menu]" != *last* &&
- "$compconfig[expand_menu]" != *only* ]] &&
- compadd -UnQ -V _expand_all - "$exp"
- [[ -n "$compconfig[expand_original]" &&
- "$compconfig[expand_original]" = *last* ]] &&
- compadd -UnQ -V _expand_original - "$word"
+ _requested original expl original && compadd "$expl[@]" -UQ - "$word"
compstate[insert]=menu
fi
diff --git a/Completion/Core/_files b/Completion/Core/_files
index d2cce35e7..1755abebd 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -1,26 +1,49 @@
#autoload
-# Utility function for completing files of a given type or any file.
-# In many cases you will want to call this one instead of _path_files().
+local opts tmp glob pats expl tag i pat descr minus
-local nm=$NMATCHES
+zparseopts -a opts \
+ '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X+: M+: F: J+: V+:
-_path_files "$@"
+type="${(@j::M)${(@)tmp#-}#?}"
+(( $tmp[(I)-g*] )) && glob="${(j: :)${(M)tmp:#-g*}#-g}"
-if [[ $# -ne 0 && -nmatches nm ]]; then
- local opt opts
+if zstyle -a ":completion:${curcontext}:" file-patterns pats; then
+ [[ "$type" = */* ]] && glob="$glob *(-/)"
+ pats=( \ ${(M)^${pats//\\%p/ ${glob:-\*} }:#*[^\\]:*} )
+else
+ if [[ "$type" = *g* ]]; then
+ if [[ "$type" = */* ]]; then
+ pats=( " ${glob//:/\\:} *(-/):globbed-files" '*:all-files' )
+ else
+ pats=( " ${glob//:/\\:}:globbed-files"
+ '*(-/):directories' '*:all-files' )
+ fi
+ elif [[ "$type" = */* ]]; then
+ pats=( '*(-/):directories' '*:all-files' )
+ else
+ pats=( '*:all-files' )
+ fi
+fi
- # We didn't get any matches for those types of files described by
- # the `-g' or `-/' option. Now we try it again accepting all files.
- # First we get those options that we have to use even if then. If
- # we find out that the `-f' option was given, we already accepted
- # all files and give up immediatly.
+for tag in "${(@)${(@)pats#*[^\\]:}%%:*}"; do
- opts=()
- while getopts "P:S:W:F:J:V:X:f/g:" opt; do
- [[ "$opt" = f ]] && return
- [[ "$opt" = [PSWFJVX] ]] && opts=("$opts[@]" "-$opt" "$OPTARG")
- done
+ i="$pats[(I)*[^\\\\]:${tag}(|:*)]"
+ pat="${${pats[i]%%:${tag}*}//\\\\:/:}"
- _path_files "$opts[@]"
-fi
+ if [[ i -gt 0 && "$pat" != \ # ]]; then
+ if [[ "$pats[i]" = *:${tag}:* ]]; then
+ descr="${pats[i]#*:${tag}:}"
+ minus=()
+ else
+ descr=file
+ minus=(-)
+ fi
+ fi
+
+ _wanted "$tag" expl "$descr" \
+ _path_files -g "$pat" "$opts[@]" "$minus[@]" && return 0
+
+done
+
+return 1
diff --git a/Completion/Core/_ignored b/Completion/Core/_ignored
index 69a5244cc..4046f4c2d 100644
--- a/Completion/Core/_ignored
+++ b/Completion/Core/_ignored
@@ -4,11 +4,10 @@
(( $compstate[ignored] )) || return 1
-local curcontext="${curcontext/:[^:]#:/:ignored-${(M)#_completers[1,_completer_num]:#_ignored}:}"
local comp i _comp_no_ignore=yes tmp expl
zstyle -a ":completion:${curcontext}:" completer comp ||
- comp=( "${(@)_completers[1,_completer_num-1][(R)_ignored,-1]}" )
+ comp=( "${(@)_completers[1,_completer_num-1][(R)_ignored(|:*),-1]}" )
for i in "$comp[@]"; do
if [[ "$i" != _ignored ]] && "$i"; then
diff --git a/Completion/Core/_list b/Completion/Core/_list
index 099c6bc7b..37167726c 100644
--- a/Completion/Core/_list
+++ b/Completion/Core/_list
@@ -1,38 +1,16 @@
#autoload
# This completer function makes the other completer functions used
-# insert possible completions only after once the list has been
-# shown.
-#
-# Configuration keys:
-#
-# 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.
-
-local pre suf
+# insert possible completions only after the list has been shown at
+# least once.
+
+[[ _matcher_num -gt 1 ]] && return 1
+
+local pre suf expr
# Get the strings to compare.
-if [[ -z "$compconfig[list_word]" ]]; then
+if zstyle -t ":completion:${curcontext}:" word; then
pre="$HISTNO$LBUFFER"
suf="$RBUFFER"
else
@@ -42,16 +20,15 @@ fi
# Should we only show a list now?
-if [[ ( -z "$compconfig[list_condition]" ||
- "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ) &&
+zstyle -s ":completion:${curcontext}:" condition expr
+if [[ ( -z "$expr" || "${(e):-\$[$expr]}" -eq 1 ) &&
( "$pre" != "$_list_prefix" || "$suf" != "$_list_suffix" ) ]]; then
# Yes. Tell the completion code about it and save the new values
# to compare the next time.
compstate[insert]=''
- compstate[list]=list
- compstate[force_list]=yes
+ compstate[list]='list force'
_list_prefix="$pre"
_list_suffix="$suf"
fi
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
index c7f5a5a96..d9278f435 100644
--- a/Completion/Core/_main_complete
+++ b/Completion/Core/_main_complete
@@ -2,47 +2,206 @@
# The main loop of the completion code. This is what is called when
# completion is attempted from the command line.
-# The completion code gives us the special variables and the arguments
-# from the command line are given as positional parameters.
-local comp name
-setopt localoptions nullglob rcexpandparam globdots
-unsetopt markdirs globsubst shwordsplit nounset
+# If you want to complete only set or unset options for the unsetopt
+# and setopt builtin, un-comment these lines:
+#
+# local _set_options _unset_options
+#
+# _set_options=(${(k)options[(R)on]})
+# _unset_options=(${(k)options[(R)off]})
+#
+# This is needed because completion functions may set options locally
+# which makes the output of setopt and unsetopt reflect a different
+# state than the global one for which you are completing.
-# An entry for `-first-' is the replacement for `compctl -T'
-# Completion functions may set `_compskip' to any value to make the
-# main loops stop calling other completion functions.
+setopt localoptions nullglob rcexpandparam extendedglob
+unsetopt markdirs globsubst shwordsplit nounset ksharrays
-comp="$_comps[-first-]"
-if [[ ! -z "$comp" ]]; then
- "$comp" "$@"
- if (( $+_compskip )); then
- unset _compskip
- return
- fi
+local func funcs ret=1 tmp _compskip format _comp_ignore \
+ _completers _completer _completer_num curtag \
+ _matchers _matcher _matcher_num _comp_tags \
+ context state line opt_args val_args curcontext="$curcontext" \
+ _last_nmatches=-1 _last_menu_style _def_menu_style _menu_style sel \
+ _saved_exact="${compstate[exact]}" \
+ _saved_lastprompt="${compstate[last_prompt]}" \
+ _saved_list="${compstate[list]}" \
+ _saved_insert="${compstate[insert]}"
+
+typeset -U _lastdescr
+
+[[ -z "$curcontext" ]] && curcontext=:::
+
+# Special completion contexts after `~' and `='.
+
+if compset -P 1 '='; then
+ compstate[context]=equal
+elif [[ "$PREFIX" != */* && "$PREFIX[1]" = '~' ]]; then
+ compset -p 1
+ compstate[context]=tilde
fi
-# For arguments we use the `_normal function.
+# Initial setup.
+
+_setup default
+_def_menu_style=( "$_last_menu_style[@]"
+
+# We can't really do that because the current value of $SELECTMIN
+# may be the one set by this function.
+# There is a similar problem with $ZLS_COLORS in _setup.
+
+# ${SELECTMIN+select${SELECTMIN:+\=$SELECTMIN}}
+
+ )
+_last_menu_style=()
-if [[ $CONTEXT == argument || $CONTEXT == command ]]; then
- _normal "$@"
+# Get the names of the completers to use in the positional parameters.
+
+if (( $# )); then
+ _completers=( "$@" )
else
- # Let's see if we have a special completion definition for the other
- # possible contexts.
+ zstyle -a ":completion:${curcontext}:" completer _completers ||
+ _completers=( _complete )
+fi
+
+# And now just call the completer functions defined.
+
+_completer_num=1
+
+# Call the pre-functions.
+
+funcs=( "$compprefuncs[@]" )
+compprefuncs=()
+for func in "$funcs[@]"; do
+ "$func"
+done
+
+for tmp in "$_completers[@]"; do
+
+ if [[ "$tmp" = *:-* ]]; then
+ _completer="${${tmp%:*}[2,-1]//_/-}${tmp#*:}"
+ tmp="${tmp%:*}"
+ elif [[ $tmp = *:* ]]; then
+ _completer="${tmp#*:}"
+ tmp="${tmp%:*}"
+ else
+ _completer="${tmp[2,-1]//_/-}"
+ fi
+ curcontext="${curcontext/:[^:]#:/:${_completer}:}"
- comp=''
+ zstyle -a ":completion:${curcontext}:" matcher-list _matchers ||
+ _matchers=( '' )
- case $CONTEXT in
- redirect) comp="$_comps[-redirect-]";;
- math) comp="$_comps[-math-]";;
- subscript) comp="$_comps[-subscript-]";;
- value) comp="$_comps[-value-]";;
- condition) comp="$_comps[-condition-]";;
- esac
+ _matcher_num=1
+ for _matcher in "$_matchers[@]"; do
+ if "$tmp"; then
+ ret=0
+ break 2
+ fi
+ (( _matcher_num++ ))
+ done
+ (( _completer_num++ ))
+done
- # If not, we use default completion, if any.
+curcontext="${curcontext/:[^:]#:/::}"
- [[ -z "$comp" ]] && comp="$_comps[-default-]"
- [[ -z "$comp" ]] || "$comp" "$@"
+if [[ $compstate[old_list] = keep || $compstate[nmatches] -gt 1 ]]; then
+ [[ _last_nmatches -ge 0 && _last_nmatches -ne $compstate[nmatches] ]] &&
+ _menu_style=( "$_last_menu_style[@]" "$_menu_style[@]" )
+
+ if [[ "$compstate[insert]" = "$_saved_insert" ]]; then
+ if [[ -n "$_menu_style[(r)(yes|true|1|on)]" ||
+ ( -n "$_menu_style[(r)auto*]" &&
+ "$compstate[insert]" = automenu ) ]]; then
+ compstate[insert]=menu
+ elif [[ -n "$_menu_style[(r)auto*]" &&
+ "$compstate[insert]" != automenu ]]; then
+ compstate[insert]=automenu-unambiguous
+ elif [[ -n "$_menu_style[(r)(no|false|0|off)]" ]]; then
+ compstate[insert]=unambiguous
+ elif [[ -n "$_def_menu_style[(r)(yes|true|1|on)]" ||
+ ( -n "$_def_menu_style[(r)auto*]" &&
+ "$compstate[insert]" = automenu ) ]]; then
+ compstate[insert]=menu
+ elif [[ -n "$_def_menu_style[(r)auto*]" &&
+ "$compstate[insert]" != automenu ]]; then
+ compstate[insert]=automenu-unambiguous
+ elif [[ -n "$_def_menu_style[(r)(no|false|0|off)]" ]]; then
+ compstate[insert]=unambiguous
+ fi
+ fi
+
+ _menu_style=( "$_menu_style[@]" "$_def_menu_style[@]" )
+
+ if [[ "$compstate[insert]" = *menu* ]]; then
+ if [[ -n "$_menu_style[(r)no-select*]" ]]; then
+ unset SELECTMIN
+ else
+ sel=( "${(@M)_menu_style:#select*}" )
+
+ if (( $# )); then
+ local min=9999999 i num
+
+ for i in "$sel[@]"; do
+ if [[ "$i" = *\=* ]]; then
+ num="${i#*\=}"
+ [[ num -lt 0 ]] && num=0
+ else
+ num=0
+ fi
+ [[ num -lt min ]] && min="$num"
+
+ (( min )) || break
+ done
+
+ zmodload -i zsh/complist
+ SELECTMIN="$min"
+ fi
+ fi
+ fi
+elif [[ $compstate[nmatches] -eq 0 &&
+ $#_lastdescr -ne 0 && $compstate[old_list] != keep ]] &&
+ zstyle -s ":completion:${curcontext}:warnings" format format; then
+
+ compstate[list]='list force'
+ compstate[insert]=''
+
+ if [[ "$format" = *%d* ]]; then
+ local str mesg
+
+ _lastdescr=( "\`${(@)^_lastdescr:#}'" )
+
+ case $#_lastdescr in
+ 1) str="$_lastdescr[1]";;
+ 2) str="$_lastdescr[1] or $_lastdescr[2]";;
+ *) str="${(j:, :)_lastdescr[1,-2]}, or $_lastdescr[-1]";;
+ esac
+
+ zformat -f mesg "$format" "d:$str"
+ compadd -UX "$mesg" -n - ''
+ else
+ _setup warnings
+ compadd -UQX "$format" -V warnings - "${(@)_lastdescr:#}"
+ fi
fi
+
+# Now call the post-functions.
+
+funcs=( "$comppostfuncs[@]" )
+comppostfuncs=()
+for func in "$funcs[@]"; do
+ "$func"
+done
+
+_lastcomp=( "${(@kv)compstate}" )
+_lastcomp[completer]="$_completer"
+_lastcomp[prefix]="$PREFIX"
+_lastcomp[suffix]="$SUFFIX"
+_lastcomp[iprefix]="$IPREFIX"
+_lastcomp[isuffix]="$ISUFFIX"
+_lastcomp[qiprefix]="$QIPREFIX"
+_lastcomp[qisuffix]="$QISUFFIX"
+_lastcomp[tags]="$_comp_tags"
+
+return ret
diff --git a/Completion/Core/_match b/Completion/Core/_match
index 3c639935c..18dab7423 100644
--- a/Completion/Core/_match
+++ b/Completion/Core/_match
@@ -1,53 +1,51 @@
#autoload
# This is intended to be used as a completer function after the normal
-# completer as in: `compconf completer=_complete:_match'.
+# completer as in: `zstyle ":completion:::::" completer _complete _match'.
# It temporarily switches on pattern matching, allowing you to try
# completion on patterns without having to setopt glob_complete.
#
# Note, however, that this is only really useful if you don't use the
# expand-or-complete function because otherwise the pattern will
# be expanded using globbing.
-#
-# Configuration key used:
-#
-# 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.
-local tmp opm="$compstate[pattern_match]" ret=0
+[[ _matcher_num -gt 1 ]] && return 1
+
+local tmp opm="$compstate[pattern_match]" ret=0 orig ins
-# Do nothing if we don't have a pattern or there are still global
-# match specifications to try.
+# Do nothing if we don't have a pattern.
tmp="${${:-$PREFIX$SUFFIX}#[~=]}"
-[[ "$tmp:q" = "$tmp" ||
- compstate[matcher] -ne compstate[total_matchers] ]] && return 1
+[[ "$tmp:q" = "$tmp" ]] && return 1
+
+zstyle -s ":completion:${curcontext}:" match-original orig
+zstyle -b ":completion:${curcontext}:" insert-unambiguous ins
# Try completion without inserting a `*'?
-if [[ -n "$compconfig[match_original]" ]]; then
- compstate[matcher]=-1
+if [[ -n "$orig" ]]; then
compstate[pattern_match]='-'
_complete && ret=1
compstate[pattern_match]="$opm"
- compstate[matcher]="$compstate[total_matchers]"
- (( ret )) && return 0
+ if (( ret )); then
+ [[ "$ins" = yes &&
+ $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] &&
+ compstate[pattern_insert]=unambiguous
+ return 0
+ fi
fi
# No completion with inserting `*'?
-[[ "$compconfig[match_original]" = only ]] && return 1
+[[ "$orig" = only ]] && return 1
-compstate[matcher]=-1
compstate[pattern_match]='*'
_complete && ret=1
compstate[pattern_match]="$opm"
-compstate[matcher]="$compstate[total_matchers]"
+
+[[ ret -eq 1 && "$ins" = yes &&
+ $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] &&
+ compstate[pattern_insert]=unambiguous
return 1-ret
diff --git a/Completion/Core/_menu b/Completion/Core/_menu
index 4cbda4e14..41fc178ba 100644
--- a/Completion/Core/_menu
+++ b/Completion/Core/_menu
@@ -1,10 +1,12 @@
#autoload
+[[ _matcher_num -gt 1 ]] && return 1
+
# This completer is an example showing how menucompletion can be
# implemented with the new completion system.
# Use this one before the normal _complete completer, as in:
#
-# compconf completer=_menu:_complete
+# zstyle ":completion:::::" completer _menu _complete
if [[ -n "$compstate[old_list]" ]]; then
diff --git a/Completion/Core/_next_label b/Completion/Core/_next_label
new file mode 100644
index 000000000..e309e53ea
--- /dev/null
+++ b/Completion/Core/_next_label
@@ -0,0 +1,24 @@
+#autoload
+
+local gopt=-J descr
+
+if [[ "$1" = -([12]|)[VJ] ]]; then
+ gopt="$1"
+ shift
+fi
+
+if comptags -A "$1" curtag; then
+ if [[ "$curtag" = *:* ]]; then
+ zformat -f descr "${curtag#*:}" "d:$3"
+ _description "$gopt" "${curtag%:*}" "$2" "$descr"
+ curtag="${curtag%:*}"
+ eval "${2}=( \${(P)2} \$argv[4,-1] )"
+ else
+ _description "$gopt" "$curtag" "$2" "$3"
+ eval "${2}=( \$argv[4,-1] \${(P)2} )"
+ fi
+
+ return 0
+fi
+
+return 1
diff --git a/Completion/Core/_oldlist b/Completion/Core/_oldlist
new file mode 100644
index 000000000..bcb3e148a
--- /dev/null
+++ b/Completion/Core/_oldlist
@@ -0,0 +1,53 @@
+#autoload
+
+[[ _matcher_num -gt 1 ]] && return 1
+
+local list
+
+zstyle -s ":completion:${curcontext}:" old-list list
+
+# If this is a listing widget and there is already an old list,
+# and either the style :oldlist:old-list is `always', or it is not `never'
+# and the list is not already shown, then use the existing list for listing
+# (even if it was generated by another widget).
+# Do this also if there is an old list and it was generated by the
+# completer named by the oldlist_list key.
+
+if [[ -n $compstate[old_list] && $list != never ]]; then
+ if [[ $WIDGET = *list* && ( $list = always || $list != shown ) ]]; then
+ compstate[old_list]=keep
+ return 0
+ elif [[ $list = *${_lastcomp[completer]}* ]]; then
+ [[ "$_lastcomp[insert]" = unambig* ]] && compstate[to_end]=single
+ compstate[old_list]=keep
+ if [[ -o automenu ]]; then
+ compstate[insert]=menu
+ else
+ compadd -Qs "$SUFFIX" - "$PREFIX"
+ fi
+ return 0
+ fi
+fi
+
+# If this is a completion widget, and we have a completion inserted already,
+# and the style :oldlist:old-menu is `true', then we cycle through the
+# existing list (even if it was generated by another widget).
+
+if [[ -z $compstate[old_insert] && -n $compstate[old_list] ]]; then
+ compstate[old_list]=keep
+elif [[ $WIDGET = *complete(|-prefix|-word) ]] &&
+ zstyle -t ":completion:${curcontext}:" old-menu; then
+ if [[ -n $compstate[old_insert] ]]; then
+ compstate[old_list]=keep
+ if [[ $WIDGET = *reverse* ]]; then
+ compstate[insert]=$(( compstate[old_insert] - 1 ))
+ else
+ compstate[insert]=$(( compstate[old_insert] + 1 ))
+ fi
+ else
+ return 1
+ fi
+ return 0
+fi
+
+return 1
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 83b6e8a09..ac4614dd8 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -1,85 +1,64 @@
#autoload
-# Utility function for in-path completion.
-# Supported arguments are: `-f', `-/', `-g <patterns>', `-J <group>',
-# `-V <group>', `-W paths', `-X explanation', and `-F <ignore>'. All but
-# the last have the same syntax and meaning as for `complist'. 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.
-#
-# This function uses the helper functions `_match_test' and `_match_pattern'.
+# Utility function for in-path completion. This allows `/u/l/b<TAB>'
+# to complete to `/usr/local/bin'.
-# First see if we should generate matches for the global matcher in use.
+local linepath realpath donepath prepath testpath exppath skips skipped
+local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre
+local pats haspats=no ignore pfxsfx rem remt sopt gopt opt
+local nm=$compstate[nmatches] menu matcher mopts atmp sort match
-_match_test _path_files || return
+typeset -U prepaths exppaths
-# Yes, so...
-
-local nm prepaths 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
-
-setopt localoptions nullglob rcexpandparam globdots extendedglob
+setopt localoptions nullglob rcexpandparam
unsetopt markdirs globsubst shwordsplit nounset
-prepaths=('')
-ignore=()
-group=()
-sopt='-'
-gopt=''
-pats=()
-addpfx=()
-addsfx=()
-expl=()
+exppaths=()
# Get the options.
-while getopts "P:S:W:F:J:V:X:f/g:" opt; do
- case "$opt" in
- P) addpfx=(-P "$OPTARG")
- ;;
- S) addsfx=(-S "$OPTARG")
- ;;
- W) tmp1="$OPTARG"
- if [[ "$tmp1[1]" = '(' ]]; then
- prepaths=( ${^=tmp1[2,-2]}/ )
- else
- prepaths=( ${(P)=${tmp1}} )
- (( ! $#prepaths )) && prepaths=( ${tmp1}/ )
- fi
- (( ! $#prepaths )) && prepaths=( '' )
- ;;
- F) tmp1="$OPTARG"
- if [[ "$tmp1[1]" = '(' ]]; then
- ignore=( ${^=tmp1[2,-2]}/ )
- else
- ignore=( ${(P)${tmp1}} )
- fi
- (( $#ignore )) && ignore=(-F "( $ignore )")
- ;;
- [JV]) group=("-$opt" "$OPTARG")
- ;;
- X) expl=(-X "$OPTARG")
- ;;
- f) sopt="${sopt}f"
- pats=("$pats[@]" '*')
- ;;
- /) sopt="${sopt}/"
- pats=("$pats[@]" '*(-/)')
- ;;
- g) gopt='-g'
- pats=("$pats[@]" ${=OPTARG})
- ;;
- esac
-done
+zparseopts -a mopts \
+ 'P:=pfxsfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \
+ 'W:=prepaths' 'F:=ignore' 'M+:=matcher' \
+ J+: V+: X+: 1: 2: n: 'f=tmp1' '/=tmp1' 'g+:-=tmp1'
+
+sopt="-${(@j::M)${(@)tmp1#-}#?}"
+(( $tmp1[(I)-[/g]*] )) && haspats=yes
+(( $tmp1[(I)-g*] )) && gopt=yes
+if (( $tmp1[(I)-/] )); then
+ pats=( '*(-/)' ${=${(M)tmp1:#-g*}#-g} )
+else
+ pats=( "${(@)=${(@M)tmp1:#-g*}#-g}" )
+fi
+pats=( "${(@)pats:# #}" )
+
+if (( $#prepaths )); then
+ tmp1="${prepaths[2]}"
+ if [[ "$tmp1[1]" = '(' ]]; then
+ prepaths=( ${^=tmp1[2,-2]%/}/ )
+ elif [[ "$tmp1[1]" = '/' ]]; then
+ prepaths=( "${tmp1%/}/" )
+ else
+ prepaths=( ${(P)^tmp1%/}/ )
+ (( ! $#prepaths )) && prepaths=( ${tmp1%/}/ )
+ fi
+ (( ! $#prepaths )) && prepaths=( '' )
+else
+ prepaths=( '' )
+fi
+
+if (( $#ignore )); then
+ if [[ "${ignore[2]}" = \(* ]]; then
+ ignore=( ${=ignore[2][2,-2]} )
+ else
+ ignore=( ${(P)ignore[2]} )
+ fi
+fi
# If we were given no file selection option, we behave as if we were given
# a `-f'.
-if [[ "$sopt" = - ]]; then
+if [[ "$sopt" = -(f|) ]]; then
if [[ -z "$gopt" ]]; then
sopt='-f'
pats=('*')
@@ -88,224 +67,472 @@ if [[ "$sopt" = - ]]; then
fi
fi
-# str holds the whole string from the command line with a `*' between
-# the prefix and the suffix.
-
-str="${PREFIX:q}*${SUFFIX:q}"
-
-# If the string began with a `~', the quoting turned this into `\~',
-# remove the slash.
+if (( ! $mopts[(I)-[JVX]] )); then
+ local expl
-[[ "$str" = \\\~* ]] && str="$str[2,-1]"
-
-# We will first try normal completion called with `complist', but only if we
-# weren't given a `-F' option.
-
-if (( ! $#ignore )); 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
- tmp1=()
+ if [[ -z "$gopt" && "$sopt" = -/ ]]; then
+ _description directories expl directory
else
- tmp1=(-W "( $prepaths )")
+ _description files expl file
+ fi
+ tmp1=$expl[(I)-M*]
+ if (( tmp1 )); then
+ if (( $#matcher )); then
+ matcher[2]="$matcher[2] $expl[1+tmp1]"
+ else
+ matcher=(-M "$expl[1+tmp1]")
+ fi
fi
+ mopts=( "$mopts[@]" "$expl[@]" )
+fi
- # Now call complist.
+if zstyle -s ":completion:${curcontext}:files" sort tmp1; then
+ case "$tmp1" in
+ *size*) sort=oL;;
+ *links*) sort=ol;;
+ *(time|date|modi)*) sort=om;;
+ *access*) sort=oa;;
+ *(inode|change)*) sort=oc;;
+ *) sort=on;;
+ esac
+ [[ "$tmp1" = *rev* ]] && sort[1]=O
- nm=$NMATCHES
- if [[ -z "$gopt" ]]; then
- complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
+ if [[ "$sort" = on ]]; then
+ sort=''
else
- complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats"
+ mopts=( "${(@)mopts/#-J/-V}" )
+
+ tmp2=()
+ for tmp1 in "$pats[@]"; do
+ if [[ "$tmp1" = (#b)(?*)(\(\([^\|~]##\)\)) ]]; then
+ tmp2=( "$tmp2[@]" "${match[1]}((${sort}${match[2][3,-1]}" )
+ elif [[ "$tmp1" = (#b)(?*)(\([^\|~]##\)) ]]; then
+ tmp2=( "$tmp2[@]" "${match[1]}(${sort}${match[2][2,-1]}" )
+ else
+ tmp2=( "$tmp2[@]" "${tmp1}(${sort})" )
+ fi
+ done
+ pats=( "$tmp2[@]" )
fi
+fi
+
+# Check if we have to skip over sequences of slashes. The value of $skips
+# is used below to match the pathname components we always have to accept
+# immediatly.
+
+if zstyle -t ":completion:${curcontext}:paths" squeeze-slashes; then
+ skips='((.|..|)/)##'
+else
+ skips='((.|..)/)##'
+fi
+
+# We get the prefix and the suffix from the line and save the whole
+# original string. Then we see if we will do menucompletion.
+
+pre="$PREFIX"
+suf="$SUFFIX"
+opre="$PREFIX"
+osuf="$SUFFIX"
+orig="${PREFIX}${SUFFIX}"
+eorig="$orig"
- # If this generated any matches, we don't want to do in-path completion.
+[[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
+ ( -n "$compstate[pattern_match]" &&
+ "${orig#\~}" != "${${orig#\~}:q}" ) ]] && menu=yes
- [[ -nmatches nm ]] || return
+# If given no `-F' option, we may want to use $fignore, turned into patterns.
- # No `-F' option, so we want to use `fignore'.
+[[ -z "$_comp_no_ignore" && $#ignore -eq 0 &&
+ ( -z $gopt || "$pats" = \ #\*\ # ) && -n $FIGNORE ]] &&
+ ignore=( "?*${^fignore[@]}" )
- ignore=(-F fignore)
+if (( $#ignore )); then
+ _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" )
+ (( $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore )
fi
+(( $#matcher )) && mopts=( "$mopts[@]" "$matcher[@]" )
+
# 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
# prefix from the string to complete, set `donepath' to build the correct
# paths and make sure that the loop below is run only once with an empty
# prefix path by setting `prepaths'.
-
- linepath="${str%%/*}/"
- eval realpath\=$linepath
- str="${str#*/}"
+
+ linepath="${pre[2,-1]%%/*}"
+ if [[ -z "$linepath" ]]; then
+ realpath="${HOME%/}/"
+ elif (( $+userdirs[$linepath] )); then
+ realpath="${userdirs[$linepath]%/}/"
+ elif (( $+nameddirs[$linepath] )); then
+ realpath="${nameddirs[$linepath]%/}/"
+ else
+ _message "unknown user \`$linepath'"
+ return 1
+ fi
+ linepath="~${linepath}/"
+ [[ "$realpath" = "$linepath" ]] && return 1
+ pre="${pre#*/}"
+ orig="${orig#*/}"
+ donepath=''
+ prepaths=( '' )
+elif [[ "$pre" = *\$*/* ]]; then
+
+ # If there is a parameter expansion in the word from the line, we try
+ # to complete the beast by expanding the prefix and completing anything
+ # after the first slash after the parameter expansion.
+ # This fails for things like `f/$foo/b/<TAB>' where the first `f' is
+ # meant as a partial path.
+
+ linepath="${(M)pre##*\$[^/]##/}"
+ realpath=${(e)~linepath}
+ [[ "$realpath" = "$linepath" ]] && return 1
+ pre="${pre#${linepath}}"
+ i="${#linepath//[^\\/]}"
+ orig="${orig[1,(in:i:)/][1,-2]}"
donepath=''
prepaths=( '' )
else
# If the string does not start with a `~' we don't remove a prefix from the
# string.
- liniepath=''
+ 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=( '' )
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
-# 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 `str' and added
-# to `donepath'.
+# Now we generate the matches. First we loop over all prefix paths given
+# with the `-W' option.
-while [[ "$str" = */* ]] do
- [[ -e "$realpath$donepath${str%%/*}" ]] || break
- donepath="$donepath${str%%/*}/"
- str="${str#*/}"
-done
+for prepath in "$prepaths[@]"; do
-# Now build the glob pattern by calling `_match_pattern'.
-patstr="$str"
-matchflags=""
-_match_pattern _path_files patstr matchflags
+ # 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.
-# 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.
+ tpre="$pre"
+ tsuf="$suf"
+ testpath="$donepath"
-patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/"
+ tmp2="${(M)tpre##${~skips}}"
+ tpre="${tpre#$tmp2}"
-# 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'.
+ tmp1=( "$prepath$realpath$donepath$tmp2" )
-for prepath in "$prepaths[@]"; do
- str="$patstr"
- testpath="$donepath"
+ while true; do
- # The second loop tests the components of the path in `str' to get the
- # possible matches.
+ # Get the prefix and suffix for matching.
- 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.
+ if [[ "$tpre" = */* ]]; then
+ PREFIX="${tpre%%/*}"
+ SUFFIX=""
+ else
+ PREFIX="${tpre}"
+ SUFFIX="${tsuf%%/*}"
+ fi
- rest="${str#*/}"
- tmp1="${prepath}${realpath}${testpath}${~matchflags}${str%%/*}(-/)"
- tmp1=( $~tmp1 )
+ # Get the matching files by globbing.
- 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.
+ tmp2=( "$tmp1[@]" )
+ if [[ "$tpre$tsuf" = */* ]]; then
+ if [[ ! -o globdots && "$PREFIX" = .* ]]; then
+ tmp1=( ${^tmp1}${skipped}*(-/) ${^tmp1}${skipped}.*(-/) )
+ else
+ tmp1=( ${^tmp1}${skipped}*(-/) )
+ fi
+ if [[ -o globdots || "$PREFIX" = .* ]] &&
+ zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
+ if [[ "$atmp" = (yes|true|1|on) ]]; then
+ tmp1=( "$tmp1[@]" . .. )
+ elif [[ "$atmp" = .. ]]; then
+ tmp1=( "$tmp1[@]" .. )
+ fi
+ fi
+ else
+ if [[ ! -o globdots && "$PREFIX" = .* ]]; then
+ tmp1=( ${^tmp1}${skipped}${^~pats} ${^tmp1}${skipped}.${^~pats:#.*} )
+ else
+ tmp1=( ${^tmp1}${skipped}${^~pats} )
+ fi
+ if [[ "$sopt" = *[/f]* && ( -o globdots || "$PREFIX" = .* ) ]] &&
+ zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
+ if [[ "$atmp" = (yes|true|1|on) ]]; then
+ tmp1=( "$tmp1[@]" . .. )
+ elif [[ "$atmp" = .. ]]; then
+ tmp1=( "$tmp1[@]" .. )
+ fi
+ fi
+ fi
- 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.
-
- collect=()
- suffixes=( $rest$^pats )
- suffixes=( "${(@)suffixes:gs.**.*.}" )
-
- # 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}/${~matchflags}${~suffixes} )
- [[ $#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 give up and
- # continue with the next `-W' path.
-
- if [[ $#collect -eq 0 ]]; then
+ if [[ -n "$PREFIX$SUFFIX" ]]; then
+ # See which of them match what's on the line.
+
+ if [[ -n "$_comp_correct" ]]; then
+ tmp2=( "$tmp1[@]" )
+ builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
+
+ if [[ $#tmp1 -eq 0 ]]; then
+ tmp1=( "$tmp2[@]" )
+ compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
+ fi
+ else
+ [[ "$tmp1[1]" = */* ]] && tmp2=( "$tmp1[@]" )
+
+ builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
+ fi
+
+ # If no file matches, save the expanded path and continue with
+ # the outer loop.
+
+ if (( ! $#tmp1 )); then
+ if [[ "$tmp2[1]" = */* ]]; then
+ tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
+ if [[ "$tmp2[1]" = */* ]]; then
+ tmp2=( "${(@)tmp2:h}" )
+ compquote tmp2
+ if [[ "$tmp2" = */ ]]; then
+ exppaths=( "$exppaths[@]" ${^tmp2}${tpre}${tsuf} )
+ else
+ exppaths=( "$exppaths[@]" ${^tmp2}/${tpre}${tsuf} )
+ fi
+ else
+ exppaths=( "$exppaths[@]" ${tpre}${tsuf} )
+ fi
+ fi
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'.
+ fi
+ elif (( ! $#tmp1 )); then
+ # A little extra hack: if we were completing `foo/<TAB>' and `foo'
+ # contains no files, this will normally produce no matches and other
+ # completers might think that's it's their time now. But if the next
+ # completer is _correct or something like that, this will result in
+ # an attempt to correct a valid directory name. So we just add the
+ # original string in such a case so that the command line doesn't
+ # change but other completers still think there are matches.
+ # We do this only if we weren't given a `-g' or `-/' option because
+ # otherwise this would keep `_files' from completing all filenames
+ # if none of the patterns match.
+
+ if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then
+ pfxsfx=(-S '' "$pfxsfx[@]")
+ ### Don't remember what the break was good for. We explicitly
+ ### execute this only when there are no matches in the directory,
+ ### so why continue?
+ ###
+ ### tmp1=( "$tmp2[@]" )
+ ### break
+ elif [[ "$haspats" = no && -z "$tpre$tsuf" &&
+ "$pre" = */ && -z "$suf" ]]; then
+ PREFIX="${opre}"
+ SUFFIX="${osuf}"
+ compadd -nQS '' - "$linepath$donepath$orig"
+ tmp4=-
+ fi
+ continue 2
+ fi
- tmp1="$prepath$realpath$testpath"
+ if [[ -z "$_comp_no_ignore" && "$tpre$tsuf" != */* && $#tmp1 -ne 0 ]] &&
+ zstyle -s ":completion:${curcontext}:files" ignore-parents rem &&
+ [[ ( "$rem" != *dir* || "$pats" = '*(-/)' ) &&
+ ( "$rem" != *..* || "$tmp1" = *../* ) ]]; then
+ if [[ "$rem" = *parent* ]]; then
+ for i in ${(M)^tmp1:#*/*}(-/); do
+ remt="${${i#$prepath$realpath$donepath}%/*}"
+ while [[ "$remt" = */* &&
+ ! "$prepath$realpath$donepath$remt" -ef "$i" ]]; do
+ remt="${remt%/*}"
+ done
+ [[ "$remt" = */* || "$remt" -ef "$i" ]] &&
+ _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
+ done
+ fi
+ if [[ "$rem" = *pwd* ]]; then
+ for i in ${^tmp1}(-/); do
+ [[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
+ done
+ fi
+ (( $#_comp_ignore && $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore )
+ fi
- # Now produce all matching pathnames in `collect'.
+ # Step over to the next component, if any.
- collect=( ${~collect}/${~matchflags}${~suffixes} )
+ if [[ "$tpre" = */* ]]; then
+ tpre="${tpre#*/}"
+ elif [[ "$tsuf" = */* ]]; then
+ tpre="${tsuf#*/}"
+ tsuf=""
+ else
+ break
+ fi
- # And then remove the common path prefix from all these matches.
+ # There are more components, so skip over the next components and make a
+ # slash be added.
- collect=( ${collect#$tmp1} )
+ tmp2="${(M)tpre##((.|..|)/)##}"
+ if [[ -n "$tmp2" ]]; then
+ skipped="/$tmp2"
+ tpre="${tpre#$tmp2}"
+ else
+ skipped=/
+ fi
+ done
+
+ # The next loop searches the first ambiguous component.
+
+ tmp3="$pre$suf"
+ tpre="$pre"
+ tsuf="$suf"
+ tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" )
- # 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).
+ while true; do
- for i in $collect; do
- compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}"
- done
+ # 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 avoids having `foo' complete to `foo' and `foobar'.
- # We have just finished handling all the matches from above, so we
- # can continue with the next `-W' path.
+ if [[ "$tmp3" = */* ]]; then
+ tmp4=( "${(@M)tmp1:#${tmp3%%/*}/*}" )
+ (( $#tmp4 )) && tmp1=( "$tmp4[@]" )
+ fi
+
+ # Next we see if this component is ambiguous.
- continue 2
+ if [[ "$tmp3" = */* ]]; then
+ tmp4=$tmp1[(I)^${(q)tmp1[1]%%/*}/*]
+ else
+ tmp4=$tmp1[(I)^${(q)tmp1[1]}]
+ fi
+
+ if [[ "$tpre" = */* ]]; then
+ tmp2="${cpre}${tpre%%/*}"
+ PREFIX="${donepath}${linepath}${tmp2}"
+ SUFFIX="/${tpre#*/}${tsuf#*/}"
+ else
+ tmp2="${cpre}${tpre}"
+ PREFIX="${donepath}${linepath}${tmp2}"
+ SUFFIX="${tsuf}"
+ fi
+
+ if (( tmp4 )) ||
+ [[ -n "$compstate[pattern_match]" && "$tmp2" != "${(q)tmp2}" ]]; 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.
+
+ tmp2="$testpath"
+ compquote tmp1 tmp2
+
+ if [[ -n $menu || -z "$compstate[insert]" ]] ||
+ ! zstyle -t ":completion:${curcontext}:paths" expand suffix; then
+ (( tmp4 )) && zstyle -t ":completion:${curcontext}:paths" cursor &&
+ compstate[to_end]=''
+ if [[ "$tmp3" = */* ]]; then
+ compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \
+ -W "$prepath$realpath$testpath" \
+ "$pfxsfx[@]" -M "r:|/=* r:|=*" \
+ - "${(@)tmp1%%/*}"
+ else
+ compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
+ -W "$prepath$realpath$testpath" \
+ "$pfxsfx[@]" -M "r:|/=* r:|=*" \
+ - "$tmp1[@]"
+ fi
+ else
+ if [[ "$tmp3" = */* ]]; then
+ atmp=( -Qf "$mopts[@]" -p "$linepath$tmp2"
+ -W "$prepath$realpath$testpath"
+ "$pfxsfx[@]" -M "r:|/=* r:|=*" )
+ for i in "$tmp1[@]"; do
+ compadd "$atmp[@]" -s "/${i#*/}" - "${i%%/*}"
+ done
+ else
+ compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
+ -W "$prepath$realpath$testpath" \
+ "$pfxsfx[@]" -M "r:|/=* r:|=*" \
+ - "$tmp1[@]"
+ fi
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.
+ tmp4=-
+ break
+ fi
+
+ # If we have checked all components, we stop now and add the
+ # strings collected after the loop.
- tmp1=( "$collect[1]" )
+ if [[ "$tmp3" != */* ]]; then
+ tmp4=""
+ break
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"
+ # Otherwise we add the unambiguous component to `testpath' and
+ # take it from the filenames.
+
+ testpath="${testpath}${tmp1[1]%%/*}/"
+ tmp1=( "${(@)tmp1#*/}" )
+
+ tmp3="${tmp3#*/}"
+
+ if [[ "$tpre" = */* ]]; then
+ cpre="${cpre}${tpre%%/*}/"
+ tpre="${tpre#*/}"
+ elif [[ "$tsuf" = */* ]]; then
+ cpre="${cpre}${tpre}/"
+ tpre="${tsuf#*/}"
+ tsuf=""
+ else
+ tpre=""
+ tsuf=""
+ fi
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.
-
- tmp1="$prepath$realpath$testpath"
- suffixes=( $str$^pats )
- suffixes=( "${(@)suffixes:gs.**.*.}" )
- tmp2=( ${~tmp1}${~matchflags}${~suffixes} )
- if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then
- [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]"
- compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath"
- else
- compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1}
+ if [[ -z "$tmp4" ]]; then
+ if [[ "$osuf" = */* ]]; then
+ PREFIX="${opre}${osuf}"
+ SUFFIX=""
+ else
+ PREFIX="${opre}"
+ SUFFIX="${osuf}"
+ fi
+ tmp4="$testpath"
+ compquote tmp4 tmp1
+ compadd -Qf "$mopts[@]" -p "$linepath$tmp4" -W "$prepath$realpath$testpath" \
+ "$pfxsfx[@]" -M "r:|/=* r:|=*" - "$tmp1[@]"
fi
done
+
+# 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.
+
+if zstyle -t ":completion:${curcontext}:paths" expand prefix &&
+ [[ nm -eq compstate[nmatches] && $#exppaths -ne 0 &&
+ "$exppaths" != "$eorig" ]]; then
+ PREFIX="${opre}"
+ SUFFIX="${osuf}"
+ compadd -Q "$mopts[@]" -S '' -M "r:|/=* r:|=*" -p "$linepath" - "$exppaths[@]"
+fi
+
+[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/Core/_prefix b/Completion/Core/_prefix
index 6306b4aa0..f6e3b0831 100644
--- a/Completion/Core/_prefix
+++ b/Completion/Core/_prefix
@@ -4,10 +4,10 @@
[[ -n "$SUFFIX" ]] || return 1
-local curcontext="${curcontext/:[^:]#:/:prefix:}" comp i
+local comp i
zstyle -a ":completion:${curcontext}:" completer comp ||
- comp=( "${(@)_completers[1,-${#_completers_left}-1][(R)_prefix,-1]}" )
+ comp=( "${(@)_completers[1,_completer_num-1][(R)_prefix(|:*),-1]}" )
if zstyle -t ":completion:${curcontext}:" add-space; then
ISUFFIX=" $SUFFIX"
diff --git a/Completion/Core/_requested b/Completion/Core/_requested
index 082c45820..bd838a28e 100644
--- a/Completion/Core/_requested
+++ b/Completion/Core/_requested
@@ -1,9 +1,20 @@
#autoload
-local tag tname="$funcstack[2,-1]"
+local gopt=-J
-for tag; do
- [[ "${_cur_tags[${tname}]}" = *:${tag}(:|\[*\]:)* ]] && return 0
-done
+if [[ "$1" = -([12]|)[VJ] ]]; then
+ gopt="$1"
+ shift
+fi
-return 1
+if comptags -R "$1"; then
+ _comp_tags="$_comp_tags $1"
+ if [[ $# -gt 3 ]]; then
+ _all_labels "$gopt" "$@"
+ elif [[ $# -gt 1 ]]; then
+ _description "$gopt" "$@"
+ fi
+ return 0
+else
+ return 1
+fi
diff --git a/Completion/Core/_setup b/Completion/Core/_setup
index f12c34b34..ed7307e69 100644
--- a/Completion/Core/_setup
+++ b/Completion/Core/_setup
@@ -1,13 +1,61 @@
#autoload
-local colors i
-
-for i; do
- if _style -a "$i" list-colors colors; then
- if [[ "$1" = default ]]; then
- ZLS_COLORS="${(j.:.)${(@)colors:gs/:/\\\:}}"
- else
- eval "ZLS_COLORS=\"(${i})\${(j.:(${i}).)\${(@)colors:gs/:/\\\:}}:\${ZLS_COLORS}\""
- fi
+local val nm="$compstate[nmatches]"
+
+if zstyle -a ":completion:${curcontext}:$1" list-colors val; then
+ zmodload -i zsh/complist
+ if [[ "$1" = default ]]; then
+ ZLS_COLORS="${(j.:.)${(@)val:gs/:/\\\:}}"
+ else
+ eval "ZLS_COLORS=\"(${1})\${(j.:(${1}).)\${(@)val:gs/:/\\\:}}:\${ZLS_COLORS}\""
fi
-done
+
+# Here is the problem mentioned in _main_complete.
+
+# elif [[ "$1" = default && -n "$ZLS_COLORS$ZLS_COLOURS" ]]; then
+# zmodload -i zsh/complist
+# ZLS_COLORS="$ZLS_COLORS$ZLS_COLOURS"
+
+fi
+
+if zstyle -t ":completion:${curcontext}:$1" list-packed; then
+ compstate[list]="${compstate[list]} packed"
+elif [[ $? -eq 1 ]]; then
+ compstate[list]="${compstate[list]:gs/packed//}"
+else
+ compstate[list]="$_saved_list"
+fi
+
+if zstyle -t ":completion:${curcontext}:$1" list-rows-first; then
+ compstate[list]="${compstate[list]} rows"
+elif [[ $? -eq 1 ]]; then
+ compstate[list]="${compstate[list]:gs/rows//}"
+else
+ compstate[list]="$_saved_list"
+fi
+
+if zstyle -t ":completion:${curcontext}:$1" last-prompt; then
+ compstate[last_prompt]=yes
+elif [[ $? -eq 1 ]]; then
+ compstate[last_prompt]=''
+else
+ compstate[last_prompt]="$_saved_lastprompt"
+fi
+
+if zstyle -t ":completion:${curcontext}:$1" accept-exact; then
+ compstate[exact]=accept
+elif [[ $? -eq 1 ]]; then
+ compstate[exact]=''
+else
+ compstate[exact]="$_saved_exact"
+fi
+
+[[ _last_nmatches -ge 0 && _last_nmatches -ne nm ]] &&
+ _menu_style=( "$_last_menu_style[@]" "$_menu_style[@]" )
+
+if zstyle -a ":completion:${curcontext}:$1" menu val; then
+ _last_nmatches=$nm
+ _last_menu_style=( "$val[@]" )
+else
+ _last_nmatches=-1
+fi
diff --git a/Completion/Core/_tags b/Completion/Core/_tags
index af8dc21dd..496f5b7e0 100644
--- a/Completion/Core/_tags
+++ b/Completion/Core/_tags
@@ -1,81 +1,83 @@
#autoload
-if (( $# )); then
- local cmd="$words[1]" func="$funcstack[2]" defs i tags tag pat style prio
-
- while getopts 'c:f:' i; do
- if [[ "$i" = c ]]; then
- cmd="$OPTARG"
- else
- func="$OPTARG"
- fi
- done
-
- shift OPTIND-1
-
- defs=( "${(@M)argv:#${(kj:|:)~override_tags[(R)(|+*)]}}" )
- (( $#defs )) && set -- "$defs[@]"
-
- _offered_tags=( "$_offered_tags[@]" "$@" )
- _last_tags=()
-
- defs=()
- for i; do
- if [[ -n ${override_tags[$i]} && ${override_tags[$i]} != (\[|+\[)* ]]; then
- if [[ ${override_tags[$i]} = *\[* ]]; then
- prio=( "${i}:*=${override_tags[$i]#+}" )
- else
- prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" )
- (( $#prio )) || prio=( "${i}:${comptags[any]}" )
- prio="${${${prio[(r)(|*:)\*=[^:]#\[*\](|:*)]}##(|*:)\*}%%:*}"
- prio=( "${i}:*=${override_tags[$i]#+}${(M)prio%%\[*\]}" )
- fi
- else
- prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" )
- (( $#prio )) || prio=( "${i}:${comptags[any]}" )
- fi
- defs=( "$defs[@]" "$prio[@]" )
- done
-
- tags=()
- for i in "$defs[@]"; do
- tag="${i%%:*}"
- for pat in "${(s.:.)i#*:}"; do
- if [[ ( "$pat" = _* && "$func" = ${~pat%%\=*} ) ||
- "$cmd" = ${~pat%%\=*} ]]; then
- prio="${pat#*\=}"
- [[ "$prio" = -* ]] && continue 2
-
- if [[ "$prio" = *\[*\] ]]; then
- style="${(M)prio%%\[*}"
- prio="${prio%%\[*}"
- else
- style=''
- fi
- [[ ${override_tags[$tag]} = (|+)\[* ]] &&
- style="${override_tags[$tag]#+}"
-
- (( prio++ ))
-
- tags[$prio]="${tags[$prio]}:${tag}${style}"
- break
- fi
- done
- done
+local prev
- prios=( "${(@)tags:#}" )
+# A `--' as the first argument says that we should tell comptags to use
+# the preceding function nesting level. This is only documented here because
+# if everythings goes well, users won't have to worry about it and should
+# not mess with it.
- return 0
+if [[ "$1" = -- ]]; then
+ prev=-
+ shift
fi
-_failed_tags=( "$_failed_tags[@]" "$_last_tags[@]" )
+if (( $# )); then
+
+ # We have arguments: the tags supported in this context.
+
+ local curcontext="$curcontext" order tag nodef tmp
+
+ if [[ "$1" = -C?* ]]; then
+ curcontext="${curcontext%:*}:${1[3,-1]}"
+ shift
+ elif [[ "$1" = -C ]]; then
+ curcontext="${curcontext%:*}:${2}"
+ shift 2
+ else
+ targs=()
+ fi
+
+ [[ "$1" = -(|-) ]] && shift
-(( $#prios )) || return 1
+ if zstyle -a ":completion:${curcontext}:" group-order order; then
+ local name
-tags="${prios[1]}:"
-shift 1 prios
+ for name in "$order[@]"; do
+ compadd -J "$name"
+ compadd -V "$name"
+ compadd -J "$name" -1
+ compadd -V "$name" -1
+ compadd -J "$name" -2
+ compadd -V "$name" -2
+ done
+ fi
+
+ # Set and remember offered tags.
+
+ comptags "-i$prev" "$curcontext" "$@"
+
+ # Sort the tags.
+
+ if [[ -n "$_sort_tags" ]]; then
+ "$_sort_tags" "$@"
+ else
+ zstyle -a ":completion:${curcontext}:" tag-order order ||
+ order=('arguments values' options)
+
+ for tag in $order; do
+ case $tag in
+ -) nodef=yes;;
+ *\(\)) if ! "${${tag%%[ ]#\(\)}##[ ]#}" "$@"; then
+ nodef=yes
+ break
+ fi
+ ;;
+ \!*) comptry "${(@)argv:#(${(j:|:)~${=~tag[2,-1]}})}";;
+ ?*) comptry -m "$tag";;
+ esac
+ done
+
+ [[ -z "$nodef" ]] && comptry "$@"
+ fi
+
+ # Return non-zero if at least one set of tags should be used.
+
+ comptags "-T$prev"
+
+ return
+fi
-_last_tags=( "${(@s.:.)${${tags#:}%:}}" )
-_tried_tags=( "$_tried_tags[@]" "$_last_tags[@]" )
+# The other mode: switch to the next set of tags.
-return 0
+comptags "-N$prev"
diff --git a/Completion/Core/_wanted b/Completion/Core/_wanted
index 7baa3e724..32875ec57 100644
--- a/Completion/Core/_wanted
+++ b/Completion/Core/_wanted
@@ -1,6 +1,6 @@
#autoload
-local targs
+local targs gopt=-J
if [[ "$1" = -C?* ]]; then
targs=( -C "${1[3,-1]}" )
@@ -12,10 +12,22 @@ else
targs=()
fi
-[[ "$1" = -(|-) ]] && shift
+if [[ "$1" = -([12]|)[VJ] ]]; then
+ gopt="$1"
+ shift
+fi
+
+if [[ $# -gt 3 ]]; then
+ if _tags "$targs[@]" "$1"; then
+ _comp_tags="$_comp_tags $1"
-if [[ $# -gt 1 ]]; then
- _tags "$targs[@]" "$1" && _description "${(@)argv[2,-1]}"
+ _all_labels -t "$gopt" "$@"
+ else
+ return 1
+ fi
+elif [[ $# -gt 1 ]]; then
+ _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1" &&
+ _description "$gopt" "$@"
else
- _tags "$targs[@]" "$1"
+ _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1"
fi
diff --git a/Completion/Core/compdump b/Completion/Core/compdump
index 8be096f50..3cccbd06e 100644
--- a/Completion/Core/compdump
+++ b/Completion/Core/compdump
@@ -1,4 +1,4 @@
-# This is a file to be sourced to dump the definitions for new-style
+# This is a function to dump the definitions for new-style
# completion defined by 'compinit' in the same directory. The output
# should be directed into the "compinit.dump" in the same directory as
# compinit. If you rename init, just stick .dump onto the end of whatever
@@ -9,33 +9,46 @@
# To do this, simply remove the .dump file, start a new shell, and
# create the .dump file as before. Again, compinit -d handles this
# automatically.
-#
-# It relies on KSH_ARRAYS not being set.
# Print the number of files used for completion. This is used in compinit
# to see if auto-dump should re-dump the dump-file.
-_d_file=${COMPDUMP-${0:h}/compinit.dump}
+emulate -L zsh
+setopt extendedglob
+
+typeset _d_file _d_f _d_bks _d_line _d_als
+
+_d_file=${_comp_dumpfile-${0:h}/compinit.dump}.$HOST.$$
typeset -U _d_files
-_d_files=( ${^~fpath}/_*~*~(N:t) )
+_d_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
print "#files: $#_d_files" > $_d_file
-unset _d_files
-
# First dump the arrays _comps and _patcomps. The quoting hieroglyphyics
# ensure that a single quote inside a variable is itself correctly quoted.
print "_comps=(" >> $_d_file
for _d_f in ${(ok)_comps}; do
- print -r - "'${_d_f//\'/'\\''}'" "'${_comps[$_d_f]//\'/'\\''}'"
+ print -r - "${(q)_d_f}" "${(q)_comps[$_d_f]}"
done >> $_d_file
print ")" >> $_d_file
print "\n_patcomps=(" >> $_d_file
-for _d_f in "$_patcomps[@]"; do
- print -r - "'${_d_f//\'/'\\''}'"
+for _d_f in "${(ok@)_patcomps}"; do
+ print -r - "${(q)_d_f}" "${(q)_patcomps[$_d_f]}"
+done >> $_d_file
+print ")" >> $_d_file
+
+print "\n_postpatcomps=(" >> $_d_file
+for _d_f in "${(ok@)_postpatcomps}"; do
+ print -r - "${(q)_d_f}" "${(q)_postpatcomps[$_d_f]}"
+done >> $_d_file
+print ")" >> $_d_file
+
+print "\n_compautos=(" >> $_d_file
+for _d_f in "${(ok@)_compautos}"; do
+ print -r - "${(q)_d_f}" "${(q)_compautos[$_d_f]}"
done >> $_d_file
print ")" >> $_d_file
@@ -44,11 +57,13 @@ print >> $_d_file
# Now dump the key bindings. We dump all bindings for zle widgets
# whose names start with a underscore.
# We need both the zle -C's and the bindkey's to recreate.
+# We can ignore any zle -C which rebinds a standard widget (second
+# argument to zle does not begin with a `_').
_d_bks=()
zle -lL |
while read -rA _d_line; do
- if [[ ${_d_line[5]} = _* ]]; then
+ if [[ ${_d_line[3]} = _* && ${_d_line[5]} = _* ]]; then
print -r - ${_d_line}
_d_bks=($_d_bks ${_d_line[3]})
fi
@@ -73,17 +88,26 @@ done))
# print them out: about five to a line looks neat
+_i=5
+print -n autoload -U >> $_d_file
while (( $#_d_als )); do
- print -n autoload
- for (( _i = 0; _i < 5; _i++ )); do
- if (( $#_d_als )); then
- print -n " $_d_als[1]"
- shift _d_als
+ if (( ! $+_compautos[$_d_als[1]] )); then
+ print -n " $_d_als[1]"
+ if (( _i-- && $#_d_als > 1 )); then
+ _i=5
+ print -n '\nautoload -U'
fi
- done
- print
+ fi
+ shift _d_als
done >> $_d_file
print >> $_d_file
-unset _d_line _d_zle _d_bks _d_als _d_f _f_file
+for _i in "${(ok@)_compautos}"; do
+ print "autoload -U $_compautos[$_i] $_i" >> $_d_file
+done
+
+mv $_d_file ${_d_file%.$HOST.$$}
+
+unfunction compdump
+autoload -U compdump
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index ec5867838..6a35d17a7 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -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,
@@ -29,35 +27,89 @@
# rather than by the context. The widget has the same name as
# the autoload file and can be bound using bindkey in the normal way.
#
-# `#autoload'
-# this is for helper functions that are not used to
+# `#compdef -K <widget-name> <style> <key-sequence> [ ... ]'
+# This is similar to -k, except it takes any number of sets of
+# three arguments. In each set, the widget <widget-name> will
+# be defined, which will behave as <style>, as with -k, and will
+# be bound to <key-sequence>, exactly one of which must be defined.
+# <widget-name> must be different for each: this must begin with an
+# underscore, else one will be added, and should not clash with other
+# completion widgets (names based on the name of the function are the
+# clearest), but is otherwise arbitrary. It can be tested in the
+# function by the parameter $WIDGET.
+#
+# `#autoload [ <options> ]'
+# This is for helper functions that are not used to
# generate matches, but should automatically be loaded
-# when they are called
+# when they are called. The <options> will be given to the
+# autoload builtin when making the function autoloaded. Note
+# that this need not include `-U'.
#
# Note that no white space is allowed between the `#' and the rest of
# the string.
#
-# See the file `compdump' for how to speed up initialiation.
-#
-# 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.
+# Functions that are used to generate matches should return zero if they
+# were able to add matches and non-zero otherwise.
#
+# See the file `compdump' for how to speed up initialisation.
+
# If we got the `-d'-flag, we will automatically dump the new state (at
-# the end).
+# the end). This takes the dumpfile as an argument. -d (with the
+# default dumpfile) is now the default; to turn off dumping use -D.
+
+emulate -L zsh
+setopt extendedglob
+
+typeset _i_dumpfile _i_files _i_line _i_done _i_dir _i_autodump=1
+typeset _i_tag _i_file _i_addfiles
+
+while [[ $# -gt 0 && $1 = -[dDf] ]]; do
+ if [[ "$1" = -d ]]; then
+ _i_autodump=1
+ shift
+ if [[ $# -gt 0 && "$1" != -[df] ]]; then
+ _i_dumpfile="$1"
+ shift
+ fi
+ elif [[ "$1" = -D ]]; then
+ _i_autodump=0
+ shift
+ elif [[ "$1" = -f ]]; then
+ # Not used any more; use _compdir
+ shift
+ shift
+ fi
+done
-if [[ "$1" = -d ]]; then
- _i_autodump=1
+# The associative array containing the definitions for the commands.
+# Definitions for patterns will be stored in the associations `_patcomps'
+# and `_postpatcomps'. `_compautos' contains the names and options
+# for autoloaded functions that get options.
+
+typeset -gA _comps _patcomps _postpatcomps _compautos
+
+# The associative array use to report information about the last
+# cmpletion to the outside.
+
+typeset -gA _lastcomp
+
+# Remember dumpfile.
+if [[ -n $_i_dumpfile ]]; then
+ # Explicitly supplied dumpfile.
+ _comp_dumpfile="$_i_dumpfile"
else
- _i_autodump=0
+ _comp_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump"
fi
-# The associative array containing the definitions for the commands.
-# Definitions for patterns will be stored in the normal array `_patcomps'.
+# These can hold names of functions that are to be called before/after all
+# matches have been generated.
-typeset -A _comps
-_patcomps=()
+compprefuncs=()
+comppostfuncs=()
+
+# Loading it now ensures that the `funcstack' parameter is always correct.
+
+: $funcstack
# This function is used to register or delete completion functions. For
# registering completion functions, it is invoked with the name of the
@@ -70,6 +122,9 @@ _patcomps=()
# function will be invoked when completing for a command whose name
# matches the pattern given as argument after the function name (in this
# case only one argument is accepted).
+# The option `-P' is like `-p', but the function will be called after
+# trying to find a function defined for the command on the line if no
+# such function could be found.
# With the `-k' option a function for a special completion keys is
# defined and immediatly bound to those keys. Here, the extra arguments
# are the name of one of the builtin completion widgets and any number
@@ -78,7 +133,8 @@ _patcomps=()
# whose name is given as the first argument be autoloaded. When defining
# a function for command names the `-n' option may be given and keeps
# the definitions from overriding any previous definitions for the
-# commands.
+# commands; with `-k', the `-n' option prevents compdef from rebinding
+# a key sequence which is already bound.
# For deleting definitions, the `-d' option must be given. Without the
# `-p' option, this deletes definitions for functions for the commands
# whose names are given as arguments. If combined with the `-p' option
@@ -110,11 +166,16 @@ compdef() {
# Get the options.
- while getopts "anpkd" opt; do
+ if [[ $#* -eq 0 ]]; then
+ echo "compdef needs parameters"
+ return 1
+ fi
+
+ while getopts "anpPkKd" opt; do
case "$opt" in
a) autol=yes;;
n) new=yes;;
- [pk]) if [[ -n "$type" ]]; then
+ [pPkK]) if [[ -n "$type" ]]; then
# Error if both `-p' and `-k' are given (or one of them
# twice).
echo "$0: type already set to $type"
@@ -122,6 +183,10 @@ compdef() {
fi
if [[ "$opt" = p ]]; then
type=pattern
+ elif [[ "$opt" = P ]]; then
+ type=postpattern
+ elif [[ "$opt" = K ]]; then
+ type=widgetkey
else
type=key
fi
@@ -131,12 +196,17 @@ compdef() {
done
shift OPTIND-1
+ if [[ $#* -eq 0 ]]; then
+ echo "compdef needs parameters"
+ return 1
+ fi
+
if [[ -z "$delete" ]]; then
# Adding definitions, first get the name of the function name
# and probably do autoloading.
func="$1"
- [[ -n "$autol" ]] && autoload "$func"
+ [[ -n "$autol" ]] && autoload -U "$func"
shift
case "$type" in
@@ -145,11 +215,33 @@ compdef() {
echo "$0: only one pattern allowed"
return 1
fi
- # Patterns are stored in strings like `c* foo', with a space
- # between the pattern and the function name.
-
- _patcomps=("$_patcomps[@]" "$1 $func")
+ _patcomps[$1]="$func"
;;
+ postpattern)
+ if [[ $# -gt 1 ]]; then
+ echo "$0: only one pattern allowed"
+ return 1
+ fi
+ _postpatcomps[$1]="$func"
+ ;;
+ widgetkey)
+ while [[ -n $1 ]]; do
+ if [[ $# -lt 3 ]]; then
+ echo "$0: compdef -K requires <widget> <comp-widget> <key>"
+ return 1
+ fi
+ [[ $1 = _* ]] || 1="_$1"
+ [[ $2 = .* ]] || 2=".$2"
+ zle -C "$1" "$2" "$func"
+ if [[ -n $new ]]; then
+ bindkey "$3" | read -A opt
+ [[ $opt[-1] = undefined-key ]] && bindkey "$3" "$1"
+ else
+ bindkey "$3" "$1"
+ fi
+ shift 3
+ done
+ ;;
key)
if [[ $# -lt 2 ]]; then
echo "$0: missing keys"
@@ -157,30 +249,44 @@ compdef() {
fi
# Define the widget.
- zle -C "$func" "$1" "$func"
+ if [[ $1 = .* ]]; then
+ zle -C "$func" "$1" "$func"
+ else
+ zle -C "$func" ".$1" "$func"
+ fi
shift
# And bind the keys...
for i; do
+ if [[ -n $new ]]; then
+ bindkey "$i" | read -A opt
+ [[ $opt[-1] = undefined-key ]] || continue
+ fi
bindkey "$i" "$func"
done
;;
*)
# For commands store the function name in the `_comps'
# associative array, command names as keys.
- for i; do
- [[ -z "$new" || "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
- done
+ if [[ -z "$new" ]]; then
+ for i; do
+ _comps[$i]="$func"
+ done
+ else
+ for i; do
+ [[ "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
+ done
+ fi
;;
esac
else
# Handle the `-d' option, deleting.
case "$type" in
pattern)
- # Note the space.
- for i; do
- _patcomps=("${(@)patcomps:#$i *}")
- done
+ unset "_patcomps[$^@]"
+ ;;
+ postpattern)
+ unset "_postpatcomps[$^@]"
;;
key)
# Oops, cannot do that yet.
@@ -189,81 +295,210 @@ compdef() {
return 1
;;
*)
- # Deleting definitons for command is even simpler.
- for i; do
- unset "_comps[$i]"
- done
+ unset "_comps[$^@]"
esac
fi
}
-# Now we automatically make the definition files autoloaded.
+# Do *not* use this...
-# First we get the name of a dump file if this will be used.
+compconf() {
-: ${COMPDUMP:=$0.dump}
+ local style name val i tmp cmt
-if [[ ! -o extendedglob ]]; then
- _i_noextglob=yes
- setopt extendedglob
-fi
+ if [[ -z "$_compconf_warn" ]]; then
+ _compconf_warn=yep
+
+ print "
+
+Hello
+
+\`compconf' will be removed in the near future, we now use a more
+general (and powerful) mechanism using the \`zstyle' builtin. An
+approximation to your old setup using \`zstyle' should be available
+in the file:
+
+ \`${HOME}/.zsh-styles'
+
+Note that the values for the styles may be partly incorrect. Please
+read the manual to find out how to configure the completion system
+with styles.
+
+Have fun
+
+ Sven
+" 1>&2
+ command rm -f ${HOME}/.zsh-styles
+ fi
+
+ for i; do
+ name="${i%%\=*}"
+ val="${i#*\=}"
+
+ tmp=''
+ cmt=''
+
+ case "$name" in
+ urls_path)
+ tmp="'*:urls' path ${(qq)val}"
+ ;;
+ urls_localhttp)
+ tmp="'*:urls' local ${${(qqs.:.)val}}"
+ ;;
+ describe_options)
+ tmp="'*:options' verbose 'yes'"
+ ;;
+ describe_values)
+ tmp="'*:values' verbose 'yes'"
+ ;;
+ autodescribe_options)
+ tmp="'*:options' auto-description ${(qq)val}"
+ ;;
+ description_format)
+ tmp="'*:descriptions' format ${(qq)val}"
+ ;;
+ message_format)
+ tmp="'*:messages' format ${(qq)val}"
+ ;;
+ warning_format)
+ tmp="'*:warnings' format ${(qq)val}"
+ ;;
+ option_prefix)
+ tmp="'*:options' prefix-needed yes"
+ [[ "$val" = hide* ]] &&
+ tmp="$tmp
+zstyle ':completion:*:options' prefix-hidden yes"
+ ;;
+ group_matches)
+ tmp="'*' group-name ''"
+ ;;
+ colors_path)
+ tmp="'*:colors' path ${(qq)val}"
+ ;;
+ path_expand)
+ tmp="'*:paths' expand ${(qq)val}"
+ ;;
+ path_cursor)
+ tmp="'*:paths' cursor ${(qq)val}"
+ ;;
+ (approximate|incremental|predict|list|oldlist|match)_*)
+ tmp="'*${name%%_*}:*' ${${name#*_}//_/-} ${(qq)val}"
+ ;;
+ correct_*)
+ cmt="# This one is a bit ugly. You may want to use only \`*:correct'
+# if you also have the \`correctword_*' or \`approximate_*' keys.
+"
+ tmp="'*(correct(|-word)|approximate):*' ${name#*_} ${(qq)val}"
+ ;;
+ correctword_*)
+ tmp="'*:correct-word' ${name#correctword_} ${(qq)val}"
+ ;;
+ expand_*)
+ cmt="# This one is a bit ugly. You may want to use only \`*:expand'
+# if you also have the \`expandword_*' keys.
+"
+ tmp="'*expand(|expand-word):*' ${name#*_} ${(qq)val}"
+ ;;
+ expandword_*)
+ tmp="'expand-word:*' ${name#expandword_} ${(qq)val}"
+ ;;
+ history_*)
+ tmp="'history-words:*' ${name#history_} ${(qq)val}"
+ ;;
+ completer)
+ tmp="'*' completer ${${(qqs.:.)val}}"
+ ;;
+ last_prompt)
+ tmp="'*' last-prompt 'yes'"
+ ;;
+ esac
+ [[ -n "$tmp" ]] && style="${style}${cmt}zstyle :completion:${tmp}
+"
+ done
+
+ eval "${style}"
+
+ print "$style" >>! ${HOME}/.zsh-styles
+}
+
+# Now we automatically make the definition files autoloaded.
typeset -U _i_files
-_i_files=( ${^~fpath}/_*~*~(N:t) )
-_i_initname=$0
+_i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
+if [[ $#_i_files -lt 20 || $_compdir = */Core || -d $_compdir/Core ]]; then
+ # Too few files: we need some more directories,
+ # or we need to check that all directories (not just Core) are present.
+ if [[ -n $_compdir ]]; then
+ _i_addfiles=()
+ if [[ $_compdir = */Core ]]; then
+ # Add all the Completion subdirectories
+ _i_addfiles=(${_compdir:h}/*(/))
+ elif [[ -d $_compdir/Core ]]; then
+ # Likewise
+ _i_addfiles=(${_compdir}/*(/))
+ fi
+ for _i_line in {1..$#i_addfiles}; do
+ _i_file=${_i_addfiles[$_i_line]}
+ [[ -d $_i_file && -z ${fpath[(r)$_i_file]} ]] ||
+ _i_addfiles[$_i_line]=
+ done
+ fpath=($fpath $_i_addfiles)
+ _i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
+ fi
+fi
+
+
+# Rebind the standard widgets
+for _i_line in complete-word delete-char-or-list expand-or-complete \
+ expand-or-complete-prefix list-choices menu-complete \
+ menu-expand-or-complete reverse-menu-complete; do
+ zle -C $_i_line .$_i_line _main_complete
+done
+zle -la menu-select && zle -C menu-select .menu-select _main_complete
+
_i_done=''
+# Make sure compdump is available, even if we aren't going to use it.
+autoload -U compdump compinstall
+
# If we have a dump file, load it.
-if [[ -f "$COMPDUMP" ]]; then
- read -rA _i_line < "$COMPDUMP"
+if [[ -f "$_comp_dumpfile" ]]; then
+ read -rA _i_line < "$_comp_dumpfile"
if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then
- builtin . "$COMPDUMP"
+ builtin . "$_comp_dumpfile"
_i_done=yes
fi
- unset _i_line
fi
if [[ -z "$_i_done" ]]; then
for _i_dir in $fpath; do
[[ $_i_dir = . ]] && continue
- for _i_file in $_i_dir/_*~*~(N); do
+ for _i_file in $_i_dir/^([^_]*|*~|*.zwc)(N); do
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[@]}"
- elif [[ $_i_tag = '#autoload' ]]; then
- autoload ${_i_file:t}
- fi
+ case $_i_tag in
+ (\#compdef)
+ if [[ $_i_line[1] = -[pPkK](n|) ]]; then
+ compdef ${_i_line[1]}na "${_i_file:t}" "${(@)_i_line[2,-1]}"
+ else
+ compdef -na "${_i_file:t}" "${_i_line[@]}"
+ fi
+ ;;
+ (\#autoload)
+ autoload -U "$_i_line[@]" ${_i_file:t}
+ [[ "$_i_line" != \ # ]] && _compautos[${_i_file:t}]="$_i_line"
+ ;;
+ esac
done
done
- bindkey |
- while read -rA _i_line; do
- if [[ "$_i_line[2]" = complete-word ||
- "$_i_line[2]" = delete-char-or-list ||
- "$_i_line[2]" = expand-or-complete ||
- "$_i_line[2]" = expand-or-complete-prefix ||
- "$_i_line[2]" = list-choices ||
- "$_i_line[2]" = menu-complete ||
- "$_i_line[2]" = menu-expand-or-complete ||
- "$_i_line[2]" = reverse-menu-complete ]]; then
- zle -C _complete_$_i_line[2] $_i_line[2] _main_complete
- bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2]
- fi
- done
-
- unset _i_dir _i_line _i_file _i_tag
-
# If autodumping was requested, do it now.
- (( _i_autodump )) && builtin . ${_i_initname:h}/compdump
+ if [[ $_i_autodump = 1 ]]; then
+ compdump
+ fi
fi
-[[ -z "$_i_noextglob" ]] || unsetopt extendedglob
-
-unset _i_files _i_initname _i_done _i_autodump _i_noextglob
+unfunction compinit
+autoload -U compinit
diff --git a/Completion/Core/compinstall b/Completion/Core/compinstall
index d96121cf2..ad05cb5a1 100644
--- a/Completion/Core/compinstall
+++ b/Completion/Core/compinstall
@@ -1,72 +1,149 @@
-# This script is to be run by a user to setup the new function based
+# This script is to be run by a user to set up the new function based
# completion system. The functions themselves are assumed to be already
# available in some directory; they should have been installed with the
-# the shell (except we haven't written that yet).
+# the shell. If they have been, the commands `autoload -U compinit; compinit'
+# in the shell startup file should be enough, although you can run
+# compinstall for more configuration choices.
#
-# Run it as a script under zsh and answer the questions.
-# You can run it as `zsh compinstall $FPATH' and it will be able to check
-# your function path for the completion functions.
-#
-# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it),
-# but you can make that unwritable and it will leave the lines in a
-# temporary file instead.
-#
-# You can use this script to modify what compinstall previously
-# added to ~/.zshrc.
+# Simply run this script as a function and answer the questions.
+# Normally it will alter ~/.zshrc (or wherever ZDOTDIR puts it), but you
+# can make that unwritable and it will leave the lines in a temporary file
+# instead. It doesn't matter if .zshrc didn't exist before. If your
+# .zshrc usually exits before the end, then you should take the code added
+# by compinstall and put it (including the comment lines at the start and
+# end) at the point you want it to be executed. If you run compinstall
+# again it will find and replace those lines, so you can use this script to
+# modify what compinstall previously added to ~/.zshrc.
#
# It is safe to abort with ^C any time you are being prompted for
# information; your .zshrc will not be altered.
#
# To do:
-# - Maybe this should be sourced, then it can check the user's current
-# setup better. But then there is a potentially horrendous option
-# setting/resetting problem. (Maybe we need another way of doing that.)
# - Should probably offer to set different options for _approximate than
# for _complete if both are used.
# - Could add code for setting other completers and options.
# - Could add keys for context-sensitive help.
-# - Probably should allow a set of directories to be added to $fpath,
-# like Core, Base, etc.
-# In case a startup script changed options
-emulate zsh
-[[ -n $1 ]] && FPATH=$1
+emulate -L zsh
-for f in $fpath; do
- if [[ $f != . && -f $f/compinit && -f $f/compdump ]]; then
- fdir=$f
- break
- fi
-done
+typeset _ci_options _ci_f _ci_fdir _ci_files _ci_dumpfile _ci_lines
+typeset _ci_type _ci_completer _ci_accept _ci_cprompt _ci_startline
+typeset _ci_endline _ci_ifile _ci_tmpf _ci_compstyle _ci_warn
+typeset _ci_dtype _ci_existing _ci_line _ci_end
-if [[ -z $fdir ]]; then
- print "Trying to find where the completion functions are..."
- if [[ $0 = */* && -f $0:h/compinit && -f $0:h/compdump ]]; then
- fdir=$0:h
- else
- # more guesses?
- print \
+# Look for the defaults.
+_ci_startline='# The following lines were added by compinstall'
+_ci_endline='# End of lines added by compinstall'
+
+_ci_ifile=${ZDOTDIR:-~}/.zshrc
+_ci_lines=''
+_ci_existing=''
+
+typeset -A _ci_defaults
+
+if [[ -f $_ci_ifile ]]; then
+ # This assumes the lines haven't been altered by the user too much
+ # after they were added.
+ _ci_compstyle=0
+ sed -n "/^$_ci_startline/,/^$_ci_endline/p" $_ci_ifile |
+ while read -rA _ci_line; do
+ if (( $_ci_compstyle )); then
+ # parse a compstyle component as first argument
+ if [[ $_ci_line[-1] != \\ ]]; then
+ _ci_end=-1
+ _ci_compstyle=0
+ else
+ _ci_end=-2
+ fi
+ if [[ $_ci_line[1] = *=* ]]; then
+ _ci_f="${${_ci_line[1,$_ci_end]}#*=}"
+ if [[ $_ci_f = \'*\' ]]; then
+ # strip quotes
+ _ci_f=${_ci_f[2,-2]//\'\\\'\'/\'}
+ fi
+ _ci_defaults[${_ci_line[1]%%\=*}]=$_ci_f
+ fi
+ _ci_existing="${_ci_existing} $_ci_line
+"
+ elif [[ $_ci_line[1] = compinit ]]; then
+ # parse the line running compinit
+ [[ $_ci_line[2] = -f ]] && _ci_fdir=$_ci_line[3]
+ [[ $_ci_line[-2] = -d ]] && _ci_dumpfile=$_ci_line[-1]
+ elif [[ $_ci_line[1] = _compdir=* ]]; then
+ _ci_fdir=${_ci_line[1]##_compdir=}
+ elif [[ $_ci_line[1] = compstyle ]]; then
+ # parse a compstyle component as second argument (should be completer)
+ [[ $_ci_line[3] = completer ]] &&
+ _ci_completer=${_ci_line[3,-1]}
+ [[ $_ci_line[-1] == \\ ]] && _ci_compstyle=1
+ _ci_existing="${_ci_existing}$_ci_line
+"
+ elif [[ $_ci_line[1] != \#* && $_ci_line[1] != (autoload|\[\[) ]]; then
+ if [[ -z $_ci_warn ]]; then
+ _ci_warn=1
+ print "Warning: existing lines in compinstall setup not understood:"
+ fi
+ print - $_ci_line
+ _ci_existing="${_ci_existing}$_ci_line
+"
+ fi
+ done
+fi
+
+
+# Find out where the completion functions are kept.
+
+if [[ -z $_ci_fdir || ! -f ${~_ci_fdir}/compinit ||
+ ! -f ${~_ci_fdir}/compdump ]]; then
+ for _ci_f in $fpath; do
+ if [[ $_ci_f != . && -f $_ci_f/compinit && -f $_ci_f/compdump ]]; then
+ _ci_fdir=$_ci_f
+ break
+ elif [[ $_ci_f != . && -f $_ci_f/Core/compinit &&
+ -f $_ci_f/Core/compdump ]]
+ then
+ _ci_fdir=$_ci_f/Core
+ break
+ fi
+ done
+fi
+
+if [[ -z $_ci_fdir || ! -d ${~_ci_fdir} ]]; then
+ print \
"Please edit the name of the directory where the completion functions are
installed. If they are not installed, you will need to find them in the
Completion/* directories of the zsh distribution and install them yourself,
or insult your system manager for incompetence."
- vared -c fdir
- while [[ ! -d ${~fdir} || ! -f ${~fdir}/compinit ||
- ! -f ${~fdir}/compdump ]]; do
- print "I can't find them in that directory. Try again or abort."
- vared fdir
- done
+ vared -c _ci_fdir
+ while [[ ! -d ${~_ci_fdir} ||
+ ((! -f ${~_ci_fdir}/compinit || ! -f ${~_ci_fdir}/compdump) &&
+ (! -f ${~_ci_fdir}/Core/compinit || ! -f ${~_ci_fdir}/Core/compdump)) ]]
+ do
+ print "I can't find them in that directory. Try again or abort."
+ vared _ci_fdir
+ done
+ if [[ -f ${~_ci_fdir}/Core/compinit && ! -f ${~_ci_fdir}/compinit ]]; then
+ _ci_fdir=$_ci_fdir/Core
fi
- eval "fpath=($fdir \$fpath)"
- fdir=${fdir/#$HOME/\~}
- lines="fpath=($fdir \$fpath)\n"
else
- print "Found completion functions in your fpath, will not alter it."
+ print "Keeping existing completion directiory $_ci_fdir"
+fi
+
+if [[ ${~_ci_fdir} != /* ]]; then
+ _ci_fdir=$(cd $_ci_fdir;builtin pwd)
fi
-files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
-if [[ $#files -lt 20 ]]; then
+# Check if this is in fpath already, else put it there (with ~'s expanded).
+_ci_f=${~_ci_fdir}
+[[ -z ${fpath[(r)$_ci_f]} ]] && fpath=($fpath $_ci_f)
+
+# Contract $HOME to ~ in the parameter to be used for writing.
+_ci_fdir=${_ci_fdir/#$HOME/\~}
+
+# Now check the fpath, ignoring the directory .
+_ci_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+if [[ $#_ci_files -lt 20 ]]; then
print "
Hmmm, completion functions seem a bit thin on the ground. There should
be lots of files with names beginning with an underscore (_). You should
@@ -75,12 +152,20 @@ look and see what's happened to these.
read
fi
-if [[ -w ${~fdir} && ( ! -f ${~fdir}/compinit.dump ||
- -w ${~fdir}/compinit.dump ) ]]
+
+# Set up the dumpfile
+_ci_dtype=existing
+if [[ -z $_ci_dumpfile ]]; then
+ _ci_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump"
+ _ci_dtype=standard
+fi
+
+if [[ -w ${~_ci_dumpfile:h} && ( ! -f ${~_ci_dumpfile} ||
+ -w ${~_ci_dumpfile} ) ]]
then
print "
-Using standard dumpfile
- ${~fdir}/compinit.dump
+Using $_ci_dtype dumpfile
+ ${_ci_dumpfile}
to speed up initialisation.
[Hit return to continue]"
read
@@ -88,23 +173,32 @@ else
print "
I will force completion to dump its status, which will speed up the shell's
start-up considerably. However, I can't write the file I'd like to, namely
-$fdir/compinit.dump. Please edit a replacement."
- dumpfile='~/.compinit.dump'
- vared dumpfile
- while ! touch ${~dumpfile} >& /dev/null; do
+${_ci_dumpfile}. Please edit a replacement."
+ vared _ci_dumpfile
+ while ! touch ${~_ci_dumpfile} >& /dev/null; do
print "Sorry, I can't write that either. Try again."
- vared dumpfile
+ vared _ci_dumpfile
done
- [[ -s $dumpfile ]] || rm -f $dumpfile
- dumpfile=" $dumpfile"
+ [[ -s $_ci_dumpfile ]] || rm -f $_ci_dumpfile
fi
-fdir=${fdir/#$HOME/\~}
-
-lines="${lines}. $fdir/compinit -d$dumpfile\n"
+_ci_lines="${_ci_lines}_compdir=$_ci_fdir
+[[ -z \$fpath[(r)\$_compdir] ]] && fpath=(\$fpath \$_compdir)
+autoload -U compinit
+compinit"
+[[ $_ci_dtype != standard ]] && _ci_lines="${_ci_lines} $_ci_dumpfile"
+_ci_lines="${_ci_lines}
+"
print "
+Would you like to set some more advanced options? Otherwise, you
+can re-run compinstall later to set these. [n]"
+
+# The whole of the next part should be indented, but I can't be bothered.
+if read -q; then
+
+ print "
In addition to completion, zsh can also perform correction of the
current word, or approximate completion, i.e. completion where the part of
the word typed so far can be corrected; or it can try correction, then
@@ -112,105 +206,156 @@ approximate completion if that fails. Would you like:
0: Just ordinary completion
C: Correction
A: Approximate completion
- B: Both?
-Please type one of the keys above:"
-while read -k type; do
- print
- case $type in
- 0*) completer=_complete
- break
- ;;
- [cC]*) completer=_complete:_correct
- break
- ;;
- [aA]*) completer=_complete:_approximate
- break;
- ;;
- [bB]*) completer=_complete:_correct:_approximate
- break
- ;;
- *) print Try again
- ;;
- esac
-done
-
-lines="${lines}compconf completer=$completer"
-
-
-if [[ $completer = *(correct|approx)* ]]; then
- print "
-Correction and approximation will normally allow up to two errors,
-and you will be able to use a numeric prefix (e.g. <Esc>4) to allow
-more. The standard prompt is \`correct to:'. Do you want to change
-any of this? [n]"
- if read -q; then
- print "Number of errors to accept normally (0 is OK):"
- read accept
- while [[ $accept != <-> ]]; do
- read accept"?Please enter a number: "
- done
- print \
+ B: Both"
+ if [[ -n $_ci_completer ]]; then
+ print " Default: use the current completers:\n$_ci_completer"
+ else
+ print "Please type one of the keys above."
+ fi
+ while read -k _ci_type; do
+ print
+ case $_ci_type in
+ 0*) _ci_completer=_complete
+ break
+ ;;
+ [cC]*) _ci_completer='_complete _correct'
+ break
+ ;;
+ [aA]*) _ci_completer='_complete _approximate'
+ break;
+ ;;
+ [bB]*) _ci_completer='_complete _correct _approximate'
+ break
+ ;;
+ *) [[ -n $_ci_completer ]] && break
+ print Try again
+ ;;
+ esac
+ done
+
+ _ci_lines="${_ci_lines}zstyle ':completion*' completer $_ci_completer"
+
+
+ if [[ $_ci_completer = *(correct|approx)* ]]; then
+ _ci_accept=${_ci_defaults[correct_accept]}
+ _ci_cprompt=${_ci_defaults[correct_prompt]}
+ print "
+Correction and approximation will allow up to ${${_ci_accept:-2}%%[^0-9]*} \
+errors. "
+ case $_ci_accept in
+ *n*!*|*!*n) print "A numeric prefix, if not 1, will cause correction \
+not to be done."
+ ;;
+ *n*) print "A numeric prefix gives the maximum number of errors which \
+will be accepted."
+ ;;
+ *) print "The numeric prefix will not be used."
+ esac
+print "The correction prompt is \`${_ci_cprompt:-correct to:}'.
+Do you want to change any of this? [n]"
+ if read -q; then
+ print "Number of errors to accept normally (0 is OK):"
+ _ci_accept=${_ci_accept%%[^0-9]*}
+ vared _ci_accept
+ while [[ $_ci_accept != <-> ]]; do
+ print "Please enter a number:"
+ vared _ci_accept
+ done
+ print \
"How would you like the numeric prefix to be treated:
0: Not used by correction
- U: Used to given the number of errors
+ U: The number gives the largest number of errors which will be
+ accepted when correcting
I: If present, and not 1, do not perform correction?
Please type one of the keys above:"
- while read -k type; do
- print
- case $type in
- 0*) break
- ;;
- [uU]*) accept="${accept}n"
- break
- ;;
- [Ii]*) accept="${accept}!n"
- break
- ;;
- *) print Try again
- ;;
- esac
- done
- lines="$lines \\\\
- correct_accept='$accept'"
- print "
+ while read -k _ci_type; do
+ print
+ case $_ci_type in
+ 0*) break
+ ;;
+ [uU]*) _ci_accept="${_ci_accept}n"
+ break
+ ;;
+ [Ii]*) _ci_accept="${_ci_accept}!n"
+ break
+ ;;
+ *) print Try again
+ ;;
+ esac
+ done
+ print "
Instead of the prompt \`correct to:', you can have no prompt, or a
prompt of your choosing which can display the number of errors found by
containing the string \`%e'. Do you wish to change the correction
prompt? [n]"
- if read -q; then
- cprompt=''
- print "Edit a new prompt (may be empty):"
- vared cprompt
- lines="$lines \\\\
- correct_prompt='${cprompt//\'/\'\\\'\'}'"
+ if read -q; then
+ print "Edit a new prompt (may be empty):"
+ vared _ci_cprompt
+ [[ -z $_ci_cprompt ]] && _ci_cprompt=':empty:'
+ fi
+ fi
+ if [[ -n $_ci_accept ]]; then
+ _ci_lines="$_ci_lines \\
+ correct_accept='$_ci_accept'"
+ unset '_ci_defaults[correct_accept]'
+ fi
+ if [[ -n $_ci_cprompt ]]; then
+ _ci_cprompt=${_ci_cprompt##:empty:}
+ _ci_lines="$_ci_lines \\
+ correct_prompt='${_ci_cprompt//\'/\'\\\'\'}'"
+ unset '_ci_defaults[correct_prompt]'
fi
fi
-fi
-lines="$lines\n"
+ _ci_warn=''
+ for _ci_f in ${(k)_ci_defaults}; do
+ if [[ -z $_ci_warn ]]; then
+ print "
+(Keeping other existing configuration settings...)"
+ _ci_warn=1
+ fi
+ _ci_lines="$_ci_lines \\
+ ${_ci_f}='${_ci_defaults[$_ci_f]//\'/\'\\\'\'}'"
+ done
+ _ci_lines="$_ci_lines
+"
-startline='# The following lines were added by compinstall'
-endline='# End of lines added by compinstall'
+else
-ifile=${ZDOTDIR:-~}/.zshrc
-[[ -f $ifile ]] || touch $ifile
-tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
+ if [[ -n $_ci_existing ]]; then
+ print -nr "
+I will retain the following lines from the existing completion setup:
+$_ci_existing"
+ _ci_lines="$_ci_lines${_ci_existing}"
+ fi
+
+fi # End of advanced options
-if [[ ! -w $ifile ]]; then
- print "\nI can't write to $ifile. I will leave the lines to add in
-\`$tmpf' and you must add them by hand."
- print "\n$startline\n$lines\n$endline" >$tmpf
- return 0
-fi
-if grep $endline $ifile >& /dev/null; then
- print -- "$startline\n$lines$endline" >$tmpf
- sed -e "/^$endline/r $tmpf
-/^$startline/,/^$endline/d" $ifile >${tmpf}2 && mv ${tmpf}2 $ifile &&
- print "\nSuccesfully modified old compinstall lines in $ifile."
- rm -f $tmpf ${tmpf}2
+[[ -f $_ci_ifile ]] || touch $_ci_ifile
+_ci_tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
+
+if [[ ! -w $_ci_ifile ]]; then
+ print "\nI can't write to $_ci_ifile. I will leave the lines to add in
+\`$_ci_tmpf' and you must add them by hand."
+ print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >$_ci_tmpf
+elif grep $_ci_endline $_ci_ifile >& /dev/null; then
+ print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >$_ci_tmpf
+ sed -e "/^$_ci_endline/r $_ci_tmpf
+/^$_ci_startline/,/^$_ci_endline/d" $_ci_ifile >${_ci_tmpf}2 &&
+ mv ${_ci_tmpf}2 $_ci_ifile &&
+ print "\nSuccesfully modified old compinstall lines in $_ci_ifile."
+ rm -f $_ci_tmpf ${_ci_tmpf}2
else
- print "\n$startline\n$lines\n$endline" >>$ifile &&
- print "\nSuccessfully appended lines to $ifile."
+ print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >>$_ci_ifile &&
+ print "\nSuccessfully appended lines to $_ci_ifile."
fi
+
+unfunction compinstall
+autoload -U compinstall
+
+return 0