Skip to content

Commit 2b5f9fa

Browse files
committed
fix(_comp_compgen): use compgen -V array_name in bash >= 5.3
In Bash >= 5.3, we can use `compgen -V array_name` to properly handle newlines in the generated completions.
1 parent 9ad6f8f commit 2b5f9fa

File tree

1 file changed

+55
-11
lines changed

1 file changed

+55
-11
lines changed

bash_completion

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -735,24 +735,68 @@ _comp_compgen__call_generator()
735735
# @arr[in] _upvars
736736
# @var[in] _append
737737
# @var[in] _var
738-
_comp_compgen__call_builtin()
739-
{
740-
local _result
741-
_result=$(
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+
{
742742
if [[ $_dir ]]; then
743+
local _original_pwd=$PWD
744+
local PWD=${PWD-} OLDPWD=${OLDPWD-}
743745
# Note: We also redirect stdout because `cd` may output the target
744746
# directory to stdout when CDPATH is set.
745-
command cd -- "$_dir" &>/dev/null || return
747+
command cd -- "$_dir" &>/dev/null || {
748+
_comp_compgen__error_fallback
749+
return
750+
}
751+
fi
752+
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+
}
763+
764+
# Go back to the original directory.
765+
# Note: Failure of this line results in the change of the current
766+
# directory visible to the user. We intentionally do not redirect
767+
# stderr so that the error message appear in the terminal.
768+
# shellcheck disable=SC2164
769+
[[ $_dir ]] && command cd -- "$_original_pwd"
770+
771+
((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}"
772+
((${#_result[@]})) || return
773+
if [[ $_append ]]; then
774+
eval -- "$_var+=(\"\${_result[@]}\")"
775+
else
776+
eval -- "$_var=(\"\${_result[@]}\")"
746777
fi
747-
IFS=$_ifs compgen "$@" ${_cur:+-- "$_cur"}
748-
) || {
749-
_comp_compgen__error_fallback
750778
return
751779
}
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+
}
752795

753-
((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}"
754-
_comp_split -l ${_append:+-a} "$_var" "$_result"
755-
}
796+
((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}"
797+
_comp_split -l ${_append:+-a} "$_var" "$_result"
798+
}
799+
fi
756800

757801
# usage: _comp_compgen_set [words...]
758802
# Reset COMPREPLY with the specified WORDS. If no arguments are specified, the

0 commit comments

Comments
 (0)