Compare commits

..

60 Commits

Author SHA1 Message Date
Eric Freese 161de32912 Use zle redraw hook if available (>= 5.4) 2019-01-11 19:02:55 -07:00
Eric Freese de4256a63b Enable zle -U test in newer zsh versions 2019-01-11 18:58:05 -07:00
Eric Freese 50579b3371 Move widget definitions inside anonymous function 2018-12-21 23:20:08 -07:00
Eric Freese 66b842579a Merge pull request #403 from okdana/dana/typeset-g
Set global parameters with typeset -g
2018-12-21 23:19:23 -07:00
dana aee1b10db6 Avoid warn_create_global warnings 2018-12-19 13:38:06 -06:00
Eric Freese ebc2c07ac8 Merge pull request #402 from zsh-users/fixes/autocd-tab-completion
Respect user's set options when running original widget
2018-12-17 17:59:06 -07:00
Eric Freese e937e89267 Respect user's set options when running original widget
Fixes GitHub #379
2018-12-16 21:13:02 -07:00
Eric Freese 11251d97ca Merge branch 'master' into develop 2018-12-16 20:50:16 -07:00
Eric Freese 41657e3565 Revert async process substitution & completion strategy
They're not quite ready. Keep them on a feature branch for now.
2018-12-16 20:49:06 -07:00
Eric Freese 70f36c007d Finish renaming "default" strategy to "history" 2018-11-24 15:07:08 -07:00
Eric Freese 4838222dde Merge branch 'master' into develop 2018-11-18 22:32:17 -07:00
Eric Freese 35c286de9a Merge pull request #390 from zsh-users/features/no-overwrite-config
Features/no overwrite config
2018-11-18 22:19:31 -07:00
Eric Nielsen e61442161e Don't overwrite config with default values
otherwise users are obliged to set the config values *after* sourcing
the plugin. They're not able to do it before. Also, re-sourcing the
plugin will reset the values to the defaults again.

See zimfw/zimfw#301

Fixes #335
2018-11-18 12:39:23 -07:00
Eric Freese 4b28d92e01 Add after_sourcing hook for tests
Is executed immediately after sourcing the plugin
2018-11-10 14:55:13 -07:00
Eric Freese b512a1b040 Merge branch 'master' into develop 2018-11-10 13:43:47 -07:00
Eric Freese fa5d9c0ff5 Merge pull request #360 from zsh-users/fixes/glob-subst-bad-pattern
Reset opts in some functions affected by GLOB_SUBST
2018-07-17 22:26:55 -07:00
Eric Freese 681ffc7b28 Reset opts in some functions affected by GLOB_SUBST
Should fix GitHub #334
2018-07-13 22:16:53 -06:00
Eric Freese b8bf86f6ab Merge pull request #359 from zsh-users/fixes/async-bad-file-descriptor
Fixes/async bad file descriptor
2018-07-13 20:50:31 -07:00
Eric Freese 7ab2124904 Kill async process by id when job control disabled 2018-07-13 21:48:25 -06:00
Eric Freese 88fe824ddf Add some error handling to async response handler
We only want to read data in case of POLLIN or POLLHUP. Not POLLNVAL or
select error.

We always want to remove the handler, so it doesn't get called in an
infinite loop when error is nval or err.

In zsh source, see main zle event loop in zle_main.c raw_getbyte
function.
2018-07-13 11:26:57 -06:00
Eric Freese 93877f6b76 We also need to remove the handler when cancelling async request
Should fix GitHub #353
2018-07-13 11:25:59 -06:00
Eric Freese 0ee5b0a5c9 Completion strategy no longer requires zutil module 2018-07-02 22:38:20 -06:00
Eric Freese bd1fd97738 Cleanup unused async pty name 2018-07-02 22:38:20 -06:00
Eric Freese 106bf02d49 Merge pull request #350 from zsh-users/features/improved-completion-suggestions
Improve completion suggestions
2018-07-02 12:28:39 -06:00
Eric Freese f1c3b98774 Only capture completions at the end of the buffer.
To prevent the suggestion from not starting with the buffer string.

Example:

`ls / /[cursor left][cursor left]b`

Before the patch, suggests `ls /b /ls /bin/ /`

After the patch, suggests `ls /b /bin/`.

