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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
# Autoload this function, run `zle -N <func-name>' and bind <func-name>
# to a key.
# This allows incremental completion of a word. After starting this
# command, a list of completion choices can be shown after every character
# you type, which you can delete with ^h or DEL. RET will accept the
# completion so far. You can hit TAB to do normal completion, ^g to
# abort back to the state when you started, and ^d to list the matches.
#
# This works best with the new function based completion system.
#
# Configuration keys:
#
# incremental_prompt
# Prompt to show in status line during icompletion. The sequence `%u'
# is replaced by the unambiguous part of all matches if there is any
# and it is different from the word on the line. A `%s' is replaced
# with `-no match-', `-no prefix-', or an empty string if there is
# no completion matching the word on the line, if the matches have
# no common prefix different from the word on the line or if there is
# such a common prefix, respectively. The sequence `%c' is replaced
# by the name of the completer function that generated the matches
# (without the leading underscore). Finally, `%n' is replaced by the
# number of matches generated, `%a' is replaced by an empty string
# if the matches are in the normal set (i.e. the one without file names
# with one of the suffixes from `fignore') and with ` -alt-' if the
# matches are in the alternate set, and if the `incremental_list' key
# (see below) is set, `%l' is replaced by `...' if the list of matches
# is too long to fit on the screen and with an empty string otherwise.
#
# incremental_stop
# Pattern matching keys which will cause icompletion to stop and the
# key to be re-executed.
#
# incremental_break
# Pattern matching keys which will cause icompletion to stop and the
# key to be discarded.
#
# incremental_completer
# Set of completers, like the `completer' key for normal completion.
#
# incremental_list
# If set to a non-empty string, the matches will be listed on every
# key-press.
# The main widget function.
incremental-complete-word() {
emulate -L zsh
unsetopt autolist menucomplete automenu # doesn't work well
local key lbuf="$LBUFFER" rbuf="$RBUFFER" pmpt word
local lastl lastr wid twid num alt post toolong
[[ -n "$compconfig[incremental_completer]" ]] &&
set ${(s.:.)compconfig[incremental_completer]}
pmpt="${compconfig[incremental_prompt]-incremental (%c): %u%s %l}"
if [[ -n "$compconfig[incremental_list]" ]]; then
wid=list-choices
post=( icw-list-helper )
else
wid=complete-word
post=()
fi
comppostfuncs=( "$post[@]" )
zle $wid "$@"
LBUFFER="$lbuf"
RBUFFER="$rbuf"
num=$_lastcomp[nmatches]
if (( ! num )); then
num="${_lastcomp[alternate_nmatches]}"
alt=' -alt-'
fi
if (( ! num )); then
word=''
state='-no match-'
elif [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
word=''
state='-no prefix-'
else
word="${_lastcomp[unambiguous]}"
state=''
fi
zle -R "${${${${${${pmpt//\\%u/$word}//\\%s/$state}//\\%c/${_lastcomp[completer][2,-1]}}//\\%n/$num}//\\%a/$alt}//\\%l/$toolong}"
read -k key
while [[ '#key' -ne '#\\r' && '#key' -ne '#\\n' &&
'#key' -ne '#\\C-g' ]]; do
twid=$wid
if [[ "$key" = ${~compconfig[incremental_stop]} ]]; then
zle -U "$key"
return
elif [[ "$key" = ${~compconfig[incremental_break]} ]]; then
return
elif [[ '#key' -eq '#\\C-h' || '#key' -eq '#\\C-?' ]]; then
[[ $#LBUFFER -gt $#l ]] && LBUFFER="$LBUFFER[1,-2]"
elif [[ '#key' -eq '#\\t' ]]; then
zle complete-word "$@"
lbuf="$LBUFFER"
rbuf="$RBUFFER"
elif [[ '#key' -eq '#\\C-d' ]]; then
twid=list-choices
else
LBUFFER="$LBUFFER$key"
fi
lastl="$LBUFFER"
lastr="$RBUFFER"
[[ "$twid" = "$wid" ]] && comppostfuncs=( "$post[@]" )
toolong=''
zle $twid "$@"
LBUFFER="$lastl"
RBUFFER="$lastr"
num=$_lastcomp[nmatches]
if (( ! num )); then
num="${_lastcomp[alternate_nmatches]}"
alt=' -alt-'
else
alt=''
fi
if (( ! num )); then
word=''
state='-no match-'
elif [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
word=''
state='-no prefix-'
else
word="${_lastcomp[unambiguous]}"
state=''
fi
zle -R "${${${${${${pmpt//\\%u/$word}//\\%s/$state}//\\%c/${_lastcomp[completer][2,-1]}}//\\%n/$num}//\\%a/$alt}//\\%l/$toolong}"
read -k key
done
if [[ '#key' -eq '#\\C-g' ]]; then
LBUFFER="$lbuf"
RBUFFER="$rbuf"
fi
zle -Rc
}
# Helper function used as a completion post-function used to make sure that
# the list of matches in only shown if it fits on the screen.
icw-list-helper() {
# +1 for the status line we will add...
if [[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]]; then
compstate[list]='list explanations'
if [[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]]; then
compstate[list]=''
compstate[force_list]=yes
fi
toolong='...'
fi
}
incremental-complete-word "$@"
|