@@ -881,13 +881,51 @@ _comp_variable_assignments()
881881 return 0
882882}
883883
884- _comp_return_hook ()
885- {
886- (( ${# FUNCNAME[*]} != 2 )) && return # this _will_ need some refinement and thought
887- echo " Hello from return hook for ${FUNCNAME[1]} "
888- echo " words: ${words[@]} "
889- echo " COMPREPLY: ${COMPREPLY[@]} "
884+ _comp_finalize__depth= ()
885+ _comp_finalize__target= ()
886+ _comp_finalize__original_return_trap=
887+
888+ # This associative array contains the finalizer commands with the key
889+ # being the name of the completed command.
890+ declare -g A BASH_COMPLETION_FINALIZE_CMD_HOOKS
891+
892+ # This array contains the general finalizer commands that will be
893+ # executed for all the commands.
894+ declare -g a BASH_COMPLETION_FINALIZE_HOOKS
895+
896+ _comp_finalize ()
897+ {
898+ (( ${# _comp_finalize__depth[@]} )) || return 0
899+ while (( ${# FUNCNAME[@]} <= ${_comp_finalize__depth[-1]} )) ; do
900+ if [[ ${# FUNCNAME[@]} -eq ${_comp_finalize__depth[-1]} && ${FUNCNAME[1]} == " ${_comp_finalize__target[-1]} " ]]; then
901+ # Call finalizer for each command
902+ local cmd=${words[0]-} _comp_local_hook
903+ if [[ $cmd ]]; then
904+ _comp_local_hook=${BASH_COMPLETION_FINALIZE_CMD_HOOKS[$cmd]-}
905+ eval -- " $_comp_local_hook "
906+ fi
907+
908+ # Call general finalizers
909+ if [[ ${BASH_COMPLETION_FINALIZE_HOOKS[*]+set} ]]; then
910+ for _comp_local_hook in " ${BASH_COMPLETION_FINALIZE_HOOKS[@]} " ; do
911+ eval -- " $_comp_local_hook "
912+ done
913+ fi
914+ fi
915+
916+ unset -v ' _comp_finalize__depth[-1]'
917+ unset -v ' _comp_finalize__target[-1]'
918+ if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
919+ eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
920+ _comp_finalize__original_return_trap=
921+ break
922+ fi
923+ done
890924}
925+ # Note: We need to set "trace" function attribute of _comp_finalize to
926+ # make the trap restoration by "trap - RETURN" take effect in the
927+ # upper level.
928+ declare -f t _comp_finalize
891929
892930# Initialize completion and deal with various general things: do file
893931# and variable completion where appropriate, and adjust prev, words,
@@ -908,7 +946,28 @@ _init_completion()
908946{
909947 local exclude=" " flag outx errx inx OPTIND=1
910948
911- trap _comp_return_hook RETURN
949+ if (( ${# FUNCNAME[@]} >= 2 )) ; then
950+ # Install "_comp_finalize" to the RETURN trap when "_init_completion" is
951+ # called for the top-level completion. [ Note: the completion function may
952+ # be called recursively using "_command_offset", etc. ]
953+ if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
954+ if shopt -q extdebug || shopt -qo functrace; then
955+ # If extdebug / functrace is set, we need to explicitly save and
956+ # restore the original trap handler because the outer trap handlers
957+ # will be affected by "trap - RETURN" inside functions with these
958+ # settings.
959+ _comp_finalize__original_return_trap=$( trap -p RETURN)
960+ else
961+ # Otherwise, the outer RETURN trap will be restored when the RETURN
962+ # trap is removed inside the functions using "trap - RETURN". So, we
963+ # do not need to explicitly save the outer trap handler.
964+ _comp_finalize__original_return_trap=
965+ fi
966+ trap _comp_finalize RETURN
967+ fi
968+ _comp_finalize__depth+=(" ${# FUNCNAME[@]} " )
969+ _comp_finalize__target+=(" ${FUNCNAME[1]} " )
970+ fi
912971
913972 while getopts " n:e:o:i:s" flag " $@ " ; do
914973 case $flag in
0 commit comments