Compare commits

..

34 Commits

Author SHA1 Message Date
Eric Freese
9cfaf5d342 v0.3.3 2016-10-17 07:45:09 -06:00
Eric Freese
9333f0653f Update changelog for v0.3.3 2016-10-17 07:43:56 -06:00
Eric Freese
b377c39d0e Only fetch a new suggestion if buffer has changed 2016-07-31 20:10:22 -06:00
Eric Freese
a44aa59321 Remove unnecessary reset of POSTDISPLAy 2016-07-31 20:09:26 -06:00
Eric Freese
25f4afb058 Add ZSH_AUTOSUGGEST_IGNORE_WIDGETS array 2016-07-31 19:35:30 -06:00
Eric Freese
472394681e Merge pull request #178 from lbolla/issue141-develop
Disable autosuggest if buffer is too large
2016-07-18 10:28:45 -06:00
Lorenzo Bolla
a9c8efa048 Update README 2016-07-18 16:06:50 +01:00
Lorenzo Bolla
cdf56a3305 Include result of make 2016-07-18 10:56:21 +01:00
Lorenzo Bolla
2450c95d8a Rename and document new config var 2016-07-18 10:55:19 +01:00
Lorenzo Bolla
7b81eb79b8 Disable autosuggest if buffer is too large
Make buffer max size configurable, defaulted to infinity
2016-07-18 08:56:00 +01:00
Eric Freese
63816c5da8 Fix #164: Use fc builtin instead of $history array for lookup
According to a few tests, the `fc` builtin appears to be quite a bit
faster than searching through the `$history` associative array when
dealing with large history files (500K+).
2016-06-10 13:52:24 -06:00
Eric Freese
b4b3a82ee3 Fix #168 and #130: Escape tildes when fetching suggestions 2016-06-10 13:51:20 -06:00
Eric Freese
85ea943789 Merge pull request #163 from tsdh/develop
Document caveats of match_prev_cmd strategy
2016-05-28 13:34:00 -06:00
Tassilo Horn
ca70612d3c Document caveats of match_prev_cmd strategy
This strategy relies on the history being exactly in the order in which
commands have been entered.  Therefore, options like suppressing
duplicates or expiring duplicates first will lead to unexpected
suggestions.
2016-05-28 21:23:35 +02:00
Eric Freese
62cdba4e0f Merge pull request #142 from zsh-users/v0.3.x
v0.3.2
2016-05-28 08:28:18 -06:00
Eric Freese
cce68de46d v0.3.2 2016-05-28 08:27:08 -06:00
Eric Freese
4a2d9f9049 Fix Makefile to not create symbolic link after PR #156 was merged 2016-05-28 08:26:24 -06:00
Eric Freese
7c688ec20c Add note to readme about PRs going to develop branch 2016-05-28 08:23:53 -06:00
Eric Freese
96eb0fae77 Changelog updates for v0.3.2 2016-05-28 08:18:52 -06:00
Eric Freese
5e5bfdb659 Merge pull request #156 from adamkruszewski/v0.3.x
Adjust plugin.zsh file to run on zsh 5.1 in mSYS2.
2016-05-12 08:53:20 -06:00
adamkruszewski
0a6c34947c Adjust plugin.zsh file to run on zsh 5.1 in mSYS2. 2016-05-11 17:02:41 +02:00
Eric Freese
e87bc74654 Fix 118: Clear suggestion before original widget to fix completions
See PR #149
2016-04-25 14:42:09 -06:00
Eric Freese
964773aa75 Use array indices for forward compatibility
See issue #152
2016-04-25 14:26:37 -06:00
Eric Freese
945c660856 Fix #152 by escaping widget names inside evals
Solves problems when dealing with widget names with irregular
characters such as those that come from `opp.zsh`.
2016-04-25 14:26:35 -06:00
Eric Freese
011d8bdfd1 Refactor to remove prev cmd function and simplify escaping 2016-04-25 14:19:26 -06:00
Eric Freese
c5f57da2b8 Pull duplicated test logic from strategies into single test file 2016-04-22 14:14:29 -06:00
Eric Freese
c477db2696 Remove unused test variables from Makefile 2016-04-15 13:41:41 -06:00
Eric Freese
d7001f2c34 Fix readme test script reference. 2016-04-15 13:40:18 -06:00
Eric Freese
6d6e7820f3 Fix #143: Add vi-add-eol to list of accept widgets. 2016-04-15 13:37:50 -06:00
Eric Freese
9bef50fac1 Merge pull request #140 from zsh-users/fixes/bound_widget_return_code
Keep track of return value from original widget (#135)
2016-04-14 11:18:01 -06:00
Eric Freese
1d4f7e157e Keep track of return value from original widget (#135) 2016-04-06 17:13:04 -06:00
Eric Freese
2acf25e065 Formatting 2016-03-15 09:24:13 -06:00
Eric Freese
ba7109169d Clean up tests with setUp and tearDown functions 2016-03-15 09:05:55 -06:00
Eric Freese
a28e72e84a Test Runner now supports running specific tests and choosing zsh bin 2016-03-15 09:04:17 -06:00
24 changed files with 513 additions and 234 deletions

View File

@@ -1,5 +1,20 @@
# Changelog
## v0.3.3
- Switch from $history array to fc builtin for better performance with large HISTFILEs (#164)
- Fix tilde handling when extended_glob is set (#168)
- Add config option for maximum buffer length to fetch suggestions for (#178)
- Add config option for list of widgets to ignore (#184)
- Don't fetch a new suggestion unless a modification widget actually modifies the buffer (#183)
## v0.3.2
- Test runner now supports running specific tests and choosing zsh binary
- Return code from original widget is now correctly passed through (#135)
- Add `vi-add-eol` to list of accept widgets (#143)
- Escapes widget names within evals to fix problems with irregular widget names (#152)
- Plugin now clears suggestion while within a completion menu (#149)
- .plugin file no longer relies on symbolic link support, fixing issues on Windows (#156)
## v0.3.1
- Fixes issue with `vi-next-char` not accepting suggestion (#137).

View File

@@ -1,5 +1,4 @@
SRC_DIR := ./src
TEST_DIR := ./script
VENDOR_DIR := ./vendor
SRC_FILES := \
@@ -19,11 +18,6 @@ HEADER_FILES := \
LICENSE
PLUGIN_TARGET := zsh-autosuggestions.zsh
OH_MY_ZSH_LINK_TARGET := zsh-autosuggestions.plugin.zsh
ALL_TARGETS := \
$(PLUGIN_TARGET) \
$(OH_MY_ZSH_LINK_TARGET)
SHUNIT2 := $(VENDOR_DIR)/shunit2/2.1.6
STUB_SH := $(VENDOR_DIR)/stub.sh/stub.sh
@@ -32,18 +26,12 @@ TEST_PREREQS := \
$(SHUNIT2) \
$(STUB_SH)
TEST_FILES := \
$(TEST_DIR)/**/*.zsh
all: $(ALL_TARGETS)
all: $(PLUGIN_TARGET)
$(PLUGIN_TARGET): $(HEADER_FILES) $(SRC_FILES)
cat $(HEADER_FILES) | sed -e 's/^/# /g' > $@
cat $(SRC_FILES) >> $@
$(OH_MY_ZSH_LINK_TARGET): $(PLUGIN_TARGET)
ln -s $(PLUGIN_TARGET) $@
$(SHUNIT2):
git submodule update --init vendor/shunit2
@@ -52,8 +40,8 @@ $(STUB_SH):
.PHONY: clean
clean:
rm $(ALL_TARGETS)
rm $(PLUGIN_TARGET)
.PHONY: test
test: all $(TEST_PREREQS)
script/test_runner.zsh
script/test_runner.zsh $(TESTS)

View File

@@ -69,7 +69,7 @@ Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion
Set `ZSH_AUTOSUGGEST_STRATEGY` to choose the strategy for generating suggestions. There are currently two 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)).
- `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`.
### Widget Mapping
@@ -80,12 +80,19 @@ This plugin works by triggering custom behavior when certain [zle widgets](http:
- `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.
- `ZSH_AUTOSUGGEST_IGNORE_WIDGETS`: Widgets in this array will not trigger any custom behavior.
Widgets not in any of these lists will update the suggestion when invoked.
Widgets that modify the buffer and are not found in any of these arrays will fetch a new suggestion after they are invoked.
**Note:** A widget shouldn't belong to more than one of the above arrays.
### Disabling suggestion for large buffers
Set `ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE` to an integer value to disable autosuggestion for large buffers. The default is unset, which means that autosuggestion will be tried for any buffer size. Recommended value is 20.
This can be useful when pasting large amount of text in the terminal, to avoid triggering autosuggestion for too long strings.
### Key Bindings
This plugin provides three widgets that you can use with `bindkey`:
@@ -139,6 +146,7 @@ Edit the source files in `src/`. Run `make` to build `zsh-autosuggestions.zsh` f
Pull requests are welcome! If you send a pull request, please:
- Request to merge into the `develop` branch (*NOT* `master`)
- Match the existing coding conventions.
- Include helpful comments to keep the barrier-to-entry low for people new to the project.
- Write tests that cover your code as much as possible.
@@ -148,7 +156,7 @@ Pull requests are welcome! If you send a pull request, please:
Testing is performed with [`shunit2`](https://github.com/kward/shunit2) (v2.1.6). Documentation can be found [here](http://shunit2.googlecode.com/svn/trunk/source/2.1/doc/shunit2.html).
The test script lives at `script/test.zsh`. To run the tests, run `make test`.
The test script lives at `script/test_runner.zsh`. To run the tests, run `make test`.
## License

View File

@@ -1 +1 @@
v0.3.1
v0.3.3

View File

@@ -15,15 +15,40 @@ header() {
EOF
}
local -a tests
# ZSH binary to use
local zsh_bin="zsh"
# Test suites to run
tests=($TEST_DIR/**/*_test.zsh)
local retval=0
for suite in $tests; do
header "${suite#"$TEST_DIR"}"
zsh -f "$suite" || retval=$?
while getopts ":z:" opt; do
case $opt in
z)
zsh_bin="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument" >&2
exit 1
;;
esac
done
exit retval
shift $((OPTIND -1))
# Test suites to run
local -a tests
if [ $#@ -gt 0 ]; then
tests=($@)
else
tests=($TEST_DIR/**/*_test.zsh)
fi
local -i retval=0
for suite in $tests; do
header "${suite#"$ROOT_DIR/"}"
"$zsh_bin" -f "$suite" || retval=$?
done
exit $retval

View File

@@ -21,13 +21,13 @@ _zsh_autosuggest_bind_widget() {
# Built-in widget
builtin)
eval "_zsh_autosuggest_orig_$widget() { zle .$widget }"
eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
zle -N $prefix$widget _zsh_autosuggest_orig_$widget
;;
# Completion widget
completion:*)
eval "zle -C $prefix$widget ${${widgets[$widget]#*:}/:/ }"
eval "zle -C $prefix${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
;;
esac
@@ -37,8 +37,8 @@ _zsh_autosuggest_bind_widget() {
# 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_$widget() {
_zsh_autosuggest_widget_$autosuggest_action $prefix$widget \$@
eval "_zsh_autosuggest_bound_${(q)widget}() {
_zsh_autosuggest_widget_$autosuggest_action $prefix${(q)widget} \$@
}"
# Create the bound widget
@@ -47,10 +47,20 @@ _zsh_autosuggest_bind_widget() {
# Map all configured widgets to the right autosuggest widgets
_zsh_autosuggest_bind_widgets() {
local widget;
local widget
local ignore_widgets
ignore_widgets=(
.\*
_\*
zle-line-\*
autosuggest-\*
$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
)
# Find every widget we might want to bind and bind it appropriately
for widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|autosuggest-*|$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX*|zle-line-*|run-help|which-command|beep|set-local-history|yank)}; do
for widget in ${${(f)"$(builtin zle -la)"}:#${(j:|:)~ignore_widgets}}; do
if [ ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]; then
_zsh_autosuggest_bind_widget $widget clear
elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then

View File

@@ -32,6 +32,7 @@ ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
end-of-line
vi-forward-char
vi-end-of-line
vi-add-eol
)
# Widgets that accept the entire suggestion and execute it
@@ -46,3 +47,16 @@ ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
vi-forward-blank-word
vi-forward-blank-word-end
)
# Widgets that should be ignored (globbing supported but must be escaped)
ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
orig-\*
beep
run-help
set-local-history
which-command
yank
)
# Max size of buffer to trigger autosuggestion. Leave undefined for no upper bound.
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=

View File

@@ -7,12 +7,5 @@
#
_zsh_autosuggest_strategy_default() {
local prefix="$(_zsh_autosuggest_escape_command "$1")"
# Get the keys of the history items that match
local -a histkeys
histkeys=(${(k)history[(r)$prefix*]})
# Echo the value of the first key
echo -E "${history[$histkeys[1]]}"
fc -lnrm "$1*" 1 2>/dev/null | head -n 1
}

View File

@@ -16,9 +16,12 @@
# will be 'ls foo' rather than 'ls bar' because your most recently
# executed command (pwd) was previously followed by 'ls foo'.
#
# 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`.
_zsh_autosuggest_strategy_match_prev_cmd() {
local prefix="$(_zsh_autosuggest_escape_command "$1")"
local prefix="$1"
# Get all history event numbers that correspond to history
# entries that match pattern $prefix*
@@ -29,8 +32,7 @@ _zsh_autosuggest_strategy_match_prev_cmd() {
local histkey="${history_match_keys[1]}"
# Get the previously executed command
local prev_cmd="$(_zsh_autosuggest_prev_command)"
prev_cmd="$(_zsh_autosuggest_escape_command "$prev_cmd")"
local prev_cmd="$(_zsh_autosuggest_escape_command "${history[$((HISTCMD-1))]}")"
# Iterate up to the first 200 history event numbers that match $prefix
for key in "${(@)history_match_keys[1,200]}"; do

View File

@@ -5,11 +5,11 @@
# Delegate to the selected strategy to determine a suggestion
_zsh_autosuggest_suggestion() {
local prefix="$1"
local escaped_prefix="$(_zsh_autosuggest_escape_command "$1")"
local strategy_function="_zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY"
if [ -n "$functions[$strategy_function]" ]; then
echo -E "$($strategy_function "$prefix")"
echo -E "$($strategy_function "$escaped_prefix")"
fi
}
@@ -17,10 +17,5 @@ _zsh_autosuggest_escape_command() {
setopt localoptions EXTENDED_GLOB
# Escape special chars in the string (requires EXTENDED_GLOB)
echo -E "${1//(#m)[\\()\[\]|*?]/\\$MATCH}"
}
# Get the previously executed command
_zsh_autosuggest_prev_command() {
echo -E "${history[$((HISTCMD-1))]}"
echo -E "${1//(#m)[\\()\[\]|*?~]/\\$MATCH}"
}

View File

@@ -13,21 +13,39 @@ _zsh_autosuggest_clear() {
# Modify the buffer and get a new suggestion
_zsh_autosuggest_modify() {
# Original widget modifies the buffer
local -i retval
# Save the contents of the buffer/postdisplay
local orig_buffer="$BUFFER"
local orig_postdisplay="$POSTDISPLAY"
# Clear suggestion while original widget runs
unset POSTDISPLAY
# Original widget may modify the buffer
_zsh_autosuggest_invoke_original_widget $@
retval=$?
# Don't fetch a new suggestion if the buffer hasn't changed
if [ "$BUFFER" = "$orig_buffer" ]; then
POSTDISPLAY="$orig_postdisplay"
return $retval
fi
# Get a new suggestion if the buffer is not empty after modification
local suggestion
if [ $#BUFFER -gt 0 ]; then
suggestion="$(_zsh_autosuggest_suggestion "$BUFFER")"
if [ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" -o $#BUFFER -lt "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]; then
suggestion="$(_zsh_autosuggest_suggestion "$BUFFER")"
fi
fi
# Add the suggestion to the POSTDISPLAY
if [ -n "$suggestion" ]; then
POSTDISPLAY="${suggestion#$BUFFER}"
else
unset POSTDISPLAY
fi
return $retval
}
# Accept the entire suggestion
@@ -70,6 +88,8 @@ _zsh_autosuggest_execute() {
# Partially accept the suggestion
_zsh_autosuggest_partial_accept() {
local -i retval
# Save the contents of the buffer so we can restore later if needed
local original_buffer="$BUFFER"
@@ -78,6 +98,7 @@ _zsh_autosuggest_partial_accept() {
# Original widget moves the cursor
_zsh_autosuggest_invoke_original_widget $@
retval=$?
# If we've moved past the end of the original buffer
if [ $CURSOR -gt $#original_buffer ]; then
@@ -90,13 +111,22 @@ _zsh_autosuggest_partial_accept() {
# Restore the original buffer
BUFFER="$original_buffer"
fi
return $retval
}
for action in clear modify accept partial_accept execute; do
eval "_zsh_autosuggest_widget_$action() {
local -i retval
_zsh_autosuggest_highlight_reset
_zsh_autosuggest_$action \$@
retval=\$?
_zsh_autosuggest_highlight_apply
return \$retval
}"
done

45
test/bind_test.zsh Normal file
View File

@@ -0,0 +1,45 @@
#!/usr/bin/env zsh
source "${0:a:h}/test_helper.zsh"
oneTimeSetUp() {
source_autosuggestions
}
testInvokeOriginalWidgetDefined() {
stub_and_eval \
zle \
'return 1'
_zsh_autosuggest_invoke_original_widget 'self-insert'
assertEquals \
'1' \
"$?"
assertTrue \
'zle was not invoked' \
'stub_called zle'
restore zle
}
testInvokeOriginalWidgetUndefined() {
stub_and_eval \
zle \
'return 1'
_zsh_autosuggest_invoke_original_widget 'some-undefined-widget'
assertEquals \
'0' \
"$?"
assertFalse \
'zle was invoked' \
'stub_called zle'
restore zle
}
run_tests "$0"

View File

@@ -53,62 +53,4 @@ testMostRecentMatch() {
'cd quux'
}
testBackslash() {
set_history <<-'EOF'
echo "hello\nworld"
EOF
assertSuggestion \
'echo "hello\' \
'echo "hello\nworld"'
}
testDoubleBackslash() {
set_history <<-'EOF'
echo "\\"
EOF
assertSuggestion \
'echo "\\' \
'echo "\\"'
}
testTilde() {
set_history <<-'EOF'
cd ~/something
EOF
assertSuggestion \
'cd' \
'cd ~/something'
assertSuggestion \
'cd ~' \
'cd ~/something'
assertSuggestion \
'cd ~/s' \
'cd ~/something'
}
testParentheses() {
set_history <<-'EOF'
echo "$(ls foo)"
EOF
assertSuggestion \
'echo "$(' \
'echo "$(ls foo)"'
}
testSquareBrackets() {
set_history <<-'EOF'
echo "$history[123]"
EOF
assertSuggestion \
'echo "$history[' \
'echo "$history[123]"'
}
run_tests "$0"

View File

@@ -55,64 +55,6 @@ testMostRecentMatch() {
'cd quux'
}
testBackslash() {
set_history <<-'EOF'
echo "hello\nworld"
EOF
assertSuggestion \
'echo "hello\' \
'echo "hello\nworld"'
}
testDoubleBackslash() {
set_history <<-'EOF'
echo "\\"
EOF
assertSuggestion \
'echo "\\' \
'echo "\\"'
}
testTilde() {
set_history <<-'EOF'
cd ~/something
EOF
assertSuggestion \
'cd' \
'cd ~/something'
assertSuggestion \
'cd ~' \
'cd ~/something'
assertSuggestion \
'cd ~/s' \
'cd ~/something'
}
testParentheses() {
set_history <<-'EOF'
echo "$(ls foo)"
EOF
assertSuggestion \
'echo "$(' \
'echo "$(ls foo)"'
}
testSquareBrackets() {
set_history <<-'EOF'
echo "$history[123]"
EOF
assertSuggestion \
'echo "$history[' \
'echo "$history[123]"'
}
testMatchMostRecentAfterPreviousCmd() {
set_history <<-'EOF'
echo what

102
test/strategies_test.zsh Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env zsh
source "${0:a:h}/test_helper.zsh"
oneTimeSetUp() {
source_autosuggestions
}
assertBackslashSuggestion() {
set_history <<-'EOF'
echo "hello\nworld"
EOF
assertSuggestion \
'echo "hello\' \
'echo "hello\nworld"'
}
assertDoubleBackslashSuggestion() {
set_history <<-'EOF'
echo "\\"
EOF
assertSuggestion \
'echo "\\' \
'echo "\\"'
}
assertTildeSuggestion() {
set_history <<-'EOF'
cd ~/something
EOF
assertSuggestion \
'cd' \
'cd ~/something'
assertSuggestion \
'cd ~' \
'cd ~/something'
assertSuggestion \
'cd ~/s' \
'cd ~/something'
}
assertTildeSuggestionWithExtendedGlob() {
setopt local_options extended_glob
assertTildeSuggestion
}
assertParenthesesSuggestion() {
set_history <<-'EOF'
echo "$(ls foo)"
EOF
assertSuggestion \
'echo "$(' \
'echo "$(ls foo)"'
}
assertSquareBracketsSuggestion() {
set_history <<-'EOF'
echo "$history[123]"
EOF
assertSuggestion \
'echo "$history[' \
'echo "$history[123]"'
}
assertHashSuggestion() {
set_history <<-'EOF'
echo "#yolo"
EOF
assertSuggestion \
'echo "#' \
'echo "#yolo"'
}
testSpecialCharsForAllStrategies() {
local strategies
strategies=(
"default"
"match_prev_cmd"
)
for s in $strategies; do
ZSH_AUTOSUGGEST_STRATEGY="$s"
assertBackslashSuggestion
assertDoubleBackslashSuggestion
assertTildeSuggestion
assertTildeSuggestionWithExtendedGlob
assertParenthesesSuggestion
assertSquareBracketsSuggestion
done
}
run_tests "$0"

View File

@@ -43,30 +43,4 @@ testEscapeCommand() {
"$(_zsh_autosuggest_escape_command '?')"
}
testPrevCommand() {
set_history <<-'EOF'
ls foo
ls bar
ls baz
EOF
assertEquals \
'Did not output the last command' \
'ls baz' \
"$(_zsh_autosuggest_prev_command)"
set_history <<-'EOF'
ls foo
ls bar
ls baz
ls quux
ls foobar
EOF
assertEquals \
'Did not output the last command' \
'ls foobar' \
"$(_zsh_autosuggest_prev_command)"
}
run_tests "$0"

View File

@@ -54,7 +54,7 @@ assertSuggestion() {
local expected_suggestion="$2"
assertEquals \
"Did not get correct suggestion for prefix:<$prefix>" \
"Did not get correct suggestion for prefix:<$prefix> using strategy <$ZSH_AUTOSUGGEST_STRATEGY>" \
"$expected_suggestion" \
"$(_zsh_autosuggest_suggestion "$prefix")"
}

View File

@@ -6,6 +6,17 @@ oneTimeSetUp() {
source_autosuggestions
}
setUp() {
BUFFER=''
POSTDISPLAY=''
CURSOR=0
KEYMAP='main'
}
tearDown() {
restore _zsh_autosuggest_invoke_original_widget
}
testCursorAtEnd() {
BUFFER='echo'
POSTDISPLAY=' hello'
@@ -104,6 +115,19 @@ testViCursorNotAtEnd() {
"$POSTDISPLAY"
}
testRetval() {
stub_and_eval \
_zsh_autosuggest_invoke_original_widget \
'return 1'
_zsh_autosuggest_widget_accept 'original-widget'
assertEquals \
'Did not return correct value from original widget' \
'1' \
"$?"
}
testWidget() {
stub _zsh_autosuggest_highlight_reset
stub _zsh_autosuggest_accept
@@ -128,6 +152,10 @@ testWidget() {
assertTrue \
'highlight_apply was not called' \
'stub_called _zsh_autosuggest_highlight_apply'
restore _zsh_autosuggest_highlight_reset
restore _zsh_autosuggest_accept
restore _zsh_autosuggest_highlight_apply
}
run_tests "$0"

View File

@@ -6,6 +6,15 @@ oneTimeSetUp() {
source_autosuggestions
}
setUp() {
BUFFER=''
POSTDISPLAY=''
}
tearDown() {
restore _zsh_autosuggest_invoke_original_widget
}
testClear() {
BUFFER='ec'
POSTDISPLAY='ho hello'
@@ -22,6 +31,19 @@ testClear() {
"$POSTDISPLAY"
}
testRetval() {
stub_and_eval \
_zsh_autosuggest_invoke_original_widget \
'return 1'
_zsh_autosuggest_widget_clear 'original-widget'
assertEquals \
'Did not return correct value from original widget' \
'1' \
"$?"
}
testWidget() {
stub _zsh_autosuggest_highlight_reset
stub _zsh_autosuggest_clear
@@ -46,6 +68,10 @@ testWidget() {
assertTrue \
'highlight_apply was not called' \
'stub_called _zsh_autosuggest_highlight_apply'
restore _zsh_autosuggest_highlight_reset
restore _zsh_autosuggest_clear
restore _zsh_autosuggest_highlight_apply
}
run_tests "$0"

View File

@@ -0,0 +1,26 @@
#!/usr/bin/env zsh
source "${0:a:h}/../test_helper.zsh"
oneTimeSetUp() {
source_autosuggestions
}
tearDown() {
restore _zsh_autosuggest_invoke_original_widget
}
testRetval() {
stub_and_eval \
_zsh_autosuggest_invoke_original_widget \
'return 1'
_zsh_autosuggest_widget_execute 'original-widget'
assertEquals \
'Did not return correct value from original widget' \
'1' \
"$?"
}
run_tests "$0"

View File

@@ -6,10 +6,18 @@ oneTimeSetUp() {
source_autosuggestions
}
testModify() {
setUp() {
BUFFER=''
POSTDISPLAY=''
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=''
}
tearDown() {
restore _zsh_autosuggest_invoke_original_widget
restore _zsh_autosuggest_suggestion
}
testModify() {
stub_and_eval \
_zsh_autosuggest_invoke_original_widget \
'BUFFER+="e"'
@@ -33,9 +41,48 @@ testModify() {
'POSTDISPLAY does not contain suggestion' \
'cho hello' \
"$POSTDISPLAY"
}
restore _zsh_autosuggest_invoke_original_widget
restore _zsh_autosuggest_suggestion
testModifyBufferTooLarge() {
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE='20'
stub_and_eval \
_zsh_autosuggest_invoke_original_widget \
'BUFFER+="012345678901234567890"'
stub_and_echo \
_zsh_autosuggest_suggestion \
'012345678901234567890123456789'
_zsh_autosuggest_modify 'original-widget'
assertTrue \
'original widget not invoked' \
'stub_called _zsh_autosuggest_invoke_original_widget'
assertEquals \
'BUFFER was not modified' \
'012345678901234567890' \
"$BUFFER"
assertEquals \
'POSTDISPLAY does not contain suggestion' \
'' \
"$POSTDISPLAY"
}
testRetval() {
stub_and_eval \
_zsh_autosuggest_invoke_original_widget \
'return 1'
_zsh_autosuggest_widget_modify 'original-widget'
assertEquals \
'Did not return correct value from original widget' \
'1' \
"$?"
}
run_tests "$0"

View File

@@ -6,6 +6,16 @@ oneTimeSetUp() {
source_autosuggestions
}
setUp() {
BUFFER=''
POSTDISPLAY=''
CURSOR=0
}
tearDown() {
restore _zsh_autosuggest_invoke_original_widget
}
testCursorMovesOutOfBuffer() {
BUFFER='ec'
POSTDISPLAY='ho hello'
@@ -58,4 +68,17 @@ testCursorStaysInBuffer() {
"$POSTDISPLAY"
}
testRetval() {
stub_and_eval \
_zsh_autosuggest_invoke_original_widget \
'return 1'
_zsh_autosuggest_widget_partial_accept 'original-widget'
assertEquals \
'Did not return correct value from original widget' \
'1' \
"$?"
}
run_tests "$0"

View File

@@ -1 +0,0 @@
zsh-autosuggestions.zsh

View File

@@ -0,0 +1 @@
source ${0:A:h}/zsh-autosuggestions.zsh

View File

@@ -1,6 +1,6 @@
# Fish-like fast/unobtrusive autosuggestions for zsh.
# https://github.com/zsh-users/zsh-autosuggestions
# v0.3.1
# v0.3.3
# Copyright (c) 2013 Thiago de Arruda
# Copyright (c) 2016 Eric Freese
#
@@ -58,6 +58,7 @@ ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
end-of-line
vi-forward-char
vi-end-of-line
vi-add-eol
)
# Widgets that accept the entire suggestion and execute it
@@ -73,6 +74,19 @@ ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
vi-forward-blank-word-end
)
# Widgets that should be ignored (globbing supported but must be escaped)
ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
orig-\*
beep
run-help
set-local-history
which-command
yank
)
# Max size of buffer to trigger autosuggestion. Leave undefined for no upper bound.
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=
#--------------------------------------------------------------------#
# Handle Deprecated Variables/Widgets #
#--------------------------------------------------------------------#
@@ -131,13 +145,13 @@ _zsh_autosuggest_bind_widget() {
# Built-in widget
builtin)
eval "_zsh_autosuggest_orig_$widget() { zle .$widget }"
eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
zle -N $prefix$widget _zsh_autosuggest_orig_$widget
;;
# Completion widget
completion:*)
eval "zle -C $prefix$widget ${${widgets[$widget]#*:}/:/ }"
eval "zle -C $prefix${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
;;
esac
@@ -147,8 +161,8 @@ _zsh_autosuggest_bind_widget() {
# 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_$widget() {
_zsh_autosuggest_widget_$autosuggest_action $prefix$widget \$@
eval "_zsh_autosuggest_bound_${(q)widget}() {
_zsh_autosuggest_widget_$autosuggest_action $prefix${(q)widget} \$@
}"
# Create the bound widget
@@ -157,10 +171,20 @@ _zsh_autosuggest_bind_widget() {
# Map all configured widgets to the right autosuggest widgets
_zsh_autosuggest_bind_widgets() {
local widget;
local widget
local ignore_widgets
ignore_widgets=(
.\*
_\*
zle-line-\*
autosuggest-\*
$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
)
# Find every widget we might want to bind and bind it appropriately
for widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|autosuggest-*|$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX*|zle-line-*|run-help|which-command|beep|set-local-history|yank)}; do
for widget in ${${(f)"$(builtin zle -la)"}:#${(j:|:)~ignore_widgets}}; do
if [ ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]; then
_zsh_autosuggest_bind_widget $widget clear
elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then
@@ -230,21 +254,39 @@ _zsh_autosuggest_clear() {
# Modify the buffer and get a new suggestion
_zsh_autosuggest_modify() {
# Original widget modifies the buffer
local -i retval
# Save the contents of the buffer/postdisplay
local orig_buffer="$BUFFER"
local orig_postdisplay="$POSTDISPLAY"
# Clear suggestion while original widget runs
unset POSTDISPLAY
# Original widget may modify the buffer
_zsh_autosuggest_invoke_original_widget $@
retval=$?
# Don't fetch a new suggestion if the buffer hasn't changed
if [ "$BUFFER" = "$orig_buffer" ]; then
POSTDISPLAY="$orig_postdisplay"
return $retval
fi
# Get a new suggestion if the buffer is not empty after modification
local suggestion
if [ $#BUFFER -gt 0 ]; then
suggestion="$(_zsh_autosuggest_suggestion "$BUFFER")"
if [ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" -o $#BUFFER -lt "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]; then
suggestion="$(_zsh_autosuggest_suggestion "$BUFFER")"
fi
fi
# Add the suggestion to the POSTDISPLAY
if [ -n "$suggestion" ]; then
POSTDISPLAY="${suggestion#$BUFFER}"
else
unset POSTDISPLAY
fi
return $retval
}
# Accept the entire suggestion
@@ -287,6 +329,8 @@ _zsh_autosuggest_execute() {
# Partially accept the suggestion
_zsh_autosuggest_partial_accept() {
local -i retval
# Save the contents of the buffer so we can restore later if needed
local original_buffer="$BUFFER"
@@ -295,6 +339,7 @@ _zsh_autosuggest_partial_accept() {
# Original widget moves the cursor
_zsh_autosuggest_invoke_original_widget $@
retval=$?
# If we've moved past the end of the original buffer
if [ $CURSOR -gt $#original_buffer ]; then
@@ -307,13 +352,22 @@ _zsh_autosuggest_partial_accept() {
# Restore the original buffer
BUFFER="$original_buffer"
fi
return $retval
}
for action in clear modify accept partial_accept execute; do
eval "_zsh_autosuggest_widget_$action() {
local -i retval
_zsh_autosuggest_highlight_reset
_zsh_autosuggest_$action \$@
retval=\$?
_zsh_autosuggest_highlight_apply
return \$retval
}"
done
@@ -327,11 +381,11 @@ zle -N autosuggest-execute _zsh_autosuggest_widget_execute
# Delegate to the selected strategy to determine a suggestion
_zsh_autosuggest_suggestion() {
local prefix="$1"
local escaped_prefix="$(_zsh_autosuggest_escape_command "$1")"
local strategy_function="_zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY"
if [ -n "$functions[$strategy_function]" ]; then
echo -E "$($strategy_function "$prefix")"
echo -E "$($strategy_function "$escaped_prefix")"
fi
}
@@ -339,12 +393,7 @@ _zsh_autosuggest_escape_command() {
setopt localoptions EXTENDED_GLOB
# Escape special chars in the string (requires EXTENDED_GLOB)
echo -E "${1//(#m)[\\()\[\]|*?]/\\$MATCH}"
}
# Get the previously executed command
_zsh_autosuggest_prev_command() {
echo -E "${history[$((HISTCMD-1))]}"
echo -E "${1//(#m)[\\()\[\]|*?~]/\\$MATCH}"
}
#--------------------------------------------------------------------#
@@ -355,14 +404,7 @@ _zsh_autosuggest_prev_command() {
#
_zsh_autosuggest_strategy_default() {
local prefix="$(_zsh_autosuggest_escape_command "$1")"
# Get the keys of the history items that match
local -a histkeys
histkeys=(${(k)history[(r)$prefix*]})
# Echo the value of the first key
echo -E "${history[$histkeys[1]]}"
fc -lnrm "$1*" 1 2>/dev/null | head -n 1
}
#--------------------------------------------------------------------#
@@ -382,9 +424,12 @@ _zsh_autosuggest_strategy_default() {
# will be 'ls foo' rather than 'ls bar' because your most recently
# executed command (pwd) was previously followed by 'ls foo'.
#
# 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`.
_zsh_autosuggest_strategy_match_prev_cmd() {
local prefix="$(_zsh_autosuggest_escape_command "$1")"
local prefix="$1"
# Get all history event numbers that correspond to history
# entries that match pattern $prefix*
@@ -395,8 +440,7 @@ _zsh_autosuggest_strategy_match_prev_cmd() {
local histkey="${history_match_keys[1]}"
# Get the previously executed command
local prev_cmd="$(_zsh_autosuggest_prev_command)"
prev_cmd="$(_zsh_autosuggest_escape_command "$prev_cmd")"
local prev_cmd="$(_zsh_autosuggest_escape_command "${history[$((HISTCMD-1))]}")"
# Iterate up to the first 200 history event numbers that match $prefix
for key in "${(@)history_match_keys[1,200]}"; do