diff --git a/README.md b/README.md index abf4790..a72ea01 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ This plugin works by triggering custom behavior when certain [zle widgets](http: - `ZSH_AUTOSUGGEST_CLEAR_WIDGETS`: Widgets in this array will clear the suggestion when invoked. - `ZSH_AUTOSUGGEST_ACCEPT_WIDGETS`: Widgets in this array will accept the suggestion when invoked. +- `ZSH_AUTOSUGGEST_EXECUTE_WIDGETS`: Widgets in this array will execute the suggestion when invoked. - `ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS`: Widgets in this array will partially accept the suggestion when invoked. Widgets not in any of these lists will update the suggestion when invoked. @@ -79,10 +80,11 @@ Widgets not in any of these lists will update the suggestion when invoked. ### Key Bindings -This plugin provides two widgets that you can use with `bindkey`: +This plugin provides three widgets that you can use with `bindkey`: 1. `autosuggest-accept`: Accepts the current suggestion. -2. `autosuggest-clear`: Clears the current suggestion. +2. `autosuggest-execute`: Accepts and executes the current suggestion. +3. `autosuggest-clear`: Clears the current suggestion. For example, this would bind ctrl + space to accept the current suggestion. diff --git a/script/test.zsh b/script/test.zsh index 45f3dbc..ba563a6 100755 --- a/script/test.zsh +++ b/script/test.zsh @@ -177,6 +177,29 @@ testWidgetFunctionAcceptCursorNotAtEnd() { "$POSTDISPLAY" } +testWidgetFunctionExecute() { + BUFFER="ec" + POSTDISPLAY="ho hello" + + stub _zsh_autosuggest_invoke_original_widget + + _zsh_autosuggest_execute + + assertTrue \ + "accept-line not invoked" \ + "stub_called_with _zsh_autosuggest_invoke_original_widget 'accept-line'" + + assertEquals \ + "BUFFER was not modified" \ + "echo hello" \ + "$BUFFER" + + assertEquals \ + "POSTDISPLAY was not cleared" \ + "" \ + "$POSTDISPLAY" +} + testWidgetFunctionPartialAcceptCursorMovesOutOfBuffer() { BUFFER="ec" POSTDISPLAY="ho hello" @@ -281,6 +304,32 @@ testWidgetClear() { "stub_called _zsh_autosuggest_highlight_apply" } +testWidgetExecute() { + stub _zsh_autosuggest_highlight_reset + stub _zsh_autosuggest_execute + stub _zsh_autosuggest_highlight_apply + + # Call the function pointed to by the widget since we can't call + # the widget itself when zle is not active + ${widgets[autosuggest-execute]#*:} "original-widget" + + assertTrue \ + "autosuggest-execute widget does not exist" \ + "zle -l autosuggest-execute" + + assertTrue \ + "highlight_reset was not called" \ + "stub_called _zsh_autosuggest_highlight_reset" + + assertTrue \ + "widget function was not called" \ + "stub_called _zsh_autosuggest_execute" + + assertTrue \ + "highlight_apply was not called" \ + "stub_called _zsh_autosuggest_highlight_apply" +} + testEscapeCommandPrefix() { assertEquals \ "Did not escape single backslash" \ diff --git a/src/bind.zsh b/src/bind.zsh index cc020de..030c6cf 100644 --- a/src/bind.zsh +++ b/src/bind.zsh @@ -55,6 +55,8 @@ _zsh_autosuggest_bind_widgets() { _zsh_autosuggest_bind_widget $widget clear elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then _zsh_autosuggest_bind_widget $widget accept + elif [ ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget execute elif [ ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]; then _zsh_autosuggest_bind_widget $widget partial_accept else diff --git a/src/config.zsh b/src/config.zsh index b5a0f02..ae34f82 100644 --- a/src/config.zsh +++ b/src/config.zsh @@ -32,6 +32,10 @@ ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=( vi-end-of-line ) +# Widgets that accept the entire suggestion and execute it +ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=( +) + # Widgets that accept the suggestion as far as the cursor moves ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=( forward-word diff --git a/src/widgets.zsh b/src/widgets.zsh index 1537b8a..925a5e2 100644 --- a/src/widgets.zsh +++ b/src/widgets.zsh @@ -47,6 +47,19 @@ _zsh_autosuggest_accept() { _zsh_autosuggest_invoke_original_widget $@ } +# Accept the entire suggestion and execute it +_zsh_autosuggest_execute() { + # Add the suggestion to the buffer + BUFFER="$BUFFER$POSTDISPLAY" + + # Remove the suggestion + unset POSTDISPLAY + + # Call the original `accept-line` to handle syntax highlighting or + # other potential custom behavior + _zsh_autosuggest_invoke_original_widget "accept-line" +} + # Partially accept the suggestion _zsh_autosuggest_partial_accept() { # Save the contents of the buffer so we can restore later if needed @@ -71,7 +84,7 @@ _zsh_autosuggest_partial_accept() { fi } -for action in clear modify accept partial_accept; do +for action in clear modify accept partial_accept execute; do eval "_zsh_autosuggest_widget_$action() { _zsh_autosuggest_highlight_reset _zsh_autosuggest_$action \$@ @@ -81,3 +94,4 @@ done zle -N autosuggest-accept _zsh_autosuggest_widget_accept zle -N autosuggest-clear _zsh_autosuggest_widget_clear +zle -N autosuggest-execute _zsh_autosuggest_widget_execute diff --git a/zsh-autosuggestions.zsh b/zsh-autosuggestions.zsh index 552bbdf..cd8ad5a 100644 --- a/zsh-autosuggestions.zsh +++ b/zsh-autosuggestions.zsh @@ -58,6 +58,10 @@ ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=( vi-end-of-line ) +# Widgets that accept the entire suggestion and execute it +ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=( +) + # Widgets that accept the suggestion as far as the cursor moves ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=( forward-word @@ -159,6 +163,8 @@ _zsh_autosuggest_bind_widgets() { _zsh_autosuggest_bind_widget $widget clear elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then _zsh_autosuggest_bind_widget $widget accept + elif [ ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget execute elif [ ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]; then _zsh_autosuggest_bind_widget $widget partial_accept else @@ -252,6 +258,19 @@ _zsh_autosuggest_accept() { _zsh_autosuggest_invoke_original_widget $@ } +# Accept the entire suggestion and execute it +_zsh_autosuggest_execute() { + # Add the suggestion to the buffer + BUFFER="$BUFFER$POSTDISPLAY" + + # Remove the suggestion + unset POSTDISPLAY + + # Call the original `accept-line` to handle syntax highlighting or + # other potential custom behavior + _zsh_autosuggest_invoke_original_widget "accept-line" +} + # Partially accept the suggestion _zsh_autosuggest_partial_accept() { # Save the contents of the buffer so we can restore later if needed @@ -276,7 +295,7 @@ _zsh_autosuggest_partial_accept() { fi } -for action in clear modify accept partial_accept; do +for action in clear modify accept partial_accept execute; do eval "_zsh_autosuggest_widget_$action() { _zsh_autosuggest_highlight_reset _zsh_autosuggest_$action \$@ @@ -286,6 +305,7 @@ done zle -N autosuggest-accept _zsh_autosuggest_widget_accept zle -N autosuggest-clear _zsh_autosuggest_widget_clear +zle -N autosuggest-execute _zsh_autosuggest_widget_execute #--------------------------------------------------------------------# # Suggestion #