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