OILS / spec / builtin-completion.test.sh View on Github | oilshell.org

596 lines, 324 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:
246oil-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/testdata
416spec/tilde.test.sh
417spec/toysh-posix.test.sh
418spec/toysh.test.sh
419spec/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!
425case $SH in
426 *bash|*osh)
427 $SH --rcfile /dev/null -i -c '
428shopt -s extglob
429fun() {
430 COMPREPLY=(one two three bin)
431}
432compgen -X "@(two|bin)" -F fun
433echo --
434compgen -X "!@(two|bin)" -F fun
435'
436esac
437## STDOUT:
438one
439three
440--
441two
442bin
443## END
444
445#### compgen -W words -X filter
446# WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
447# differently!
448case $SH in
449 *bash|*osh)
450 $SH --rcfile /dev/null -i -c 'shopt -s extglob; compgen -X "@(two|bin)" -W "one two three bin"'
451esac
452## STDOUT:
453one
454three
455## END
456
457#### compgen -f -X filter -- $cur
458cd $TMP
459touch spam.py spam.sh
460compgen -f -- sp | sort
461echo --
462# WORKAROUND: wrap in bash -i -c because non-interactive bash behaves
463# differently!
464case $SH in
465 *bash|*osh)
466 $SH --rcfile /dev/null -i -c 'shopt -s extglob; compgen -f -X "!*.@(py)" -- sp'
467esac
468## STDOUT:
469spam.py
470spam.sh
471--
472spam.py
473## END
474
475#### compgen doesn't need shell quoting
476# There is an obsolete comment in bash_completion that claims the opposite.
477cd $TMP
478touch 'foo bar'
479touch "foo'bar"
480compgen -f "foo b"
481compgen -f "foo'"
482## STDOUT:
483foo bar
484foo'bar
485## END
486
487#### compgen -W 'one two three'
488cd $REPO_ROOT
489compgen -W 'one two three'
490echo --
491compgen -W 'w1 w2 three' -A directory w
492echo --
493compgen -A directory -W 'w1 w2 three' w # order doesn't matter
494## STDOUT:
495one
496two
497three
498--
499web
500w1
501w2
502--
503web
504w1
505w2
506## END
507
508#### compgen -W evaluates code in $()
509IFS=':%'
510compgen -W '$(echo "spam:eggs%ham cheese")'
511## STDOUT:
512spam
513eggs
514ham cheese
515## END
516
517#### compgen -W uses IFS, and delimiters are escaped with \
518IFS=':%'
519compgen -W 'spam:eggs%ham cheese\:colon'
520## STDOUT:
521spam
522eggs
523ham 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.
528compgen -W '${'
529echo status=$?
530complete -W '${' foo
531echo status=$?
532## STDOUT:
533status=2
534status=2
535## END
536## BUG bash STDOUT:
537status=1
538status=0
539## END
540
541#### Runtime errors for compgen -W
542compgen -W 'foo $(( 1 / 0 )) bar'
543echo status=$?
544## STDOUT:
545status=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}
553compgen -F _foo foo
554echo status=$?
555## STDOUT:
556status=1
557## END
558
559#### compgen -W '' cmd is not a usage error
560# Bug fix due to '' being falsey in Python
561compgen -W '' -- foo
562echo status=$?
563## stdout: status=1
564
565#### compgen -A builtin
566compgen -A builtin g
567## STDOUT:
568getopts
569## END
570
571#### complete -C vs. compgen -C
572
573f() { 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
585compgen -C f b
586echo compgen=$?
587
588complete -C f b
589echo complete=$?
590
591## STDOUT:
592foo
593bar
594compgen=0
595complete=0
596## END