diff options
author | Joe Rayhawk <jrayhawk@fairlystable.org> | 2025-04-30 02:07:56 -0700 |
---|---|---|
committer | Joe Rayhawk <jrayhawk@fairlystable.org> | 2025-04-30 02:07:56 -0700 |
commit | 26e09889646be3ea65b4a3dfeda26213e4bb6a27 (patch) | |
tree | 4f3c73a9416bf47ad7e125383d23cf42879e38d7 /Completion/Base/Utility/_shadow | |
parent | 841bce705a58b04220b1f257abcc00ae71cbdbdc (diff) | |
parent | 001cba48ce3b964cf01fb3e2af54b20eacbc9bf5 (diff) | |
download | zsh-26e09889646be3ea65b4a3dfeda26213e4bb6a27.tar.gz zsh-26e09889646be3ea65b4a3dfeda26213e4bb6a27.zip |
Merge branch 'upstream' into debian
Diffstat (limited to 'Completion/Base/Utility/_shadow')
-rw-r--r-- | Completion/Base/Utility/_shadow | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/Completion/Base/Utility/_shadow b/Completion/Base/Utility/_shadow new file mode 100644 index 000000000..9e78af38f --- /dev/null +++ b/Completion/Base/Utility/_shadow @@ -0,0 +1,97 @@ +#autoload + +## Recommended usage: +# { +# _shadow fname +# function fname { +# # Do your new thing +# } +# # Invoke callers of fname +# } always { +# _unshadow +# } +## Alternate usage: +# { +# _shadow -s suffix fname +# function fname { +# # Do other stuff +# fname@suffix new args for fname +# } +# # Invoke callers of fname +# } always { +# _unshadow +# } +## + +# 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. +builtin typeset -gHi .shadow.depth=0 +builtin typeset -gHa .shadow.stack + +# Create a copy of each fname so that a caller may redefine +_shadow() { + emulate -L zsh + local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:$((.shadow.depth+1)) ) + local fname shadowname + local -a fnames + zparseopts -K -A fsfx -D s: + for fname; do + shadowname=${fname}@${fsfx[-s]} + if (( ${+functions[$shadowname]} )) + then + # Called again with the same -s, just ignore it + continue + elif (( ${+functions[$fname]} )) + then + builtin functions -c -- $fname $shadowname + fnames+=(f@$fname) + elif (( ${+builtins[$fname]} )) + then + eval "function -- ${(q-)shadowname} { builtin ${(q-)fname} \"\$@\" }" + fnames+=(b@$fname) + else + eval "function -- ${(q-)shadowname} { command ${(q-)fname} \"\$@\" }" + fnames+=(c@$fname) + fi + done + [[ -z $REPLY ]] && REPLY=${fsfx[-s]} + builtin set -A .shadow.stack ${fsfx[-s]} $fnames -- ${.shadow.stack} + ((.shadow.depth++)) +} + +# Remove the redefined function and shadowing name +_unshadow() { + emulate -L zsh + local fname shadowname fsfx=${.shadow.stack[1]} + local -a fnames + [[ -n $fsfx ]] || return 1 + shift .shadow.stack + while [[ ${.shadow.stack[1]?no shadows} != -- ]]; do + fname=${.shadow.stack[1]#?@} + shadowname=${fname}@${fsfx} + if (( ${+functions[$fname]} )); then + builtin unfunction -- $fname + fi + case ${.shadow.stack[1]} in + (f@*) builtin functions -c -- $shadowname $fname ;& + ([bc]@*) builtin unfunction -- $shadowname ;; + esac + shift .shadow.stack + done + [[ -z $REPLY ]] && REPLY=$fsfx + shift .shadow.stack + ((.shadow.depth--)) +} + +# 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 "$@" |