@@ -905,6 +905,7 @@ _comp_variable_assignments()
905905_comp_finalize__depth= ()
906906_comp_finalize__target= ()
907907_comp_finalize__original_return_trap=
908+ _comp_finalize__original_int_trap=
908909
909910# This associative array contains the finalizer commands with the key
910911# being the name of the completed command.
@@ -914,6 +915,28 @@ declare -gA BASH_COMPLETION_FINALIZE_CMD_HOOKS
914915# executed for all the commands.
915916declare -g a BASH_COMPLETION_FINALIZE_HOOKS
916917
918+ # This array contains the finalizer commands that will be executed for the
919+ # top-level bash-completion functions. Unlike BASH_COMPLETION_FINALIZE_HOOKS,
920+ # these hooks are only called at the end of the top-level bash-completion.
921+ # These hooks are ensured to be called even when the completion is canceled by
922+ # SIGINT.
923+ declare -g a BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS
924+
925+ _comp_finalize__clear ()
926+ {
927+ local _hook
928+ if [[ ${BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS[*]+set} ]]; then
929+ for _hook in " ${BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS[@]} " ; do
930+ eval -- " $_hook "
931+ done
932+ fi
933+ _comp_finalize__depth=()
934+ _comp_finalize__target=()
935+ eval -- " ${_comp_finalize__original_int_trap:- trap - INT} "
936+ eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
937+ _comp_finalize__original_int_trap=
938+ _comp_finalize__original_return_trap=
939+ }
917940_comp_finalize ()
918941{
919942 (( ${# _comp_finalize__depth[@]} )) || return 0
@@ -940,16 +963,15 @@ _comp_finalize()
940963 unset -v ' _comp_finalize__depth[${#_comp_finalize__depth[@]}-1]'
941964 unset -v ' _comp_finalize__target[${#_comp_finalize__target[@]}-1]'
942965 if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
943- eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
944- _comp_finalize__original_return_trap=
966+ _comp_finalize__clear
945967 break
946968 fi
947969 done
948970}
949- # Note: We need to set "trace" function attribute of _comp_finalize to
950- # make the trap restoration by "trap - RETURN" take effect in the
951- # upper level.
952- declare -f t _comp_finalize
971+ # Note: We need to set "trace" function attribute of _comp_finalize{,__clear}
972+ # to make the trap restoration by "trap - RETURN" take effect in the upper
973+ # level.
974+ declare -f t _comp_finalize__clear _comp_finalize
953975
954976# Initialize completion and deal with various general things: do file
955977# and variable completion where appropriate, and adjust prev, words,
@@ -989,6 +1011,7 @@ _comp_initialize()
9891011 # called for the top-level completion. [ Note: the completion function may
9901012 # be called recursively using "_command_offset", etc. ]
9911013 if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
1014+ _comp_finalize__original_int_trap=$( trap -p INT)
9921015 if shopt -q extdebug || shopt -qo functrace; then
9931016 # If extdebug / functrace is set, we need to explicitly save and
9941017 # restore the original trap handler because the outer trap handlers
@@ -1001,7 +1024,15 @@ _comp_initialize()
10011024 # do not need to explicitly save the outer trap handler.
10021025 _comp_finalize__original_return_trap=
10031026 fi
1027+
1028+ # Note: Ignore the traps previously set by us to avoid infinite
1029+ # loop in case that the previously set traps remain by some
1030+ # accidents.
1031+ _comp_finalize__original_return_trap=${_comp_finalize__original_int_trap## " trap -- '_comp_finalize" * }
1032+ _comp_finalize__original_int_trap=${_comp_finalize__original_int_trap## " trap -- '_comp_finalize" * }
1033+
10041034 trap _comp_finalize RETURN
1035+ trap ' _comp_finalize__clear; kill -INT "$BASHPID"' INT
10051036 fi
10061037 _comp_finalize__depth+=(" ${# FUNCNAME[@]} " )
10071038 _comp_finalize__target+=(" ${FUNCNAME[1]-} " )
0 commit comments