@@ -381,14 +381,8 @@ _comp_split()
381
381
(( _new_size > _old_size))
382
382
}
383
383
384
- # Call `compgen` with the specified arguments and store the results in the
385
- # specified array.
386
- # Usage: _comp_compgen [-alR|-F sep|-v arr|-c cur] -- args...
387
- # This function essentially performs arr=($(compgen args...)) but properly
388
- # handles shell options, IFS, etc. using _comp_split. This function is
389
- # equivalent to `_comp_split [-a] -l arr "$(IFS=sep; compgen args... -- cur)"`,
390
- # but this pattern is frequent in the codebase and is good to separate out as a
391
- # function for the possible future implementation change.
384
+ # Provide a common interface to generate completion candidates in COMPREPLY or
385
+ # in a specified array.
392
386
# OPTIONS
393
387
# -a Append to the array
394
388
# -v arr Store the results to the array ARR. The default is `COMPREPLY`.
@@ -404,25 +398,72 @@ _comp_split()
404
398
# -c cur Set a word used as a prefix to filter the completions. The default
405
399
# is ${cur-}.
406
400
# -R The same as -c ''. Use raw outputs without filtering.
407
- # @param $1... args Arguments that are passed to compgen
401
+ # @var[in,opt] cur Used as the default value of a prefix to filter the
402
+ # completions.
403
+ #
404
+ # Usage #1: _comp_compgen [-alR|-F sep|-v arr|-c cur] -- options...
405
+ # Call `compgen` with the specified arguments and store the results in the
406
+ # specified array. This function essentially performs arr=($(compgen args...))
407
+ # but properly handles shell options, IFS, etc. using _comp_split. This
408
+ # function is equivalent to `_comp_split [-a] -l arr "$(IFS=sep; compgen
409
+ # args... -- cur)"`, but this pattern is frequent in the codebase and is good
410
+ # to separate out as a function for the possible future implementation change.
411
+ # @param $1... options Arguments that are passed to compgen (if $1 starts with
412
+ # a hyphen `-`).
408
413
#
409
414
# Note: References to positional parameters $1, $2, ... (such as -W '$1')
410
415
# will not work as expected because these reference the arguments of
411
416
# `_comp_compgen' instead of those of the caller function. When there are
412
417
# needs to reference them, save the arguments to an array and reference the
413
- # array instead. The array option `-V arr` in bash >= 5.3 should be instead
414
- # specified as `-v arr` as a part of the `_comp_compgen` options.
415
- # @var[in] cur Used as the default value of a prefix to filter the
416
- # completions.
418
+ # array instead.
419
+ #
420
+ # Note: The array option `-V arr` in bash >= 5.3 should be instead specified
421
+ # as `-v arr` as a part of the `_comp_compgen` options.
422
+ #
423
+ # Usage #2: _comp_compgen [-alR|-v arr|-c cur] name args...
424
+ # Call `_comp_compgen_NAME ARGS...` with the specified options. This provides
425
+ # a common interface to call the functions `_comp_compgen_NAME`, which produce
426
+ # completion candidates, with custom options [-alR|-v arr|-cur]. The option
427
+ # `-F sep` is not used with this usage.
428
+ # @param $1... name args Calls the function _comp_compgen_NAME with the
429
+ # specified ARGS (if $1 does not start with a hyphen `-`). The options
430
+ # [-alR|-v arr|-c cur] are inherited by the child calls of `_comp_compgen`
431
+ # inside `_comp_compgen_NAME` unless the child call `_comp_compgen` receives
432
+ # overriding options.
433
+ # @var[in,opt,internal] _comp_compgen__append
434
+ # @var[in,opt,internal] _comp_compgen__var
435
+ # @var[in,opt,internal] _comp_compgen__cur
436
+ # These variables are internally used to pass the effect of the options
437
+ # [-alR|-v arr|-c cur] to the child calls of `_comp_compgen` in
438
+ # `_comp_compgen_NAME`.
439
+ #
440
+ # @remarks Design `_comp_compgen_NAME`: a function that produce completions can
441
+ # be defined with the name _comp_compgen_NAME. The function is supposed to
442
+ # generate completions by calling `_comp_compgen`. To reflect the options
443
+ # specified to the outer calls of `_comp_compgen`, the function should not
444
+ # directly modify `COMPREPLY`. To add words, one can call
445
+ #
446
+ # _comp_compgen -- -W '"${words[@]}"'
447
+ #
448
+ # To directly add words without filtering by `cur`, one can call
449
+ #
450
+ # _comp_compgen -R -- -W '"${words[@]}"'
451
+ #
452
+ # Other nested calls of _comp_compgen can also be used. The function is
453
+ # supposed to replace the existing content of the array by default to allow the
454
+ # caller control whether to replace or append by the option `-a`.
455
+ #
417
456
_comp_compgen ()
418
457
{
419
- local _append=" " _var=COMPREPLY _cur=${cur-} _ifs=$' \t\n '
420
- local -a _split_options=(-l)
458
+ local _append=${_comp_compgen__append-}
459
+ local _var=${_comp_compgen__var-COMPREPLY}
460
+ local _cur=${_comp_compgen__cur-${cur-} }
461
+ local _ifs=$' \t\n '
421
462
422
463
local OPTIND=1 OPTARG=" " OPTERR=0 _opt
423
464
while getopts ' :alF:v:Rc:' _opt " $@ " ; do
424
465
case $_opt in
425
- a) _append=set _split_options+=(-a) ;;
466
+ a) _append=set ;;
426
467
v)
427
468
if [[ $OPTARG == @ (* [^_a-zA-Z0-9]* | [0-9]* | ' ' | _* | IFS| OPTIND| OPTARG| OPTERR) ]]; then
428
469
printf ' bash_completion: %s: -v: invalid array name `%s' \' ' .\n' " $FUNCNAME " " $OPTARG " >&2
@@ -445,17 +486,38 @@ _comp_compgen()
445
486
printf ' bash_completion: %s: unexpected number of arguments.\n' " $FUNCNAME " >&2
446
487
printf ' usage: %s [-alR|-F SEP|-v ARR|-c CUR] -- ARGS...' " $FUNCNAME " >&2
447
488
return 2
448
- elif
449
- # Note: $* in the below checks would be affected by uncontrolled IFS in
450
- # bash >= 5.0, so we need to set IFS to the normal value. The behavior
451
- # in bash < 5.0, where unquoted $* in conditional command did not honor
452
- # IFS, was a bug.
453
- local IFS=$' \t\n '
454
- # Note: extglob *\$?(\{)[0-9]* can be extremely slow when the string
455
- # "${*:2:_nopt}" becomes longer, so we test \$[0-9] and \$\{[0-9]
456
- # separately.
457
- [[ $* == * \$ [0-9]* || $* == * \$\{ [0-9]* ]]
458
- then
489
+ fi
490
+
491
+ if [[ $1 != -* ]]; then
492
+ # usage: _comp_compgen [options] NAME args
493
+ if ! declare -F " _comp_compgen_$1 " & > /dev/null; then
494
+ printf ' bash_completion: %s: unrecognized category `%s' \' ' (function _comp_compgen_%s not found).\n' " $FUNCNAME " " $1 " " $1 " >&2
495
+ return 2
496
+ fi
497
+
498
+ local _comp_compgen__append=$_append
499
+ local _comp_compgen__var=$_var
500
+ local _comp_compgen__cur=$_cur cur=$_cur
501
+ # Note: we use $1 as a part of a function name, and we use $2... as
502
+ # arguments to the function if any.
503
+ # shellcheck disable=SC2145
504
+ _comp_compgen_" $@ "
505
+ return
506
+ fi
507
+
508
+ # usage: _comp_compgen [options] -- [compgen_options]
509
+
510
+ # Note: $* in the below checks would be affected by uncontrolled IFS in
511
+ # bash >= 5.0, so we need to set IFS to the normal value. The behavior in
512
+ # bash < 5.0, where unquoted $* in conditional command did not honor IFS,
513
+ # was a bug.
514
+ # Note: Also, ${_cur:+-- "$_cur"} and ${_append:+-a} would be affected by
515
+ # uncontrolled IFS.
516
+ local IFS=$' \t\n '
517
+ # Note: extglob *\$?(\{)[0-9]* can be extremely slow when the string
518
+ # "${*:2:_nopt}" becomes longer, so we test \$[0-9] and \$\{[0-9]
519
+ # separately.
520
+ if [[ $* == * \$ [0-9]* || $* == * \$\{ [0-9]* ]]; then
459
521
printf ' bash_completion: %s: positional parameter $1, $2, ... do not work inside this function.\n' " $FUNCNAME " >&2
460
522
return 2
461
523
fi
@@ -475,7 +537,7 @@ _comp_compgen()
475
537
return " $_status "
476
538
}
477
539
478
- _comp_split " ${_split_options[@]} " " $_var " " $_result "
540
+ _comp_split -l ${_append : +-a} " $_var " " $_result "
479
541
}
480
542
481
543
# Check if the argument looks like a path.
0 commit comments