From a99f96797f5fc424554a94313dfc0d4a5b0923a1 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 4 Jun 2022 14:19:42 -0700 Subject: 50323: create helper for shadowing builtins or existing functions and use it when redefining compadd et al. --- ChangeLog | 7 ++++ Completion/Base/Utility/_shadow | 71 +++++++++++++++++++++++++++++++++++ Completion/Base/Widget/_complete_help | 3 +- Functions/Zle/keeper | 3 +- 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 Completion/Base/Utility/_shadow diff --git a/ChangeLog b/ChangeLog index 839beb4f9..5490385f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2022-06-04 Bart Schaefer + + * 50323: Completion/Base/Utility/_shadow (new file), + Completion/Base/Widget/_complete_help, Functions/Zle/keeper: + create helper for shadowing builtins or existing functions and + use it when redefining compadd et al. + 2022-06-03 Jun-ichi Takimoto * 50306: Src/jobs.c, Src/signals.c, Test/A05execution.ztst: fix diff --git a/Completion/Base/Utility/_shadow b/Completion/Base/Utility/_shadow new file mode 100644 index 000000000..5b0f79c36 --- /dev/null +++ b/Completion/Base/Utility/_shadow @@ -0,0 +1,71 @@ +#autoload + +## Recommended usage: +# { +# _shadow fname +# function fname { +# # Do your new thing +# } +# # Invoke callers of fname +# } always { +# _unshadow fname +# } +## Alternate usage: +# { +# _shadow -s suffix fname +# function fname { +# # Do other stuff +# fname@suffix new args for fname +# } +# # Invoke callers of fname +# } always { +# _unshadow -s suffix fname +# } +## + +# BUGS: +# * `functions -c` acts like `autoload +X` +# * name collisions are possible in alternate usage +# * functions that examine $0 probably misfire + +zmodload zsh/parameter # Or what? + +# This probably never comes up, but protect ourself from recursive call +# chains that may duplicate the top elements of $funcstack by creating +# a counter of _shadow calls and using it to make shadow names unique. +typeset -gHi _shadowdepth=0 + +# Create a copy of each fname so that a caller may redefine +_shadow() { + local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:$((_shadowdepth+1)) ) + local fname + zparseopts -K -A fsfx -D s: + for fname; do + local shadowname=${fname}@${fsfx[-s]} + (( ${+functions[$fname]} )) && + builtin functions -c $fname $shadowname + done + ((_shadowdepth++)) +} + +# Remove the redefined function and shadowing name +_unshadow() { + local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:${_shadowdepth} ) + local fname + zparseopts -K -A fsfx -D s: + for fname; do + local shadowname=${fname}@${fsfx[-s]} + if (( ${+functions[$shadowname]} )); then + builtin functions -c $shadowname $fname + builtin unfunction $shadowname + elif (( ${+functions[$fname]} )); then + builtin unfunction $fname + fi + done + ((_shadowdepth--)) +} + +# This is tricky. When we call _shadow recursively from autoload, +# there's an extra level of stack in $functrace that will confuse +# the later call to _unshadow. Fool ourself into working correctly. +(( ARGC )) && _shadow -s ${funcstack[2]}:${functrace[2]}:1 "$@" diff --git a/Completion/Base/Widget/_complete_help b/Completion/Base/Widget/_complete_help index 69855de9d..da5947e7f 100644 --- a/Completion/Base/Widget/_complete_help +++ b/Completion/Base/Widget/_complete_help @@ -10,6 +10,7 @@ _complete_help() { local -H _help_filter_funcstack="alternative|call_function|describe|dispatch|wanted|requested|all_labels|next_label" { + _shadow compadd compcall zstyle compadd() { return 1 } compcall() { _help_sort_tags use-compctl } zstyle() { @@ -43,7 +44,7 @@ _complete_help() { ${1:-_main_complete} } always { - unfunction compadd compcall zstyle + _unshadow compadd compcall zstyle } for i in "${(@ok)help_funcs}"; do diff --git a/Functions/Zle/keeper b/Functions/Zle/keeper index a40125771..1570eb94a 100644 --- a/Functions/Zle/keeper +++ b/Functions/Zle/keeper @@ -73,6 +73,7 @@ zstyle ':completion:expand-kept-result:*' completer _insert_kept _expand_word_and_keep() { { + _shadow compadd function compadd { local -A args zparseopts -E -A args J: @@ -85,7 +86,7 @@ _expand_word_and_keep() { } _expand_word } always { - unfunction compadd + _unshadow compadd } } -- cgit 1.4.1