From bcbdad83e940917db9bbd0afd62057229446c00f Mon Sep 17 00:00:00 2001 From: Eric Freese Date: Wed, 6 Jun 2018 21:49:03 -0600 Subject: [PATCH] Support fallback strategies by setting array in config --- Makefile | 1 + README.md | 11 ++++-- spec/integrations/zle_input_stack_spec.rb | 2 +- spec/options/strategy_spec.rb | 45 ++++++++++++++++----- src/async.zsh | 2 +- src/config.zsh | 4 +- src/fetch.zsh | 23 +++++++++++ src/strategies/default.zsh | 17 -------- src/widgets.zsh | 2 +- zsh-autosuggestions.zsh | 48 +++++++++++++---------- 10 files changed, 100 insertions(+), 55 deletions(-) create mode 100644 src/fetch.zsh delete mode 100644 src/strategies/default.zsh diff --git a/Makefile b/Makefile index d5d162c..b89ff04 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ SRC_FILES := \ $(SRC_DIR)/highlight.zsh \ $(SRC_DIR)/widgets.zsh \ $(SRC_DIR)/strategies/*.zsh \ + $(SRC_DIR)/fetch.zsh \ $(SRC_DIR)/async.zsh \ $(SRC_DIR)/start.zsh diff --git a/README.md b/README.md index 4ad07d8..5039b53 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ _[Fish](http://fishshell.com/)-like fast/unobtrusive autosuggestions for zsh._ -It suggests commands as you type, based on command history. +It suggests commands as you type. Requirements: Zsh v4.3.11 or later @@ -39,10 +39,13 @@ Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion ### Suggestion Strategy -Set `ZSH_AUTOSUGGEST_STRATEGY` to choose the strategy for generating suggestions. There are currently two to choose from: +`ZSH_AUTOSUGGEST_STRATEGY` is an array that specifies how suggestions should be generated. The strategies in the array are tried successively until a suggestion is found. There are currently three built-in strategies to choose from: -- `default`: Chooses the most recent match. -- `match_prev_cmd`: Chooses the most recent match whose preceding history item matches the most recently executed command ([more info](src/strategies/match_prev_cmd.zsh)). Note that this strategy won't work as expected with ZSH options that don't preserve the history order such as `HIST_IGNORE_ALL_DUPS` or `HIST_EXPIRE_DUPS_FIRST`. +- `history`: Chooses the most recent match from history. +- `match_prev_cmd`: Like `history`, but chooses the most recent match whose preceding history item matches the most recently executed command ([more info](src/strategies/match_prev_cmd.zsh)). Note that this strategy won't work as expected with ZSH options that don't preserve the history order such as `HIST_IGNORE_ALL_DUPS` or `HIST_EXPIRE_DUPS_FIRST`. +- `completion`: (experimental) Chooses a suggestion based on what tab-completion would suggest. + +For example, setting `ZSH_AUTOSUGGEST_STRATEGY=(history completion)` will first try to find a suggestion from your history, but, if it can't find a match, will find a suggestion from the completion engine. ### Widget Mapping diff --git a/spec/integrations/zle_input_stack_spec.rb b/spec/integrations/zle_input_stack_spec.rb index 8a2c990..12cfbc7 100644 --- a/spec/integrations/zle_input_stack_spec.rb +++ b/spec/integrations/zle_input_stack_spec.rb @@ -2,7 +2,7 @@ describe 'using `zle -U`' do let(:before_sourcing) do -> do session. - run_command('_zsh_autosuggest_strategy_test() { sleep 1; _zsh_autosuggest_strategy_default "$1" }'). + run_command('_zsh_autosuggest_strategy_test() { sleep 1; _zsh_autosuggest_strategy_history "$1" }'). run_command('foo() { zle -U - "echo hello" }; zle -N foo; bindkey ^B foo') end end diff --git a/spec/options/strategy_spec.rb b/spec/options/strategy_spec.rb index c9f01e1..378d01e 100644 --- a/spec/options/strategy_spec.rb +++ b/spec/options/strategy_spec.rb @@ -1,20 +1,45 @@ describe 'a suggestion for a given prefix' do - let(:options) { ['_zsh_autosuggest_strategy_default() { suggestion="echo foo" }'] } + let(:history_strategy) { '_zsh_autosuggest_strategy_history() { suggestion="history" }' } + let(:foobar_strategy) { '_zsh_autosuggest_strategy_foobar() { [[ "foobar baz" = $1* ]] && suggestion="foobar baz" }' } + let(:foobaz_strategy) { '_zsh_autosuggest_strategy_foobaz() { [[ "foobaz bar" = $1* ]] && suggestion="foobaz bar" }' } - it 'is determined by calling the default strategy function' do - session.send_string('e') - wait_for { session.content }.to eq('echo foo') + let(:options) { [ history_strategy ] } + + it 'by default is determined by calling the `history` strategy function' do + session.send_string('h') + wait_for { session.content }.to eq('history') end - context 'when ZSH_AUTOSUGGEST_STRATEGY is set' do + context 'when ZSH_AUTOSUGGEST_STRATEGY is set to an array' do let(:options) { [ - '_zsh_autosuggest_strategy_custom() { suggestion="echo foo" }', - 'ZSH_AUTOSUGGEST_STRATEGY=custom' + foobar_strategy, + foobaz_strategy, + 'ZSH_AUTOSUGGEST_STRATEGY=(foobar foobaz)' ] } - it 'is determined by calling the specified strategy function' do - session.send_string('e') - wait_for { session.content }.to eq('echo foo') + it 'is determined by the first strategy function to return a suggestion' do + session.send_string('foo') + wait_for { session.content }.to eq('foobar baz') + + session.send_string('baz') + wait_for { session.content }.to eq('foobaz bar') + end + end + + context 'when ZSH_AUTOSUGGEST_STRATEGY is set to a string' do + let(:options) { [ + foobar_strategy, + foobaz_strategy, + 'ZSH_AUTOSUGGEST_STRATEGY="foobar foobaz"' + ] } + + it 'is determined by the first strategy function to return a suggestion' do + session.send_string('foo') + wait_for { session.content }.to eq('foobar baz') + + session.send_string('baz') + wait_for { session.content }.to eq('foobaz bar') end end end + diff --git a/src/async.zsh b/src/async.zsh index 62e3329..dd54c24 100644 --- a/src/async.zsh +++ b/src/async.zsh @@ -35,7 +35,7 @@ _zsh_autosuggest_async_server() { # Run suggestion search in the background ( local suggestion - _zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY "$query" + _zsh_autosuggest_fetch_suggestion "$query" echo -n -E "$suggestion"$'\0' ) & diff --git a/src/config.zsh b/src/config.zsh index 9b3dbae..4598191 100644 --- a/src/config.zsh +++ b/src/config.zsh @@ -11,7 +11,9 @@ ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8' # Prefix to use when saving original versions of bound widgets ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig- -ZSH_AUTOSUGGEST_STRATEGY=default +# Strategies to use to fetch a suggestion +# Will try each strategy in order until a suggestion is returned +ZSH_AUTOSUGGEST_STRATEGY=(history) # Widgets that clear the suggestion ZSH_AUTOSUGGEST_CLEAR_WIDGETS=( diff --git a/src/fetch.zsh b/src/fetch.zsh new file mode 100644 index 0000000..f94e66d --- /dev/null +++ b/src/fetch.zsh @@ -0,0 +1,23 @@ + +#--------------------------------------------------------------------# +# Fetch Suggestion # +#--------------------------------------------------------------------# +# Loops through all specified strategies and returns a suggestion +# from the first strategy to provide one. +# + +_zsh_autosuggest_fetch_suggestion() { + typeset -g suggestion + local -a strategies + + # Ensure we are working with an array + strategies=(${=ZSH_AUTOSUGGEST_STRATEGY}) + + for strategy in $strategies; do + # Try to get a suggestion from this strategy + _zsh_autosuggest_strategy_$strategy "$1" + + # Break once we've found a suggestion + [[ -n "$suggestion" ]] && break + done +} diff --git a/src/strategies/default.zsh b/src/strategies/default.zsh deleted file mode 100644 index 68617ff..0000000 --- a/src/strategies/default.zsh +++ /dev/null @@ -1,17 +0,0 @@ - -#--------------------------------------------------------------------# -# Default Suggestion Strategy # -#--------------------------------------------------------------------# -# Will provide suggestions from your history. If no matches are found -# in history, will provide a suggestion from the completion engine. -# - -_zsh_autosuggest_strategy_default() { - typeset -g suggestion - - _zsh_autosuggest_strategy_history "$1" - - if [[ -z "$suggestion" ]]; then - _zsh_autosuggest_strategy_completion "$1" - fi -} diff --git a/src/widgets.zsh b/src/widgets.zsh index 87bb62e..89af395 100644 --- a/src/widgets.zsh +++ b/src/widgets.zsh @@ -97,7 +97,7 @@ _zsh_autosuggest_fetch() { _zsh_autosuggest_async_request "$BUFFER" else local suggestion - _zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY "$BUFFER" + _zsh_autosuggest_fetch_suggestion "$BUFFER" _zsh_autosuggest_suggest "$suggestion" fi } diff --git a/zsh-autosuggestions.zsh b/zsh-autosuggestions.zsh index 6683262..02d4b2f 100644 --- a/zsh-autosuggestions.zsh +++ b/zsh-autosuggestions.zsh @@ -47,7 +47,9 @@ ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8' # Prefix to use when saving original versions of bound widgets ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig- -ZSH_AUTOSUGGEST_STRATEGY=default +# Strategies to use to fetch a suggestion +# Will try each strategy in order until a suggestion is returned +ZSH_AUTOSUGGEST_STRATEGY=(history) # Widgets that clear the suggestion ZSH_AUTOSUGGEST_CLEAR_WIDGETS=( @@ -381,7 +383,7 @@ _zsh_autosuggest_fetch() { _zsh_autosuggest_async_request "$BUFFER" else local suggestion - _zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY "$BUFFER" + _zsh_autosuggest_fetch_suggestion "$BUFFER" _zsh_autosuggest_suggest "$suggestion" fi } @@ -619,23 +621,6 @@ _zsh_autosuggest_strategy_completion() { suggestion="${1[1,$i-1]}$completion" } -#--------------------------------------------------------------------# -# Default Suggestion Strategy # -#--------------------------------------------------------------------# -# Will provide suggestions from your history. If no matches are found -# in history, will provide a suggestion from the completion engine. -# - -_zsh_autosuggest_strategy_default() { - typeset -g suggestion - - _zsh_autosuggest_strategy_history "$1" - - if [[ -z "$suggestion" ]]; then - _zsh_autosuggest_strategy_completion "$1" - fi -} - #--------------------------------------------------------------------# # History Suggestion Strategy # #--------------------------------------------------------------------# @@ -720,6 +705,29 @@ _zsh_autosuggest_strategy_match_prev_cmd() { typeset -g suggestion="$history[$histkey]" } +#--------------------------------------------------------------------# +# Fetch Suggestion # +#--------------------------------------------------------------------# +# Loops through all specified strategies and returns a suggestion +# from the first strategy to provide one. +# + +_zsh_autosuggest_fetch_suggestion() { + typeset -g suggestion + local -a strategies + + # Ensure we are working with an array + strategies=(${=ZSH_AUTOSUGGEST_STRATEGY}) + + for strategy in $strategies; do + # Try to get a suggestion from this strategy + _zsh_autosuggest_strategy_$strategy "$1" + + # Break once we've found a suggestion + [[ -n "$suggestion" ]] && break + done +} + #--------------------------------------------------------------------# # Async # #--------------------------------------------------------------------# @@ -756,7 +764,7 @@ _zsh_autosuggest_async_server() { # Run suggestion search in the background ( local suggestion - _zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY "$query" + _zsh_autosuggest_fetch_suggestion "$query" echo -n -E "$suggestion"$'\0' ) &