From e74702b467171dbdafb56dfe354794a212e020d9 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 15 Apr 1999 18:05:38 +0000 Subject: Initial revision --- Completion/Core/_approximate | 197 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 Completion/Core/_approximate (limited to 'Completion/Core/_approximate') 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 -- cgit 1.4.1