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