mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-19 21:44:11 +01:00
198 lines
7.0 KiB
Plaintext
198 lines
7.0 KiB
Plaintext
#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
|