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
|
#compdef -k complete-word \C-x\C-r
# This allows an on-the-fly choice of completions. On typing the key
# sequence given above, you will be prompted for a string of arguments. If
# this string begins with `_', it will be taken as the name of a function to
# evaluate to generate the completions; unambiguous strings in the function
# name are automatically completed.
#
# Else it is taken to be a set of arguments for compgen to generate a list
# of choices. The possibilities are the same as the flags for generating
# completions given in the zshcompctl manual page. Note the arguments are
# verbatim: include minus signs, spaces, quotes, etc.
#
# On subsequent calls, the same completion will be re-performed. To
# force a new type of completion to be read, supply a numeric argument.
#
# For example,
# % bindkey | grep rever<C-xC-r>
# Completion: -b<RET>
# % bindkey | grep reverse-menu-complete _
#
# Global variables used:
# _read_comp Last completion string read from user
emulate -L zsh
setopt extendedglob nobadpattern # xtrace promptsubst
# local PS4='%N:%i:$((#key))> '
# Took me ages to work this out. If we're not on the first global
# matcher specification, we mustn't do any I/O.
if [[ compstate[matcher] -gt 1 && -z $_read_comp ]]; then
return 1
fi
if [[ compstate[matcher] -gt 1 ||
( ${+NUMERIC} = 0 && -n $_read_comp ) ]]; then
if [[ $_read_comp = _* ]]; then
eval $_read_comp
else
eval "compgen $_read_comp"
fi
return
fi
_read_comp=
local key search str str2 newch funcs funcs2 exact msg list
integer pos
msg="Completion: "
zle -R $msg
if ! read -k key; then
zle -cR ''
return 1
fi
while [[ '#key' -ne 10 && '#key' -ne 13 ]]; do
if [[ '#key' -eq 0 && '#key' -eq 3 || '#key' -eq 7 ]]; then
zle -cR ''
return 1
fi
if [[ ( '#key' -eq 8 || '#key' -eq 127 ) && -n $str ]]; then
# delete character
str="$str[1,-2]"
exact=
list=()
elif [[ '#key' -eq 21 ]]; then
# ^U: delete line
str=
exact=
list=()
elif [[ '#key' -eq 4 && $str = _[^\ ]# && $str != *' '* ]]; then
# ^D: list completions
list=(${$(whence -m "$str*" 2>/dev/null)%: function})
elif [[ ( -n $exact && $key != ' ' ) || '#key & 127' -lt 32 ]]; then
# If we've got an exact function, only allow a space after it.
# Don't try to insert non-printing characters.
if [[ -n $ZBEEP ]]; then
print -nb $ZBEEP
elif [[ -o beep ]]; then
print -n "\a"
fi
list=()
else
str="$str$key"
if [[ $str = _[^\ ]# ]]; then
# Rudimentary completion for function names.
# Allow arguments, i.e. don't do this after we've got a space.
funcs=(${$(whence -m "$str*" 2>/dev/null)%: function})
if [[ -o autolist && $#str -gt 1 ]]; then
list=($funcs)
else
list=()
fi
if (( $#funcs == 1 )); then
# Exact match; prompt the user for a newline to confirm
str=$funcs[1]
exact=" (Confirm)"
elif (( $#funcs == 0 )); then
# We can't call zle beep, because this isn't a zle widget.
if [[ -n $ZBEEP ]]; then
print -nb $ZBEEP
elif [[ -o beep ]]; then
print -n "\a"
fi
str="$str[1,-2]"
list=()
else
# Add characters to the string until a name doesn't
# match any more, then backtrack one character to get
# the longest unambiguous match.
str2=$str
pos=$#str2
while true; do
(( pos++ ))
newch=${funcs[1][pos]}
[[ -z $newch ]] && break
str2=$str2$newch
funcs2=(${funcs##$str2*})
(( $#funcs2 )) && break
str=$str2
done
fi
else
exact=
fi
fi
if (( $#list )); then
zle -R "$msg$str$exact" $list
else
zle -cR "$msg$str$exact"
fi
if ! read -k key; then
zle -cR ''
return 1
fi
done
if [[ -z $str ]]; then
# string must be non-zero
return 1
elif [[ $str = _* ]] && ! whence ${str%% *} >& /dev/null; then
# a function must be known to the shell
return 1
else
# remember the string for re-use
_read_comp=$str
fi
zle -cR ''
if [[ $str = _* ]]; then
eval $str
else
eval "compgen $str"
fi
|