From a4f13aec98a827dc63199da217d104c4daa0ceeb Mon Sep 17 00:00:00 2001 From: Mahesh Subramanian Date: Mon, 27 Apr 2026 12:53:33 -0700 Subject: [PATCH] fix(z): prevent stack overflow from recursive Tab binding on re-source The ZLE widget added in #13710 saves the current Tab binding and delegates to it. If the plugin is sourced more than once, the saved binding points to the widget itself, causing infinite recursion and "maximum nested function level reached" errors on any Tab press. Guard against self-reference by only capturing the binding on first load and falling back to expand-or-complete if the saved value is our own widget. Fixes #13714 Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/z/z.plugin.zsh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/plugins/z/z.plugin.zsh b/plugins/z/z.plugin.zsh index 456802d3d..6509d8817 100644 --- a/plugins/z/z.plugin.zsh +++ b/plugins/z/z.plugin.zsh @@ -960,8 +960,15 @@ add-zsh-hook chpwd _zshz_chpwd (( ${fpath[(ie)${0:A:h}]} <= ${#fpath} )) || fpath=( "${0:A:h}" "${fpath[@]}" ) -# Save the existing Tab binding -ZSHZ[TAB_BINDING]="${$(bindkey -M main '^I')##* }" +# Save the existing Tab binding (only on first load to avoid self-reference +# if the plugin is sourced more than once) +if [[ -z ${ZSHZ[TAB_BINDING]} ]] || \ + [[ ${ZSHZ[TAB_BINDING]} == _zshz_zle_completion_widget ]]; then + ZSHZ[TAB_BINDING]="${$(bindkey -M main '^I')##* }" + # If we somehow captured our own widget (race condition), fall back to default + [[ ${ZSHZ[TAB_BINDING]} == _zshz_zle_completion_widget ]] && \ + ZSHZ[TAB_BINDING]=expand-or-complete +fi ############################################################ # ZLE widget to fix spaces-as-wildcards completion