OILS / spec / builtin-completion.test.sh View on Github | oils.pub

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