@@ -990,6 +990,7 @@ _comp_variable_assignments()
990990_comp_finalize__depth= ()
991991_comp_finalize__target= ()
992992_comp_finalize__original_return_trap=
993+ _comp_finalize__original_int_trap=
993994
994995# This associative array contains the finalizer commands with the key
995996# being the name of the completed command.
@@ -999,6 +1000,28 @@ declare -gA BASH_COMPLETION_FINALIZE_CMD_HOOKS
9991000# executed for all the commands.
10001001declare -g a BASH_COMPLETION_FINALIZE_HOOKS
10011002
1003+ # This array contains the finalizer commands that will be executed for the
1004+ # top-level bash-completion functions. Unlike BASH_COMPLETION_FINALIZE_HOOKS,
1005+ # these hooks are only called at the end of the top-level bash-completion.
1006+ # These hooks are ensured to be called even when the completion is canceled by
1007+ # SIGINT.
1008+ declare -g a BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS
1009+
1010+ _comp_finalize__clear ()
1011+ {
1012+ local _hook
1013+ if [[ ${BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS[*]+set} ]]; then
1014+ for _hook in " ${BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS[@]} " ; do
1015+ eval -- " $_hook "
1016+ done
1017+ fi
1018+ _comp_finalize__depth=()
1019+ _comp_finalize__target=()
1020+ eval -- " ${_comp_finalize__original_int_trap:- trap - INT} "
1021+ eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
1022+ _comp_finalize__original_int_trap=
1023+ _comp_finalize__original_return_trap=
1024+ }
10021025_comp_finalize ()
10031026{
10041027 (( ${# _comp_finalize__depth[@]} )) || return 0
@@ -1025,16 +1048,15 @@ _comp_finalize()
10251048 unset -v ' _comp_finalize__depth[${#_comp_finalize__depth[@]}-1]'
10261049 unset -v ' _comp_finalize__target[${#_comp_finalize__target[@]}-1]'
10271050 if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
1028- eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
1029- _comp_finalize__original_return_trap=
1051+ _comp_finalize__clear
10301052 break
10311053 fi
10321054 done
10331055}
1034- # Note: We need to set "trace" function attribute of _comp_finalize to
1035- # make the trap restoration by "trap - RETURN" take effect in the
1036- # upper level.
1037- declare -f t _comp_finalize
1056+ # Note: We need to set "trace" function attribute of _comp_finalize{,__clear}
1057+ # to make the trap restoration by "trap - RETURN" take effect in the upper
1058+ # level.
1059+ declare -f t _comp_finalize__clear _comp_finalize
10381060
10391061# Initialize completion and deal with various general things: do file
10401062# and variable completion where appropriate, and adjust prev, words,
@@ -1074,6 +1096,7 @@ _comp_initialize()
10741096 # called for the top-level completion. [ Note: the completion function may
10751097 # be called recursively using "_command_offset", etc. ]
10761098 if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
1099+ _comp_finalize__original_int_trap=$( trap -p INT)
10771100 if shopt -q extdebug || shopt -qo functrace; then
10781101 # If extdebug / functrace is set, we need to explicitly save and
10791102 # restore the original trap handler because the outer trap handlers
@@ -1086,7 +1109,15 @@ _comp_initialize()
10861109 # do not need to explicitly save the outer trap handler.
10871110 _comp_finalize__original_return_trap=
10881111 fi
1112+
1113+ # Note: Ignore the traps previously set by us to avoid infinite
1114+ # loop in case that the previously set traps remain by some
1115+ # accidents.
1116+ _comp_finalize__original_return_trap=${_comp_finalize__original_return_trap## " trap -- '_comp_finalize" * }
1117+ _comp_finalize__original_int_trap=${_comp_finalize__original_int_trap## " trap -- '_comp_finalize" * }
1118+
10891119 trap _comp_finalize RETURN
1120+ trap ' _comp_finalize__clear; kill -INT "$BASHPID"' INT
10901121 fi
10911122 _comp_finalize__depth+=(" ${# FUNCNAME[@]} " )
10921123 _comp_finalize__target+=(" ${FUNCNAME[1]-} " )
0 commit comments