summaryrefslogtreecommitdiff
path: root/Completion/Base/Utility
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Base/Utility')
-rw-r--r--Completion/Base/Utility/_as_if10
-rw-r--r--Completion/Base/Utility/_numbers2
-rw-r--r--Completion/Base/Utility/_shadow97
3 files changed, 108 insertions, 1 deletions
diff --git a/Completion/Base/Utility/_as_if b/Completion/Base/Utility/_as_if
new file mode 100644
index 000000000..c961aaa88
--- /dev/null
+++ b/Completion/Base/Utility/_as_if
@@ -0,0 +1,10 @@
+#autoload
+local words=("$words[@]") CURRENT=$CURRENT
+local _comp_command1 _comp_command2 _comp_command
+
+words[1]=("$@")
+(( CURRENT += $# - 1 ))
+
+_set_command
+
+_dispatch "$_comp_command" "$_comp_command1" "$_comp_command2" -default-
diff --git a/Completion/Base/Utility/_numbers b/Completion/Base/Utility/_numbers
index 97bb8b4c8..069fc75a4 100644
--- a/Completion/Base/Utility/_numbers
+++ b/Completion/Base/Utility/_numbers
@@ -73,7 +73,7 @@ elif [[ -prefix $~pat || $PREFIX = $~partial ]]; then
zformat -f suffix "$suffixfmt" "x:${${argv[i+1]#:}%%:*}" \
"X:${${argv[i+1]#:}#*:}" "d:${#${argv[i+1]}[1]#:}" \
i:i r:$(( $# - i - 1))
- suffixes+="$suffix"
+ suffixes+="${suffix//\%/%%}"
done
[[ -n $suffixes ]] && formats+=( x:$suffixes )
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 "$@"