1
2 #### -A function prints functions
3 add () { expr 4 + 4; }
4 div () { expr 6 / 2; }
5 ek () { echo hello; }
6 __ec () { echo hi; }
7 _ab () { expr 10 % 3; }
8 compgen -A function
9 echo --
10 compgen -A function _
11 ## status: 0
12 ## STDOUT:
13 __ec
14 _ab
15 add
16 div
17 ek
18 --
19 __ec
20 _ab
21 ## END
22
23 #### Invalid syntax
24 compgen -A foo
25 echo status=$?
26 ## stdout: status=2
27
28 #### how compgen calls completion functions
29 foo_complete() {
30 # first, cur, prev
31 argv.py argv "$@"
32 argv.py COMP_WORDS "${COMP_WORDS[@]}"
33 argv.py COMP_CWORD "${COMP_CWORD}"
34 argv.py COMP_LINE "${COMP_LINE}"
35 argv.py COMP_POINT "${COMP_POINT}"
36 #return 124
37 COMPREPLY=(one two three)
38 }
39 compgen -F foo_complete foo a b c
40 ## STDOUT:
41 ['argv', 'compgen', 'foo', '']
42 ['COMP_WORDS']
43 ['COMP_CWORD', '-1']
44 ['COMP_LINE', '']
45 ['COMP_POINT', '0']
46 one
47 two
48 three
49 ## END
50
51 #### complete -o -F (git)
52 foo() { echo foo; }
53 wrapper=foo
54 complete -o default -o nospace -F $wrapper git
55 ## status: 0
56
57 #### compopt with invalid syntax
58 compopt -o invalid
59 echo status=$?
60 ## stdout: status=2
61
62 #### compopt fails when not in completion function
63 # NOTE: Have to be executing a completion function
64 compopt -o filenames +o nospace
65 ## status: 1
66
67 #### compgen -f on invalid dir
68 compgen -f /non-existing-dir/
69 ## status: 1
70 ## stdout-json: ""
71
72 #### compgen -f
73 mkdir -p $TMP/compgen
74 touch $TMP/compgen/{one,two,three}
75 cd $TMP/compgen
76 compgen -f | sort
77 echo --
78 compgen -f t | sort
79 ## STDOUT:
80 one
81 three
82 two
83 --
84 three
85 two
86 ## END
87
88 #### compgen -v with local vars
89 v1_global=0
90 f() {
91 local v2_local=0
92 compgen -v v
93 }
94 f
95 ## STDOUT:
96 v1_global
97 v2_local
98 ## END
99
100 #### compgen -v on unknown var
101 compgen -v __nonexistent__
102 ## status: 1
103 ## stdout-json: ""
104
105 #### compgen -v P
106 cd > /dev/null # for some reason in bash, this makes PIPESTATUS appear!
107 compgen -v P | grep -E '^PATH|PWD' | sort
108 ## STDOUT:
109 PATH
110 PWD
111 ## END
112
113 #### compgen with actions: function / variable / file
114 mkdir -p $TMP/compgen2
115 touch $TMP/compgen2/{PA,Q}_FILE
116 cd $TMP/compgen2 # depends on previous test above!
117 PA_FUNC() { echo P; }
118 Q_FUNC() { echo Q; }
119 compgen -A function -A variable -A file PA
120 ## STDOUT:
121 PA_FUNC
122 PATH
123 PA_FILE
124 ## END
125
126 #### compgen with actions: alias, setopt
127 alias v_alias='ls'
128 alias v_alias2='ls'
129 alias a1='ls'
130 compgen -A alias -A setopt v
131 ## STDOUT:
132 v_alias
133 v_alias2
134 verbose
135 vi
136 ## END
137
138 #### compgen with actions: shopt
139 compgen -A shopt -P [ -S ] nu
140 ## STDOUT:
141 [nullglob]
142 ## END
143
144 #### compgen with action and suffix: helptopic
145 compgen -A helptopic -S ___ fa
146 ## STDOUT:
147 false___
148 ## END
149
150 #### compgen -A directory
151 # omit portable-files.mk
152 cd $REPO_ROOT
153 compgen -A directory p | sort
154 ## STDOUT:
155 pgen2
156 pylib
157 py-yajl
158 ## END
159
160 #### compgen -A file
161 cd $REPO_ROOT
162 compgen -A file b | sort
163 ## STDOUT:
164 benchmarks
165 bin
166 build
167 ## END
168
169 #### compgen -A user
170 # no assertion because this isn't hermetic
171 compgen -A user
172 ## status: 0
173
174 #### compgen -A command completes external commands
175 # NOTE: this test isn't hermetic
176 compgen -A command xarg | uniq
177 echo status=$?
178 ## STDOUT:
179 xargs
180 status=0
181 ## END
182
183 #### compgen -A command completes functions and aliases
184 my_func() { echo ; }
185 my_func2() { echo ; }
186 alias my_alias=foo
187 compgen -A command my_
188 echo status=$?
189 ## STDOUT:
190 my_alias
191 my_func
192 my_func2
193 status=0
194 ## END
195
196 #### compgen -A command completes builtins and keywords
197 compgen -A command eva
198 echo status=$?
199 compgen -A command whil
200 echo status=$?
201 ## STDOUT:
202 eval
203 status=0
204 while
205 status=0
206 ## END
207
208 #### complete with nonexistent function
209 complete -F invalidZZ -D
210 echo status=$?
211 ## stdout: status=2
212 ## BUG bash stdout: status=0
213
214 #### complete with no action
215 complete foo
216 echo status=$?
217 ## stdout: status=2
218 ## BUG bash stdout: status=0
219
220 #### -o filenames and -o nospace have no effect with compgen
221 # they are POSTPROCESSING.
222 compgen -o filenames -o nospace -W 'bin build'
223 ## STDOUT:
224 bin
225 build
226 ## END
227
228 #### -o plusdirs and -o dirnames with compgen
229 cd $REPO_ROOT
230 compgen -o plusdirs -W 'a b1 b2' b | sort
231 echo ---
232 compgen -o dirnames b | sort
233 ## STDOUT:
234 b1
235 b2
236 benchmarks
237 bin
238 build
239 ---
240 benchmarks
241 bin
242 build
243 ## END
244
245 #### compgen -o default completes files and dirs
246 cd $REPO_ROOT
247 compgen -o default spec/t | sort
248 ## STDOUT:
249 spec/tea-func.test.sh
250 spec/testdata
251 spec/tilde.test.sh
252 spec/toysh-posix.test.sh
253 spec/toysh.test.sh
254 spec/type-compat.test.sh
255 ## END
256
257 #### compgen doesn't respect -X for user-defined functions
258 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
259 # differently!
260 case $SH in
261 *bash|*osh)
262 $SH --rcfile /dev/null -i -c '
263 shopt -s extglob
264 fun() {
265 COMPREPLY=(one two three bin)
266 }
267 compgen -X "@(two|bin)" -F fun
268 echo --
269 compgen -X "!@(two|bin)" -F fun
270 '
271 esac
272 ## STDOUT:
273 one
274 three
275 --
276 two
277 bin
278 ## END
279
280 #### compgen -W words -X filter
281 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
282 # differently!
283 case $SH in
284 *bash|*osh)
285 $SH --rcfile /dev/null -i -c 'shopt -s extglob; compgen -X "@(two|bin)" -W "one two three bin"'
286 esac
287 ## STDOUT:
288 one
289 three
290 ## END
291
292 #### compgen -f -X filter -- $cur
293 cd $TMP
294 touch spam.py spam.sh
295 compgen -f -- sp | sort
296 echo --
297 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
298 # differently!
299 case $SH in
300 *bash|*osh)
301 $SH --rcfile /dev/null -i -c 'shopt -s extglob; compgen -f -X "!*.@(py)" -- sp'
302 esac
303 ## STDOUT:
304 spam.py
305 spam.sh
306 --
307 spam.py
308 ## END
309
310 #### compgen doesn't need shell quoting
311 # There is an obsolete comment in bash_completion that claims the opposite.
312 cd $TMP
313 touch 'foo bar'
314 touch "foo'bar"
315 compgen -f "foo b"
316 compgen -f "foo'"
317 ## STDOUT:
318 foo bar
319 foo'bar
320 ## END
321
322 #### compgen -W 'one two three'
323 cd $REPO_ROOT
324 compgen -W 'one two three'
325 echo --
326 compgen -W 'w1 w2 three' -A directory w
327 echo --
328 compgen -A directory -W 'w1 w2 three' w # order doesn't matter
329 ## STDOUT:
330 one
331 two
332 three
333 --
334 web
335 w1
336 w2
337 --
338 web
339 w1
340 w2
341 ## END
342
343 #### compgen -W evaluates code in $()
344 IFS=':%'
345 compgen -W '$(echo "spam:eggs%ham cheese")'
346 ## STDOUT:
347 spam
348 eggs
349 ham cheese
350 ## END
351
352 #### compgen -W uses IFS, and delimiters are escaped with \
353 IFS=':%'
354 compgen -W 'spam:eggs%ham cheese\:colon'
355 ## STDOUT:
356 spam
357 eggs
358 ham cheese:colon
359 ## END
360
361 #### Parse errors for compgen -W and complete -W
362 # bash doesn't detect as many errors because it lacks static parsing.
363 compgen -W '${'
364 echo status=$?
365 complete -W '${' foo
366 echo status=$?
367 ## STDOUT:
368 status=2
369 status=2
370 ## END
371 ## BUG bash STDOUT:
372 status=1
373 status=0
374 ## END
375
376 #### Runtime errors for compgen -W
377 compgen -W 'foo $(( 1 / 0 )) bar'
378 echo status=$?
379 ## STDOUT:
380 status=1
381 ## END
382
383 #### Runtime errors for compgen -F func
384 _foo() {
385 COMPREPLY=( foo bar )
386 COMPREPLY+=( $(( 1 / 0 )) ) # FATAL, but we still have candidates
387 }
388 compgen -F _foo foo
389 echo status=$?
390 ## STDOUT:
391 status=1
392 ## END
393
394 #### compgen -W '' cmd is not a usage error
395 # Bug fix due to '' being falsey in Python
396 compgen -W '' -- foo
397 echo status=$?
398 ## stdout: status=1