From c52c428793fc4ea2326b9ad0860853959b0d2954 Mon Sep 17 00:00:00 2001 From: Eric Freese Date: Tue, 28 Feb 2017 11:14:16 -0700 Subject: [PATCH] Fix issues with widgets wrapped by other plugins Puts in a better fix for #126 and related issues. --- spec/integrations/wrapped_widget_spec.rb | 39 +++++++++++++++++++++++ src/bind.zsh | 40 +++++++++++++++++++----- zsh-autosuggestions.zsh | 40 +++++++++++++++++++----- 3 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 spec/integrations/wrapped_widget_spec.rb diff --git a/spec/integrations/wrapped_widget_spec.rb b/spec/integrations/wrapped_widget_spec.rb new file mode 100644 index 0000000..61dfc2d --- /dev/null +++ b/spec/integrations/wrapped_widget_spec.rb @@ -0,0 +1,39 @@ +describe 'a wrapped widget' do + let(:widget) { 'backward-delete-char' } + + context 'initialized before sourcing the plugin' do + let(:before_sourcing) do + -> do + session. + run_command("_orig_#{widget}() { zle .#{widget} }"). + run_command("zle -N orig-#{widget} _orig_#{widget}"). + run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }"). + run_command("zle -N #{widget} #{widget}-magic") + end + end + + it 'executes the custom behavior and the built-in behavior' do + with_history('foobar', 'foodar') do + session.send_string('food').send_keys('C-h') + wait_for { session.content }.to eq('foobar') + end + end + end + + context 'initialized after sourcing the plugin' do + before do + session. + run_command("zle -N orig-#{widget} ${widgets[#{widget}]#*:}"). + run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }"). + run_command("zle -N #{widget} #{widget}-magic"). + clear_screen + end + + it 'executes the custom behavior and the built-in behavior' do + with_history('foobar', 'foodar') do + session.send_string('food').send_keys('C-h') + wait_for { session.content }.to eq('foobar') + end + end + end +end diff --git a/src/bind.zsh b/src/bind.zsh index e2ca5c9..d8629f1 100644 --- a/src/bind.zsh +++ b/src/bind.zsh @@ -3,12 +3,34 @@ # Widget Helpers # #--------------------------------------------------------------------# +_zsh_autosuggest_incr_bind_count() { + if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then + ((_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]++)) + else + _ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=1 + fi + + bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] +} + +_zsh_autosuggest_get_bind_count() { + if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then + bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] + else + bind_count=0 + fi +} + # Bind a single widget to an autosuggest widget, saving a reference to the original widget _zsh_autosuggest_bind_widget() { + typeset -gA _ZSH_AUTOSUGGEST_BIND_COUNTS + local widget=$1 local autosuggest_action=$2 local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX + local -i bind_count + # Save a reference to the original widget case $widgets[$widget] in # Already bound @@ -16,34 +38,38 @@ _zsh_autosuggest_bind_widget() { # User-defined widget user:*) - zle -l "$prefix$widget" && zle -N "$widget" ${widgets[$prefix$widget]#*:} - zle -N $prefix$widget ${widgets[$widget]#*:} + _zsh_autosuggest_incr_bind_count $widget + zle -N $prefix${bind_count}-$widget ${widgets[$widget]#*:} ;; # Built-in widget builtin) + _zsh_autosuggest_incr_bind_count $widget eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }" - zle -N $prefix$widget _zsh_autosuggest_orig_$widget + zle -N $prefix${bind_count}-$widget _zsh_autosuggest_orig_$widget ;; # Completion widget completion:*) - eval "zle -C $prefix${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}" + _zsh_autosuggest_incr_bind_count $widget + eval "zle -C $prefix${bind_count}-${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}" ;; esac + _zsh_autosuggest_get_bind_count $widget + # Pass the original widget's name explicitly into the autosuggest # function. Use this passed in widget name to call the original # widget instead of relying on the $WIDGET variable being set # correctly. $WIDGET cannot be trusted because other plugins call # zle without the `-w` flag (e.g. `zle self-insert` instead of # `zle self-insert -w`). - eval "_zsh_autosuggest_bound_${(q)widget}() { - _zsh_autosuggest_widget_$autosuggest_action $prefix${(q)widget} \$@ + eval "_zsh_autosuggest_bound_${bind_count}_${(q)widget}() { + _zsh_autosuggest_widget_$autosuggest_action $prefix$bind_count-${(q)widget} \$@ }" # Create the bound widget - zle -N $widget _zsh_autosuggest_bound_$widget + zle -N $widget _zsh_autosuggest_bound_${bind_count}_$widget } # Map all configured widgets to the right autosuggest widgets diff --git a/zsh-autosuggestions.zsh b/zsh-autosuggestions.zsh index 34ca080..05e1bb4 100644 --- a/zsh-autosuggestions.zsh +++ b/zsh-autosuggestions.zsh @@ -137,12 +137,34 @@ _zsh_autosuggest_feature_detect_zpty_returns_fd() { # Widget Helpers # #--------------------------------------------------------------------# +_zsh_autosuggest_incr_bind_count() { + if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then + ((_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]++)) + else + _ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=1 + fi + + bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] +} + +_zsh_autosuggest_get_bind_count() { + if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then + bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] + else + bind_count=0 + fi +} + # Bind a single widget to an autosuggest widget, saving a reference to the original widget _zsh_autosuggest_bind_widget() { + typeset -gA _ZSH_AUTOSUGGEST_BIND_COUNTS + local widget=$1 local autosuggest_action=$2 local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX + local -i bind_count + # Save a reference to the original widget case $widgets[$widget] in # Already bound @@ -150,34 +172,38 @@ _zsh_autosuggest_bind_widget() { # User-defined widget user:*) - zle -l "$prefix$widget" && zle -N "$widget" ${widgets[$prefix$widget]#*:} - zle -N $prefix$widget ${widgets[$widget]#*:} + _zsh_autosuggest_incr_bind_count $widget + zle -N $prefix${bind_count}-$widget ${widgets[$widget]#*:} ;; # Built-in widget builtin) + _zsh_autosuggest_incr_bind_count $widget eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }" - zle -N $prefix$widget _zsh_autosuggest_orig_$widget + zle -N $prefix${bind_count}-$widget _zsh_autosuggest_orig_$widget ;; # Completion widget completion:*) - eval "zle -C $prefix${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}" + _zsh_autosuggest_incr_bind_count $widget + eval "zle -C $prefix${bind_count}-${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}" ;; esac + _zsh_autosuggest_get_bind_count $widget + # Pass the original widget's name explicitly into the autosuggest # function. Use this passed in widget name to call the original # widget instead of relying on the $WIDGET variable being set # correctly. $WIDGET cannot be trusted because other plugins call # zle without the `-w` flag (e.g. `zle self-insert` instead of # `zle self-insert -w`). - eval "_zsh_autosuggest_bound_${(q)widget}() { - _zsh_autosuggest_widget_$autosuggest_action $prefix${(q)widget} \$@ + eval "_zsh_autosuggest_bound_${bind_count}_${(q)widget}() { + _zsh_autosuggest_widget_$autosuggest_action $prefix$bind_count-${(q)widget} \$@ }" # Create the bound widget - zle -N $widget _zsh_autosuggest_bound_$widget + zle -N $widget _zsh_autosuggest_bound_${bind_count}_$widget } # Map all configured widgets to the right autosuggest widgets