about summary refs log tree commit diff
path: root/Completion/Core/_approximate
blob: 910742feebe55f6b77ad0c855464d5e3f53b4820 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#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

# Probably set initial context.

[[ -z "$curcontext" ]] && curcontext=':approximate'

oldcontext="$curcontext"

_style -s '' accept cfgacc
_style -s '' original cfgorig
_style -s '' prompt cfgps
_style -s '' insert cfgins

# Get the number of errors to accept.

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

  [[ "$cfgacc" = *\!* ]] && 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