https://github.com/zsh-users/zsh-autosuggestions/issues/343#issuecomment-401675712
2018-07-02 12:25:20 -06:00
Eric Freese 4869a757c8 Ensure we always destroy the zpty
If running in sync mode and a completion takes a long time, the user can
^C out of it. Without this patch, the pty will not be destroyed in this
case and the next time we go to create it, it will fail, making the
shell unusable.
2018-07-02 12:25:20 -06:00
Eric Freese 302bd7c059 Setup zshexit hook immediately in both sync/async cases 2018-07-02 12:25:20 -06:00
Eric Freese 245f5d2ba2 Improve completion suggestions
Just insert the first completion directly into the buffer and read the
whole buffer from the zpty.
2018-07-02 12:25:20 -06:00
Martin Väth 8ae0283c90 Do not rely on implicit NULLCMD=cat 2018-07-02 12:21:49 -06:00
Eric Freese 07b37fd9ce Merge pull request #349 from zsh-users/features/antigen-install-directions
Add install directions for Antigen
2018-07-01 01:54:01 -06:00
Eric Freese 7c83775bc7 Merge pull request #348 from zsh-users/fixes/no-zpty
Fixes/no zpty
2018-06-30 18:07:06 -06:00
Eric Freese e97d132b3b Add install directions for Antigen 2018-06-30 17:15:31 -06:00
Eric Freese c0315e96d8 Don't use -s option to zmodload
It is not available in zsh versions older than 5.3
2018-06-30 16:54:33 -06:00
Eric Freese 5529102afc zpty module is only needed for completion strategy 2018-06-30 15:09:24 -06:00
Eric Freese dad6be4d5e Remove unused feature detection
Not needed after move away from zpty for async
2018-06-30 15:05:37 -06:00
Eric Freese 7d968869e3 Return if no completion found 2018-06-30 15:03:14 -06:00
Eric Freese 8593624996 Merge pull request #330 from zsh-users/features/completion-suggestions
Features/completion suggestions
2018-06-30 14:35:50 -06:00
Eric Freese 1ec43c7291 Fix error when single quote entered into buffer
Error looked something like:

```
% echo 'f(zpty):8: unmatched '
_zsh_autosuggest_capture_completion:zpty:9: no such pty command: zsh_autosuggest_completion_pty
_zsh_autosuggest_capture_completion:zpty:14: no such pty command: zsh_autosuggest_completion_pty
_zsh_autosuggest_capture_completion:zpty:21: no such pty command: zsh_autosuggest_completion_pty
```

According to `man zshmodules`, the args to `zpty` are "concatenated with
spaces between, then executed as a command, as if passed to the eval
builtin." So we need to escape the `$` so that `$1` is passed to eval
instead of the value of `$1`.
2018-06-29 22:08:33 -06:00
Martin Väth 43a011026f Do not leak global variables REPLY and strategy
https://github.com/zsh-users/zsh-autosuggestions/issues/341
2018-06-18 16:39:48 -06:00
Eric Freese cd81522b30 Attempt to kill async worker process when new request comes in
See http://www.zsh.org/mla/users/2018/msg00432.html
2018-06-12 23:45:29 -06:00
Eric Freese 4a268da1df Fix readme- async no longer uses zpty 2018-06-11 02:39:00 -06:00
Eric Freese d7171232c3 Merge branch 'develop' into features/completion-suggestions 2018-06-11 02:34:24 -06:00
Eric Freese faf0f9a698 Merge pull request #338 from zsh-users/fixes/async-refactor
Refactor async mode to no longer use zpty
2018-06-11 02:25:12 -06:00
Eric Freese 9cb0101512 Refactor async mode to no longer use zpty
See technique used in `fast-syntax-highlighting`:
- https://github.com/zdharma/fast-syntax-highlighting/commit/ca2e18bbc9e27b9264206c257d2ab68838162c70
- http://www.zsh.org/mla/users/2018/msg00424.html
2018-06-11 02:12:47 -06:00
Eric Freese b0ffc34fb8 completion should be a local var 2018-06-10 23:35:22 -06:00
Eric Freese 4e466f0e4e Support widgets starting with dashes (ex: -a-widget)
Fixes #337
2018-06-10 22:39:58 -06:00
Eric Freese bcbdad83e9 Support fallback strategies by setting array in config 2018-06-06 22:03:56 -06:00
Eric Freese 949c374195 Fix completion strategy on older versions of zsh
`zpty -r` with a pattern seems to have some funky behavior on older
versions, giving unpredictable results
2018-05-26 15:42:50 -06:00
Eric Freese 973205005c Add spec for completion strategy 2018-05-26 15:42:50 -06:00
Eric Freese 7d19f8f9b2 Rename default spec to history spec 2018-05-26 15:35:29 -06:00
Eric Freese cf458d2a3b Fix completion suggestions when compinit is not enabled
Need to make sure compinit is called in the pty or the shell hangs
2018-05-26 15:35:29 -06:00
Eric Freese 3dbd9afaec Fix completion strategy killing other pty's
Only a problem in synchronous mode
2018-05-26 15:35:29 -06:00
Eric Freese 6ffaec725a Allow completion suggestions from current shell
The `zsh -f` running in the PTY doesn't know about the non-exported
variables and functions defined in the original shell, thus can't make
suggestions for them. Run local functions in the PTY instead of a new
`zsh` process.

