mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-18 15:21:16 +02:00
52028: improvements to _shadow / _unshadow, plus helper and doc
This commit is contained in:
parent
97b4a30c4e
commit
2a854aae48
5 changed files with 113 additions and 44 deletions
|
@ -1,5 +1,9 @@
|
||||||
2023-08-27 Bart Schaefer <schaefer@zsh.org>
|
2023-08-27 Bart Schaefer <schaefer@zsh.org>
|
||||||
|
|
||||||
|
* 52028: Completion/Base/Utility/_shadow, Doc/Zsh/compsys.yo,
|
||||||
|
Doc/Zsh/contrib.yo, Functions/Misc/mkshadow: improve _shadow
|
||||||
|
and _unshadow, add helper function and update documentation
|
||||||
|
|
||||||
* Robert Woods: 52053: Src/utils.c: whitelist capability
|
* Robert Woods: 52053: Src/utils.c: whitelist capability
|
||||||
CAP_WAKE_ALARM in 'privasserted' function
|
CAP_WAKE_ALARM in 'privasserted' function
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# }
|
# }
|
||||||
# # Invoke callers of fname
|
# # Invoke callers of fname
|
||||||
# } always {
|
# } always {
|
||||||
# _unshadow fname
|
# _unshadow
|
||||||
# }
|
# }
|
||||||
## Alternate usage:
|
## Alternate usage:
|
||||||
# {
|
# {
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
# }
|
# }
|
||||||
# # Invoke callers of fname
|
# # Invoke callers of fname
|
||||||
# } always {
|
# } always {
|
||||||
# _unshadow -s suffix fname
|
# _unshadow
|
||||||
# }
|
# }
|
||||||
##
|
##
|
||||||
|
|
||||||
|
@ -33,36 +33,62 @@ zmodload zsh/parameter # Or what?
|
||||||
# This probably never comes up, but protect ourself from recursive call
|
# This probably never comes up, but protect ourself from recursive call
|
||||||
# chains that may duplicate the top elements of $funcstack by creating
|
# chains that may duplicate the top elements of $funcstack by creating
|
||||||
# a counter of _shadow calls and using it to make shadow names unique.
|
# a counter of _shadow calls and using it to make shadow names unique.
|
||||||
typeset -gHi _shadowdepth=0
|
builtin typeset -gHi .shadow.depth=0
|
||||||
|
builtin typeset -gHa .shadow.stack
|
||||||
|
|
||||||
# Create a copy of each fname so that a caller may redefine
|
# Create a copy of each fname so that a caller may redefine
|
||||||
_shadow() {
|
_shadow() {
|
||||||
local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:$((_shadowdepth+1)) )
|
emulate -L zsh
|
||||||
local fname
|
local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:$((.shadow.depth+1)) )
|
||||||
|
local fname shadowname
|
||||||
|
local -a fnames
|
||||||
zparseopts -K -A fsfx -D s:
|
zparseopts -K -A fsfx -D s:
|
||||||
for fname; do
|
for fname; do
|
||||||
local shadowname=${fname}@${fsfx[-s]}
|
shadowname=${fname}@${fsfx[-s]}
|
||||||
(( ${+functions[$fname]} )) &&
|
if (( ${+functions[$shadowname]} ))
|
||||||
builtin functions -c $fname $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 -- $shadowname { builtin $fname \"\$@\" }"
|
||||||
|
fnames+=(b@$fname)
|
||||||
|
else
|
||||||
|
eval "function -- $shadowname { command $fname \"\$@\" }"
|
||||||
|
fnames+=(c@$fname)
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
((_shadowdepth++))
|
[[ -z $REPLY ]] && REPLY=${fsfx[-s]}
|
||||||
|
builtin set -A .shadow.stack ${fsfx[-s]} $fnames -- ${.shadow.stack}
|
||||||
|
((.shadow.depth++))
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove the redefined function and shadowing name
|
# Remove the redefined function and shadowing name
|
||||||
_unshadow() {
|
_unshadow() {
|
||||||
local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:${_shadowdepth} )
|
emulate -L zsh
|
||||||
local fname
|
local fname shadowname fsfx=${.shadow.stack[1]}
|
||||||
zparseopts -K -A fsfx -D s:
|
local -a fnames
|
||||||
for fname; do
|
[[ -n $fsfx ]] || return 1
|
||||||
local shadowname=${fname}@${fsfx[-s]}
|
shift .shadow.stack
|
||||||
if (( ${+functions[$shadowname]} )); then
|
while [[ ${.shadow.stack[1]?no shadows} != -- ]]; do
|
||||||
builtin functions -c $shadowname $fname
|
fname=${.shadow.stack[1]#?@}
|
||||||
builtin unfunction $shadowname
|
shadowname=${fname}@${fsfx}
|
||||||
elif (( ${+functions[$fname]} )); then
|
if (( ${+functions[$fname]} )); then
|
||||||
builtin unfunction $fname
|
builtin unfunction -- $fname
|
||||||
fi
|
fi
|
||||||
|
case ${.shadow.stack[1]} in
|
||||||
|
(f@*) builtin functions -c -- $shadowname $fname ;&
|
||||||
|
([bc]@*) builtin unfunction -- $shadowname ;;
|
||||||
|
esac
|
||||||
|
shift .shadow.stack
|
||||||
done
|
done
|
||||||
((_shadowdepth--))
|
[[ -z $REPLY ]] && REPLY=$fsfx
|
||||||
|
shift .shadow.stack
|
||||||
|
((.shadow.depth--))
|
||||||
}
|
}
|
||||||
|
|
||||||
# This is tricky. When we call _shadow recursively from autoload,
|
# This is tricky. When we call _shadow recursively from autoload,
|
||||||
|
|
|
@ -5229,13 +5229,12 @@ and hence is not normally called explicitly.
|
||||||
)
|
)
|
||||||
findex(_shadow)
|
findex(_shadow)
|
||||||
findex(_unshadow)
|
findex(_unshadow)
|
||||||
xitem(tt(_shadow) [ tt(-s) var(suffix) ] var(command_name) ...)
|
xitem(tt(_shadow) [ tt(-s) var(suffix) ] [ -- ] var(command_name) ...)
|
||||||
item(tt(_unshadow) [ tt(-s) var(suffix) ] var(command_name) ...)(
|
item(tt(_unshadow))(
|
||||||
The tt(_shadow) function creates a copy of each of the shell functions
|
The tt(_shadow) function creates a copy of each of the shell functions
|
||||||
in the var(command_name) arguments. The original functions can then
|
in the var(command_name) arguments. The original functions can then
|
||||||
be replaced by new implementations. A later call to tt(_unshadow),
|
be replaced by new implementations. A later call to tt(_unshadow)
|
||||||
with the same var(command_name) list, removes the new implementations,
|
removes the new implementations, if any, and restores the originals.
|
||||||
if any, and restores the originals.
|
|
||||||
|
|
||||||
Recommended usage is to pair tt(_shadow) and tt(_unshadow) calls by
|
Recommended usage is to pair tt(_shadow) and tt(_unshadow) calls by
|
||||||
use of an `tt(always)' block:
|
use of an `tt(always)' block:
|
||||||
|
@ -5246,30 +5245,38 @@ example({
|
||||||
}
|
}
|
||||||
# Invoke callers of fname
|
# Invoke callers of fname
|
||||||
} always {
|
} always {
|
||||||
_unshadow fname
|
_unshadow
|
||||||
})
|
|
||||||
|
|
||||||
Any var(command_name) may instead be a builtin, but in that case no
|
|
||||||
copy is created. The expectation is that an initial tt(_shadow) is
|
|
||||||
followed by creating a wrapper function, and therafter any nested or
|
|
||||||
recursive calls thus copy and replace the wrapper function.
|
|
||||||
example({
|
|
||||||
_shadow compadd
|
|
||||||
compadd LPAR()RPAR() { builtin compadd -O tmparr "$@" }
|
|
||||||
} always {
|
|
||||||
_unshadow compadd
|
|
||||||
})
|
})
|
||||||
|
|
||||||
The var(suffix), if supplied, is prepended by an `tt(@)' character and
|
The var(suffix), if supplied, is prepended by an `tt(@)' character and
|
||||||
then appended to each var(command_name) to create the copy. Thus
|
then appended to each var(command_name) to create the copy. Thus
|
||||||
example(_shadow -s XX foo)
|
example(_shadow -s XX foo)
|
||||||
creates a function named `tt(foo@XX)' (unless `tt(foo)' is a builtin).
|
creates a function named `tt(foo@XX)'. This provides a well-known
|
||||||
Note that a nested call to tt(_shadow) with the same var(suffix) may
|
name for the original implementation if the new implementation needs
|
||||||
result in name collisions and unexpected results, but this provides a
|
to call it as a wrapper. If a nested call to tt(_shadow) uses the
|
||||||
well-known name for the original function if the new implementation
|
same var(suffix), em(no new copy is made). The presumption thus is
|
||||||
needs to call it as a wrapper. The same var(suffix) must be used in
|
that suffixes and new implementations correspond one to one.
|
||||||
the call to tt(_unshadow). When no var(suffix) is present,
|
|
||||||
tt(_shadow) creates a unique suffix to avoid name collisions.
|
If var(command_name) is a builtin or external command, and there has been
|
||||||
|
no preceding tt(_shadow) replacement made, the function so created calls
|
||||||
|
the shadowed name prefixed by the tt(builtin) or tt(command) keywords as
|
||||||
|
appropriate.
|
||||||
|
example({
|
||||||
|
_shadow -s wrap compadd
|
||||||
|
compadd LPAR()RPAR() {
|
||||||
|
# compadd@wrap runs builtin compadd
|
||||||
|
compadd@wrap -O tmparr "$@" }
|
||||||
|
} always {
|
||||||
|
_unshadow
|
||||||
|
})
|
||||||
|
|
||||||
|
When no var(suffix) argument is present, tt(_shadow) creates a unique
|
||||||
|
suffix to avoid name collisions.
|
||||||
|
|
||||||
|
Arguments of tt(_unshadow) are ignored. Every listed var(command_name)
|
||||||
|
for the most recent call to tt(_shadow) is removed. This differs from
|
||||||
|
an early implementation that required tt(_unshadow) to receive the
|
||||||
|
same var(suffix) and var(command_name) list as tt(_shadow).
|
||||||
)
|
)
|
||||||
findex(_store_cache)
|
findex(_store_cache)
|
||||||
item(tt(_store_cache) var(cache_identifier) var(param) ...)(
|
item(tt(_store_cache) var(cache_identifier) var(param) ...)(
|
||||||
|
|
|
@ -4336,6 +4336,27 @@ example(is-at-least 3.1.6-15 && setopt NO_GLOBAL_RCS
|
||||||
is-at-least 3.1.0 && setopt HIST_REDUCE_BLANKS
|
is-at-least 3.1.0 && setopt HIST_REDUCE_BLANKS
|
||||||
is-at-least 2.6-17 || print "You can't use is-at-least here.")
|
is-at-least 2.6-17 || print "You can't use is-at-least here.")
|
||||||
)
|
)
|
||||||
|
findex(mkshadow)
|
||||||
|
findex(rmshadow)
|
||||||
|
xitem(tt(mkshadow) [ tt(-s) var(suffix) ] [ -- ] var(command_name) ...)
|
||||||
|
item(tt(rmshadow))(
|
||||||
|
These functions are an interface to the tt(_shadow) and tt(_unshadow)
|
||||||
|
completion utilities to make them more easily accessible in other
|
||||||
|
contexts. Usage is exactly as for the completion utility:
|
||||||
|
example({
|
||||||
|
mkshadow fname
|
||||||
|
function fname {
|
||||||
|
# Do your new thing
|
||||||
|
}
|
||||||
|
# Invoke callers of fname
|
||||||
|
} always {
|
||||||
|
rmshadow
|
||||||
|
})
|
||||||
|
|
||||||
|
Upon return, the value of tt($REPLY) is the suffix used to create a
|
||||||
|
copy of the original var(command_name), so var(command_name)tt(@$REPLY)
|
||||||
|
invokes that original.
|
||||||
|
)
|
||||||
findex(nslookup)
|
findex(nslookup)
|
||||||
item(tt(nslookup) [ var(arg) ... ])(
|
item(tt(nslookup) [ var(arg) ... ])(
|
||||||
This wrapper function for the tt(nslookup) command requires the
|
This wrapper function for the tt(nslookup) command requires the
|
||||||
|
|
11
Functions/Misc/mkshadow
Normal file
11
Functions/Misc/mkshadow
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#autoload
|
||||||
|
# Front-end to the completion helper _shadow for use outside completion.
|
||||||
|
# This just forces proper autoload of _shadow/_unshadow and calls them.
|
||||||
|
|
||||||
|
autoload _shadow
|
||||||
|
mkshadow() { unset REPLY; _shadow "$@" }
|
||||||
|
rmshadow() { unset REPLY; _unshadow }
|
||||||
|
|
||||||
|
# Bootstrap because of autoload special case
|
||||||
|
unset REPLY
|
||||||
|
_shadow "$@"
|
Loading…
Reference in a new issue