@@ -890,6 +890,7 @@ _comp_variable_assignments()
890890_comp_finalize__depth= ()
891891_comp_finalize__target= ()
892892_comp_finalize__original_return_trap=
893+ _comp_finalize__original_int_trap=
893894
894895# This associative array contains the finalizer commands with the key
895896# being the name of the completed command.
@@ -899,6 +900,28 @@ declare -gA BASH_COMPLETION_FINALIZE_CMD_HOOKS
899900# executed for all the commands.
900901declare -g a BASH_COMPLETION_FINALIZE_HOOKS
901902
903+ # This array contains the finalizer commands that will be executed for the
904+ # top-level bash-completion functions. Unlike BASH_COMPLETION_FINALIZE_HOOKS,
905+ # these hooks are only called at the end of the top-level bash-completion.
906+ # These hooks are ensured to be called even when the completion is canceled by
907+ # SIGINT.
908+ declare -g a BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS
909+
910+ _comp_finalize__clear ()
911+ {
912+ local _hook
913+ if [[ ${BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS[*]+set} ]]; then
914+ for _hook in " ${BASH_COMPLETION_FINALIZE_TOPLEVEL_HOOKS[@]} " ; do
915+ eval -- " $_hook "
916+ done
917+ fi
918+ _comp_finalize__depth=()
919+ _comp_finalize__target=()
920+ eval -- " ${_comp_finalize__original_int_trap:- trap - INT} "
921+ eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
922+ _comp_finalize__original_int_trap=
923+ _comp_finalize__original_return_trap=
924+ }
902925_comp_finalize ()
903926{
904927 (( ${# _comp_finalize__depth[@]} )) || return 0
@@ -925,16 +948,15 @@ _comp_finalize()
925948 unset -v ' _comp_finalize__depth[${#_comp_finalize__depth[@]}-1]'
926949 unset -v ' _comp_finalize__target[${#_comp_finalize__target[@]}-1]'
927950 if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
928- eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
929- _comp_finalize__original_return_trap=
951+ _comp_finalize__clear
930952 break
931953 fi
932954 done
933955}
934- # Note: We need to set "trace" function attribute of _comp_finalize to
935- # make the trap restoration by "trap - RETURN" take effect in the
936- # upper level.
937- declare -f t _comp_finalize
956+ # Note: We need to set "trace" function attribute of _comp_finalize{,__clear}
957+ # to make the trap restoration by "trap - RETURN" take effect in the upper
958+ # level.
959+ declare -f t _comp_finalize__clear _comp_finalize
938960
939961# Initialize completion and deal with various general things: do file
940962# and variable completion where appropriate, and adjust prev, words,
@@ -974,6 +996,7 @@ _comp_initialize()
974996 # called for the top-level completion. [ Note: the completion function may
975997 # be called recursively using "_command_offset", etc. ]
976998 if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
999+ _comp_finalize__original_int_trap=$( trap -p INT)
9771000 if shopt -q extdebug || shopt -qo functrace; then
9781001 # If extdebug / functrace is set, we need to explicitly save and
9791002 # restore the original trap handler because the outer trap handlers
@@ -986,7 +1009,15 @@ _comp_initialize()
9861009 # do not need to explicitly save the outer trap handler.
9871010 _comp_finalize__original_return_trap=
9881011 fi
1012+
1013+ # Note: Ignore the traps previously set by us to avoid infinite
1014+ # loop in case that the previously set traps remain by some
1015+ # accidents.
1016+ _comp_finalize__original_return_trap=${_comp_finalize__original_return_trap## " trap -- '_comp_finalize" * }
1017+ _comp_finalize__original_int_trap=${_comp_finalize__original_int_trap## " trap -- '_comp_finalize" * }
1018+
9891019 trap _comp_finalize RETURN
1020+ trap ' _comp_finalize__clear; kill -INT "$BASHPID"' INT
9901021 fi
9911022 _comp_finalize__depth+=(" ${# FUNCNAME[@]} " )
9921023 _comp_finalize__target+=(" ${FUNCNAME[1]-} " )
0 commit comments