@@ -902,13 +902,51 @@ _comp_variable_assignments()
902902 return 0
903903}
904904
905- _comp_return_hook ()
906- {
907- (( ${# FUNCNAME[*]} != 2 )) && return # this _will_ need some refinement and thought
908- echo " Hello from return hook for ${FUNCNAME[1]} "
909- echo " words: ${words[@]} "
910- echo " COMPREPLY: ${COMPREPLY[@]} "
905+ _comp_finalize__depth= ()
906+ _comp_finalize__target= ()
907+ _comp_finalize__original_return_trap=
908+
909+ # This associative array contains the finalizer commands with the key
910+ # being the name of the completed command.
911+ declare -g A BASH_COMPLETION_FINALIZE_CMD_HOOKS
912+
913+ # This array contains the general finalizer commands that will be
914+ # executed for all the commands.
915+ declare -g a BASH_COMPLETION_FINALIZE_HOOKS
916+
917+ _comp_finalize ()
918+ {
919+ (( ${# _comp_finalize__depth[@]} )) || return 0
920+ while (( ${# FUNCNAME[@]} <= ${_comp_finalize__depth[-1]} )) ; do
921+ if [[ ${# FUNCNAME[@]} -eq ${_comp_finalize__depth[-1]} && ${FUNCNAME[1]-} == " ${_comp_finalize__target[-1]} " ]]; then
922+ # Call finalizer for each command
923+ local cmd=${words[0]-} _comp_local_hook
924+ if [[ $cmd ]]; then
925+ _comp_local_hook=${BASH_COMPLETION_FINALIZE_CMD_HOOKS[$cmd]-}
926+ eval -- " $_comp_local_hook "
927+ fi
928+
929+ # Call general finalizers
930+ if [[ ${BASH_COMPLETION_FINALIZE_HOOKS[*]+set} ]]; then
931+ for _comp_local_hook in " ${BASH_COMPLETION_FINALIZE_HOOKS[@]} " ; do
932+ eval -- " $_comp_local_hook "
933+ done
934+ fi
935+ fi
936+
937+ unset -v ' _comp_finalize__depth[-1]'
938+ unset -v ' _comp_finalize__target[-1]'
939+ if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
940+ eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
941+ _comp_finalize__original_return_trap=
942+ break
943+ fi
944+ done
911945}
946+ # Note: We need to set "trace" function attribute of _comp_finalize to
947+ # make the trap restoration by "trap - RETURN" take effect in the
948+ # upper level.
949+ declare -f t _comp_finalize
912950
913951# Initialize completion and deal with various general things: do file
914952# and variable completion where appropriate, and adjust prev, words,
@@ -943,7 +981,28 @@ _comp_initialize()
943981{
944982 local exclude=" " outx errx inx
945983
946- trap _comp_return_hook RETURN
984+ if (( ${# FUNCNAME[@]} >= 2 )) ; then
985+ # Install "_comp_finalize" to the RETURN trap when "_init_completion" is
986+ # called for the top-level completion. [ Note: the completion function may
987+ # be called recursively using "_command_offset", etc. ]
988+ if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
989+ if shopt -q extdebug || shopt -qo functrace; then
990+ # If extdebug / functrace is set, we need to explicitly save and
991+ # restore the original trap handler because the outer trap handlers
992+ # will be affected by "trap - RETURN" inside functions with these
993+ # settings.
994+ _comp_finalize__original_return_trap=$( trap -p RETURN)
995+ else
996+ # Otherwise, the outer RETURN trap will be restored when the RETURN
997+ # trap is removed inside the functions using "trap - RETURN". So, we
998+ # do not need to explicitly save the outer trap handler.
999+ _comp_finalize__original_return_trap=
1000+ fi
1001+ trap _comp_finalize RETURN
1002+ fi
1003+ _comp_finalize__depth+=(" ${# FUNCNAME[@]} " )
1004+ _comp_finalize__target+=(" ${FUNCNAME[1]-} " )
1005+ fi
9471006
9481007 local flag OPTIND=1 OPTARG=' ' OPTERR=0
9491008 while getopts " n:e:o:i:s" flag " $@ " ; do
0 commit comments