Skip to content

Commit e34e38f

Browse files
committed
feat(_comp_compgen): inherit options inside _comp_compgen NAME
1 parent 5598b5c commit e34e38f

File tree

1 file changed

+90
-28
lines changed

1 file changed

+90
-28
lines changed

bash_completion

Lines changed: 90 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -381,14 +381,8 @@ _comp_split()
381381
((_new_size > _old_size))
382382
}
383383

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.
392386
# OPTIONS
393387
# -a Append to the array
394388
# -v arr Store the results to the array ARR. The default is `COMPREPLY`.
@@ -404,25 +398,72 @@ _comp_split()
404398
# -c cur Set a word used as a prefix to filter the completions. The default
405399
# is ${cur-}.
406400
# -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 `-`).
408413
#
409414
# Note: References to positional parameters $1, $2, ... (such as -W '$1')
410415
# will not work as expected because these reference the arguments of
411416
# `_comp_compgen' instead of those of the caller function. When there are
412417
# 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+
#
417456
_comp_compgen()
418457
{
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'
421462

422463
local OPTIND=1 OPTARG="" OPTERR=0 _opt
423464
while getopts ':alF:v:Rc:' _opt "$@"; do
424465
case $_opt in
425-
a) _append=set _split_options+=(-a) ;;
466+
a) _append=set ;;
426467
v)
427468
if [[ $OPTARG == @(*[^_a-zA-Z0-9]*|[0-9]*|''|_*|IFS|OPTIND|OPTARG|OPTERR) ]]; then
428469
printf 'bash_completion: %s: -v: invalid array name `%s'\''.\n' "$FUNCNAME" "$OPTARG" >&2
@@ -445,17 +486,38 @@ _comp_compgen()
445486
printf 'bash_completion: %s: unexpected number of arguments.\n' "$FUNCNAME" >&2
446487
printf 'usage: %s [-alR|-F SEP|-v ARR|-c CUR] -- ARGS...' "$FUNCNAME" >&2
447488
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
459521
printf 'bash_completion: %s: positional parameter $1, $2, ... do not work inside this function.\n' "$FUNCNAME" >&2
460522
return 2
461523
fi
@@ -475,7 +537,7 @@ _comp_compgen()
475537
return "$_status"
476538
}
477539

478-
_comp_split "${_split_options[@]}" "$_var" "$_result"
540+
_comp_split -l ${_append:+-a} "$_var" "$_result"
479541
}
480542

481543
# Check if the argument looks like a path.

0 commit comments

Comments
 (0)