Add match_prev_cmd strategy.

A new suggestion strategy 'match_prev_cmd' is available. This is a bit
more context aware variaton on the default strategy.
The suggestion will be:
- The newest history entry that matches the current prefix, AND
- Whose preceding history entry also matches the previously executed
command.

See src/strategies/match_prev_cmd.zsh for an example.
This commit is contained in:
Geza Lore 2016-03-01 21:58:57 +00:00 committed by Eric Freese
parent 976acc708c
commit 73f774bd5d
4 changed files with 232 additions and 0 deletions

View file

@ -0,0 +1,122 @@
#!/usr/bin/env zsh
SCRIPT_DIR=$(dirname "$0")
TEST_DIR=$SCRIPT_DIR/../test
DIST_DIR=$SCRIPT_DIR/../
# Use stub.sh for stubbing/mocking
source $TEST_DIR/stub-1.0.2.sh
source $DIST_DIR/zsh-autosuggestions.zsh
#--------------------------------------------------------------------#
# Match Previous Command Suggestion Strategy #
#--------------------------------------------------------------------#
TMPHIST_FILE=/tmp/zsh-autosuggestions-test-tmp-hist
HISTSIZE=0 # Clear history
HISTSIZE=100
cat > $TMPHIST_FILE <<-EOH
one
two
three
four
five
six
seven
eight
nine
ten
eleven
EOH
echo >> $TMPHIST_FILE
fc -R $TMPHIST_FILE
rm $TMPHIST_FILE
ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd
testNoMatchPrevIsOne() {
stub_and_echo _zsh_autosuggest_prev_command "one"
assertEquals \
"Did not pick correct suggestion for prefix 'garbage' after 'one'" \
"" \
"$(_zsh_autosuggest_suggestion garbage)"
}
testMatchPrevIsOne() {
stub_and_echo _zsh_autosuggest_prev_command "one"
assertEquals \
"Did not pick correct suggestion for prefix 'o' after 'one'" \
"one" \
"$(_zsh_autosuggest_suggestion o)"
assertEquals \
"Did not pick correct suggestion for prefix 't' after 'one'" \
"two" \
"$(_zsh_autosuggest_suggestion t)"
assertEquals \
"Did not pick correct suggestion for prefix 'th' after 'one'" \
"three" \
"$(_zsh_autosuggest_suggestion th)"
assertEquals \
"Did not pick correct suggestion for prefix 'f' after 'one'" \
"five" \
"$(_zsh_autosuggest_suggestion f)"
assertEquals \
"Did not pick correct suggestion for prefix 'fo' after 'one" \
"four" \
"$(_zsh_autosuggest_suggestion fo)"
}
testNoMatchPrevIsTwo() {
stub_and_echo _zsh_autosuggest_prev_command "two"
assertEquals \
"Did not pick correct suggestion for prefix 'garbage' after 'two'" \
"" \
"$(_zsh_autosuggest_suggestion garbage)"
}
testMatchPrevIsTwo() {
stub_and_echo _zsh_autosuggest_prev_command "two"
assertEquals \
"Did not pick correct suggestion for prefix 'o' after 'two'" \
"one" \
"$(_zsh_autosuggest_suggestion o)"
assertEquals \
"Did not pick correct suggestion for prefix 't' after 'two'" \
"three" \
"$(_zsh_autosuggest_suggestion t)"
assertEquals \
"Did not pick correct suggestion for prefix 'tw' after 'two'" \
"two" \
"$(_zsh_autosuggest_suggestion tw)"
assertEquals \
"Did not pick correct suggestion for prefix 'f' after 'two'" \
"five" \
"$(_zsh_autosuggest_suggestion f)"
assertEquals \
"Did not pick correct suggestion for prefix 'fo' after 'two" \
"four" \
"$(_zsh_autosuggest_suggestion fo)"
}
setopt shwordsplit
SHUNIT_PARENT=$0
source $TEST_DIR/shunit2-2.1.6/src/shunit2

View file

