about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBart Schaefer <schaefer@zsh.org>2022-06-04 14:19:42 -0700
committerBart Schaefer <schaefer@zsh.org>2022-06-04 14:19:42 -0700
commita99f96797f5fc424554a94313dfc0d4a5b0923a1 (patch)
tree5cb7d78e59fb24c5ae8ab5f2c1579da279df73b8
parent3e3cfabcc74dc79d4d8717c4e5859d8d01be6c54 (diff)
downloadzsh-a99f96797f5fc424554a94313dfc0d4a5b0923a1.tar.gz
zsh-a99f96797f5fc424554a94313dfc0d4a5b0923a1.tar.xz
zsh-a99f96797f5fc424554a94313dfc0d4a5b0923a1.zip
50323: create helper for shadowing builtins or existing functions and use it when redefining compadd et al.
-rw-r--r--ChangeLog7
-rw-r--r--Completion/Base/Utility/_shadow71
-rw-r--r--Completion/Base/Widget/_complete_help3
-rw-r--r--Functions/Zle/keeper3
4 files changed, 82 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 839beb4f9..5490385f7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2022-06-04  Bart Schaefer  <schaefer@zsh.org>
+
+	* 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  <takimoto-j@kba.biglobe.ne.jp>
 
 	* 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
     }
 }