@@ -887,13 +887,51 @@ _comp_variable_assignments()
887887 return 0
888888}
889889
890- _comp_return_hook ()
891- {
892- (( ${# FUNCNAME[*]} != 2 )) && return # this _will_ need some refinement and thought
893- echo " Hello from return hook for ${FUNCNAME[1]} "
894- echo " words: ${words[@]} "
895- echo " COMPREPLY: ${COMPREPLY[@]} "
890+ _comp_finalize__depth= ()
891+ _comp_finalize__target= ()
892+ _comp_finalize__original_return_trap=
893+
894+ # This associative array contains the finalizer commands with the key
895+ # being the name of the completed command.
896+ declare -g A BASH_COMPLETION_FINALIZE_CMD_HOOKS
897+
898+ # This array contains the general finalizer commands that will be
899+ # executed for all the commands.
900+ declare -g a BASH_COMPLETION_FINALIZE_HOOKS
901+
902+ _comp_finalize ()
903+ {
904+ (( ${# _comp_finalize__depth[@]} )) || return 0
905+ while (( ${# FUNCNAME[@]} <= ${_comp_finalize__depth[-1]} )) ; do
906+ if [[ ${# FUNCNAME[@]} -eq ${_comp_finalize__depth[-1]} && ${FUNCNAME[1]-} == " ${_comp_finalize__target[-1]} " ]]; then
907+ # Call finalizer for each command
908+ local cmd=${words[0]-} _comp_local_hook
909+ if [[ $cmd ]]; then
910+ _comp_local_hook=${BASH_COMPLETION_FINALIZE_CMD_HOOKS[$cmd]-}
911+ eval -- " $_comp_local_hook "
912+ fi
913+
914+ # Call general finalizers
915+ if [[ ${BASH_COMPLETION_FINALIZE_HOOKS[*]+set} ]]; then
916+ for _comp_local_hook in " ${BASH_COMPLETION_FINALIZE_HOOKS[@]} " ; do
917+ eval -- " $_comp_local_hook "
918+ done
919+ fi
920+ fi
921+
922+ unset -v ' _comp_finalize__depth[-1]'
923+ unset -v ' _comp_finalize__target[-1]'
924+ if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
925+ eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
926+ _comp_finalize__original_return_trap=
927+ break
928+ fi
929+ done
896930}
931+ # Note: We need to set "trace" function attribute of _comp_finalize to
932+ # make the trap restoration by "trap - RETURN" take effect in the
933+ # upper level.
934+ declare -f t _comp_finalize
897935
898936# Initialize completion and deal with various general things: do file
899937# and variable completion where appropriate, and adjust prev, words,
@@ -928,7 +966,28 @@ _comp_initialize()
928966{
929967 local exclude=" " outx errx inx
930968
931- trap _comp_return_hook RETURN
969+ if (( ${# FUNCNAME[@]} >= 2 )) ; then
970+ # Install "_comp_finalize" to the RETURN trap when "_init_completion" is
971+ # called for the top-level completion. [ Note: the completion function may
972+ # be called recursively using "_command_offset", etc. ]
973+ if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
974+ if shopt -q extdebug || shopt -qo functrace; then
975+ # If extdebug / functrace is set, we need to explicitly save and
976+ # restore the original trap handler because the outer trap handlers
977+ # will be affected by "trap - RETURN" inside functions with these
978+ # settings.
979+ _comp_finalize__original_return_trap=$( trap -p RETURN)
980+ else
981+ # Otherwise, the outer RETURN trap will be restored when the RETURN
982+ # trap is removed inside the functions using "trap - RETURN". So, we
983+ # do not need to explicitly save the outer trap handler.
984+ _comp_finalize__original_return_trap=
985+ fi
986+ trap _comp_finalize RETURN
987+ fi
988+ _comp_finalize__depth+=(" ${# FUNCNAME[@]} " )
989+ _comp_finalize__target+=(" ${FUNCNAME[1]-} " )
990+ fi
932991
933992 local flag OPTIND=1 OPTARG=" " OPTERR=0
934993 while getopts " n:e:o:i:s" flag " $@ " ; do
0 commit comments