@ -0,0 +1,50 @@
#--------------------------------------------------------------------#
# Match Previous Command Suggestion Strategy #
#--------------------------------------------------------------------#
# Suggests the most recent history item that matches the given
# prefix, and whose preceding history item also matches the most
# recently executed command.
#
# For example, if your have just executed:
# pwd
# ls foo
# ls bar
# pwd
# And then you start typing 'ls', then the suggestion will be 'ls foo',
# rather than 'ls bar', as your most recently executed command (pwd)
# was followed by 'ls foo' on it's previous invocation.
#
_zsh_autosuggest_strategy_match_prev_cmd() {
local prefix="$(_zsh_autosuggest_escape_command_prefix "$1")"
# Get all history event numbers that correspond to history
# entries that match pattern $prefix*
local history_match_keys
history_match_keys=(${(k)history[(R)$prefix*]})
# By default we use the first history number (most recent history entry)
local histkey="${history_match_keys[1]}"
# Get the previously executed command
local prev_cmd="$(_zsh_autosuggest_prev_command)"
prev_cmd="$(_zsh_autosuggest_escape_command_prefix $prev_cmd)"
# Iterate up to the first 200 history event numbers that match $prefix
for key in "${(@)history_match_keys[1,200]}"; do
# Stop if we ran out of history
[[ $key -gt 1 ]] || break
# See if the history entry preceding the suggestion matches the
# previous command, and use it if it does
if [[ "${history[$((key - 1))]}" == $prev_cmd ]]; then
histkey="$key"
break
fi
done
# Echo the matched history entry
echo -E "$history[$histkey]"
}

View file

@ -19,3 +19,8 @@ _zsh_autosuggest_escape_command_prefix() {
# Escape special chars in the string (requires EXTENDED_GLOB) # Escape special chars in the string (requires EXTENDED_GLOB)
echo -E "${1//(#m)[\\()\[\]|*?]/\\$MATCH}" echo -E "${1//(#m)[\\()\[\]|*?]/\\$MATCH}"
} }
# Get the previously executed command (hookable for testing)
_zsh_autosuggest_prev_command() {
echo -E "${history[$((HISTCMD-1))]}"
}

View file

@ -330,6 +330,11 @@ _zsh_autosuggest_escape_command_prefix() {
echo -E "${1//(#m)[\\()\[\]|*?]/\\$MATCH}" echo -E "${1//(#m)[\\()\[\]|*?]/\\$MATCH}"
} }
# Get the previously executed command (hookable for testing)
_zsh_autosuggest_prev_command() {
echo -E "${history[$((HISTCMD-1))]}"
}
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
# Default Suggestion Strategy # # Default Suggestion Strategy #
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
@ -347,6 +352,56 @@ _zsh_autosuggest_strategy_default() {
echo -E "${history[$histkey]}" echo -E "${history[$histkey]}"
} }
#--------------------------------------------------------------------#
# Match Previous Command Suggestion Strategy #
#--------------------------------------------------------------------#
# Suggests the most recent history item that matches the given
# prefix, and whose preceding history item also matches the most
# recently executed command.
#
# For example, if your have just executed:
# pwd
# ls foo
# ls bar
# pwd
# And then you start typing 'ls', then the suggestion will be 'ls foo',
# rather than 'ls bar', as your most recently executed command (pwd)
# was followed by 'ls foo' on it's previous invocation.
#
_zsh_autosuggest_strategy_match_prev_cmd() {
local prefix="$(_zsh_autosuggest_escape_command_prefix "$1")"
# Get all history event numbers that correspond to history
# entries that match pattern $prefix*
local history_match_keys
history_match_keys=(${(k)history[(R)$prefix*]})
# By default we use the first history number (most recent history entry)
local histkey="${history_match_keys[1]}"
# Get the previously executed command
local prev_cmd="$(_zsh_autosuggest_prev_command)"
prev_cmd="$(_zsh_autosuggest_escape_command_prefix $prev_cmd)"
# Iterate up to the first 200 history event numbers that match $prefix
for key in "${(@)history_match_keys[1,200]}"; do
# Stop if we ran out of history
[[ $key -gt 1 ]] || break
# See if the history entry preceding the suggestion matches the
# previous command, and use it if it does
if [[ "${history[$((key - 1))]}" == $prev_cmd ]]; then
histkey="$key"
break
fi
done
# Echo the matched history entry
echo -E "$history[$histkey]"
}
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
# Start # # Start #
#--------------------------------------------------------------------# #--------------------------------------------------------------------#