#autoload

# This code will try to correct the string on the line based on the
# 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.

local _comp_correct _correct_prompt comax
local cfgacc cfgorig cfgps cfgins
local curcontext="${curcontext}" oldcontext

# Only if all global matchers have 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

[[ "$curcontext" != *:correct ]] && curcontext="${curcontext}:approximate"

oldcontext="$curcontext"

_style -s '' max-errors cfgacc
_style -s '' original cfgorig
_style -s '' prompt cfgps
_style -s '' insert cfgins

# Get the number of errors to accept.

if [[ "$cfgacc" = *numeric* && ${NUMERIC:-1} -ne 1 ]]; then
  # Stop if we also have a `!'.

  [[ "$cfgacc" = *not-numeric* ]] && return 1

  # Prefer the numeric argument if that has a sensible value.

  comax="${NUMERIC:-1}"
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
}

# 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}"

[[ -z "$compstate[pattern_match]" ]] && compstate[pattern_match]='*'

while [[ _comp_correct -le comax ]]; do
  curcontext="${oldcontext}:$_comp_correct"

  if _complete; then
    if [[ "$cfgins" = unambig* &&
          "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then
      compstate[pattern_insert]=unambiguous
    elif [[ compstate[nmatches] -gt 1 || "$cfgorig" = *always* ]]; then
      local expl format

      if [[ "$cfgorig" = *show* ]]; then
        if _style -s descriptions format format; then
	  expl=(-X "${format//\\%d/original}")
        else
	  expl=()
        fi
      else
        expl=(-n)
      fi
      if [[ "$cfgorig" = *last* ]]; then
        builtin compadd "$expl[@]" -U -V _correct_original -Q - "$PREFIX$SUFFIX"
      elif [[ -n "$cfgorig" ]]; then
	builtin compadd "$expl[@]" -U -Q - "$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

    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

return 1