We have to handle things differently based on whether zle is active or
not (async vs. sync mode).
2018-05-26 15:35:29 -06:00
Eric Freese 0a548c62f4 Forgot to make after small tweak 2018-05-26 15:35:29 -06:00
Eric Freese 4cca26ec84 Modify completion code to better fit our needs
Only need the first completion result
2018-05-26 15:35:29 -06:00
Eric Freese f63afd5969 Fix async pty name option spec 2018-05-26 15:35:29 -06:00
Eric Freese c5551daabc Default strategy now tries history first and falls back to completion 2018-05-26 15:35:29 -06:00
Eric Freese 82b08e2dc8 First pass at getting suggestions from completion engine (#111)
Uses https://github.com/Valodim/zsh-capture-completion with some slight
modifications.
2018-05-26 15:35:29 -06:00
Eric Freese 5549b68e6e Async is less reliable in zsh versions < 5.0.8
`stty` occasionally hangs (always in CircleCI) inside the async pty.

Disable the tests for now until we can figure out and fix/workaround
this issue.
2018-05-26 15:34:57 -06:00
Eric Freese 63789e96b5 Fix handling of newline + carriage return in async pty (#333) 2018-05-26 14:16:00 -06:00
15 changed files with 460 additions and 273 deletions
+14
View File
@@ -0,0 +1,14 @@
describe 'with `AUTO_CD` option set' do
let(:after_sourcing) do
-> {
session.run_command('setopt AUTO_CD')
session.run_command('autoload compinit && compinit')
}
end
it 'directory names are still completed' do
session.send_string('sr')
session.send_keys('C-i')
wait_for { session.content }.to eq('src/')
end
end
+12
View File
@@ -0,0 +1,12 @@
describe 'with `GLOB_SUBST` option set' do
let(:after_sourcing) do
-> {
session.run_command('setopt GLOB_SUBST')
}
end
it 'error messages are not printed' do
session.send_string('[[')
wait_for { session.content }.to eq('[[')
end
end
+18 -16
View File
@@ -1,16 +1,24 @@
describe 'a wrapped widget' do
let(:widget) { 'backward-delete-char' }
context 'initialized before sourcing the plugin' do
let(:before_sourcing) do
-> do
session.
run_command("_orig_#{widget}() { zle .#{widget} }").
run_command("zle -N orig-#{widget} _orig_#{widget}").
run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }").
run_command("zle -N #{widget} #{widget}-magic")
end
let(:initialize_widget) do
-> do
session.run_command(<<~ZSH)
if [[ "$widgets[#{widget}]" == "builtin" ]]; then
_orig_#{widget}() { zle .#{widget} }
zle -N orig-#{widget} _orig_#{widget}
else
zle -N orig-#{widget} ${widgets[#{widget}]#*:}
fi
#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }
zle -N #{widget} #{widget}-magic
ZSH
end
end
context 'initialized before sourcing the plugin' do
let(:before_sourcing) { initialize_widget }
it 'executes the custom behavior and the built-in behavior' do
with_history('foobar', 'foodar') do
@@ -21,13 +29,7 @@ describe 'a wrapped widget' do
end
context 'initialized after sourcing the plugin' do
before do
session.
run_command("zle -N orig-#{widget} ${widgets[#{widget}]#*:}").
run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }").
run_command("zle -N #{widget} #{widget}-magic").
clear_screen
end
let(:after_sourcing) { initialize_widget }
it 'executes the custom behavior and the built-in behavior' do
with_history('foobar', 'foodar') do
+3 -2
View File
@@ -9,8 +9,9 @@ describe 'using `zle -U`' do
let(:options) { ['unset ZSH_AUTOSUGGEST_USE_ASYNC', 'ZSH_AUTOSUGGEST_STRATEGY=test'] }
# TODO: This is only possible with the $KEYS_QUEUED_COUNT widget parameter, coming soon...
xit 'does not fetch a suggestion for every inserted character' do
it 'does not fetch a suggestion for every inserted character' do
skip 'KEYS_QUEUED_COUNT not supported below v5.4.0' if session.zsh_version < Gem::Version.new('5.4.0')
session.send_keys('C-b')
wait_for { session.content }.to eq('echo hello')
end
+13 -5
View File
@@ -41,12 +41,20 @@ describe 'a zle widget' do
end
end
context 'when added to ZSH_AUTOSUGGEST_IGNORE_WIDGETS' do
let(:options) { ["ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(#{widget})"] }
context 'that accesses POSTDISPLAY' do
before { session.run_command("#{widget}() { zle -M \"POSTDISPLAY=$POSTDISPLAY\" }") }
it 'should not be wrapped with an autosuggest widget' do
session.run_command("echo $widgets[#{widget}]")
wait_for { session.content }.to end_with("\nuser:#{widget}")
context 'when added to ZSH_AUTOSUGGEST_IGNORE_WIDGETS' do
let(:options) { ["ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(#{widget})"] }
it 'gets the correct POSTDISPLAY value' do
with_history('echo hello') do
session.send_string('e')
wait_for { session.content }.to start_with('echo hello')
session.send_keys('C-b')
wait_for { session.content }.to end_with("\nPOSTDISPLAY=cho hello")
end
end
end
end
@@ -1,6 +1,6 @@
require 'strategies/special_characters_helper'
describe 'the default suggestion strategy' do
describe 'the `history` suggestion strategy' do
it 'suggests the last matching history entry' do
with_history('ls foo', 'ls bar', 'echo baz') do
session.send_string('ls')
+1 -1
View File
@@ -1,6 +1,6 @@
require 'strategies/special_characters_helper'
describe 'the match_prev_cmd strategy' do
describe 'the `match_prev_cmd` strategy' do
let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd'] }
it 'suggests the last matching history entry after the previous command' do
+28 -15
View File
@@ -72,11 +72,31 @@ _zsh_autosuggest_bind_widget() {
zle -N -- $widget _zsh_autosuggest_bound_${bind_count}_$widget
}
_zsh_autosuggest_bind_autosuggest_widgets() {
local widget
for widget in $ZSH_AUTOSUGGEST_CLEAR_WIDGETS; do
_zsh_autosuggest_bind_widget $widget clear
done
for widget in $ZSH_AUTOSUGGEST_ACCEPT_WIDGETS; do
_zsh_autosuggest_bind_widget $widget accept
done
for widget in $ZSH_AUTOSUGGEST_EXECUTE_WIDGETS; do
_zsh_autosuggest_bind_widget $widget execute
done
for widget in $ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS; do
_zsh_autosuggest_bind_widget $widget partial_accept
done
}
# Map all configured widgets to the right autosuggest widgets
_zsh_autosuggest_bind_widgets() {
_zsh_autosuggest_bind_modify_widgets() {
emulate -L zsh
local widget
local widget
local ignore_widgets
ignore_widgets=(
@@ -86,22 +106,15 @@ _zsh_autosuggest_bind_widgets() {
autosuggest-\*
$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
$ZSH_AUTOSUGGEST_CLEAR_WIDGETS
$ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
$ZSH_AUTOSUGGEST_EXECUTE_WIDGETS
$ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
)
# Find every widget we might want to bind and bind it appropriately
# Assume any widget omitted from the config arrays might modify the buffer
for widget in ${${(f)"$(builtin zle -la)"}:#${(j:|:)~ignore_widgets}}; do
if [[ -n ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]]; then
_zsh_autosuggest_bind_widget $widget clear
elif [[ -n ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]]; then
_zsh_autosuggest_bind_widget $widget accept
elif [[ -n ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]]; then
_zsh_autosuggest_bind_widget $widget execute
elif [[ -n ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]]; then
_zsh_autosuggest_bind_widget $widget partial_accept
else
# Assume any unspecified widget might modify the buffer
_zsh_autosuggest_bind_widget $widget modify
fi
_zsh_autosuggest_bind_widget $widget modify
done
}
+69 -46
View File
@@ -6,68 +6,91 @@
# Color to use when highlighting suggestion
# Uses format of `region_highlight`
# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets
: ${ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'}
(( ! ${+ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE} )) &&
typeset -g 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_ORIGINAL_WIDGET_PREFIX} )) &&
typeset -g ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig-
# Strategies to use to fetch a suggestion
# Will try each strategy in order until a suggestion is returned
(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && ZSH_AUTOSUGGEST_STRATEGY=(history)
(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && {
typeset -ga ZSH_AUTOSUGGEST_STRATEGY
ZSH_AUTOSUGGEST_STRATEGY=(history)
}
# Widgets that clear the suggestion
(( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
history-search-forward
history-search-backward
history-beginning-search-forward
history-beginning-search-backward
history-substring-search-up
history-substring-search-down
up-line-or-beginning-search
down-line-or-beginning-search
up-line-or-history
down-line-or-history
accept-line
)
(( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_CLEAR_WIDGETS
ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
history-search-forward
history-search-backward
history-beginning-search-forward
history-beginning-search-backward
history-substring-search-up
history-substring-search-down
up-line-or-beginning-search
down-line-or-beginning-search
up-line-or-history
down-line-or-history
accept-line
)
}
# Widgets that accept the entire suggestion
(( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
forward-char
end-of-line
vi-forward-char
vi-end-of-line
vi-add-eol
)
(( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
forward-char
end-of-line
vi-forward-char
vi-end-of-line
vi-add-eol
)
}
# Widgets that accept the entire suggestion and execute it
(( ! ${+ZSH_AUTOSUGGEST_EXECUTE_WIDGETS} )) && ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=(
)
(( ! ${+ZSH_AUTOSUGGEST_EXECUTE_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_EXECUTE_WIDGETS
ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=(
)
}
# Widgets that accept the suggestion as far as the cursor moves
(( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
forward-word
emacs-forward-word
vi-forward-word
vi-forward-word-end
vi-forward-blank-word
vi-forward-blank-word-end
vi-find-next-char
vi-find-next-char-skip
)
(( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
forward-word
emacs-forward-word
vi-forward-word
vi-forward-word-end
vi-forward-blank-word
vi-forward-blank-word-end
vi-find-next-char
vi-find-next-char-skip
)
}
# Widgets that should be ignored (globbing supported but must be escaped)
(( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
orig-\*
beep
run-help
set-local-history
which-command
yank
yank-pop
)
# Only relevant for zsh versions older than 5.4
(( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_IGNORE_WIDGETS
ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
orig-\*
beep
run-help
set-local-history
which-command
yank
yank-pop
)
}
# Max size of buffer to trigger autosuggestion. Leave null for no upper bound.
: ${ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=}
(( ! ${+ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE} )) &&
typeset -g ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=
# Pty name for calculating autosuggestions asynchronously
: ${ZSH_AUTOSUGGEST_ASYNC_PTY_NAME=zsh_autosuggest_pty}
(( ! ${+ZSH_AUTOSUGGEST_ASYNC_PTY_NAME} )) &&
typeset -g ZSH_AUTOSUGGEST_ASYNC_PTY_NAME=zsh_autosuggest_pty
+1
View File
@@ -9,6 +9,7 @@
_zsh_autosuggest_fetch_suggestion() {
typeset -g suggestion
local -a strategies
local strategy
# Ensure we are working with an array
strategies=(${=ZSH_AUTOSUGGEST_STRATEGY})
+2
View File
@@ -5,6 +5,8 @@
# Precmd hooks for initializing the library and starting pty's
autoload -Uz add-zsh-hook
autoload -Uz add-zle-hook-widget
autoload -Uz is-at-least
# Asynchronous suggestions are generated in a pty
zmodload zsh/zpty
+12 -3
View File
@@ -7,13 +7,22 @@
_zsh_autosuggest_start() {
add-zsh-hook -d precmd _zsh_autosuggest_start
_zsh_autosuggest_bind_widgets
# Re-bind widgets on every precmd to ensure we wrap other wrappers.
# Specifically, highlighting breaks if our widgets are wrapped by
# zsh-syntax-highlighting widgets. This also allows modifications
# to the widget list variables to take effect on the next precmd.
add-zsh-hook precmd _zsh_autosuggest_bind_widgets
_zsh_autosuggest_bind_autosuggest_widgets
add-zsh-hook precmd _zsh_autosuggest_bind_autosuggest_widgets
# If available, use a ZLE redraw hook to trigger fetching suggestions.
# Otherwise, we need to wrap all widgets and fetch suggestions after
# running them.
if is-at-least 5.4; then
add-zle-hook-widget line-pre-redraw autosuggest-redraw
else
_zsh_autosuggest_bind_modify_widgets
add-zsh-hook precmd _zsh_autosuggest_bind_modify_widgets
fi
if [[ -n "${ZSH_AUTOSUGGEST_USE_ASYNC+x}" ]]; then
_zsh_autosuggest_async_start
+87 -60
View File
@@ -37,58 +37,23 @@ _zsh_autosuggest_clear() {
# Modify the buffer and get a new suggestion
_zsh_autosuggest_modify() {
emulate -L zsh
local -i retval
# Only available in zsh >= 5.4
local -i KEYS_QUEUED_COUNT
# Save the contents of the buffer/postdisplay
local orig_buffer="$BUFFER"
# Save the contents of the postdisplay
local orig_postdisplay="$POSTDISPLAY"
# Clear suggestion while waiting for next one
# 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 there's more input to be read immediately
if (( $PENDING > 0 )) || (( $KEYS_QUEUED_COUNT > 0 )); then
POSTDISPLAY="$orig_postdisplay"
return $retval
fi
# Restore postdisplay to be used in redraw
POSTDISPLAY="$orig_postdisplay"
# Optimize if manually typing in the suggestion
if (( $#BUFFER > $#orig_buffer )); then
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
fi
# Bail out if suggestions are disabled
if [[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]]; then
return $?
fi
# Get a new suggestion if the buffer is not empty after modification
if (( $#BUFFER > 0 )); then
if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
_zsh_autosuggest_fetch
fi
fi
# Run redraw to fetch a suggestion if needed
_zsh_autosuggest_redraw
return $retval
}
@@ -190,28 +155,90 @@ _zsh_autosuggest_partial_accept() {
return $retval
}
for action in clear modify fetch suggest accept partial_accept execute enable disable toggle; do
eval "_zsh_autosuggest_widget_$action() {
local -i retval
_zsh_autosuggest_redraw() {
emulate -L zsh
_zsh_autosuggest_highlight_reset
typeset -g _ZSH_AUTOSUGGEST_LAST_BUFFER
_zsh_autosuggest_$action \$@
retval=\$?
# Only available in zsh >= 5.4
local -i KEYS_QUEUED_COUNT
_zsh_autosuggest_highlight_apply
local orig_buffer="$_ZSH_AUTOSUGGEST_LAST_BUFFER"
local widget
zle -R
# Store the current state of the buffer for next time
_ZSH_AUTOSUGGEST_LAST_BUFFER="$BUFFER"
return \$retval
}"
done
# Buffer hasn't changed
[[ "$BUFFER" = "$orig_buffer" ]] && return 0
zle -N autosuggest-fetch _zsh_autosuggest_widget_fetch
zle -N autosuggest-suggest _zsh_autosuggest_widget_suggest
zle -N autosuggest-accept _zsh_autosuggest_widget_accept
zle -N autosuggest-clear _zsh_autosuggest_widget_clear
zle -N autosuggest-execute _zsh_autosuggest_widget_execute
zle -N autosuggest-enable _zsh_autosuggest_widget_enable
zle -N autosuggest-disable _zsh_autosuggest_widget_disable
zle -N autosuggest-toggle _zsh_autosuggest_widget_toggle
local ignore_widgets
ignore_widgets=(
$ZSH_AUTOSUGGEST_CLEAR_WIDGETS
$ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
$ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
)
# Don't fetch a new suggestion after mapped widgets
for widget in $ignore_widgets; do
[[ "$LASTWIDGET" == "$widget" ]] && return 0
done
# Optimize if manually typing in the suggestion
if (( $#BUFFER > $#orig_buffer )); then
local added=${BUFFER#$orig_buffer}
# If the string added matches the beginning of the postdisplay
if [[ "$added" = "${POSTDISPLAY:0:$#added}" ]]; then
POSTDISPLAY="${POSTDISPLAY:$#added}"
return 0
fi
fi
unset POSTDISPLAY
# Don't fetch a new suggestion if there's more input to be read immediately
(( $PENDING > 0 )) || (( $KEYS_QUEUED_COUNT > 0 )) && return 0
# Buffer is empty
(( ! $#BUFFER )) && return 0
# Buffer longer than max size
[[ -n "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] && (( $#BUFFER > $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )) && return 0
# Suggestions disabled
[[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]] && return 0
_zsh_autosuggest_fetch
}
() {
local action
for action in clear modify fetch suggest accept partial_accept execute enable disable toggle redraw; do
eval "_zsh_autosuggest_widget_$action() {
local -i retval
_zsh_autosuggest_highlight_reset
_zsh_autosuggest_$action \$@
retval=\$?
_zsh_autosuggest_highlight_apply
zle -R
return \$retval
}"
done
zle -N autosuggest-redraw _zsh_autosuggest_widget_redraw
zle -N autosuggest-fetch _zsh_autosuggest_widget_fetch
zle -N autosuggest-suggest _zsh_autosuggest_widget_suggest
zle -N autosuggest-accept _zsh_autosuggest_widget_accept
zle -N autosuggest-clear _zsh_autosuggest_widget_clear
zle -N autosuggest-execute _zsh_autosuggest_widget_execute
zle -N autosuggest-enable _zsh_autosuggest_widget_enable
zle -N autosuggest-disable _zsh_autosuggest_widget_disable
zle -N autosuggest-toggle _zsh_autosuggest_widget_toggle
}
+199 -124
View File
@@ -31,6 +31,8 @@
# Precmd hooks for initializing the library and starting pty's
autoload -Uz add-zsh-hook
autoload -Uz add-zle-hook-widget
autoload -Uz is-at-least
# Asynchronous suggestions are generated in a pty
zmodload zsh/zpty
@@ -42,71 +44,94 @@ zmodload zsh/zpty
# Color to use when highlighting suggestion
# Uses format of `region_highlight`
# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets
: ${ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'}
(( ! ${+ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE} )) &&
typeset -g 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_ORIGINAL_WIDGET_PREFIX} )) &&
typeset -g ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig-
# Strategies to use to fetch a suggestion
# Will try each strategy in order until a suggestion is returned
(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && ZSH_AUTOSUGGEST_STRATEGY=(history)
(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && {
typeset -ga ZSH_AUTOSUGGEST_STRATEGY
ZSH_AUTOSUGGEST_STRATEGY=(history)
}
# Widgets that clear the suggestion
(( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
history-search-forward
history-search-backward
history-beginning-search-forward
history-beginning-search-backward
history-substring-search-up
history-substring-search-down
up-line-or-beginning-search
down-line-or-beginning-search
up-line-or-history
down-line-or-history
accept-line
)
(( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_CLEAR_WIDGETS
ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
history-search-forward
history-search-backward
history-beginning-search-forward
history-beginning-search-backward
history-substring-search-up
history-substring-search-down
up-line-or-beginning-search
down-line-or-beginning-search
up-line-or-history
down-line-or-history
accept-line
)
}
# Widgets that accept the entire suggestion
(( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
forward-char
end-of-line
vi-forward-char
vi-end-of-line
vi-add-eol
)
(( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
forward-char
end-of-line
vi-forward-char
vi-end-of-line
vi-add-eol
)
}
# Widgets that accept the entire suggestion and execute it
(( ! ${+ZSH_AUTOSUGGEST_EXECUTE_WIDGETS} )) && ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=(
)
(( ! ${+ZSH_AUTOSUGGEST_EXECUTE_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_EXECUTE_WIDGETS
ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=(
)
}
# Widgets that accept the suggestion as far as the cursor moves
(( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
forward-word
emacs-forward-word
vi-forward-word
vi-forward-word-end
vi-forward-blank-word
vi-forward-blank-word-end
vi-find-next-char
vi-find-next-char-skip
)
(( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
forward-word
emacs-forward-word
vi-forward-word
vi-forward-word-end
vi-forward-blank-word
vi-forward-blank-word-end
vi-find-next-char
vi-find-next-char-skip
)
}
# Widgets that should be ignored (globbing supported but must be escaped)
(( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
orig-\*
beep
run-help
set-local-history
which-command
yank
yank-pop
)
# Only relevant for zsh versions older than 5.4
(( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && {
typeset -ga ZSH_AUTOSUGGEST_IGNORE_WIDGETS
ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
orig-\*
beep
run-help
set-local-history
which-command
yank
yank-pop
)
}
# Max size of buffer to trigger autosuggestion. Leave null for no upper bound.
: ${ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=}
(( ! ${+ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE} )) &&
typeset -g ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=
# Pty name for calculating autosuggestions asynchronously
: ${ZSH_AUTOSUGGEST_ASYNC_PTY_NAME=zsh_autosuggest_pty}
(( ! ${+ZSH_AUTOSUGGEST_ASYNC_PTY_NAME} )) &&
typeset -g ZSH_AUTOSUGGEST_ASYNC_PTY_NAME=zsh_autosuggest_pty
#--------------------------------------------------------------------#
# Utility Functions #
@@ -211,11 +236,31 @@ _zsh_autosuggest_bind_widget() {
zle -N -- $widget _zsh_autosuggest_bound_${bind_count}_$widget
}
_zsh_autosuggest_bind_autosuggest_widgets() {
local widget
for widget in $ZSH_AUTOSUGGEST_CLEAR_WIDGETS; do
_zsh_autosuggest_bind_widget $widget clear
done
for widget in $ZSH_AUTOSUGGEST_ACCEPT_WIDGETS; do
_zsh_autosuggest_bind_widget $widget accept
done
for widget in $ZSH_AUTOSUGGEST_EXECUTE_WIDGETS; do
_zsh_autosuggest_bind_widget $widget execute
done
for widget in $ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS; do
_zsh_autosuggest_bind_widget $widget partial_accept
done
}
# Map all configured widgets to the right autosuggest widgets
_zsh_autosuggest_bind_widgets() {
_zsh_autosuggest_bind_modify_widgets() {
emulate -L zsh
local widget
local widget
local ignore_widgets
ignore_widgets=(
@@ -225,22 +270,15 @@ _zsh_autosuggest_bind_widgets() {
autosuggest-\*
$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
$ZSH_AUTOSUGGEST_CLEAR_WIDGETS
$ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
$ZSH_AUTOSUGGEST_EXECUTE_WIDGETS
$ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
)
# Find every widget we might want to bind and bind it appropriately
# Assume any widget omitted from the config arrays might modify the buffer
for widget in ${${(f)"$(builtin zle -la)"}:#${(j:|:)~ignore_widgets}}; do
if [[ -n ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]]; then
_zsh_autosuggest_bind_widget $widget clear
elif [[ -n ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]]; then
_zsh_autosuggest_bind_widget $widget accept
elif [[ -n ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]]; then
_zsh_autosuggest_bind_widget $widget execute
elif [[ -n ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]]; then
_zsh_autosuggest_bind_widget $widget partial_accept
else
# Assume any unspecified widget might modify the buffer
_zsh_autosuggest_bind_widget $widget modify
fi
_zsh_autosuggest_bind_widget $widget modify
done
}
@@ -322,58 +360,23 @@ _zsh_autosuggest_clear() {
# Modify the buffer and get a new suggestion
_zsh_autosuggest_modify() {
emulate -L zsh
local -i retval
# Only available in zsh >= 5.4
local -i KEYS_QUEUED_COUNT
# Save the contents of the buffer/postdisplay
local orig_buffer="$BUFFER"
# Save the contents of the postdisplay
local orig_postdisplay="$POSTDISPLAY"
# Clear suggestion while waiting for next one
# 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 there's more input to be read immediately
if (( $PENDING > 0 )) || (( $KEYS_QUEUED_COUNT > 0 )); then
POSTDISPLAY="$orig_postdisplay"
return $retval
fi
# Restore postdisplay to be used in redraw
POSTDISPLAY="$orig_postdisplay"
# Optimize if manually typing in the suggestion
if (( $#BUFFER > $#orig_buffer )); then
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
fi
# Bail out if suggestions are disabled
if [[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]]; then
return $?
fi
# Get a new suggestion if the buffer is not empty after modification
if (( $#BUFFER > 0 )); then
if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
_zsh_autosuggest_fetch
fi
fi
# Run redraw to fetch a suggestion if needed
_zsh_autosuggest_redraw
return $retval
}
@@ -475,31 +478,93 @@ _zsh_autosuggest_partial_accept() {
return $retval
}
for action in clear modify fetch suggest accept partial_accept execute enable disable toggle; do
eval "_zsh_autosuggest_widget_$action() {
local -i retval
_zsh_autosuggest_redraw() {
emulate -L zsh
_zsh_autosuggest_highlight_reset
typeset -g _ZSH_AUTOSUGGEST_LAST_BUFFER
_zsh_autosuggest_$action \$@
retval=\$?
# Only available in zsh >= 5.4
local -i KEYS_QUEUED_COUNT
_zsh_autosuggest_highlight_apply
local orig_buffer="$_ZSH_AUTOSUGGEST_LAST_BUFFER"
local widget
zle -R
# Store the current state of the buffer for next time
_ZSH_AUTOSUGGEST_LAST_BUFFER="$BUFFER"
return \$retval
}"
done
# Buffer hasn't changed
[[ "$BUFFER" = "$orig_buffer" ]] && return 0
zle -N autosuggest-fetch _zsh_autosuggest_widget_fetch
zle -N autosuggest-suggest _zsh_autosuggest_widget_suggest
zle -N autosuggest-accept _zsh_autosuggest_widget_accept
zle -N autosuggest-clear _zsh_autosuggest_widget_clear
zle -N autosuggest-execute _zsh_autosuggest_widget_execute
zle -N autosuggest-enable _zsh_autosuggest_widget_enable
zle -N autosuggest-disable _zsh_autosuggest_widget_disable
zle -N autosuggest-toggle _zsh_autosuggest_widget_toggle
local ignore_widgets
ignore_widgets=(
$ZSH_AUTOSUGGEST_CLEAR_WIDGETS
$ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
$ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
)
# Don't fetch a new suggestion after mapped widgets
for widget in $ignore_widgets; do
[[ "$LASTWIDGET" == "$widget" ]] && return 0
done
# Optimize if manually typing in the suggestion
if (( $#BUFFER > $#orig_buffer )); then
local added=${BUFFER#$orig_buffer}
# If the string added matches the beginning of the postdisplay
if [[ "$added" = "${POSTDISPLAY:0:$#added}" ]]; then
POSTDISPLAY="${POSTDISPLAY:$#added}"
return 0
fi
fi
unset POSTDISPLAY
# Don't fetch a new suggestion if there's more input to be read immediately
(( $PENDING > 0 )) || (( $KEYS_QUEUED_COUNT > 0 )) && return 0
# Buffer is empty
(( ! $#BUFFER )) && return 0
# Buffer longer than max size
[[ -n "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] && (( $#BUFFER > $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )) && return 0
# Suggestions disabled
[[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]] && return 0
_zsh_autosuggest_fetch
}
() {
local action
for action in clear modify fetch suggest accept partial_accept execute enable disable toggle redraw; do
eval "_zsh_autosuggest_widget_$action() {
local -i retval
_zsh_autosuggest_highlight_reset
_zsh_autosuggest_$action \$@
retval=\$?
_zsh_autosuggest_highlight_apply
zle -R
return \$retval
}"
done
zle -N autosuggest-redraw _zsh_autosuggest_widget_redraw
zle -N autosuggest-fetch _zsh_autosuggest_widget_fetch
zle -N autosuggest-suggest _zsh_autosuggest_widget_suggest
zle -N autosuggest-accept _zsh_autosuggest_widget_accept
zle -N autosuggest-clear _zsh_autosuggest_widget_clear
zle -N autosuggest-execute _zsh_autosuggest_widget_execute
zle -N autosuggest-enable _zsh_autosuggest_widget_enable
zle -N autosuggest-disable _zsh_autosuggest_widget_disable
zle -N autosuggest-toggle _zsh_autosuggest_widget_toggle
}
#--------------------------------------------------------------------#
# History Suggestion Strategy #
@@ -595,6 +660,7 @@ _zsh_autosuggest_strategy_match_prev_cmd() {
_zsh_autosuggest_fetch_suggestion() {
typeset -g suggestion
local -a strategies
local strategy
# Ensure we are working with an array
strategies=(${=ZSH_AUTOSUGGEST_STRATEGY})
@@ -725,13 +791,22 @@ _zsh_autosuggest_async_start() {
_zsh_autosuggest_start() {
add-zsh-hook -d precmd _zsh_autosuggest_start
_zsh_autosuggest_bind_widgets
# Re-bind widgets on every precmd to ensure we wrap other wrappers.
# Specifically, highlighting breaks if our widgets are wrapped by
# zsh-syntax-highlighting widgets. This also allows modifications
# to the widget list variables to take effect on the next precmd.
add-zsh-hook precmd _zsh_autosuggest_bind_widgets
_zsh_autosuggest_bind_autosuggest_widgets
add-zsh-hook precmd _zsh_autosuggest_bind_autosuggest_widgets
# If available, use a ZLE redraw hook to trigger fetching suggestions.
# Otherwise, we need to wrap all widgets and fetch suggestions after
# running them.
if is-at-least 5.4; then
add-zle-hook-widget line-pre-redraw autosuggest-redraw
else
_zsh_autosuggest_bind_modify_widgets
add-zsh-hook precmd _zsh_autosuggest_bind_modify_widgets
fi
if [[ -n "${ZSH_AUTOSUGGEST_USE_ASYNC+x}" ]]; then
_zsh_autosuggest_async_start