Skip to content

Commit 3c7a9cf

Browse files
committed
feat(bash_completion): support BASH_COMPLETION_FINALIZE{,_CMD}_HOOKS
- deal with nested completion initializations - rename the function `_comp_{return_hook => finalize}` - add an associative array `BASH_COMPLETION_FINALIZE_CMD_HOOKS` originally suggested as `_comp_return_hooks` in Ref. [1] - add a new array `BASH_COMPLETION_FINALIZE_HOOKS` [1] #720 (comment)
1 parent 8d46e6f commit 3c7a9cf

File tree

1 file changed

+66
-7
lines changed

1 file changed

+66
-7
lines changed

bash_completion

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,13 +1485,51 @@ _comp_variable_assignments()
14851485
return 0
14861486
}
14871487

1488-
_comp_return_hook()
1489-
{
1490-
((${#FUNCNAME[*]} != 2)) && return # this _will_ need some refinement and thought
1491-
echo "Hello from return hook for ${FUNCNAME[1]}"
1492-
echo "words: ${words[@]}"
1493-
echo "COMPREPLY: ${COMPREPLY[@]}"
1488+
_comp_finalize__depth=()
1489+
_comp_finalize__target=()
1490+
_comp_finalize__original_return_trap=
1491+
1492+
# This associative array contains the finalizer commands with the key
1493+
# being the name of the completed command.
1494+
declare -gA BASH_COMPLETION_FINALIZE_CMD_HOOKS
1495+
1496+
# This array contains the general finalizer commands that will be
1497+
# executed for all the commands.
1498+
declare -ga BASH_COMPLETION_FINALIZE_HOOKS
1499+
1500+
_comp_finalize()
1501+
{
1502+
((${#_comp_finalize__depth[@]})) || return 0
1503+
while ((${#FUNCNAME[@]} <= ${_comp_finalize__depth[-1]})); do
1504+
if [[ ${#FUNCNAME[@]} -eq ${_comp_finalize__depth[-1]} && ${FUNCNAME[1]-} == "${_comp_finalize__target[-1]}" ]]; then
1505+
# Call finalizer for each command
1506+
local cmd=${words[0]-} _comp_local_hook
1507+
if [[ $cmd ]]; then
1508+
_comp_local_hook=${BASH_COMPLETION_FINALIZE_CMD_HOOKS[$cmd]-}
1509+
eval -- "$_comp_local_hook"
1510+
fi
1511+
1512+
# Call general finalizers
1513+
if [[ ${BASH_COMPLETION_FINALIZE_HOOKS[*]+set} ]]; then
1514+
for _comp_local_hook in "${BASH_COMPLETION_FINALIZE_HOOKS[@]}"; do
1515+
eval -- "$_comp_local_hook"
1516+
done
1517+
fi
1518+
fi
1519+
1520+
unset -v '_comp_finalize__depth[-1]'
1521+
unset -v '_comp_finalize__target[-1]'
1522+
if ((${#_comp_finalize__depth[@]} == 0)); then
1523+
eval -- "${_comp_finalize__original_return_trap:-trap - RETURN}"
1524+
_comp_finalize__original_return_trap=
1525+
break
1526+
fi
1527+
done
14941528
}
1529+
# Note: We need to set "trace" function attribute of _comp_finalize to
1530+
# make the trap restoration by "trap - RETURN" take effect in the
1531+
# upper level.
1532+
declare -ft _comp_finalize
14951533

14961534
# Initialize completion and deal with various general things: do file
14971535
# and variable completion where appropriate, and adjust prev, words,
@@ -1530,7 +1568,28 @@ _comp_initialize()
15301568
{
15311569
local exclude="" opt_split="" outx="" errx="" inx=""
15321570

1533-
trap _comp_return_hook RETURN
1571+
if ((${#FUNCNAME[@]} >= 2)); then
1572+
# Install "_comp_finalize" to the RETURN trap when "_init_completion" is
1573+
# called for the top-level completion. [ Note: the completion function may
1574+
# be called recursively using "_command_offset", etc. ]
1575+
if ((${#_comp_finalize__depth[@]} == 0)); then
1576+
if shopt -q extdebug || shopt -qo functrace; then
1577+
# If extdebug / functrace is set, we need to explicitly save and
1578+
# restore the original trap handler because the outer trap handlers
1579+
# will be affected by "trap - RETURN" inside functions with these
1580+
# settings.
1581+
_comp_finalize__original_return_trap=$(trap -p RETURN)
1582+
else
1583+
# Otherwise, the outer RETURN trap will be restored when the RETURN
1584+
# trap is removed inside the functions using "trap - RETURN". So, we
1585+
# do not need to explicitly save the outer trap handler.
1586+
_comp_finalize__original_return_trap=
1587+
fi
1588+
trap _comp_finalize RETURN
1589+
fi
1590+
_comp_finalize__depth+=("${#FUNCNAME[@]}")
1591+
_comp_finalize__target+=("${FUNCNAME[1]-}")
1592+
fi
15341593

15351594
local flag OPTIND=1 OPTARG="" OPTERR=0
15361595
while getopts "n:e:o:i:s" flag "$@"; do

0 commit comments

Comments
 (0)