From b87a4972c8be188af347fb3e29b8c47a923c4f75 Mon Sep 17 00:00:00 2001 From: Eric Freese Date: Sat, 29 Jun 2019 21:44:29 -0600 Subject: [PATCH] Allow configuring to ignore history entries matching a pattern Set ZSH_AUTOSUGGEST_HISTORY_IGNORE to a glob pattern to have the history and match_prev_cmd suggestion strategies never make suggestions matching that pattern. For example, set to "cd *" to never suggest any `cd` commands from history (see issues #340 and #425). Or set to "?(#c50,)" to never suggest anything 50 characters or longer (see issue #429). --- README.md | 6 ++++++ spec/strategies/history_spec.rb | 11 ++++++++++ spec/strategies/match_prev_cmd_spec.rb | 29 +++++++++++++++++++------- src/strategies/history.zsh | 13 +++++++++--- src/strategies/match_prev_cmd.zsh | 13 +++++++++--- zsh-autosuggestions.zsh | 26 +++++++++++++++++------ 6 files changed, 78 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index fad9bf5..2f4f973 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,12 @@ As of `v0.4.0`, suggestions can be fetched asynchronously. To enable this behavi Set `ZSH_AUTOSUGGEST_MANUAL_REBIND` (it can be set to anything) to disable automatic widget re-binding on each precmd. This can be a big boost to performance, but you'll need to handle re-binding yourself if any of the widget lists change or if you or another plugin wrap any of the autosuggest widgets. To re-bind widgets, run `_zsh_autosuggest_bind_widgets`. +### Ignoring history suggestions that match a pattern + +Set `ZSH_AUTOSUGGEST_HISTORY_IGNORE` to a glob pattern to prevent offering suggestions for history entries that match the pattern. For example, set it to `"cd *"` to never suggest any `cd` commands from history. Or set to `"?(#c50,)"` to never suggest anything 50 characters or longer. + +**Note:** This only affects the `history` and `match_prev_cmd` suggestion strategies. + ### Key Bindings diff --git a/spec/strategies/history_spec.rb b/spec/strategies/history_spec.rb index f8ae526..eee8efd 100644 --- a/spec/strategies/history_spec.rb +++ b/spec/strategies/history_spec.rb @@ -8,5 +8,16 @@ describe 'the `history` suggestion strategy' do end end + context 'when ZSH_AUTOSUGGEST_HISTORY_IGNORE is set to a pattern' do + let(:options) { ['ZSH_AUTOSUGGEST_HISTORY_IGNORE="* bar"'] } + + it 'does not make suggestions that match the pattern' do + with_history('ls foo', 'ls bar', 'echo baz') do + session.send_string('ls') + wait_for { session.content }.to eq('ls foo') + end + end + end + include_examples 'special characters' end diff --git a/spec/strategies/match_prev_cmd_spec.rb b/spec/strategies/match_prev_cmd_spec.rb index 5a143b8..c435f16 100644 --- a/spec/strategies/match_prev_cmd_spec.rb +++ b/spec/strategies/match_prev_cmd_spec.rb @@ -3,19 +3,32 @@ require 'strategies/special_characters_helper' describe 'the `match_prev_cmd` strategy' do let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd'] } + let(:history) { [ + 'echo what', + 'ls foo', + 'echo what', + 'ls bar', + 'ls baz', + 'echo what' + ] } + it 'suggests the last matching history entry after the previous command' do - with_history( - 'echo what', - 'ls foo', - 'echo what', - 'ls bar', - 'ls baz', - 'echo what' - ) do + with_history(*history) do session.send_string('ls') wait_for { session.content }.to eq('ls bar') end end + context 'when ZSH_AUTOSUGGEST_HISTORY_IGNORE is set to a pattern' do + let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd', 'ZSH_AUTOSUGGEST_HISTORY_IGNORE="* bar"'] } + + it 'does not make suggestions that match the pattern' do + with_history(*history) do + session.send_string('ls') + wait_for { session.content }.to eq('ls foo') + end + end + end + include_examples 'special characters' end diff --git a/src/strategies/history.zsh b/src/strategies/history.zsh index a2755a5..0672a13 100644 --- a/src/strategies/history.zsh +++ b/src/strategies/history.zsh @@ -10,7 +10,7 @@ _zsh_autosuggest_strategy_history() { # Reset options to defaults and enable LOCAL_OPTIONS emulate -L zsh - # Enable globbing flags so that we can use (#m) + # Enable globbing flags so that we can use (#m) and (x~y) glob operator setopt EXTENDED_GLOB # Escape backslashes and all of the glob operators so we can use @@ -19,7 +19,14 @@ _zsh_autosuggest_strategy_history() { # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8 local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}" - # Get the history items that match + # Get the history items that match the prefix, excluding those that match + # the ignore pattern + local pattern="$prefix*" + if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then + pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)" + fi + + # Give the first history item matching the pattern as the suggestion # - (r) subscript flag makes the pattern match on values - typeset -g suggestion="${history[(r)${prefix}*]}" + typeset -g suggestion="${history[(r)$pattern]}" } diff --git a/src/strategies/match_prev_cmd.zsh b/src/strategies/match_prev_cmd.zsh index f76d3c1..b709783 100644 --- a/src/strategies/match_prev_cmd.zsh +++ b/src/strategies/match_prev_cmd.zsh @@ -24,16 +24,23 @@ _zsh_autosuggest_strategy_match_prev_cmd() { # Reset options to defaults and enable LOCAL_OPTIONS emulate -L zsh - # Enable globbing flags so that we can use (#m) + # Enable globbing flags so that we can use (#m) and (x~y) glob operator setopt EXTENDED_GLOB # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8 local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}" + # Get the history items that match the prefix, excluding those that match + # the ignore pattern + local pattern="$prefix*" + if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then + pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)" + fi + # Get all history event numbers that correspond to history - # entries that match pattern $prefix* + # entries that match the pattern local history_match_keys - history_match_keys=(${(k)history[(R)$prefix*]}) + history_match_keys=(${(k)history[(R)$~pattern]}) # By default we use the first history number (most recent history entry) local histkey="${history_match_keys[1]}" diff --git a/zsh-autosuggestions.zsh b/zsh-autosuggestions.zsh index 872b647..950cf5b 100644 --- a/zsh-autosuggestions.zsh +++ b/zsh-autosuggestions.zsh @@ -626,7 +626,7 @@ _zsh_autosuggest_strategy_history() { # Reset options to defaults and enable LOCAL_OPTIONS emulate -L zsh - # Enable globbing flags so that we can use (#m) + # Enable globbing flags so that we can use (#m) and (x~y) glob operator setopt EXTENDED_GLOB # Escape backslashes and all of the glob operators so we can use @@ -635,9 +635,16 @@ _zsh_autosuggest_strategy_history() { # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8 local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}" - # Get the history items that match + # Get the history items that match the prefix, excluding those that match + # the ignore pattern + local pattern="$prefix*" + if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then + pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)" + fi + + # Give the first history item matching the pattern as the suggestion # - (r) subscript flag makes the pattern match on values - typeset -g suggestion="${history[(r)${prefix}*]}" + typeset -g suggestion="${history[(r)$pattern]}" } #--------------------------------------------------------------------# @@ -665,16 +672,23 @@ _zsh_autosuggest_strategy_match_prev_cmd() { # Reset options to defaults and enable LOCAL_OPTIONS emulate -L zsh - # Enable globbing flags so that we can use (#m) + # Enable globbing flags so that we can use (#m) and (x~y) glob operator setopt EXTENDED_GLOB # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8 local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}" + # Get the history items that match the prefix, excluding those that match + # the ignore pattern + local pattern="$prefix*" + if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then + pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)" + fi + # Get all history event numbers that correspond to history - # entries that match pattern $prefix* + # entries that match the pattern local history_match_keys - history_match_keys=(${(k)history[(R)$prefix*]}) + history_match_keys=(${(k)history[(R)$~pattern]}) # By default we use the first history number (most recent history entry) local histkey="${history_match_keys[1]}"