Compare commits

..
Author SHA1 Message Date
Eric Freese 4ccfdb2435 Fix issue where partial accept duplicates last word
When z-sy-h is enabled after autosuggestion widgets have already been
bound, partial accepting the last part of a suggestion will result in
that string being duplicated.

I was able to reproduce using the following versions of the two plugins:
- z-sy-h: dde84e1b25f059a298ce3189cddfd0778f998df3
- z-asug: ae315ded4d

and running the following commands interactively one after another:

```
zsh -df
% source path/to/zsh-autosuggestions.zsh
% source path/to/zsh-syntax-highlighting.zsh
% bindkey -e
% bindkey <alt-f>         # shows 'bindkey -e-e'
```

The order of the `source` statements matters and the issue cannot be
reproduced if the two source statements are executed together on one
line.

The problem is very similar to this one:
  https://github.com/zsh-users/zsh-autosuggestions/issues/126#issuecomment-217121315

See GitHub issue #483
2020-01-29 21:47:57 -07:00
11 changed files with 68 additions and 63 deletions
-6
View File
@@ -1,11 +1,5 @@
# Changelog # Changelog
## v0.7.0
- Enable asynchronous mode by default (#498)
- No longer wrap user widgets starting with `autosuggest-` prefix (#496)
- Fix a bug wrapping widgets that modify the buffer (#541)
## v0.6.4 ## v0.6.4
- Fix `vi-forward-char` triggering a bell when using it to accept a suggestion (#488) - Fix `vi-forward-char` triggering a bell when using it to accept a suggestion (#488)
- New configuration option to skip completion suggestions when buffer matches a pattern (#487) - New configuration option to skip completion suggestions when buffer matches a pattern (#487)
+1 -4
View File
@@ -39,10 +39,7 @@
2. Add the plugin to the list of plugins for Oh My Zsh to load (inside `~/.zshrc`): 2. Add the plugin to the list of plugins for Oh My Zsh to load (inside `~/.zshrc`):
```sh ```sh
plugins=( plugins=(zsh-autosuggestions)
# other plugins...
zsh-autosuggestions
)
``` ```
3. Start a new terminal session. 3. Start a new terminal session.
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2013 Thiago de Arruda Copyright (c) 2013 Thiago de Arruda
Copyright (c) 2016-2021 Eric Freese Copyright (c) 2016-2019 Eric Freese
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
+1 -1
View File
@@ -1 +1 @@
v0.7.0 v0.6.4
-1
View File
@@ -14,4 +14,3 @@
5.5.1 5.5.1
5.6.2 5.6.2
5.7.1 5.7.1
5.8
+6 -1
View File
@@ -1,6 +1,11 @@
describe 'a multi-line suggestion' do describe 'a multi-line suggestion' do
it 'should be displayed on multiple lines' do it 'should be displayed on multiple lines' do
with_history("echo \"\n\"") do with_history(-> {
session.send_string('echo "')
session.send_keys('enter')
session.send_string('"')
session.send_keys('enter')
}) do
session.send_keys('e') session.send_keys('e')
wait_for { session.content }.to eq("echo \"\n\"") wait_for { session.content }.to eq("echo \"\n\"")
end end
+4 -7
View File
@@ -1,7 +1,6 @@
require 'pry' require 'pry'
require 'rspec/wait' require 'rspec/wait'
require 'terminal_session' require 'terminal_session'
require 'tempfile'
RSpec.shared_context 'terminal session' do RSpec.shared_context 'terminal session' do
let(:term_opts) { {} } let(:term_opts) { {} }
@@ -22,12 +21,11 @@ RSpec.shared_context 'terminal session' do
end end
def with_history(*commands, &block) def with_history(*commands, &block)
Tempfile.create do |f|
f.write(commands.map{|c| c.gsub("\n", "\\\n")}.join("\n"))
f.flush
session.run_command('fc -p') session.run_command('fc -p')
session.run_command("fc -R #{f.path}")
commands.each do |c|
c.respond_to?(:call) ? c.call : session.run_command(c)
end
session.clear_screen session.clear_screen
@@ -37,7 +35,6 @@ RSpec.shared_context 'terminal session' do
session.run_command('fc -P') session.run_command('fc -P')
end end
end end
end
RSpec.configure do |config| RSpec.configure do |config|
config.expect_with :rspec do |expectations| config.expect_with :rspec do |expectations|
+6 -19
View File
@@ -1,71 +1,58 @@
shared_examples 'special characters' do shared_examples 'special characters' do
describe 'a special character in the buffer should be treated like any other character' do describe 'a special character in the buffer' do
it 'asterisk' do it 'should be treated like any other character' do
with_history('echo "hello*"', 'echo "hello."') do with_history('echo "hello*"', 'echo "hello."') do
session.send_string('echo "hello*') session.send_string('echo "hello*')
wait_for { session.content }.to eq('echo "hello*"') wait_for { session.content }.to eq('echo "hello*"')
end end
end
it 'question mark' do
with_history('echo "hello?"', 'echo "hello."') do with_history('echo "hello?"', 'echo "hello."') do
session.send_string('echo "hello?') session.send_string('echo "hello?')
wait_for { session.content }.to eq('echo "hello?"') wait_for { session.content }.to eq('echo "hello?"')
end end
end
it 'backslash' do
with_history('echo "hello\nworld"') do with_history('echo "hello\nworld"') do
session.send_string('echo "hello\\') session.send_string('echo "hello\\')
wait_for { session.content }.to eq('echo "hello\nworld"') wait_for { session.content }.to eq('echo "hello\nworld"')
end end
end
it 'double backslash' do
with_history('echo "\\\\"') do with_history('echo "\\\\"') do
session.send_string('echo "\\\\') session.send_string('echo "\\\\')
wait_for { session.content }.to eq('echo "\\\\"') wait_for { session.content }.to eq('echo "\\\\"')
end end
end
it 'tilde' do
with_history('echo ~/foo') do with_history('echo ~/foo') do
session.send_string('echo ~') session.send_string('echo ~')
wait_for { session.content }.to eq('echo ~/foo') wait_for { session.content }.to eq('echo ~/foo')
end end
end
it 'parentheses' do
with_history('echo "$(ls foo)"') do with_history('echo "$(ls foo)"') do
session.send_string('echo "$(') session.send_string('echo "$(')
wait_for { session.content }.to eq('echo "$(ls foo)"') wait_for { session.content }.to eq('echo "$(ls foo)"')
end end
end
it 'square bracket' do
with_history('echo "$history[123]"') do with_history('echo "$history[123]"') do
session.send_string('echo "$history[') session.send_string('echo "$history[')
wait_for { session.content }.to eq('echo "$history[123]"') wait_for { session.content }.to eq('echo "$history[123]"')
session.send_string('123]') session.send_string('123]')
wait_for { session.content }.to eq('echo "$history[123]"') wait_for { session.content }.to eq('echo "$history[123]"')
end end
end
it 'octothorpe' do
with_history('echo "#yolo"') do with_history('echo "#yolo"') do
session.send_string('echo "#') session.send_string('echo "#')
wait_for { session.content }.to eq('echo "#yolo"') wait_for { session.content }.to eq('echo "#yolo"')
end end
with_history('echo "#foo"', 'echo $#abc') do
session.send_string('echo "#')
wait_for { session.content }.to eq('echo "#foo"')
end end
it 'caret' do
with_history('echo "^A"', 'echo "^B"') do with_history('echo "^A"', 'echo "^B"') do
session.send_string('echo "^A') session.send_string('echo "^A')
wait_for { session.content }.to eq('echo "^A"') wait_for { session.content }.to eq('echo "^A"')
end end
end
it 'dash' do
with_history('-foo() {}') do with_history('-foo() {}') do
session.send_string('-') session.send_string('-')
wait_for { session.content }.to eq('-foo() {}') wait_for { session.content }.to eq('-foo() {}')
+1 -2
View File
@@ -44,8 +44,7 @@ _zsh_autosuggest_async_request() {
# There's a weird bug here where ^C stops working unless we force a fork # There's a weird bug here where ^C stops working unless we force a fork
# See https://github.com/zsh-users/zsh-autosuggestions/issues/364 # See https://github.com/zsh-users/zsh-autosuggestions/issues/364
autoload -Uz is-at-least command true
is-at-least 5.8 || command true
# Read the pid from the child process # Read the pid from the child process
read _ZSH_AUTOSUGGEST_CHILD_PID <&$_ZSH_AUTOSUGGEST_ASYNC_FD read _ZSH_AUTOSUGGEST_CHILD_PID <&$_ZSH_AUTOSUGGEST_ASYNC_FD
+19 -5
View File
@@ -61,9 +61,20 @@ _zsh_autosuggest_modify() {
return $retval return $retval
fi fi
# Optimize if manually typing in the suggestion or if buffer hasn't changed # Optimize if manually typing in the suggestion
if [[ "$BUFFER" = "$orig_buffer"* && "$orig_postdisplay" = "${BUFFER:$#orig_buffer}"* ]]; then if (( $#BUFFER > $#orig_buffer )); then
POSTDISPLAY="${orig_postdisplay:$(($#BUFFER - $#orig_buffer))}" local added=${BUFFER#$orig_buffer}
# If the string added matches the beginning of the postdisplay
if [[ "$added" = "${orig_postdisplay:0:$#added}" ]]; then
POSTDISPLAY="${orig_postdisplay:$#added}"
return $retval
fi
fi
# Don't fetch a new suggestion if the buffer hasn't changed
if [[ "$BUFFER" = "$orig_buffer" ]]; then
POSTDISPLAY="$orig_postdisplay"
return $retval return $retval
fi fi
@@ -162,11 +173,13 @@ _zsh_autosuggest_execute() {
_zsh_autosuggest_partial_accept() { _zsh_autosuggest_partial_accept() {
local -i retval cursor_loc local -i retval cursor_loc
# Save the contents of the buffer so we can restore later if needed # Save the original buffer/postdisplay so we can restore later if needed
local original_buffer="$BUFFER" local original_buffer="$BUFFER"
local original_postdisplay="$POSTDISPLAY"
# Temporarily accept the suggestion. # Temporarily accept the suggestion.
BUFFER="$BUFFER$POSTDISPLAY" BUFFER="$BUFFER$POSTDISPLAY"
unset POSTDISPLAY
# Original widget moves the cursor # Original widget moves the cursor
_zsh_autosuggest_invoke_original_widget $@ _zsh_autosuggest_invoke_original_widget $@
@@ -186,8 +199,9 @@ _zsh_autosuggest_partial_accept() {
# Clip the buffer at the cursor # Clip the buffer at the cursor
BUFFER="${BUFFER[1,$cursor_loc]}" BUFFER="${BUFFER[1,$cursor_loc]}"
else else
# Restore the original buffer # Restore the original buffer/postdisplay
BUFFER="$original_buffer" BUFFER="$original_buffer"
POSTDISPLAY="$original_postdisplay"
fi fi
return $retval return $retval
+22 -9
View File
@@ -1,8 +1,8 @@
# Fish-like fast/unobtrusive autosuggestions for zsh. # Fish-like fast/unobtrusive autosuggestions for zsh.
# https://github.com/zsh-users/zsh-autosuggestions # https://github.com/zsh-users/zsh-autosuggestions
# v0.7.0 # v0.6.4
# Copyright (c) 2013 Thiago de Arruda # Copyright (c) 2013 Thiago de Arruda
# Copyright (c) 2016-2021 Eric Freese # Copyright (c) 2016-2019 Eric Freese
# #
# Permission is hereby granted, free of charge, to any person # Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation # obtaining a copy of this software and associated documentation
@@ -323,9 +323,20 @@ _zsh_autosuggest_modify() {
return $retval return $retval
fi fi
# Optimize if manually typing in the suggestion or if buffer hasn't changed # Optimize if manually typing in the suggestion
if [[ "$BUFFER" = "$orig_buffer"* && "$orig_postdisplay" = "${BUFFER:$#orig_buffer}"* ]]; then if (( $#BUFFER > $#orig_buffer )); then
POSTDISPLAY="${orig_postdisplay:$(($#BUFFER - $#orig_buffer))}" local added=${BUFFER#$orig_buffer}
# If the string added matches the beginning of the postdisplay
if [[ "$added" = "${orig_postdisplay:0:$#added}" ]]; then
POSTDISPLAY="${orig_postdisplay:$#added}"
return $retval
fi
fi
# Don't fetch a new suggestion if the buffer hasn't changed
if [[ "$BUFFER" = "$orig_buffer" ]]; then
POSTDISPLAY="$orig_postdisplay"
return $retval return $retval
fi fi
@@ -424,11 +435,13 @@ _zsh_autosuggest_execute() {
_zsh_autosuggest_partial_accept() { _zsh_autosuggest_partial_accept() {
local -i retval cursor_loc local -i retval cursor_loc
# Save the contents of the buffer so we can restore later if needed # Save the original buffer/postdisplay so we can restore later if needed
local original_buffer="$BUFFER" local original_buffer="$BUFFER"
local original_postdisplay="$POSTDISPLAY"
# Temporarily accept the suggestion. # Temporarily accept the suggestion.
BUFFER="$BUFFER$POSTDISPLAY" BUFFER="$BUFFER$POSTDISPLAY"
unset POSTDISPLAY
# Original widget moves the cursor # Original widget moves the cursor
_zsh_autosuggest_invoke_original_widget $@ _zsh_autosuggest_invoke_original_widget $@
@@ -448,8 +461,9 @@ _zsh_autosuggest_partial_accept() {
# Clip the buffer at the cursor # Clip the buffer at the cursor
BUFFER="${BUFFER[1,$cursor_loc]}" BUFFER="${BUFFER[1,$cursor_loc]}"
else else
# Restore the original buffer # Restore the original buffer/postdisplay
BUFFER="$original_buffer" BUFFER="$original_buffer"
POSTDISPLAY="$original_postdisplay"
fi fi
return $retval return $retval
@@ -799,8 +813,7 @@ _zsh_autosuggest_async_request() {
# There's a weird bug here where ^C stops working unless we force a fork # There's a weird bug here where ^C stops working unless we force a fork
# See https://github.com/zsh-users/zsh-autosuggestions/issues/364 # See https://github.com/zsh-users/zsh-autosuggestions/issues/364
autoload -Uz is-at-least command true
is-at-least 5.8 || command true
# Read the pid from the child process # Read the pid from the child process
read _ZSH_AUTOSUGGEST_CHILD_PID <&$_ZSH_AUTOSUGGEST_ASYNC_FD read _ZSH_AUTOSUGGEST_CHILD_PID <&$_ZSH_AUTOSUGGEST_ASYNC_FD