@@ -655,29 +655,111 @@ _comp_compgen()
655655 printf ' bash_completion: %s: unrecognized generator `%s' \' ' (function %s not found)\n' " $FUNCNAME " " $1 " " ${_generator[0]} " >&2
656656 return 2
657657 fi
658+ shift
658659
659- (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
660+ _comp_compgen__call_generator " $@ "
661+ else
662+ # usage: _comp_compgen [options] -- [compgen_options]
663+ if [[ $_icmd || $_xcmd ]]; then
664+ printf ' bash_completion: %s: generator name is unspecified for `%s' \' ' \n' " $FUNCNAME " " ${_icmd: +-i $_icmd }${_xcmd: +x $_xcmd } " >&2
665+ return 2
666+ fi
667+
668+ # Note: $* in the below checks would be affected by uncontrolled IFS in
669+ # bash >= 5.0, so we need to set IFS to the normal value. The behavior
670+ # in bash < 5.0, where unquoted $* in conditional command did not honor
671+ # IFS, was a bug.
672+ # Note: Also, ${_cur:+-- "$_cur"} and ${_append:+-a} would be affected
673+ # by uncontrolled IFS.
674+ local IFS=$' \t\n '
675+ # Note: extglob *\$?(\{)[0-9]* can be extremely slow when the string
676+ # "${*:2:_nopt}" becomes longer, so we test \$[0-9] and \$\{[0-9]
677+ # separately.
678+ if [[ $* == * \$ [0-9]* || $* == * \$\{ [0-9]* ]]; then
679+ printf ' bash_completion: %s: positional parameter $1, $2, ... do not work inside this function\n' " $FUNCNAME " >&2
680+ return 2
681+ fi
660682
683+ _comp_compgen__call_builtin " $@ "
684+ fi
685+ }
686+
687+ # Helper function for _comp_compgen. This function calls a generator.
688+ # @param $1... generator_args
689+ # @var[in] _dir
690+ # @var[in] _cur
691+ # @arr[in] _generator
692+ # @arr[in] _upvars
693+ # @var[in] _append
694+ # @var[in] _var
695+ _comp_compgen__call_generator ()
696+ {
697+ (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
698+
699+ if [[ $_dir ]]; then
700+ local _original_pwd=$PWD
701+ local PWD=${PWD-} OLDPWD=${OLDPWD-}
702+ # Note: We also redirect stdout because `cd` may output the target
703+ # directory to stdout when CDPATH is set.
704+ command cd -- " $_dir " & > /dev/null ||
705+ {
706+ _comp_compgen__error_fallback
707+ return
708+ }
709+ fi
710+
711+ local _comp_compgen__append=$_append
712+ local _comp_compgen__var=$_var
713+ local _comp_compgen__cur=$_cur cur=$_cur
714+ # Note: we use $1 as a part of a function name, and we use $2... as
715+ # arguments to the function if any.
716+ # shellcheck disable=SC2145
717+ " ${_generator[@]} " " $@ "
718+ local _status=$?
719+
720+ # Go back to the original directory.
721+ # Note: Failure of this line results in the change of the current
722+ # directory visible to the user. We intentionally do not redirect
723+ # stderr so that the error message appear in the terminal.
724+ # shellcheck disable=SC2164
725+ [[ $_dir ]] && command cd -- " $_original_pwd "
726+
727+ return " $_status "
728+ }
729+
730+ # Helper function for _comp_compgen. This function calls the builtin compgen.
731+ # @param $1... compgen_args
732+ # @var[in] _dir
733+ # @var[in] _ifs
734+ # @var[in] _cur
735+ # @arr[in] _upvars
736+ # @var[in] _append
737+ # @var[in] _var
738+ if (( BASH_VERSINFO[0 ] > 5 || BASH_VERSINFO[0 ] == 5 && BASH_VERSINFO[1 ] >= 3 )) ; then
739+ # bash >= 5.3 has `compgen -V array_name`
740+ _comp_compgen__call_builtin ()
741+ {
661742 if [[ $_dir ]]; then
662743 local _original_pwd=$PWD
663744 local PWD=${PWD-} OLDPWD=${OLDPWD-}
664745 # Note: We also redirect stdout because `cd` may output the target
665746 # directory to stdout when CDPATH is set.
666- command cd -- " $_dir " & > /dev/null ||
667- {
668- _comp_compgen__error_fallback
669- return
670- }
747+ command cd -- " $_dir " & > /dev/null || {
748+ _comp_compgen__error_fallback
749+ return
750+ }
671751 fi
672752
673- local _comp_compgen__append=$_append
674- local _comp_compgen__var=$_var
675- local _comp_compgen__cur=$_cur cur=$_cur
676- # Note: we use $1 as a part of a function name, and we use $2... as
677- # arguments to the function if any.
678- # shellcheck disable=SC2145
679- " ${_generator[@]} " " ${@: 2} "
680- local _status=$?
753+ local -a _result=()
754+
755+ # Note: We specify -X '' to exclude empty completions to make the
756+ # behavior consistent with the implementation for Bash < 5.3 where
757+ # `_comp_split -l` removes empty lines. If the caller specifies -X
758+ # pat, the effect of -X '' is overwritten by the specified one.
759+ IFS=$_ifs compgen -V _result -X ' ' " $@ " ${_cur: +-- " $_cur " } || {
760+ _comp_compgen__error_fallback
761+ return
762+ }
681763
682764 # Go back to the original directory.
683765 # Note: Failure of this line results in the change of the current
@@ -686,46 +768,35 @@ _comp_compgen()
686768 # shellcheck disable=SC2164
687769 [[ $_dir ]] && command cd -- " $_original_pwd "
688770
689- return " $_status "
690- fi
691-
692- # usage: _comp_compgen [options] -- [compgen_options]
693- if [[ $_icmd || $_xcmd ]]; then
694- printf ' bash_completion: %s: generator name is unspecified for `%s' \' ' \n' " $FUNCNAME " " ${_icmd: +-i $_icmd }${_xcmd: +x $_xcmd } " >&2
695- return 2
696- fi
697-
698- # Note: $* in the below checks would be affected by uncontrolled IFS in
699- # bash >= 5.0, so we need to set IFS to the normal value. The behavior in
700- # bash < 5.0, where unquoted $* in conditional command did not honor IFS,
701- # was a bug.
702- # Note: Also, ${_cur:+-- "$_cur"} and ${_append:+-a} would be affected by
703- # uncontrolled IFS.
704- local IFS=$' \t\n '
705- # Note: extglob *\$?(\{)[0-9]* can be extremely slow when the string
706- # "${*:2:_nopt}" becomes longer, so we test \$[0-9] and \$\{[0-9]
707- # separately.
708- if [[ $* == * \$ [0-9]* || $* == * \$\{ [0-9]* ]]; then
709- printf ' bash_completion: %s: positional parameter $1, $2, ... do not work inside this function\n' " $FUNCNAME " >&2
710- return 2
711- fi
712-
713- local _result
714- _result=$(
715- if [[ $_dir ]]; then
716- # Note: We also redirect stdout because `cd` may output the target
717- # directory to stdout when CDPATH is set.
718- command cd -- " $_dir " & > /dev/null || return
771+ (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
772+ (( ${# _result[@]} )) || return
773+ if [[ $_append ]]; then
774+ eval -- " $_var +=(\"\$ {_result[@]}\" )"
775+ else
776+ eval -- " $_var =(\"\$ {_result[@]}\" )"
719777 fi
720- IFS=$_ifs compgen " $@ " ${_cur: +-- " $_cur " }
721- ) || {
722- _comp_compgen__error_fallback
723778 return
724779 }
780+ else
781+ _comp_compgen__call_builtin ()
782+ {
783+ local _result
784+ _result=$(
785+ if [[ $_dir ]]; then
786+ # Note: We also redirect stdout because `cd` may output the target
787+ # directory to stdout when CDPATH is set.
788+ command cd -- " $_dir " & > /dev/null || return
789+ fi
790+ IFS=$_ifs compgen " $@ " ${_cur: +-- " $_cur " }
791+ ) || {
792+ _comp_compgen__error_fallback
793+ return
794+ }
725795
726- (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
727- _comp_split -l ${_append: +-a} " $_var " " $_result "
728- }
796+ (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
797+ _comp_split -l ${_append: +-a} " $_var " " $_result "
798+ }
799+ fi
729800
730801# usage: _comp_compgen_set [words...]
731802# Reset COMPREPLY with the specified WORDS. If no arguments are specified, the
0 commit comments