From 6c1fb551ba0973c9a86e1ea479d553d66c6bf6b7 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 15 Apr 1999 18:24:09 +0000 Subject: zsh-3.1.5-pws-14 --- Completion/Base/.distfiles | 2 +- Completion/Base/_brace_parameter | 10 +- Completion/Base/_condition | 2 +- Completion/Base/_long_options | 1 + Completion/Base/_math | 18 +++ Completion/Base/_tilde | 8 +- Completion/Builtins/_cd | 2 +- Completion/Builtins/_command | 3 +- Completion/Builtins/_hash | 4 +- Completion/Builtins/_kill | 2 +- Completion/Builtins/_sched | 2 +- Completion/Builtins/_setopt | 17 ++- Completion/Builtins/_source | 3 +- Completion/Builtins/_unsetopt | 17 ++- Completion/Builtins/_zmodload | 2 +- Completion/Commands/_correct_filename | 4 +- Completion/Commands/_most_recent_file | 2 +- Completion/Core/.distfiles | 5 +- Completion/Core/_approximate | 197 +++++++++++++++++++++++++++ Completion/Core/_complete | 52 +++++++ Completion/Core/_correct | 19 +++ Completion/Core/_expand | 149 ++++++++++++++++++++ Completion/Core/_list | 61 +++++++++ Completion/Core/_main_complete | 249 ++++++---------------------------- Completion/Core/_match | 53 ++++++++ Completion/Core/_multi_parts | 25 ++-- Completion/Core/_options | 5 + Completion/Core/_parameters | 8 ++ Completion/Core/_path_files | 84 +++++++++--- Completion/Core/_sep_parts | 7 +- Completion/Core/_set_options | 7 + Completion/Core/_unset_options | 7 + Completion/Core/compdump | 2 +- Completion/Core/compinit | 13 +- Completion/README | 243 +++++++++++++++++++++++++++++++-- Completion/User/_dd | 6 +- Completion/User/_find | 6 +- Completion/User/_mh | 4 +- Completion/User/_stty | 2 +- 39 files changed, 1004 insertions(+), 299 deletions(-) create mode 100644 Completion/Base/_math create mode 100644 Completion/Core/_approximate create mode 100644 Completion/Core/_complete create mode 100644 Completion/Core/_correct create mode 100644 Completion/Core/_expand create mode 100644 Completion/Core/_list create mode 100644 Completion/Core/_match create mode 100644 Completion/Core/_options create mode 100644 Completion/Core/_parameters create mode 100644 Completion/Core/_set_options create mode 100644 Completion/Core/_unset_options (limited to 'Completion') diff --git a/Completion/Base/.distfiles b/Completion/Base/.distfiles index 7e7635fa6..6f634c0b8 100644 --- a/Completion/Base/.distfiles +++ b/Completion/Base/.distfiles @@ -1,6 +1,6 @@ DISTFILES_SRC=' .distfiles _brace_parameter _command_names _condition _default _equal - _long_options _match_pattern _match_pattern.orig _match_test _parameter + _long_options _match_pattern _match_test _math _parameter _precommand _redirect _subscript _tilde _vars ' diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter index 3fab8510a..3d663a777 100644 --- a/Completion/Base/_brace_parameter +++ b/Completion/Base/_brace_parameter @@ -1,5 +1,9 @@ #defcomp -brace-parameter- -# Simple but without spiffy suffix handling: compgen -v -S '} ' - -compadd -S '} ' -r '-:?#%+=[/' - "${(@)${(@)${(@f)$(set)}%%\=*}:gs/'//}" +if [[ "$SUFFIX" = *\}* ]]; then + ISUFFIX="${SUFFIX#*\}}$ISUFFIX" + SUFFIX="${SUFFIX%%\}*}" + _parameters -S '} ' -r '-:?#%+=[/' +else + _parameters -S '} ' -r '-:?#%+=[/' +fi diff --git a/Completion/Base/_condition b/Completion/Base/_condition index db1adfd9a..df1bf913e 100644 --- a/Completion/Base/_condition +++ b/Completion/Base/_condition @@ -3,7 +3,7 @@ local prev="$words[CURRENT-1]" if [[ "$prev" = -o ]]; then - compgen -o -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' + _options elif [[ "$prev" = -([no]t|ef) ]]; then _files else diff --git a/Completion/Base/_long_options b/Completion/Base/_long_options index cc3175592..97b11f2dc 100644 --- a/Completion/Base/_long_options +++ b/Completion/Base/_long_options @@ -212,6 +212,7 @@ if [[ "$str" = *\=* ]]; then pat="${pre}*" patflags='' _match_pattern _long_options pat patflags + [[ -n "$_comp_correct" ]] && patflags="$patflags(#a$_comp_correct)" # Then we walk through the array names. For each array we test if it diff --git a/Completion/Base/_math b/Completion/Base/_math new file mode 100644 index 000000000..f7f4c360f --- /dev/null +++ b/Completion/Base/_math @@ -0,0 +1,18 @@ +#defcomp -math- + +if [[ "$PREFIX" = *[^a-zA-Z0-9_]* ]]; then + IPREFIX="$IPREFIX${PREFIX%%[a-zA-Z0-9_]#}" + PREFIX="${PREFIX##*[^a-zA-Z0-9_]}" +fi +if [[ "$SUFFIX" = *[^a-zA-Z0-9_]* ]]; then + ISUFFIX="${SUFFIX##[a-zA-Z0-9_]#}$ISUFFIX" + SUFFIX="${SUFFIX%%[^a-zA-Z0-9_]*}" +fi + +compgen -v +#defcomp -math- + +IPREFIX="$IPREFIX${PREFIX%[a-zA-Z0-9_]*}" +PREFIX="${PREFIX##*[^a-zA-Z0-9_]}" + +compgen -v diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde index aef575e19..c5ebb66d5 100644 --- a/Completion/Base/_tilde +++ b/Completion/Base/_tilde @@ -7,4 +7,10 @@ # `(( compstate[nmatches] )) || compgen -nu -qS/' # below that. -compgen -nu -qS/ +if [[ "$SUFFIX" = */* ]]; then + ISUFFIX="/${SUFFIX#*/}$ISUFFIX" + SUFFIX="${SUFFIX%%/*}" + compgen -nu -S '' +else + compgen -nu -qS/ +fi diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd index 44443c3d5..a4fd56327 100644 --- a/Completion/Builtins/_cd +++ b/Completion/Builtins/_cd @@ -17,7 +17,7 @@ local pushdminus emulate -LR zsh setopt extendedglob -if [[ -position 3 ]]; then +if [[ CURRENT -eq 3 ]]; then # cd old new: look for old in $PWD and see what can replace it local rep # Get possible completions using word in position 2 diff --git a/Completion/Builtins/_command b/Completion/Builtins/_command index 47eb0d667..4facceb12 100644 --- a/Completion/Builtins/_command +++ b/Completion/Builtins/_command @@ -1,6 +1,7 @@ #defcomp command -if [[ -position 3 -1 ]]; then +if [[ CURRENT -ge 3 ]]; then + compset -n 2 _normal else compgen -em diff --git a/Completion/Builtins/_hash b/Completion/Builtins/_hash index 8c100b801..4d4ba4244 100644 --- a/Completion/Builtins/_hash +++ b/Completion/Builtins/_hash @@ -1,12 +1,12 @@ #defcomp hash if [[ "$words[2]" = -*d* ]]; then - if [[ -string 1 '=' ]]; then + if compset -P 1 '*\='; then _path_files -g '*(-/)' else compgen -n -q -S '=' fi -elif [[ -string 1 '=' ]]; then +elif compset -P 1 '*\='; then _files -/g '*(*)' else compgen -m -q -S '=' diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill index 36a23ccb2..0b0f5c188 100644 --- a/Completion/Builtins/_kill +++ b/Completion/Builtins/_kill @@ -2,7 +2,7 @@ local list -if [[ -iprefix '-' ]]; then +if compset -P 1 -; then compgen -k "($signals[1,-3])" else local ret=1 diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched index 62cdbb070..5fba71eac 100644 --- a/Completion/Builtins/_sched +++ b/Completion/Builtins/_sched @@ -1,3 +1,3 @@ #defcomp sched -[[ -position 3 -1 ]] && _normal +compset -n 3 && _normal diff --git a/Completion/Builtins/_setopt b/Completion/Builtins/_setopt index b458cb2b0..e5a6c054f 100644 --- a/Completion/Builtins/_setopt +++ b/Completion/Builtins/_setopt @@ -1,11 +1,10 @@ #defcomp setopt -local nm=$compstate[nmatches] ret=1 - -compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ - -s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)' && ret=0 - -[[ compstate[nmatches] -eq nm ]] && - compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o && ret=0 - -return ret +# If you first want to complete only unset options, un-comment the lines +# setting the _unset_options array and then use: +# +# _unset_options || _options +# +# here. + +_options diff --git a/Completion/Builtins/_source b/Completion/Builtins/_source index 1bbbf15a4..efac4f32b 100644 --- a/Completion/Builtins/_source +++ b/Completion/Builtins/_source @@ -1,6 +1,7 @@ #defcomp source -if [[ -position 3 -1 ]]; then +if [[ CURRENT -ge 3 ]]; then + compset -n 2 _normal else _files diff --git a/Completion/Builtins/_unsetopt b/Completion/Builtins/_unsetopt index 1194e28a7..cdc2ab9f3 100644 --- a/Completion/Builtins/_unsetopt +++ b/Completion/Builtins/_unsetopt @@ -1,11 +1,10 @@ #defcomp unsetopt -local nm=$compstate[nmatches] ret=1 - -compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ - -s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)' && ret=0 - -[[ compstate[nmatches] -eq nm ]] && - compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o && ret=0 - -return ret +# If you first want to complete only unset options, uncomment the lines +# setting the _set_options array and then use: +# +# _set_options || _options +# +# here. + +_options diff --git a/Completion/Builtins/_zmodload b/Completion/Builtins/_zmodload index 4259adf06..9247ba0ce 100644 --- a/Completion/Builtins/_zmodload +++ b/Completion/Builtins/_zmodload @@ -2,7 +2,7 @@ local fl="$words[2]" -if [[ "$fl" = -*(a*u|u*a)* || "$fl" = -*a* && -position 4 -1 ]]; then +if [[ "$fl" = -*(a*u|u*a)* || "$fl" = -*a* && CURRENT -ge 4 ]]; then compgen -B elif [[ "$fl" = -*u* ]]; then compgen -s '$(zmodload)' diff --git a/Completion/Commands/_correct_filename b/Completion/Commands/_correct_filename index 27295738c..72bac5f1b 100644 --- a/Completion/Commands/_correct_filename +++ b/Completion/Commands/_correct_filename @@ -45,7 +45,7 @@ fi if [[ -z $testcmd && -e "$file" ]] || { [[ -n $testcmd ]] && whence "$file" >&/dev/null }; then if [[ -n $WIDGET ]]; then - compadd -QUf -i "$IPREFIX" "${file/#$etilde/$tilde}" + compadd -QUf -i "$IPREFIX" -I "$ISUFFIX" "${file/#$etilde/$tilde}" [[ -n "$compstate[insert]" ]] && compstate[insert]=menu else print "$file" @@ -65,7 +65,7 @@ done (( $#trylist )) || return 1 if [[ -n $WIDGET ]]; then - compadd -QUf -i "$IPREFIX" "${trylist[@]/#$etilde/$tilde}" + compadd -QUf -i "$IPREFIX" -I "$ISUFFIX" "${trylist[@]/#$etilde/$tilde}" [[ -n "$compstate[insert]" ]] && compstate[insert]=menu else print "$IPREFIX${^trylist[@]}" diff --git a/Completion/Commands/_most_recent_file b/Completion/Commands/_most_recent_file index df35ecba7..5bd737fd2 100644 --- a/Completion/Commands/_most_recent_file +++ b/Completion/Commands/_most_recent_file @@ -19,4 +19,4 @@ if [[ $PREFIX = \~*/* ]]; then else file=($~PREFIX*$~SUFFIX(om[$NUMERIC]N)) fi -(( $#file )) && compadd -U -f -Q $file +(( $#file )) && compadd -U -i "$IPREFIX" -I "$ISUFFIX" -f -Q $file diff --git a/Completion/Core/.distfiles b/Completion/Core/.distfiles index ddf2a707e..6babe9701 100644 --- a/Completion/Core/.distfiles +++ b/Completion/Core/.distfiles @@ -1,5 +1,6 @@ DISTFILES_SRC=' .distfiles - _compalso _files _main_complete _multi_parts _normal _path_files - _sep_parts compdump compinit + _approximate _compalso _complete _correct _expand _files _list + _main_complete _match _multi_parts _normal _options _parameters + _path_files _sep_parts _set_options _unset_options compdump compinit ' diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate new file mode 100644 index 000000000..1b40f7cbf --- /dev/null +++ b/Completion/Core/_approximate @@ -0,0 +1,197 @@ +#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 + +# Get the number of errors to accept. + +if [[ "$cfgacc" = *[nN]* && NUMERIC -ne 1 ]]; then + # Stop if we also have a `!'. + + [[ "$cfgacc" = *\!* ]] && return 1 + + # Prefer the numeric argument if that has a sensible value. + + comax="$NUMERIC" +else + comax="${cfgacc//[^0-9]}" +fi + +# If the number of errors to accept is too small, give up. + +[[ "$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 +# ignored prefix). + +compadd() { + [[ "$*" != *-([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 compadd -X "$_correct_prompt" -J _correct "$@" + else + builtin compadd -J _correct "$@" + fi +} + +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 + if _complete; then + if [[ "$cfgins" = unambig* && + "${#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 + + # If you always want to see the list of possible corrections, + # set `compstate[list]=list' here. + + compstate[force_list]=list + fi + compstate[matcher]="$compstate[total_matchers]" + unfunction compadd compgen + + 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 + +return 1 diff --git a/Completion/Core/_complete b/Completion/Core/_complete new file mode 100644 index 000000000..0f4d5ff4b --- /dev/null +++ b/Completion/Core/_complete @@ -0,0 +1,52 @@ +#autoload + +# 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. + +local comp name + +# 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 + "$comp" + if (( $+_compskip )); then + unset _compskip + (( compstate[nmatches] )) + return + fi +fi + +# For arguments and command names we use the `_normal' function. + +if [[ "$compstate[context]" = command ]]; then + _normal +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 + + # If not, we use default completion, if any. + + [[ -z "$comp" ]] && comp="$_comps[-default-]" + [[ -z "$comp" ]] || "$comp" +fi + +(( compstate[nmatches] )) diff --git a/Completion/Core/_correct b/Completion/Core/_correct new file mode 100644 index 000000000..35ab01cf1 --- /dev/null +++ b/Completion/Core/_correct @@ -0,0 +1,19 @@ +#autoload + +# 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 +# with the corrected prefix and something after it. +# +# Supported configuration keys are the same as for `_approximate', only +# starting with `correct'. + +local ret=1 opm="$compstate[pattern_match]" + +compstate[pattern_match]='-' + +_approximate && ret=0 + +compstate[pattern_match]="$opm" + +return ret diff --git a/Completion/Core/_expand b/Completion/Core/_expand new file mode 100644 index 000000000..9172b6cbf --- /dev/null +++ b/Completion/Core/_expand @@ -0,0 +1,149 @@ +#autoload + +# This completer function is intended to be used as the first completer +# function and allows one to say more explicitly when and how the word +# from the line should be expanded than expand-or-complete. +# 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 + +# In exp we will collect the expansion. + +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 ]] && + exp=( "${(e)exp//\\[ +]/ }" ) + +# If the array is empty, store the original string again. + +[[ -z "$exp" ]] && exp=("$word") + +# Now try globbing. + +[[ -z "$compconfig[expand_glob]" || + "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ]] && + exp=( ${~exp}(N) ) + +# 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 + +# We have expansions, should we menucomplete them? + +if [[ -z "$compconfig[expand_menu]" ]]; then + + # 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. + + 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" + + compadd -UQ -V _expand - "$exp" + + [[ -n "$compconfig[expand_original]" && + "$compconfig[expand_original]" = *last* ]] && + compadd -UnQ -V _expand_original - "$word" + + compstate[insert]=menu + fi +else + # Sorting? We just use a different group type then. + + [[ "$compconfig[expand_menu]" = *sort* ]] && group=-J + + # Now add the expansion string, probably also adding the original + # and/or the string containing all expanded string. + + [[ -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 [[ -z "$compconfig[expand_prompt]" ]]; then + compadd -UQ $group _expand - "$exp[@]" + else + compadd -UQ -X "${compconfig[expand_prompt]//\%o/$word}" \ + $group _expand - "$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" + + compstate[insert]=menu +fi + +return 0 diff --git a/Completion/Core/_list b/Completion/Core/_list new file mode 100644 index 000000000..099c6bc7b --- /dev/null +++ b/Completion/Core/_list @@ -0,0 +1,61 @@ +#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 + +# Get the strings to compare. + +if [[ -z "$compconfig[list_word]" ]]; then + pre="$HISTNO$LBUFFER" + suf="$RBUFFER" +else + pre="$PREFIX" + suf="$SUFFIX" +fi + +# Should we only show a list now? + +if [[ ( -z "$compconfig[list_condition]" || + "${(e):-\$[$compconfig[expand_glob]]}" -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 + _list_prefix="$pre" + _list_suffix="$suf" +fi + +# We always return one, because we don't really do any work here. + +return 1 diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete index 3571b712c..62e60a1cc 100644 --- a/Completion/Core/_main_complete +++ b/Completion/Core/_main_complete @@ -3,229 +3,56 @@ # The main loop of the completion code. This is what is called when # completion is attempted from the command line. # -# This code will automatically try to correct the string on the line -# based on the strings generated for the context if -# `compconfig[correct]' is set and normal completion didn't yield any -# matches. These corrected strings will be shown in a list and one can -#cycle through them as in a menucompletion. To use this feature, -#`compconfig[correct]' 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 -# `compconfig[correct]' will be used. E.g. with `compconfig[correct]=2n' -# two errors will be accepted, but if the user gives another number -# with the numeric argument, this will be prefered. Also, with -# `compconfig[correct]=0n',normally no automatic correction will be -# tried, but if a numeric argument is given, automatic correction will -# be used. 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. -# The value of `compconfig[correct_orig]' 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 apear 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 immediatly). Also, if the value of -# `compconfig[correct_orig]' 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. -# Finally, `compconfig[correct_prompt]' may 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. +# Configuration keys used: +# +# completer +# This should be set to the names of the functions to generate the +# matches separated by colons. E.g. with +# +# compconf completer=_complete:_correct:_approximate +# +# the code will first try normal completion. If that doesn't yield +# any matches, correction is tried and if that doesn't yield +# anything either, correcting completion is attempted. +# +# These completer functions are only used when this function is called +# without arguments. If arguments are given, they should be names of +# completer functions which will then be called. + + +# 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=("${(@f)$({ unsetopt kshoptionprint; setopt } 2>/dev/null)}") +# _unset_options=("${(@f)$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)}") +# +# This is needed because completion function 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. -local comp name _comp_correct _correct_prompt comax + +local comp setopt localoptions nullglob rcexpandparam unsetopt markdirs globsubst shwordsplit nounset ksharrays # Special completion contexts after `~' and `='. -if [[ -iprefix '=' ]]; then +if compset -P 1 '\='; then compstate[context]=equal -elif [[ "$PREFIX$SUFFIX" != */* && -iprefix '~' ]]; then +elif [[ "$PREFIX" != */* && "$PREFIX[1]" = '~' ]]; then + compset -p 1 compstate[context]=tilde fi -# This is not an endless loop. - -while true; do - - # 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 - "$comp" - if (( $+_compskip )); then - unset _compskip - return - fi - fi - - # For arguments and command names we use the `_normal' function. - - if [[ "$compstate[context]" = command ]]; then - _normal - 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 - - # If not, we use default completion, if any. - - [[ -z "$comp" ]] && comp="$_comps[-default-]" - [[ -z "$comp" ]] || "$comp" - fi - - # Use automatic correction? - - if (( $+compconfig[correct] )); then - - # Do we have matches? - if (( compstate[nmatches] )); then - - # Yes, were they added using correction? (More than one match?) +# Get the names of the completers to use in the positional parameters. - if [[ -n "$_comp_correct" && - ( "$compconfig[correct_orig]" = *always* || - compstate[nmatches] -gt 1 ) ]]; then +(( $# )) || set ${(s.:.)compconfig[completer]} - if [[ "$compconfig[correct_orig]" = *last* ]]; then - builtin compadd -V _correct_orig -nQ - "$PREFIX$SUFFIX" - elif [[ -n "$compconfig[correct_orig]" ]]; then - builtin compadd -nQ - "$PREFIX$SUFFIX" - fi +# And now just call the completer functions defined. - # If you always want to see the list of possible corrections, - # set `compstate[list]=list' here. - - compstate[force_list]=list - fi - # Since we have matches, we don't want to try again. - - break - fi - - # No matches, so let's see if we already tried correction. - - if [[ -n "$_comp_correct" ]]; then - - # Yes, give up if we reached the maximum number of tries or the - # string from the line is too short, otherwise increment our - # counter. - - [[ _comp_correct -eq comax || - "${#${:-$PREFIX$SUFFIX}}" -le _comp_correct+1 ]] && break - (( _comp_correct++ )) - - _correct_prompt="${compconfig[correct_prompt]//\%e/$_comp_correct}" - - elif [[ compstate[matcher] -eq compstate[total_matchers] ]]; then - - # We don't try correction if the string is too short. - - [[ "${#${:-$PREFIX$SUFFIX}}" -le 1 ]] && return - - # No matches and no correction tried yet, but we just tried the - # last global match specification, so let's see if we should use - # correction now. First, get the maximum number of errors. - - if [[ "$compconfig[correct]" = *[nN]* && NUMERIC -ne 1 ]]; then - # Prefer the numeric argument if that has a sensible value. - comax="$NUMERIC" - else - comax="${compconfig[correct]//[^0-9]}" - fi - # If the number of errors to accept is too small, give up. - - [[ "$comax" -lt 1 ]] && break - - # 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 - # ignored prefix). - - compadd() { - [[ "$*" != *-([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 compadd -X "$_correct_prompt" -J _correct "$@" - else - builtin compadd -J _correct "$@" - fi - } - 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="${compconfig[correct_prompt]//\%e/$_comp_correct}" - - # We also need to set `extendedglob' and to make the completion - # code behave as if globcomplete were set. - - setopt extendedglob - compstate[pattern_match]=yes - else - # We are still trying global match specifications... - break - fi - else - # No automatic correction to try, just give up. - break - fi +for comp; do + "$comp" && return done - -# If we added wrapper functions, remove them. - -[[ -n "$_comp_correct" ]] && unfunction compadd compgen diff --git a/Completion/Core/_match b/Completion/Core/_match new file mode 100644 index 000000000..3c639935c --- /dev/null +++ b/Completion/Core/_match @@ -0,0 +1,53 @@ +#autoload + +# This is intended to be used as a completer function after the normal +# completer as in: `compconf 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 + +# Do nothing if we don't have a pattern or there are still global +# match specifications to try. + +tmp="${${:-$PREFIX$SUFFIX}#[~=]}" +[[ "$tmp:q" = "$tmp" || + compstate[matcher] -ne compstate[total_matchers] ]] && return 1 + +# Try completion without inserting a `*'? + +if [[ -n "$compconfig[match_original]" ]]; then + compstate[matcher]=-1 + compstate[pattern_match]='-' + _complete && ret=1 + compstate[pattern_match]="$opm" + compstate[matcher]="$compstate[total_matchers]" + + (( ret )) && return 0 +fi + +# No completion with inserting `*'? + +[[ "$compconfig[match_original]" = only ]] && return 1 + +compstate[matcher]=-1 +compstate[pattern_match]='*' +_complete && ret=1 +compstate[pattern_match]="$opm" +compstate[matcher]="$compstate[total_matchers]" + +return 1-ret diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts index 0c677aab7..ab9438494 100644 --- a/Completion/Core/_multi_parts +++ b/Completion/Core/_multi_parts @@ -45,7 +45,11 @@ fi # the original string in `orig'. if [[ $#compstate[pattern_match] -ne 0 ]]; then - patstr="${PREFIX}*${SUFFIX}*" + if [[ "${compstate[pattern_match]-*}" = \** ]]; then + str="${PREFIX}*${SUFFIX}*" + else + str="${PREFIX}${SUFFIX}" + fi else patstr="${PREFIX:q}*${SUFFIX:q}*" fi @@ -145,7 +149,8 @@ if (( $#tmp1 )); then # found. Strings that have a separator will be added with a suffix. if [[ -z "$orig" && "$PREFIX$SUFFIX" != "$pref$orig" ]]; then - compadd -QU "$group[@]" "$expl[@]" -i "$IPREFIX" -S '' - "${pref}${orig}" + compadd -QU "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" -S '' - \ + "${pref}${orig}" elif [[ -n "$menu" ]]; then if [[ "$orig" = *${sep}* ]]; then orig="${sep}${orig#*${sep}}" @@ -154,20 +159,21 @@ if (( $#tmp1 )); then fi for i in "$matches[@]" ; do if [[ "$i" = *${sep}* ]]; then - compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \ + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \ -p "$pref" -s "$orig" - "${i%%${sep}*}${sep}" else - compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \ + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \ -p "$pref" -s "$orig" - "${i%%${sep}*}" fi done else for i in "$matches[@]" ; do if [[ "$i" = *${sep}* ]]; then - compadd -U -i "$IPREFIX" -p "$pref" -s "${i#*${sep}}" \ + compadd -U -i "$IPREFIX" -I "$ISUFFIX" -p "$pref" -s "${i#*${sep}}" \ "$group[@]" "$expl[@]" -M "r:|${sep:q}=*" - "${i%%${sep}*}${sep}" else - compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -p "$pref" - "$i" + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \ + -p "$pref" - "$i" fi done fi @@ -201,8 +207,8 @@ elif [[ "$patstr" = *${sep}* ]]; then # the completion code together with our prefix and the rest of # the string from the line as the suffix. - compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" \ - -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}" + compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -I "$ISUFFIX" \ + -p "$pref" -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}" return 0 fi @@ -218,7 +224,8 @@ elif [[ "$patstr" = *${sep}* ]]; then # Finally, add the unambiguous prefix and the rest of the string # from the line. - compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" - "$orig" + compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -I "$ISUFFIX" \ + -p "$pref" - "$orig" fi # This sets the return value to indicate that we added matches (or not). diff --git a/Completion/Core/_options b/Completion/Core/_options new file mode 100644 index 000000000..0a852e6ce --- /dev/null +++ b/Completion/Core/_options @@ -0,0 +1,5 @@ +#autoload + +# This should be used to complete all option names. + +compgen "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o diff --git a/Completion/Core/_parameters b/Completion/Core/_parameters new file mode 100644 index 000000000..0e8c548f7 --- /dev/null +++ b/Completion/Core/_parameters @@ -0,0 +1,8 @@ +#autoload + +# This should be used to complete parameter names if you need some of the +# extra options of compadd. It first tries to complete only non-local +# parameters. All arguments are given to compadd. + +compadd "$@" - "${(@)${(@)${(@)${(@f)$(typeset)}:#*local *\=*}%%\=*}##* }" || + compadd "$@" - "${(@)${(@)${(@f)$(typeset)}%%\=*}##* }" diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 4c61ac7ef..54b04a368 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -12,6 +12,14 @@ # like files with one of the suffixes in the `fignore' array in normal # completion. # +# This function supports one configuration key: +# +# path_expand +# If this is set to a non-empty string, the partially typed path +# from the line will be expanded as far as possible even if trailing +# pathname components can not be completed. +# +# # This function uses the helper functions `_match_test' and `_match_pattern'. # First see if we should generate matches for the global matcher in use. @@ -20,14 +28,17 @@ _match_test _path_files || return 1 # Yes, so... -local nm prepaths str linepath realpath donepath patstr prepath testpath rest +local nm str linepath realpath donepath patstr prepath testpath rest local tmp1 collect tmp2 suffixes i ignore matchflags opt group sopt pats gopt local addpfx addsfx expl orig ostr nm=$compstate[nmatches] menu remsfx patlast -local origflags mflags +local origflags mflags tmp3 tmp4 exppaths + +typeset -U prepaths setopt localoptions nullglob rcexpandparam extendedglob unsetopt markdirs globsubst shwordsplit nounset +exppaths=() prepaths=('') ignore=() group=() @@ -102,7 +113,11 @@ fi # the prefix and the suffix. Then we see if we will do menucompletion. if [[ $#compstate[pattern_match] -ne 0 ]]; then - str="${PREFIX}*${SUFFIX}" + if [[ "${compstate[pattern_match]-*}" = \** ]]; then + str="${PREFIX}*${SUFFIX}" + else + str="${PREFIX}${SUFFIX}" + fi else str="${PREFIX:q}*${SUFFIX:q}" [[ "$str" = \\\~* ]] && str="$str[2,-1]" @@ -200,7 +215,7 @@ origflags="$matchflags" # have special meaning for globbing, we remove them. But before that, we # add the pattern for matching any characters before a slash. -patstr="$patstr:gs-/-*/-:gs/*.*./../:gs-/*.-/.-:gs/**/*/:gs-.*/-./-" +patstr="$patstr:gs-/-*/-:gs/*.*./../:gs/**/*/:gs-.*/-./-" # We take the last pathname component from the pattern and store it in # `patlast', replacing `*'s in it with patterns that match any character @@ -214,16 +229,16 @@ patstr="$patstr:gs-/-*/-:gs/*.*./../:gs-/*.-/.-:gs/**/*/:gs-.*/-./-" if [[ "$patstr" = */* ]]; then if [[ -n "$_comp_correct" && "${#orig##*/}" -le _comp_correct ]]; then - patlast="*/${origflags}${${patstr##*/}//\*/[^/]#}" + patlast="*/${origflags}${${${patstr##*/}//\*/[^/]#}:gs.\[^/]#.\\\*.}" else - patlast="*/${matchflags}${${patstr##*/}//\*/[^/]#}" + patlast="*/${matchflags}${${${patstr##*/}//\*/[^/]#}:gs.\[^/]#.\\\*.}" fi patstr="${patstr%/*}/" else if [[ -n "$_comp_correct" && "$#orig" -le _comp_correct ]]; then - patlast="${origflags}${patstr//\*/[^/]#}" + patlast="${origflags}${${patstr//\*/[^/]#}:gs.\[^/]#.\\\*.}" else - patlast="${matchflags}${patstr//\*/[^/]#}" + patlast="${matchflags}${${patstr//\*/[^/]#}:gs.\[^/]#.\\\*.}" fi patstr="" fi @@ -234,7 +249,7 @@ fi # to `donepath'. while [[ "$orig" = */* ]] do - tmp1=( $realpath$donepath${orig%%/*}/${~matchflags}${~patstr#*/}$^pats ) + tmp1=( $realpath$donepath${orig%%/*}/${~matchflags}${~patstr#*/}${^~pats} ) tmp1=("${(@M)tmp1:#$~patlast}") [[ $#tmp1 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break donepath="$donepath${orig%%/*}/" @@ -311,6 +326,24 @@ for prepath in "$prepaths[@]"; do # next `-W' path. if [[ $#collect -eq 0 ]]; then + # Before giving, we first try to get the longest expandable path- + # prefix, though. The result is stored in `exppaths' + + tmp2=() + tmp3="$rest" + tmp4="${ostr##*/}" + ostr="${ostr%/*}" + while [[ "$tmp3" = */* ]]; do + tmp2=( ${^tmp1}/${~mflags}${~tmp3} ) + if [[ $#tmp2 -eq 1 ]]; then + exppaths=( "$exppaths[@]" "${tmp2[1]}${tmp4}" ) + exppaths=( "${(@)exppaths#${prepath}${realpath}}" ) + break; + fi + tmp3="${tmp3%/*}" + tmp4="${ostr##*/}/${tmp4}" + ostr="${ostr%/*}" + done continue 2 elif [[ $#collect -ne 1 ]]; then # If we have more than one possible match, this means that the @@ -338,13 +371,14 @@ for prepath in "$prepaths[@]"; do if [[ -n "$menu" ]]; then compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -p "$linepath${testpath:q}" \ + -i "$IPREFIX" -I "$ISUFFIX" -p "$linepath${testpath:q}" \ -s "/${ostr#*/}" \ -W "$tmp1" -f "$ignore[@]" - "${(@)${(@)collect%%/*}:q}" else for i in $collect; do compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -p "$linepath${testpath:q}" -s "/${${i#*/}:q}" \ + -i "$IPREFIX" -I "$ISUFFIX" \ + -p "$linepath${testpath:q}" -s "/${${i#*/}:q}" \ -M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${${i%%/*}:q}" done fi @@ -371,7 +405,8 @@ for prepath in "$prepaths[@]"; do if [[ $#tmp1 -ne $#tmp2 ]]; then compadd -QU "$addpfx[@]" -S '' "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -p "$linepath${testpath:q}" -s "/${ostr#*/}" \ + -i "$IPREFIX" -I "$ISUFFIX" \ + -p "$linepath${testpath:q}" -s "/${ostr#*/}" \ - "${${tmp1#${prepath}${realpath}${testpath}}:q}" continue 2 fi @@ -399,8 +434,11 @@ for prepath in "$prepaths[@]"; do suffixes=( $str$^pats ) suffixes=( "${(@)suffixes:gs.**.*.}" ) tmp2=( ${~tmp1}${~matchflags}${~suffixes} ) - tmp2=("${(@M)tmp2:#$~patlast}") - + if [[ "$tmp1" = */* && "$patlast" != \*/* ]]; then + tmp2=("${(@M)tmp2:#*${~patlast}}") + else + tmp2=("${(@M)tmp2:#$~patlast}") + fi if [[ $#tmp2 -eq 0 ]]; then # No match, insert the expanded path and add the original tail. @@ -409,17 +447,29 @@ for prepath in "$prepaths[@]"; do [[ -n "$ostr" && -n "$linepath$testpath" ]] && ostr="/$ostr" # But only if something changed. - [[ "$linepath$testpath$ostr" = "$PREFIX$SUFFIX" ]] && return 1 + [[ "${PREFIX}${SUFFIX}" = $linepath$testpath$ostr(|/) ]] && return 1 compadd -QU -S '' "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -f - "$linepath${testpath:q}$ostr" + -i "$IPREFIX" -I "$ISUFFIX" -f - "$linepath${testpath:q}$ostr" else compadd -QU "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" "$group[@]" "$expl[@]" \ - -i "$IPREFIX" -p "$linepath${testpath:q}" -f "$ignore[@]" \ + -i "$IPREFIX" -I "$ISUFFIX" \ + -p "$linepath${testpath:q}" -f "$ignore[@]" \ -W "$prepath$realpath$testpath" - "${(@)${(@)tmp2#$tmp1}:q}" fi done +# If no matches were found but we have expanded paths which are different +# from the original string, use them. + +exppaths=( "${(@)exppaths:#$orig}" ) + +if [[ -n "$compconfig[path_expand]" && + nm -eq compstate[nmatches] && $#exppaths -ne 0 ]]; then + compadd -UQ -S '' "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" - \ + "${linepath}${(@)^exppaths}" +fi + # This sets the return value to indicate that we added matches (or not). [[ nm -ne compstate[nmatches] ]] diff --git a/Completion/Core/_sep_parts b/Completion/Core/_sep_parts index c1cda2b9a..fc927163b 100644 --- a/Completion/Core/_sep_parts +++ b/Completion/Core/_sep_parts @@ -101,6 +101,8 @@ if [[ $# -le 1 || "$str" != *${2}* ]]; then _match_pattern _sep_parts test matchflags [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" + [[ "${compstate[pattern_match]-*}" != \** ]] && test="$test:gs/*//" + test="${matchflags}${test}" testarr=( "${(@M)${(@P)arr}:#${~test}*}" ) testarr=( "${(@)testarr:#}" ) @@ -131,6 +133,9 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do matchflags="" _match_pattern _sep_parts test matchflags [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" + + [[ "${compstate[pattern_match]-*}" != \** ]] && test="$test:gs/*//" + test="${matchflags}${test}" # We incrementally add suffixes by appending to them the seperators @@ -163,7 +168,7 @@ done # Add the matches for each of the suffixes. for i in "$suffixes[@]"; do compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \ - -i "$IPREFIX" -p "$prefix" -s "$i" - "$testarr[@]" + -i "$IPREFIX" -I "$ISUFFIX" -p "$prefix" -s "$i" - "$testarr[@]" done # This sets the return value to indicate that we added matches (or not). diff --git a/Completion/Core/_set_options b/Completion/Core/_set_options new file mode 100644 index 000000000..5f634a2cd --- /dev/null +++ b/Completion/Core/_set_options @@ -0,0 +1,7 @@ +#autoload + +# Complete all set options. This relies on `_main_complete' to store the +# names of the options that were set when it was called in the array +# `_set_options'. + +compadd "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' - $=_set_options diff --git a/Completion/Core/_unset_options b/Completion/Core/_unset_options new file mode 100644 index 000000000..c5150c2e5 --- /dev/null +++ b/Completion/Core/_unset_options @@ -0,0 +1,7 @@ +#autoload + +# Complete all unset options. This relies on `_main_complete' to store the +# names of the options that were set when it was called in the array +# `_set_options'. + +compadd "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' - $=_unset_options diff --git a/Completion/Core/compdump b/Completion/Core/compdump index 5fdee8c7a..6a46f3265 100644 --- a/Completion/Core/compdump +++ b/Completion/Core/compdump @@ -15,7 +15,7 @@ # 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=${compconfig[dump_file]-${0:h}/compinit.dump} +_d_file=${compconfig[dumpfile]-${0:h}/compinit.dump} typeset -U _d_files _d_files=( ${^~fpath}/_*~*~(N:t) ) diff --git a/Completion/Core/compinit b/Completion/Core/compinit index 466c80d36..19a0fd1ad 100644 --- a/Completion/Core/compinit +++ b/Completion/Core/compinit @@ -71,11 +71,12 @@ typeset -A compconfig # Standard initialisation for `compconfig'. -(( $# )) && compconfig[dump_file]="$1" -[[ -z "$compconfig[dump_file]" ]] && compconfig[dump_file]="$0.dump" +(( $# )) && compconfig[dumpfile]="$1" +[[ -z "$compconfig[dumpfile]" ]] && compconfig[dumpfile]="$0.dump" +compconfig[correct_accept]=2n compconfig[correct_prompt]='correct to:' - +compconfig[completer]=_complete # This function is used to register or delete completion functions. For # registering completion functions, it is invoked with the name of the @@ -246,10 +247,10 @@ _i_done='' # If we have a dump file, load it. -if [[ -f "$compconfig[dump_file]" ]]; then - read -rA _i_line < "$compconfig[dump_file]" +if [[ -f "$compconfig[dumpfile]" ]]; then + read -rA _i_line < "$compconfig[dumpfile]" if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then - builtin . "$compconfig[dump_file]" + builtin . "$compconfig[dumpfile]" _i_done=yes fi unset _i_line diff --git a/Completion/README b/Completion/README index 931d14355..bf677066a 100644 --- a/Completion/README +++ b/Completion/README @@ -14,7 +14,7 @@ The name of the file to use may be given as an extra argument. This will rebind any keys which do completion to use the new system. For more detailed instructions, including how to add new completions, see the top of Core/compinit. For information about how to configure the code, -see the comment at the top of Core/_main_complete. +see the section below. The subdirectories contain: @@ -30,32 +30,61 @@ Core: This dumps the completions status for faster initialisation. The easiest way of doing this is to use the -d option to compinit rather than calling compdump directly. - _sep_parts - Utility used for completing words with multiple separate parts, such as - `@' - _multi_parts - Utility for completion parts of words given a separator character and - a list of words. + _approximate + A completer function that does correcting completion. _compalso Utility for calling a function to add additional completions to an already existing set. + _complete + The main completer function that generates the completions by calling + the context and command specific functions. + _correct + A completer function that attempts correction on the word from the + line. Unlike _approximate this does only correction, not completion. + _expand + A completer function for expanding the word on the line. _files A frontend to _path_files which will default to any old file if the specified file was not found. + _list + A completer function that allows showing only a list on the first + TAB and insert completions on the second one. + _match + A completer function that temporarily swicthes on pattern matching + when comparing the string from the line with possible completions. _main_complete The main entry point called by the key bindings which compinit sets - up (the main `completion widget' in zsh jargon). + up (the main `completion widget' in zsh jargon). This mainly calls + completer functions like _complete, either those given as arguments + or (if it is called without arguments) those from the completer + configuration key (see below). + _multi_parts + Utility for completion parts of words given a separator character and + a list of words. _normal The function called by _main_complete to handle the most common cases, such as completing a command name or its arguments. This function dispatches to the various other functions for individual commands. (Actually, the system is fairly context-sensitive, so it is wider than just command+argument.) + _options + Utility to complete option names, allowing the optional `no' prefix + and correctly handling upper case letters and underscores. + _parameters + This can be used to complete parameter names if you need some of the + options of compadd not supported by compgen. _path_files The function usually called to complete filenames and directories. It replaces the standard -f, -g and -/ options for the basic completion commands: it can do various extra tricks, such as expanding a whole path at once, e.g. F/C/C/_p -> Functions/Completion/Core/_path_files + _sep_parts + Utility used for completing words with multiple separate parts, such as + `@' + _set_options + _unset_options + These can be used to complete only set or unset options. For this to + work, you'll have to un-comment a few lines in _main_complete. Base: You will almost certainly want these files, too, which handle standard tasks like completing files. However, you may want to edit them for @@ -127,3 +156,201 @@ Commands: _most_recent_file, bound to \C-xm Insert the name of the most recent file matching the pattern so far on the command line. + + +Configuration + +You can configure several aspects of the completion functions and the +overall completion behavior using the compconf shell function defined +in compinit. This function gets any number of arguments of the form +`key=value', where `key' is one of the keys described below and `value' +is any string. Most configuration keys are defined by the completer +functions. + +The completion widget function _main_complete currently understands +one configuration key: + + completer + This should be set to the names of the functions to generate the + matches separated by colons. E.g. with + + compconf completer=_complete:_correct:_approximate + + the code will first try normal completion. If that doesn't yield + any matches, correction is tried and if that doesn't yield + anything either, correcting completion is attempted. + +The keys understood by the _approximate completer function are: + + approximate_accept + This should be set to a number, specifying the maximum number + of errors that should be accepted. If the string also contains + a `n' or `N', the code will use the numeric argument as the + maximum number of errors if a numeric argument was given. If no + numeric argument was given, the number from the value of this + key will be used. E.g. with `compconf approximate_accept=2n' two + errors will be accepted, but if the user gives another number + with the numeric argument, this will be prefered. Also, with + `compconf approximate_accept=0n', normally no correction will be + tried, but if a numeric argument is given, automatic correction + will be used. On the other hand, if the string contains an `!' + and a `n' or `N', correction is not attempted if a numeric + argument is given. Once the number of errors to accept is + determined, the code will repeatedly try to generate matches by + allowing one error, two errors, and so on. Independent of the + number of errors the user wants to accept, the code will allow + only fewer errors than there are characters in the string from + the line. + + approximate_original + This value is used to determine if the original string should + be included in the list (and thus be presented to the user when + cycling through the corrections). If it is set to any non-empty + value, the original string will be offered. If it contains the + sub-string `last', the original string will appear as the last + string when cycling through the corrections, otherwise it will + appear as the first one (so that the command line does not + change immediately). Also, if the value contains the sub-string + `always', the original string will always be included, whereas + normally it is included only if more than one possible + correction was generated. + + approximate_prompt + This can be set to a string that should be printed before the + list of corrected strings when cycling through them. This string + may contain the control sequences `%n', `%B', etc. known from + the `-X' option of `compctl'. Also, the sequence `%e' will be + replaced by the number of errors accepted to generate the + corrected strings. + + approximate_insert + If this is set to a string starting with `unambig', the code + will try to insert a usable unambiguous string in the command + line instead of always cycling through the corrected strings. + If such a unambiguous string could be found, the original + string is not used, independent of the setting of + `approximate_original'. If no sensible string could be found, + one can cycle through the corrected strings as usual. + +If any of these keys is not set, but the the same key with the +prefix `correct' instead of `approximate' is set, that value will +be used. The forms beginning with `correct' are also used by the +_correct completer function, and this function uses only them, not +the ones starting with `approximate'. This allows one to give +different value to be used with correction and correcting +completion. For example, with: + + compconf completer=_complete:_correct:_approximate + compconf correct_accept='2n!' approximate_accept=3n + +correction will accept up to two errors. If a numeric argument is +given, correction will not be used, but correcting completion will +and it will accept as many errors as given by the numeric argument. +Without a numeric argument first correction and then correcting +completion will be tried, with the first one accepting two errors +and the second one accepting three errors. + +The _match completer function, which allows to give patterns on the +command line and complete all strings matching it from the set of +possible completions, understands the following key: + + match_original + If this is set to a `only', pattern matching will only be tried + with the string from the line. If it is set to any other non-empty + string, the original pattern will be tried first and if that yields + no completions, matching will be tried again with a `*' inserted + at the cursor position. If this key is not set or set to an empty + string, matching will only be attempted with the `*' inserted. + +The _expand completer allows one to do expansion on the word from the +line. Note that you may either want to use the configuration keys or +not use this completer at all if you also use the _match completer +because the _expand completer will otherwise expand patterns before +they are seen by the _match completer. +Configuration keys supported are: + + expand_substitute + If this is unset or set to the empty string, the code will first + try to expand all substitutions in the string (such as $(...) and + ${...}). If this is set to an non-empty string it should be + an expression usable inside a $[...] arithmetical expression. + In this case, expansion of substitutions will be done if the + expression evaluates to `1'. For example, with + + compconf expand_substitute='NUMERIC != 1' + + substitution will be performed only if given an explicit numeric + argument other than `1', as by typing ESC 2 TAB. + + expand_glob + If this is unset or set to an empty string, globbing will be + attempted on the word resulting from substitution or the + original string. The values accepted for this key are the same + as for expand_substitute. + + expand_menu + If this is unset or set to the empty string, the words resulting + from expansion (if any) will simply be inserted in the ommand line, + replacing the original string. However, if this key is set to an + non-empty string, the user can cycle through the expansion as in + a menucompletion. Unless the value contains the sub-string `only', + the user will still be offered all expansions at once as one of + the strings to insert in the command line. Also, if the value + contains the sub-string `last', the string with all expansion will + be offered first, whereas normally it is offered as the last string + to insert. Finally, if the value contains the sub-string `sort', + the expansions will be sorted alphabetically, normally they are + kept in the order the expansion produced them in. + + expand_original + If this is set to an non-empty string, the original string from the + line will be included in the list of strings the user can cycle + through as in a menucompletion. If the value contains the sub-string + `last', the original string will appear as the last string, with + other values it is inserted as the first one (so that the command + line does not change immediatly). + + expand_prompt + This may be set to a string that should be displayed before the + possible expansions. This is given to the -X option and thus may + contain the control sequences `%n', `%B', etc. Also, the sequence + `%o' in this string will be replaced by the original string. + +The _list completer allows one to delay the insertion of matches until +completion is attempted a second time without the word on the line +being changed. On the first attempt, only the list of matches will +be shown. Configuration keys understood are: + + list_condition + If this key is unset or set to the empty string, this completer + will delay the insertion of matches unconditionally. However, + if this value is set, it should be set to an expression usable + inside a $[...] arithmetical expression. In this case, delaying + will be done if the expression evaluates to `1'. + For example, with + + compconf list_condition='NUMERIC != 1' + + delaying will be done only if given an explicit numeric argument + other than `1'. + + list_word + To find out if only listing should be done, the code normally + compares the contents of the line with the contents the line + had at the time of the last invocation. If this key is set to + an non-empty string comparison is done using only the current + word. So if it is set, attempting completion on a word equal + to the one completion was called on the last time will not + delay the generation of matches. + +For more information about what the completers do, see the files +containing them (_complete, _correct, _approximate, _match, and +_expand in the Core directory). + +The _path_files function used to complete filenames has one +configuration key: + + path_expand + If this is set to a non-empty string, the partially typed path + from the line will be expanded as far as possible even if trailing + pathname components can not be completed. diff --git a/Completion/User/_dd b/Completion/User/_dd index 63ae40f50..6b07a382c 100644 --- a/Completion/User/_dd +++ b/Completion/User/_dd @@ -1,12 +1,12 @@ #defcomp dd -if [[ -iprefix conv= ]]; then +if compset -P 1 'conv\='; then # If there's a comma present, ignore up to the last one. The # test alone will have that effect. - [[ -string , ]] + compset -p '*,' compgen -S, -q \ -k '(ascii ebcdic ibm block unblock lcase ucase swab noerror sync)' -elif [[ -iprefix 'if=' || -iprefix 'of=' ]]; then +elif compset -P 1 '[io]f\='; then _files else compgen -S '=' -k '(if of ibs obs bs cbs skip files seek count conv)' diff --git a/Completion/User/_find b/Completion/User/_find index cb637fc26..13d1d797e 100644 --- a/Completion/User/_find +++ b/Completion/User/_find @@ -2,14 +2,14 @@ local prev="$words[CURRENT-1]" -if [[ -mbetween -(ok|exec) \\\; ]]; then +if compset -N '-(ok|exec)' '\;' then _normal -elif [[ -iprefix - ]]; then +elif compset -P 1 -; then compgen -s 'daystart {max,min,}depth follow noleaf version xdev \ {a,c,}newer {a,c,m}{min,time} empty false {fs,x,}type gid inum links \ {i,}{l,}name {no,}{user,group} path perm regex size true uid used \ exec {f,}print{f,0,} ok prune ls' -elif [[ -position 2 ]]; then +elif [[ CURRENT -eq 2 ]]; then local ret=1 compgen -g '. ..' && ret=0 diff --git a/Completion/User/_mh b/Completion/User/_mh index c6c018220..ab78468d8 100644 --- a/Completion/User/_mh +++ b/Completion/User/_mh @@ -13,7 +13,7 @@ local prev="$words[CURRENT-1]" # To be on the safe side, check this exists and if not, get it anyway. [[ -d $mymhdir ]] || mymhdir=$(mhpath +) -if [[ -iprefix - ]]; then +if compset -P 1 -; then # get list of options, which MH commands can generate themselves # awk is just too icky to use for this, sorry. send me one if # you come up with it. @@ -23,7 +23,7 @@ if [[ -iprefix - ]]; then print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n"; }') return -elif [[ -iprefix '+' || -iprefix '@' || "$prev" = -draftfolder ]]; then +elif compset -P 1 '[+@] || [ "$prev" = -draftfolder ]]; then # Complete folder names. local mhpath diff --git a/Completion/User/_stty b/Completion/User/_stty index d32d6bdff..73c860d54 100644 --- a/Completion/User/_stty +++ b/Completion/User/_stty @@ -5,7 +5,7 @@ if [[ "$words[CURRENT-1]" = \ then compadd -Q '^-' '^h' '^?' '^c' '^u' else - [[ -string '-' || -string '+' ]] + compset -P '[-+]' compadd rows columns intr quit erase kill eof eol \ eol2 start stop susp dsusp reprint discard werase lnext \ parenb parodd cs8 cstopb hupcl cread clocal parext \ -- cgit 1.4.1