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

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