@@ -971,6 +971,7 @@ _comp_variable_assignments()
971971_comp_finalize__depth= ()
972972_comp_finalize__target= ()
973973_comp_finalize__original_return_trap=
974+ _comp_finalize__original_int_trap=
974975
975976# This associative array contains the finalizer commands with the key
976977# being the name of the completed command.
@@ -980,6 +981,28 @@ declare -gA BASH_COMPLETION_FINALIZE_CMD_HOOKS
980981# executed for all the commands.
981982declare -g a BASH_COMPLETION_FINALIZE_HOOKS
982983
984+ # This array contains the finalizer commands that will be executed for the
985+ # top-level bash-completion functions. Unlike BASH_COMPLETION_FINALIZE_HOOKS,
986+ # these hooks are only called at the end of the top-level bash-completion.
987+ # These hooks are ensured to be called even when the completion is canceled by
988+ # SIGINT.
989+ declare -g a BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS
990+
991+ _comp_finalize__clear ()
992+ {
993+ local _hook
994+ if [[ ${BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS[*]+set} ]]; then
995+ for _hook in " ${BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS[@]} " ; do
996+ eval -- " $_hook "
997+ done
998+ fi
999+ _comp_finalize__depth=()
1000+ _comp_finalize__target=()
1001+ eval -- " ${_comp_finalize__original_int_trap:- trap - INT} "
1002+ eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
1003+ _comp_finalize__original_int_trap=
1004+ _comp_finalize__original_return_trap=
1005+ }
9831006_comp_finalize ()
9841007{
9851008 (( ${# _comp_finalize__depth[@]} )) || return 0
@@ -1006,16 +1029,15 @@ _comp_finalize()
10061029 unset -v ' _comp_finalize__depth[${#_comp_finalize__depth[@]}-1]'
10071030 unset -v ' _comp_finalize__target[${#_comp_finalize__target[@]}-1]'
10081031 if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
1009- eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
1010- _comp_finalize__original_return_trap=
1032+ _comp_finalize__clear
10111033 break
10121034 fi
10131035 done
10141036}
1015- # Note: We need to set "trace" function attribute of _comp_finalize to
1016- # make the trap restoration by "trap - RETURN" take effect in the
1017- # upper level.
1018- declare -f t _comp_finalize
1037+ # Note: We need to set "trace" function attribute of _comp_finalize{,__clear}
1038+ # to make the trap restoration by "trap - RETURN" take effect in the upper
1039+ # level.
1040+ declare -f t _comp_finalize__clear _comp_finalize
10191041
10201042# Initialize completion and deal with various general things: do file
10211043# and variable completion where appropriate, and adjust prev, words,
@@ -1055,6 +1077,7 @@ _comp_initialize()
10551077 # called for the top-level completion. [ Note: the completion function may
10561078 # be called recursively using "_command_offset", etc. ]
10571079 if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
1080+ _comp_finalize__original_int_trap=$( trap -p INT)
10581081 if shopt -q extdebug || shopt -qo functrace; then
10591082 # If extdebug / functrace is set, we need to explicitly save and
10601083 # restore the original trap handler because the outer trap handlers
@@ -1067,7 +1090,15 @@ _comp_initialize()
10671090 # do not need to explicitly save the outer trap handler.
10681091 _comp_finalize__original_return_trap=
10691092 fi
1093+
1094+ # Note: Ignore the traps previously set by us to avoid infinite
1095+ # loop in case that the previously set traps remain by some
1096+ # accidents.
1097+ _comp_finalize__original_return_trap=${_comp_finalize__original_return_trap## " trap -- '_comp_finalize" * }
1098+ _comp_finalize__original_int_trap=${_comp_finalize__original_int_trap## " trap -- '_comp_finalize" * }
1099+
10701100 trap _comp_finalize RETURN
1101+ trap ' _comp_finalize__clear; kill -INT "$BASHPID"' INT
10711102 fi
10721103 _comp_finalize__depth+=(" ${# FUNCNAME[@]} " )
10731104 _comp_finalize__target+=(" ${FUNCNAME[1]-} " )
0 commit comments