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