@@ -974,13 +974,51 @@ _comp_variable_assignments()
974974 return 0
975975}
976976
977- _comp_return_hook ()
978- {
979- (( ${# FUNCNAME[*]} != 2 )) && return # this _will_ need some refinement and thought
980- echo " Hello from return hook for ${FUNCNAME[1]} "
981- echo " words: ${words[@]} "
982- echo " COMPREPLY: ${COMPREPLY[@]} "
977+ _comp_finalize__depth= ()
978+ _comp_finalize__target= ()
979+ _comp_finalize__original_return_trap=
980+
981+ # This associative array contains the finalizer commands with the key
982+ # being the name of the completed command.
983+ declare -g A BASH_COMPLETION_FINALIZE_CMD_HOOKS
984+
985+ # This array contains the general finalizer commands that will be
986+ # executed for all the commands.
987+ declare -g a BASH_COMPLETION_FINALIZE_HOOKS
988+
989+ _comp_finalize ()
990+ {
991+ (( ${# _comp_finalize__depth[@]} )) || return 0
992+ while (( ${# FUNCNAME[@]} <= ${_comp_finalize__depth[-1]} )) ; do
993+ if [[ ${# FUNCNAME[@]} -eq ${_comp_finalize__depth[-1]} && ${FUNCNAME[1]-} == " ${_comp_finalize__target[-1]} " ]]; then
994+ # Call finalizer for each command
995+ local cmd=${words[0]-} _comp_local_hook
996+ if [[ $cmd ]]; then
997+ _comp_local_hook=${BASH_COMPLETION_FINALIZE_CMD_HOOKS[$cmd]-}
998+ eval -- " $_comp_local_hook "
999+ fi
1000+
1001+ # Call general finalizers
1002+ if [[ ${BASH_COMPLETION_FINALIZE_HOOKS[*]+set} ]]; then
1003+ for _comp_local_hook in " ${BASH_COMPLETION_FINALIZE_HOOKS[@]} " ; do
1004+ eval -- " $_comp_local_hook "
1005+ done
1006+ fi
1007+ fi
1008+
1009+ unset -v ' _comp_finalize__depth[-1]'
1010+ unset -v ' _comp_finalize__target[-1]'
1011+ if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
1012+ eval -- " ${_comp_finalize__original_return_trap:- trap - RETURN} "
1013+ _comp_finalize__original_return_trap=
1014+ break
1015+ fi
1016+ done
9831017}
1018+ # Note: We need to set "trace" function attribute of _comp_finalize to
1019+ # make the trap restoration by "trap - RETURN" take effect in the
1020+ # upper level.
1021+ declare -f t _comp_finalize
9841022
9851023# Initialize completion and deal with various general things: do file
9861024# and variable completion where appropriate, and adjust prev, words,
@@ -1001,7 +1039,28 @@ _init_completion()
10011039{
10021040 local exclude=" " flag outx errx inx OPTIND=1
10031041
1004- trap _comp_return_hook RETURN
1042+ if (( ${# FUNCNAME[@]} >= 2 )) ; then
1043+ # Install "_comp_finalize" to the RETURN trap when "_init_completion" is
1044+ # called for the top-level completion. [ Note: the completion function may
1045+ # be called recursively using "_command_offset", etc. ]
1046+ if (( ${# _comp_finalize__depth[@]} == 0 )) ; then
1047+ if shopt -q extdebug || shopt -qo functrace; then
1048+ # If extdebug / functrace is set, we need to explicitly save and
1049+ # restore the original trap handler because the outer trap handlers
1050+ # will be affected by "trap - RETURN" inside functions with these
1051+ # settings.
1052+ _comp_finalize__original_return_trap=$( trap -p RETURN)
1053+ else
1054+ # Otherwise, the outer RETURN trap will be restored when the RETURN
1055+ # trap is removed inside the functions using "trap - RETURN". So, we
1056+ # do not need to explicitly save the outer trap handler.
1057+ _comp_finalize__original_return_trap=
1058+ fi
1059+ trap _comp_finalize RETURN
1060+ fi
1061+ _comp_finalize__depth+=(" ${# FUNCNAME[@]} " )
1062+ _comp_finalize__target+=(" ${FUNCNAME[1]-} " )
1063+ fi
10051064
10061065 while getopts " n:e:o:i:s" flag " $@ " ; do
10071066 case $flag in
0 commit comments