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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
# Initialisation for new style completion. This mainly contains some helper
# function and aliases. Everything else is split into different files in this
# directory that will automatically be made autoloaded (see the end of this
# file).
# The names of the files that will be considered for autoloading have to
# start with a underscores (like `_setopt).
# The first line of these files will be read and has to say what should be
# done with its contents:
#
# `#defcomp <names ...>'
# if the first line looks like this, the file is
# autoloaded as a function and that function will
# be called to generate the matches when completing
# for one of the commands whose <name> is given
#
# `#defpatcomp <pattern>'
# this defines a function that should be called to generate
# matches for commands whose name matches <pattern>; note
# that only one pattern may be given
#
# `#defkeycomp <style> [ <key-sequence> ... ]
# this is used to bind special completions to all the given
# <key-sequence>(s). The <style> is the name of one of the built-in
# completion widgets (complete-word, delete-char-or-list,
# expand-or-complete, expand-or-complete-prefix, list-choices,
# menu-complete, menu-expand-or-complete, or reverse-menu-complete).
# This creates a widget behaving like <style> so that the
# completions are chosen as given in the the rest of the file,
# rather than by the context. The widget has the same name as
# the autoload file and can be bound using bindkey in the normal way.
#
# `#autoload'
# this is for helper functions that are not used to
# generate matches, but should automatically be loaded
# when they are called
#
# Note that no white space is allowed between the `#' and the rest of
# the string.
#
# See the file `dump' for how to speed up initialiation.
# If we got the `-d'-flag, we will automatically dump the new state (at
# the end).
if [[ "$1" = -d ]]; then
_i_autodump=1
else
_i_autodump=0
fi
# The associative array containing the definitions for the commands.
# Definitions for patterns will be stored in the normal array `patcomps'.
typeset -A comps
# This may be used to define completion handlers. The first argument is the
# name of the function containing the definition, the other arguments are the
# command names for which this definition should be used.
# With only one argument the function/variable-name _$1 is used.
# If given the `-a' option, the function is defined as being autoloaded.
defcomp() {
local name
if [[ "$1" = -a ]]; then
shift
autol=yes
fi
if [[ $# -eq 1 ]]; then
comps[$1]="_$1"
[[ -z "$autol" ]] || autoload "_$1"
else
name="$1"
shift
for i; do
comps[$i]="$name"
done
[[ -z "$autol" ]] || autoload "$name"
fi
}
# Almost like `defcomp', but this always gets two arguments: the name of a
# function describing what should be completed and the pattern that will be
# compared to the command names for which completion is attempted.
defpatcomp() {
if [[ "$1" = -a ]]; then
shift
autoload "$1"
fi
if (( $+patcomps )) then
patcomps=("$patcomps[@]" "$2 $1")
else
patcomps=("$2 $1")
fi
}
# This is used to define completion handlers directly bound to keys. The
# first argument is as for `defcomp', giving the handler. The second
# argument is the name of one of the built-in completion widgets. Any
# remaining arguments are used as key sequences to bind the widget.
# Typing that key sequence will complete the word the cursor is on
# according to the completion definition given and will behave as if the
# built-in completion widget was used.
defkeycomp() {
local name
if [[ "$1" = -a ]]; then
shift
autoload "$1"
fi
name="$1"
shift
zle -C "$name" "$1" "$name"
shift
while (( $# )); do
bindkey "$1" "$name"
shift
done
}
# This searches $1 in the array for normal completions and calls the result.
_compalso() {
local tmp
tmp="$comps[$1]"
[[ -z "$tmp" ]] || "$tmp" "$@"
}
# These can be used to easily save and restore the state of the special
# variables used by the completion code.
alias _compsave='local _oprefix$_level _oiprefix$_level _oargv$_level _ocurrent$_level _ocommand$_level _ocontext$_level; \
eval "_oprefix${_level}=\"\$PREFIX\"; \
_oiprefix${_level}=\"\$IPREFIX\"; \
_oargv${_level}=( \"\$@\" ); \
_ocurrent${_level}=\"\$CURRENT\"; \
_ocommand${_level}=\"\$COMMAND\"; \
_ocontext${_level}=\"\$CONTEXT\""'
alias _compreset='eval "PREFIX=\"\$_oprefix${_level}\"; \
IPREFIX=\"\$_oiprefix${_level}\"; \
argv=( \"\$_oargv${_level}[@]\" ); \
CURRENT=\"\$_ocur${_level}\"; \
COMMAND=\"\$_ocommand${_level}\"; \
CONTEXT=\"\$_ocontext${_level}\""'
# These can be used to build tests that modify the special parameters
# without having to reset them by hand.
alias _if='(( $+_level )) || local _level=0; (( _level++ )); _compsave; if'
alias _elif='_compreset; elif'
alias _else='_compreset; else'
alias _fi='_compreset; fi; unset _oprefix$_level _oiprefix$_level _oargv$_level _ocurrent$_level _ocommand$_level _ocontext$_level; (( _level-- ))'
# Now we automatically make the definition files autoloaded.
# First we get the name of a dump file if this will be used.
: ${COMPDUMP:=$0.dump}
_i_files=( ${^~fpath}/_*~*~ )
_i_initname=$0
_i_done=''
# If we have a dump file, load it.
if [[ -f "$COMPDUMP" ]]; then
read -rA _i_line < "$COMPDUMP"
if [[ _i_autodump -eq 1 || $_i_line[2] -eq $#_i_files ]]; then
builtin . "$COMPDUMP"
_i_done=yes
fi
unset _i_line
fi
if [[ -z "$_i_done" ]]; then
for _i_dir in $fpath; do
[[ $_i_dir = . ]] && continue
for _i_file in $_i_dir/_*~*~(N); do
read -rA _i_line < $_i_file
_i_tag=$_i_line[1]
shift _i_line
if [[ $_i_tag = '#defcomp' ]]; then
defcomp -a ${_i_file:t} "${_i_line[@]}"
elif [[ $_i_tag = '#defpatcomp' ]]; then
defpatcomp -a "${_i_file:t}" "${_i_line[@]}"
elif [[ $_i_tag = '#defkeycomp' ]]; then
defkeycomp -a "${_i_file:t}" "${_i_line[@]}"
elif [[ $_i_tag = '#autoload' ]]; then
autoload ${_i_file:t}
fi
done
done
bindkey |
while read -rA _i_line; do
if [[ "$_i_line[2]" = complete-word ||
"$_i_line[2]" = delete-char-or-list ||
"$_i_line[2]" = expand-or-complete ||
"$_i_line[2]" = expand-or-complete-prefix ||
"$_i_line[2]" = list-choices ||
"$_i_line[2]" = menu-complete ||
"$_i_line[2]" = menu-expand-or-complete ||
"$_i_line[2]" = reverse-menu-complete ]]; then
zle -C _complete_$_i_line[2] $_i_line[2] _main_complete
bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2]
fi
done
unset _i_dir _i_line _i_file _i_tag
# if autodumping was requested, do it now.
(( _i_autodump )) && builtin . ${_i_initname:h}/dump
fi
unset _i_files _i_initname _i_done _i_autodump
|