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 oils-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/temp-binding.test.sh
416 spec/testdata
417 spec/tilde.test.sh
418 spec/toysh-posix.test.sh
419 spec/toysh.test.sh
420 spec/type-compat.test.sh
421 ## END
422
423 #### compgen doesn't respect -X for user-defined functions
424 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
425 # differently!
426 case $SH in
427 *bash|*osh)
428 $SH --rcfile /dev/null -i -c '
429 shopt -s extglob
430 fun() {
431 COMPREPLY=(one two three bin)
432 }
433 compgen -X "@(two|bin)" -F fun
434 echo --
435 compgen -X "!@(two|bin)" -F fun
436 '
437 esac
438 ## STDOUT:
439 one
440 three
441 --
442 two
443 bin
444 ## END
445
446 #### compgen -W words -X filter
447 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
448 # differently!
449 case $SH in
450 *bash|*osh)
451 $SH --rcfile /dev/null -i -c 'shopt -s extglob; compgen -X "@(two|bin)" -W "one two three bin"'
452 esac
453 ## STDOUT:
454 one
455 three
456 ## END
457
458 #### compgen -f -X filter -- $cur
459 cd $TMP
460 touch spam.py spam.sh
461 compgen -f -- sp | sort
462 echo --
463 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
464 # differently!
465 case $SH in
466 *bash|*osh)
467 $SH --rcfile /dev/null -i -c 'shopt -s extglob; compgen -f -X "!*.@(py)" -- sp'
468 esac
469 ## STDOUT:
470 spam.py
471 spam.sh
472 --
473 spam.py
474 ## END
475
476 #### compgen doesn't need shell quoting
477 # There is an obsolete comment in bash_completion that claims the opposite.
478 cd $TMP
479 touch 'foo bar'
480 touch "foo'bar"
481 compgen -f "foo b"
482 compgen -f "foo'"
483 ## STDOUT:
484 foo bar
485 foo'bar
486 ## END
487
488 #### compgen -W 'one two three'
489 cd $REPO_ROOT
490 compgen -W 'one two three'
491 echo --
492 compgen -W 'v1 v2 three' -A directory v
493 echo --
494 compgen -A directory -W 'v1 v2 three' v # order doesn't matter
495 ## STDOUT:
496 one
497 two
498 three
499 --
500 vendor
501 v1
502 v2
503 --
504 vendor
505 v1
506 v2
507 ## END
508
509 #### compgen -W evaluates code in $()
510 IFS=':%'
511 compgen -W '$(echo "spam:eggs%ham cheese")'
512 ## STDOUT:
513 spam
514 eggs
515 ham cheese
516 ## END
517
518 #### compgen -W uses IFS, and delimiters are escaped with \
519 IFS=':%'
520 compgen -W 'spam:eggs%ham cheese\:colon'
521 ## STDOUT:
522 spam
523 eggs
524 ham cheese:colon
525 ## END
526
527 #### Parse errors for compgen -W and complete -W
528 # bash doesn't detect as many errors because it lacks static parsing.
529 compgen -W '${'
530 echo status=$?
531 complete -W '${' foo
532 echo status=$?
533 ## STDOUT:
534 status=2
535 status=2
536 ## END
537 ## BUG bash STDOUT:
538 status=1
539 status=0
540 ## END
541
542 #### Runtime errors for compgen -W
543 compgen -W 'foo $(( 1 / 0 )) bar'
544 echo status=$?
545 ## STDOUT:
546 status=1
547 ## END
548
549 #### Runtime errors for compgen -F func
550 _foo() {
551 COMPREPLY=( foo bar )
552 COMPREPLY+=( $(( 1 / 0 )) ) # FATAL, but we still have candidates
553 }
554 compgen -F _foo foo
555 echo status=$?
556 ## STDOUT:
557 status=1
558 ## END
559
560 #### compgen -W '' cmd is not a usage error
561 # Bug fix due to '' being falsey in Python
562 compgen -W '' -- foo
563 echo status=$?
564 ## stdout: status=1
565
566 #### compgen -A builtin
567 compgen -A builtin g
568 ## STDOUT:
569 getopts
570 ## END
571
572 #### complete -C vs. compgen -C
573
574 f() { echo foo; echo bar; }
575
576 # Bash prints warnings: -C option may not work as you expect
577 # -F option may not work as you expect
578 #
579 # https://unix.stackexchange.com/questions/117987/compgen-warning-c-option-not-working-as-i-expected
580 #
581 # compexport fixes this problem, because it invokves ShellFuncAction, whcih
582 # sets COMP_ARGV, COMP_WORDS, etc.
583 #
584 # Should we print a warning?
585
586 compgen -C f b
587 echo compgen=$?
588
589 complete -C f b
590 echo complete=$?
591
592 ## STDOUT:
593 foo
594 bar
595 compgen=0
596 complete=0
597 ## END
598
599
600 #### compadjust with empty COMP_ARGV
601 case $SH in bash) exit ;; esac
602
603 COMP_ARGV=()
604 compadjust words
605 argv.py "${words[@]}"
606
607 ## STDOUT:
608 []
609 ## END
610
611 ## N-I bash STDOUT:
612 ## END
613
614
615 #### compadjust with sparse COMP_ARGV
616 case $SH in bash) exit ;; esac
617
618 COMP_ARGV=({0..9})
619 unset -v 'COMP_ARGV['{1,3,4,6,7,8}']'
620 compadjust words
621 argv.py "${words[@]}"
622
623 ## STDOUT:
624 ['0', '2', '5', '9']
625 ## END
626
627 ## N-I bash STDOUT:
628 ## END
629
630
631 #### compgen -F with scalar COMPREPLY
632
633 _comp_cmd_test() {
634 unset -v COMPREPLY
635 COMPREPLY=hello
636 }
637 compgen -F _comp_cmd_test
638
639 ## STDOUT:
640 hello
641 ## END