1 ## oils_failures_allowed: 3
2 ## oils_cpp_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 -e with global/local exported vars
166 export v1_global=0
167 f() {
168 local v2_local=0
169 export v2_local
170 compgen -e v
171 }
172 f
173 ## STDOUT:
174 v1_global
175 v2_local
176 ## END
177
178 #### compgen -e on known, but unexported, var
179 unexported=0
180 compgen -e unexported
181 ## status: 1
182 ## stdout-json: ""
183
184 #### compgen -e on unknown var
185 compgen -e __nonexistent__
186 ## status: 1
187 ## stdout-json: ""
188
189 #### compgen -e P
190 cd > /dev/null # for some reason in bash, this makes PIPESTATUS appear!
191 compgen -e P | grep -E '^PATH|PWD' | sort
192 ## STDOUT:
193 PATH
194 PWD
195 ## END
196
197 #### compgen with actions: function / variable / file
198 mkdir -p $TMP/compgen2
199 touch $TMP/compgen2/{PA,Q}_FILE
200 cd $TMP/compgen2 # depends on previous test above!
201 PA_FUNC() { echo P; }
202 Q_FUNC() { echo Q; }
203 compgen -A function -A variable -A file PA
204 ## STDOUT:
205 PA_FUNC
206 PATH
207 PA_FILE
208 ## END
209
210 #### compgen with actions: alias, setopt
211 alias v_alias='ls'
212 alias v_alias2='ls'
213 alias a1='ls'
214 compgen -A alias -A setopt v
215 ## STDOUT:
216 v_alias
217 v_alias2
218 verbose
219 vi
220 ## END
221
222 #### compgen with actions: shopt
223 compgen -A shopt -P [ -S ] nu
224 ## STDOUT:
225 [nullglob]
226 ## END
227
228 #### compgen with action and suffix: helptopic
229 compgen -A helptopic -S ___ fal
230 ## STDOUT:
231 false___
232 ## END
233
234 #### compgen -A directory
235 cd $REPO_ROOT
236 compgen -A directory c | sort
237 ## STDOUT:
238 client
239 core
240 cpp
241 ## END
242
243 #### compgen -A file
244 cd $REPO_ROOT
245 compgen -A file o | sort
246 ## STDOUT:
247 oils-version.txt
248 opy
249 osh
250 ## END
251
252 #### compgen -A user
253 # no assertion because this isn't hermetic
254 compgen -A user
255 ## status: 0
256
257 #### compgen -A command completes external commands
258 # NOTE: this test isn't hermetic
259 compgen -A command xarg | uniq
260 echo status=$?
261 ## STDOUT:
262 xargs
263 status=0
264 ## END
265
266 #### compgen -A command completes functions and aliases
267 our_func() { echo ; }
268 our_func2() { echo ; }
269 alias our_alias=foo
270
271 compgen -A command our_
272 echo status=$?
273
274 # Introduce another function. Note that we're missing test coverage for
275 # 'complete', i.e. bug #1064.
276 our_func3() { echo ; }
277
278 compgen -A command our_
279 echo status=$?
280
281 ## STDOUT:
282 our_alias
283 our_func
284 our_func2
285 status=0
286 our_alias
287 our_func
288 our_func2
289 our_func3
290 status=0
291 ## END
292
293 #### compgen -A command completes builtins and keywords
294 compgen -A command eva
295 echo status=$?
296 compgen -A command whil
297 echo status=$?
298 ## STDOUT:
299 eval
300 status=0
301 while
302 status=0
303 ## END
304
305 #### compgen -k shows the same keywords as bash
306
307 # bash adds ]] and } and coproc
308
309 # Use bash as an oracle
310 bash -c 'compgen -k' | sort > bash.txt
311
312 # osh vs. bash, or bash vs. bash
313 $SH -c 'compgen -k' | sort > this-shell.txt
314
315 #comm bash.txt this-shell.txt
316
317 # show lines in both files
318 comm -12 bash.txt this-shell.txt | egrep -v 'coproc|select'
319
320 ## STDOUT:
321 !
322 [[
323 ]]
324 case
325 do
326 done
327 elif
328 else
329 esac
330 fi
331 for
332 function
333 if
334 in
335 then
336 time
337 until
338 while
339 {
340 }
341 ## END
342
343 #### compgen -k shows Oils keywords too
344
345 # YSH has a superset of keywords:
346 # const var
347 # setvar setglobal
348 # proc func typed
349 # call = # hm = is not here
350
351 compgen -k | sort | egrep '^(const|var|setvar|setglobal|proc|func|typed|call|=)$'
352 echo --
353
354 ## STDOUT:
355 =
356 call
357 const
358 func
359 proc
360 setglobal
361 setvar
362 typed
363 var
364 --
365 ## END
366
367 ## N-I bash STDOUT:
368 --
369 ## END
370
371 #### compgen -k completes reserved shell keywords
372 compgen -k do | sort
373 echo status=$?
374 compgen -k el | sort
375 echo status=$?
376 ## STDOUT:
377 do
378 done
379 status=0
380 elif
381 else
382 status=0
383 ## END
384
385 #### -o filenames and -o nospace have no effect with compgen
386 # they are POSTPROCESSING.
387 compgen -o filenames -o nospace -W 'bin build'
388 ## STDOUT:
389 bin
390 build
391 ## END
392
393 #### -o plusdirs and -o dirnames with compgen
394 cd $REPO_ROOT
395 compgen -o plusdirs -W 'a b1 b2' b | sort
396 echo ---
397 compgen -o dirnames b | sort
398 ## STDOUT:
399 b1
400 b2
401 benchmarks
402 bin
403 build
404 builtin
405 ---
406 benchmarks
407 bin
408 build
409 builtin
410 ## END
411
412 #### compgen -o default completes files and dirs
413 cd $REPO_ROOT
414 compgen -o default spec/t | sort
415 ## STDOUT:
416 spec/temp-binding.test.sh
417 spec/testdata
418 spec/tilde.test.sh
419 spec/toysh-posix.test.sh
420 spec/toysh.test.sh
421 spec/type-compat.test.sh
422 ## END
423
424 #### compgen doesn't respect -X for user-defined functions
425 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
426 # differently!
427 case $SH in
428 *bash|*osh)
429 $SH --rcfile /dev/null -i -c '
430 shopt -s extglob
431 fun() {
432 COMPREPLY=(one two three bin)
433 }
434 compgen -X "@(two|bin)" -F fun
435 echo --
436 compgen -X "!@(two|bin)" -F fun
437 '
438 esac
439 ## STDOUT:
440 one
441 three
442 --
443 two
444 bin
445 ## END
446
447 #### compgen -W words -X filter
448 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
449 # differently!
450 case $SH in
451 *bash|*osh)
452 $SH --rcfile /dev/null -i -c 'shopt -s extglob; compgen -X "@(two|bin)" -W "one two three bin"'
453 esac
454 ## STDOUT:
455 one
456 three
457 ## END
458
459 #### compgen -f -X filter -- $cur
460 cd $TMP
461 touch spam.py spam.sh
462 compgen -f -- sp | sort
463 echo --
464 # WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
465 # differently!
466 case $SH in
467 *bash|*osh)
468 $SH --rcfile /dev/null -i -c 'shopt -s extglob; compgen -f -X "!*.@(py)" -- sp'
469 esac
470 ## STDOUT:
471 spam.py
472 spam.sh
473 --
474 spam.py
475 ## END
476
477 #### compgen doesn't need shell quoting
478 # There is an obsolete comment in bash_completion that claims the opposite.
479 cd $TMP
480 touch 'foo bar'
481 touch "foo'bar"
482 compgen -f "foo b"
483 compgen -f "foo'"
484 ## STDOUT:
485 foo bar
486 foo'bar
487 ## END
488
489 #### compgen -W 'one two three'
490 cd $REPO_ROOT
491 compgen -W 'one two three'
492 echo --
493 compgen -W 'v1 v2 three' -A directory v
494 echo --
495 compgen -A directory -W 'v1 v2 three' v # order doesn't matter
496 ## STDOUT:
497 one
498 two
499 three
500 --
501 vendor
502 v1
503 v2
504 --
505 vendor
506 v1
507 v2
508 ## END
509
510 #### compgen -W evaluates code in $()
511 IFS=':%'
512 compgen -W '$(echo "spam:eggs%ham cheese")'
513 ## STDOUT:
514 spam
515 eggs
516 ham cheese
517 ## END
518
519 #### compgen -W uses IFS, and delimiters are escaped with \
520 IFS=':%'
521 compgen -W 'spam:eggs%ham cheese\:colon'
522 ## STDOUT:
523 spam
524 eggs
525 ham cheese:colon
526 ## END
527
528 #### Parse errors for compgen -W and complete -W
529 # bash doesn't detect as many errors because it lacks static parsing.
530 compgen -W '${'
531 echo status=$?
532 complete -W '${' foo
533 echo status=$?
534 ## STDOUT:
535 status=2
536 status=2
537 ## END
538 ## BUG bash STDOUT:
539 status=1
540 status=0
541 ## END
542
543 #### Runtime errors for compgen -W
544 compgen -W 'foo $(( 1 / 0 )) bar'
545 echo status=$?
546 ## STDOUT:
547 status=1
548 ## END
549
550 #### Runtime errors for compgen -F func
551 _foo() {
552 COMPREPLY=( foo bar )
553 COMPREPLY+=( $(( 1 / 0 )) ) # FATAL, but we still have candidates
554 }
555 compgen -F _foo foo
556 echo status=$?
557 ## STDOUT:
558 status=1
559 ## END
560
561 #### compgen -W '' cmd is not a usage error
562 # Bug fix due to '' being falsey in Python
563 compgen -W '' -- foo
564 echo status=$?
565 ## stdout: status=1
566
567 #### compgen -A builtin
568 compgen -A builtin g
569 ## STDOUT:
570 getopts
571 ## END
572
573 #### complete -C vs. compgen -C
574
575 f() { echo foo; echo bar; }
576
577 # Bash prints warnings: -C option may not work as you expect
578 # -F option may not work as you expect
579 #
580 # https://unix.stackexchange.com/questions/117987/compgen-warning-c-option-not-working-as-i-expected
581 #
582 # compexport fixes this problem, because it invokves ShellFuncAction, whcih
583 # sets COMP_ARGV, COMP_WORDS, etc.
584 #
585 # Should we print a warning?
586
587 compgen -C f b
588 echo compgen=$?
589
590 complete -C f b
591 echo complete=$?
592
593 ## STDOUT:
594 foo
595 bar
596 compgen=0
597 complete=0
598 ## END
599
600
601 #### compadjust with empty COMP_ARGV
602 case $SH in bash) exit ;; esac
603
604 COMP_ARGV=()
605 compadjust words
606 argv.py "${words[@]}"
607
608 ## STDOUT:
609 []
610 ## END
611
612 ## N-I bash STDOUT:
613 ## END
614
615
616 #### compadjust with sparse COMP_ARGV
617 case $SH in bash) exit ;; esac
618
619 COMP_ARGV=({0..9})
620 unset -v 'COMP_ARGV['{1,3,4,6,7,8}']'
621 compadjust words
622 argv.py "${words[@]}"
623
624 ## STDOUT:
625 ['0', '2', '5', '9']
626 ## END
627
628 ## N-I bash STDOUT:
629 ## END
630
631
632 #### compgen -F with scalar COMPREPLY
633
634 _comp_cmd_test() {
635 unset -v COMPREPLY
636 COMPREPLY=hello
637 }
638 compgen -F _comp_cmd_test
639
640 ## STDOUT:
641 hello
642 ## END