Compare commits

...

77 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
a7f0106b31 Merge pull request #393 from zsh-users/releases/v0.5.0
Releases/v0.5.0
2018-11-24 10:00:59 -07:00
Eric Freese
286656635c v0.5.0 2018-11-24 09:56:52 -07:00
Eric Freese
0d994d4732 Update changelog for v0.5.0 release 2018-11-24 09:56:52 -07:00
Eric Nielsen
9e4d3c337f 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-24 09:56:52 -07:00
Eric Freese
f0f1332e6b Add after_sourcing hook for tests
Is executed immediately after sourcing the plugin
2018-11-24 09:56:52 -07:00
Eric Freese
a78ea16c50 Support fallback strategies by setting array in config 2018-11-24 09:56:30 -07:00
Eric Freese
62f5f14f2f default => history 2018-11-24 09:56:00 -07:00
Eric Freese
4540304fa0 Reset opts in some functions affected by GLOB_SUBST
Should fix GitHub #334
2018-11-19 15:15:48 -07:00
Eric Freese
df6f6f9ff4 Add install directions for Antigen 2018-11-19 15:15:48 -07:00
Eric Freese
4097d6e0ae Support widgets starting with dashes (ex: -a-widget)
Fixes #337
2018-11-19 15:15:48 -07:00
Eric Freese
822a1f30e0 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-11-19 15:15:48 -07:00
Eric Freese
0f80f9511d Fix handling of newline + carriage return in async pty (#333) 2018-11-19 15:15:48 -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 Freese
be6b22b864 Add info to the readme about docker testing image 2018-11-18 21:35:52 -07:00
Eric Freese
69d7fa14d3 Build docker image for running tests
Published at `ericfreese/zsh-autosuggestions-test`.

Contains:
- Ruby 2.5.3
- Supported zsh versions 4.3.11 through 5.6.2
- Test ruby dependencies

Also updates Circle CI config to use built docker image.
2018-11-18 21:11:35 -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
affe7c687e Run circle-ci upgrade script
From: https://raw.githubusercontent.com/CircleCI-Public/circleci-config-generator/9979b712033a072c3135aafb3c06e252c4e791f1/cci-config-generator.sh
2018-11-10 13:11:25 -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
ebaf409002 Merge pull request #355 from amehmeto/patch-1
Update INSTALL.md
2018-07-02 20:59:14 -06:00
amehmeto
2d0ae6044c Update INSTALL.md
I lost myself in the internet abyss because of this imprecision. It might be helpful for the new noob trying to install that great tweak. :)
2018-07-03 04:25:20 +02: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`:
- ca2e18bbc9
- 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
31 changed files with 755 additions and 316 deletions

16
.circleci/config.yml Normal file
View File

@@ -0,0 +1,16 @@
version: 2
jobs:
build:
parallelism: 4
shell: /bin/bash --login
docker:
- image: ericfreese/zsh-autosuggestions-test:latest
command: /sbin/init
steps:
- checkout
- run:
name: Running tests
command: |
for v in $(grep "^[^#]" ZSH_VERSIONS | awk "(NR + $CIRCLE_NODE_INDEX) % $CIRCLE_NODE_TOTAL == 0"); do
TEST_ZSH_BIN=zsh-$v make test || exit 1
done

View File

@@ -1 +1 @@
2.3.1 2.5.3

View File

@@ -1,5 +1,15 @@
# Changelog # Changelog
## v0.5.0
- Don't overwrite config with default values (#335)
- Support fallback strategies by supplying array to suggestion config var
- Rename "default" suggestion strategy to "history" to name it based on what it actually does
- Reset opts in some functions affected by `GLOB_SUBST` (#334)
- Support widgets starting with dashes (ex: `-a-widget`) (#337)
- Skip async tests in zsh versions less than 5.0.8 because of reliability issues
- Fix handling of newline + carriage return in async pty (#333)
## v0.4.3 ## v0.4.3
- Avoid bell when accepting suggestions with `autosuggest-accept` (#228) - Avoid bell when accepting suggestions with `autosuggest-accept` (#228)
- Don't fetch suggestions after [up,down]-line-or-beginning-search (#227, #241) - Don't fetch suggestions after [up,down]-line-or-beginning-search (#227, #241)

20
Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM ruby:2.5.3-alpine
RUN apk add --no-cache autoconf
RUN apk add --no-cache libtool
RUN apk add --no-cache libcap-dev
RUN apk add --no-cache pcre-dev
RUN apk add --no-cache curl
RUN apk add --no-cache build-base
RUN apk add --no-cache ncurses-dev
RUN apk add --no-cache tmux
WORKDIR /zsh-autosuggestions
ADD ZSH_VERSIONS /zsh-autosuggestions/ZSH_VERSIONS
ADD install_test_zsh.sh /zsh-autosuggestions/install_test_zsh.sh
RUN ./install_test_zsh.sh
ADD Gemfile /zsh-autosuggestions/Gemfile
ADD Gemfile.lock /zsh-autosuggestions/Gemfile.lock
RUN bundle install

View File

@@ -16,6 +16,16 @@
3. Start a new terminal session. 3. Start a new terminal session.
### Antigen
1. Add the following to your `.zshrc`:
```sh
antigen bundle zsh-users/zsh-autosuggestions
```
2. Start a new terminal session.
### Oh My Zsh ### Oh My Zsh
1. Clone this repository into `$ZSH_CUSTOM/plugins` (by default `~/.oh-my-zsh/custom/plugins`) 1. Clone this repository into `$ZSH_CUSTOM/plugins` (by default `~/.oh-my-zsh/custom/plugins`)
@@ -24,7 +34,7 @@
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
``` ```
2. Add the plugin to the list of plugins for Oh My Zsh to load: 2. Add the plugin to the list of plugins for Oh My Zsh to load (inside `~/.zshrc`):
```sh ```sh
plugins=(zsh-autosuggestions) plugins=(zsh-autosuggestions)

View File

@@ -9,6 +9,7 @@ SRC_FILES := \
$(SRC_DIR)/highlight.zsh \ $(SRC_DIR)/highlight.zsh \
$(SRC_DIR)/widgets.zsh \ $(SRC_DIR)/widgets.zsh \
$(SRC_DIR)/strategies/*.zsh \ $(SRC_DIR)/strategies/*.zsh \
$(SRC_DIR)/fetch.zsh \
$(SRC_DIR)/async.zsh \ $(SRC_DIR)/async.zsh \
$(SRC_DIR)/start.zsh $(SRC_DIR)/start.zsh

View File

@@ -27,7 +27,7 @@ If you invoke the `forward-word` widget, it will partially accept the suggestion
## Configuration ## Configuration
You may want to override the default global config variables after sourcing the plugin. Default values of these variables can be found [here](src/config.zsh). You may want to override the default global config variables. Default values of these variables can be found [here](src/config.zsh).
**Note:** If you are using Oh My Zsh, you can put this configuration in a file in the `$ZSH_CUSTOM` directory. See their comments on [overriding internals](https://github.com/robbyrussell/oh-my-zsh/wiki/Customization#overriding-internals). **Note:** If you are using Oh My Zsh, you can put this configuration in a file in the `$ZSH_CUSTOM` directory. See their comments on [overriding internals](https://github.com/robbyrussell/oh-my-zsh/wiki/Customization#overriding-internals).
@@ -39,10 +39,10 @@ Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion
### Suggestion Strategy ### Suggestion Strategy
Set `ZSH_AUTOSUGGEST_STRATEGY` to choose the strategy for generating suggestions. There are currently two to choose from: `ZSH_AUTOSUGGEST_STRATEGY` is an array that specifies how suggestions should be generated. The strategies in the array are tried successively until a suggestion is found. There are currently two built-in strategies to choose from:
- `default`: Chooses the most recent match. - `history`: Chooses the most recent match from history.
- `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`. - `match_prev_cmd`: Like `history`, but 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 ### Widget Mapping
@@ -139,6 +139,20 @@ Tests are written in ruby using the [`rspec`](http://rspec.info/) framework. The
Test files live in `spec/`. To run the tests, run `make test`. To run a specific test, run `TESTS=spec/some_spec.rb make test`. You can also specify a `zsh` binary to use by setting the `TEST_ZSH_BIN` environment variable (ex: `TEST_ZSH_BIN=/bin/zsh make test`). Test files live in `spec/`. To run the tests, run `make test`. To run a specific test, run `TESTS=spec/some_spec.rb make test`. You can also specify a `zsh` binary to use by setting the `TEST_ZSH_BIN` environment variable (ex: `TEST_ZSH_BIN=/bin/zsh make test`).
A docker image for testing is available [on docker hub](https://hub.docker.com/r/ericfreese/zsh-autosuggestions-test). It comes with ruby, the bundler dependencies, and all supported versions of zsh installed.
Pull the docker image with:
```sh
docker pull ericfreese/zsh-autosuggestions-test
```
To run the tests for a specific version of zsh (where `<version>` below is substituted with the contents of a line from the [`ZSH_VERSIONS`](ZSH_VERSIONS) file):
```sh
docker run -it -e TEST_ZSH_BIN=zsh-<version> -v $PWD:/zsh-autosuggestions zsh-autosuggestions-test make test
```
## License ## License

View File

@@ -1 +1 @@
v0.4.3 v0.5.0

15
ZSH_VERSIONS Normal file
View File

@@ -0,0 +1,15 @@
# Zsh releases to run tests against
# See https://github.com/zsh-users/zsh/releases
#
# When modifying this file, rebuild and push docker image:
# $ docker build -t ericfreese/zsh-autosuggestions-test .
# $ docker push ericfreese/zsh-autosuggestions-test
4.3.11
5.0.2
5.0.8
5.1.1
5.2
5.3.1
5.4.2
5.5.1
5.6.2

View File

@@ -1,12 +0,0 @@
machine:
environment:
ZSH_VERSIONS: zsh-dev/4.3.11 zsh/5.0.2 zsh/5.0.8 zsh/5.1.1 zsh/5.2 zsh/5.3.1 zsh/5.4.2 zsh/5.5.1
dependencies:
pre:
- for v in $(echo $ZSH_VERSIONS | awk "{ for (i=$((1+CIRCLE_NODE_INDEX));i<=NF;i+=$CIRCLE_NODE_TOTAL) print \$i }"); do wget https://sourceforge.net/projects/zsh/files/$v/zsh-${v#*/}.tar.gz && tar xzf zsh-${v#*/}.tar.gz && pushd zsh-${v#*/} && ./configure && sudo make install && popd || exit 1; done
test:
override:
- for v in $(echo $ZSH_VERSIONS | awk "{ for (i=$((1+CIRCLE_NODE_INDEX));i<=NF;i+=$CIRCLE_NODE_TOTAL) print \$i }"); do TEST_ZSH_BIN=/usr/local/bin/zsh-${v#*/} make test || exit 1; done:
parallel: true

26
install_test_zsh.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/sh
set -ex
for v in $(grep "^[^#]" ZSH_VERSIONS); do
mkdir zsh-$v
cd zsh-$v
curl -L https://api.github.com/repos/zsh-users/zsh/tarball/zsh-$v | tar xz --strip=1
./Util/preconfig
./configure --enable-pcre \
--enable-cap \
--enable-multibyte \
--with-term-lib='ncursesw tinfo' \
--without-tcsetpgrp \
--program-suffix="-$v"
make install.bin
make install.modules
make install.fns
cd ..
rm -rf zsh-$v
done

View File

@@ -1,4 +1,8 @@
context 'with asynchronous suggestions enabled' do context 'with asynchronous suggestions enabled' do
before do
skip 'Async mode not supported below v5.0.8' if session.zsh_version < Gem::Version.new('5.0.8')
end
let(:options) { ["ZSH_AUTOSUGGEST_USE_ASYNC="] } let(:options) { ["ZSH_AUTOSUGGEST_USE_ASYNC="] }
describe '`up-line-or-beginning-search`' do describe '`up-line-or-beginning-search`' do
@@ -27,6 +31,45 @@ context 'with asynchronous suggestions enabled' do
end end
end end
it 'should not add extra carriage returns before newlines' do
session.
send_string('echo "').
send_keys('escape').
send_keys('enter').
send_string('"').
send_keys('enter')
session.clear_screen
session.send_string('echo')
wait_for { session.content }.to eq("echo \"\n\"")
end
it 'should treat carriage returns and newlines as separate characters' do
session.
send_string('echo "').
send_keys('C-v').
send_keys('enter').
send_string('foo"').
send_keys('enter')
session.
send_string('echo "').
send_keys('control').
send_keys('enter').
send_string('bar"').
send_keys('enter')
session.clear_screen
session.
send_string('echo "').
send_keys('C-v').
send_keys('enter')
wait_for { session.content }.to eq('echo "^Mfoo"')
end
describe 'exiting a subshell' do describe 'exiting a subshell' do
it 'should not cause error messages to be printed' do it 'should not cause error messages to be printed' do
session.run_command('$(exit)') session.run_command('$(exit)')

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

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

View File

@@ -1,16 +1,24 @@
describe 'a wrapped widget' do describe 'a wrapped widget' do
let(:widget) { 'backward-delete-char' } let(:widget) { 'backward-delete-char' }
context 'initialized before sourcing the plugin' do let(:initialize_widget) do
let(:before_sourcing) do -> do
-> do session.run_command(<<~ZSH)
session. if [[ "$widgets[#{widget}]" == "builtin" ]]; then
run_command("_orig_#{widget}() { zle .#{widget} }"). _orig_#{widget}() { zle .#{widget} }
run_command("zle -N orig-#{widget} _orig_#{widget}"). zle -N orig-#{widget} _orig_#{widget}
run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }"). else
run_command("zle -N #{widget} #{widget}-magic") zle -N orig-#{widget} ${widgets[#{widget}]#*:}
end fi
#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }
zle -N #{widget} #{widget}-magic
ZSH
end 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 it 'executes the custom behavior and the built-in behavior' do
with_history('foobar', 'foodar') do with_history('foobar', 'foodar') do
@@ -21,13 +29,7 @@ describe 'a wrapped widget' do
end end
context 'initialized after sourcing the plugin' do context 'initialized after sourcing the plugin' do
before do let(:after_sourcing) { initialize_widget }
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
it 'executes the custom behavior and the built-in behavior' do it 'executes the custom behavior and the built-in behavior' do
with_history('foobar', 'foodar') do with_history('foobar', 'foodar') do

View File

@@ -2,15 +2,16 @@ describe 'using `zle -U`' do
let(:before_sourcing) do let(:before_sourcing) do
-> do -> do
session. session.
run_command('_zsh_autosuggest_strategy_test() { sleep 1; _zsh_autosuggest_strategy_default "$1" }'). run_command('_zsh_autosuggest_strategy_test() { sleep 1; _zsh_autosuggest_strategy_history "$1" }').
run_command('foo() { zle -U - "echo hello" }; zle -N foo; bindkey ^B foo') run_command('foo() { zle -U - "echo hello" }; zle -N foo; bindkey ^B foo')
end end
end end
let(:options) { ['unset ZSH_AUTOSUGGEST_USE_ASYNC', 'ZSH_AUTOSUGGEST_STRATEGY=test'] } 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... it 'does not fetch a suggestion for every inserted character' do
xit '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') session.send_keys('C-b')
wait_for { session.content }.to eq('echo hello') wait_for { session.content }.to eq('echo hello')
end end

View File

@@ -1,20 +1,55 @@
describe 'a suggestion for a given prefix' do describe 'a suggestion for a given prefix' do
let(:options) { ['_zsh_autosuggest_strategy_default() { suggestion="echo foo" }'] } let(:history_strategy) { '_zsh_autosuggest_strategy_history() { suggestion="history" }' }
let(:foobar_strategy) { '_zsh_autosuggest_strategy_foobar() { [[ "foobar baz" = $1* ]] && suggestion="foobar baz" }' }
let(:foobaz_strategy) { '_zsh_autosuggest_strategy_foobaz() { [[ "foobaz bar" = $1* ]] && suggestion="foobaz bar" }' }
it 'is determined by calling the default strategy function' do let(:after_sourcing) do
session.send_string('e') -> do
wait_for { session.content }.to eq('echo foo') session.run_command(history_strategy)
end
end end
context 'when ZSH_AUTOSUGGEST_STRATEGY is set' do it 'by default is determined by calling the `history` strategy function' do
let(:options) { [ session.send_string('h')
'_zsh_autosuggest_strategy_custom() { suggestion="echo foo" }', wait_for { session.content }.to eq('history')
'ZSH_AUTOSUGGEST_STRATEGY=custom' end
] }
it 'is determined by calling the specified strategy function' do context 'when ZSH_AUTOSUGGEST_STRATEGY is set to an array' do
session.send_string('e') let(:after_sourcing) do
wait_for { session.content }.to eq('echo foo') -> do
session.
run_command(foobar_strategy).
run_command(foobaz_strategy).
run_command('ZSH_AUTOSUGGEST_STRATEGY=(foobar foobaz)')
end
end
it 'is determined by the first strategy function to return a suggestion' do
session.send_string('foo')
wait_for { session.content }.to eq('foobar baz')
session.send_string('baz')
wait_for { session.content }.to eq('foobaz bar')
end
end
context 'when ZSH_AUTOSUGGEST_STRATEGY is set to a string' do
let(:after_sourcing) do
-> do
session.
run_command(foobar_strategy).
run_command(foobaz_strategy).
run_command('ZSH_AUTOSUGGEST_STRATEGY="foobar foobaz"')
end
end
it 'is determined by the first strategy function to return a suggestion' do
session.send_string('foo')
wait_for { session.content }.to eq('foobar baz')
session.send_string('baz')
wait_for { session.content }.to eq('foobaz bar')
end end
end end
end end

View File

@@ -41,12 +41,20 @@ describe 'a zle widget' do
end end
end end
context 'when added to ZSH_AUTOSUGGEST_IGNORE_WIDGETS' do context 'that accesses POSTDISPLAY' do
let(:options) { ["ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(#{widget})"] } before { session.run_command("#{widget}() { zle -M \"POSTDISPLAY=$POSTDISPLAY\" }") }
it 'should not be wrapped with an autosuggest widget' do context 'when added to ZSH_AUTOSUGGEST_IGNORE_WIDGETS' do
session.run_command("echo $widgets[#{widget}]") let(:options) { ["ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(#{widget})"] }
wait_for { session.content }.to end_with("\nuser:#{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
end end

View File

@@ -6,12 +6,14 @@ RSpec.shared_context 'terminal session' do
let(:term_opts) { {} } let(:term_opts) { {} }
let(:session) { TerminalSession.new(term_opts) } let(:session) { TerminalSession.new(term_opts) }
let(:before_sourcing) { -> {} } let(:before_sourcing) { -> {} }
let(:after_sourcing) { -> {} }
let(:options) { [] } let(:options) { [] }
around do |example| around do |example|
before_sourcing.call before_sourcing.call
session.run_command(options.join('; '))
session.run_command((['source zsh-autosuggestions.zsh'] + options).join('; ')) session.run_command('source zsh-autosuggestions.zsh')
after_sourcing.call
session.clear_screen session.clear_screen
example.run example.run

View File

@@ -1,6 +1,6 @@
require 'strategies/special_characters_helper' 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 it 'suggests the last matching history entry' do
with_history('ls foo', 'ls bar', 'echo baz') do with_history('ls foo', 'ls bar', 'echo baz') do
session.send_string('ls') session.send_string('ls')

View File

@@ -1,6 +1,6 @@
require 'strategies/special_characters_helper' 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'] } let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd'] }
it 'suggests the last matching history entry after the previous command' do it 'suggests the last matching history entry after the previous command' do

View File

@@ -18,6 +18,10 @@ class TerminalSession
tmux_command("new-session -d -x #{opts[:width]} -y #{opts[:height]} '#{cmd}'") tmux_command("new-session -d -x #{opts[:width]} -y #{opts[:height]} '#{cmd}'")
end end
def zsh_version
@zsh_version ||= Gem::Version.new(`#{ZSH_BIN} -c 'echo -n $ZSH_VERSION'`)
end
def tmux_socket_name def tmux_socket_name
@tmux_socket_name ||= SecureRandom.hex(6) @tmux_socket_name ||= SecureRandom.hex(6)
end end

View File

@@ -17,9 +17,12 @@ _zsh_autosuggest_async_server() {
sleep 1 # Block for long enough for the signal to come through sleep 1 # Block for long enough for the signal to come through
} }
# Output only newlines (not carriage return + newline) # Don't add any extra carriage returns
stty -onlcr stty -onlcr
# Don't translate carriage returns to newlines
stty -icrnl
# Silence any error messages # Silence any error messages
exec 2>/dev/null exec 2>/dev/null
@@ -32,7 +35,7 @@ _zsh_autosuggest_async_server() {
# Run suggestion search in the background # Run suggestion search in the background
( (
local suggestion local suggestion
_zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY "$query" _zsh_autosuggest_fetch_suggestion "$query"
echo -n -E "$suggestion"$'\0' echo -n -E "$suggestion"$'\0'
) & ) &

View File

@@ -69,11 +69,33 @@ _zsh_autosuggest_bind_widget() {
}" }"
# Create the bound widget # Create the bound widget
zle -N $widget _zsh_autosuggest_bound_${bind_count}_$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 # 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 local ignore_widgets
@@ -84,22 +106,15 @@ _zsh_autosuggest_bind_widgets() {
autosuggest-\* autosuggest-\*
$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\* $ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS $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 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 modify
_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
done done
} }

View File

@@ -6,66 +6,91 @@
# Color to use when highlighting suggestion # Color to use when highlighting suggestion
# Uses format of `region_highlight` # Uses format of `region_highlight`
# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets # 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 # 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-
ZSH_AUTOSUGGEST_STRATEGY=default # Strategies to use to fetch a suggestion
# Will try each strategy in order until a suggestion is returned
(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && {
typeset -ga ZSH_AUTOSUGGEST_STRATEGY
ZSH_AUTOSUGGEST_STRATEGY=(history)
}
# Widgets that clear the suggestion # Widgets that clear the suggestion
ZSH_AUTOSUGGEST_CLEAR_WIDGETS=( (( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && {
history-search-forward typeset -ga ZSH_AUTOSUGGEST_CLEAR_WIDGETS
history-search-backward ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
history-beginning-search-forward history-search-forward
history-beginning-search-backward history-search-backward
history-substring-search-up history-beginning-search-forward
history-substring-search-down history-beginning-search-backward
up-line-or-beginning-search history-substring-search-up
down-line-or-beginning-search history-substring-search-down
up-line-or-history up-line-or-beginning-search
down-line-or-history down-line-or-beginning-search
accept-line up-line-or-history
) down-line-or-history
accept-line
)
}
# Widgets that accept the entire suggestion # Widgets that accept the entire suggestion
ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=( (( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && {
forward-char typeset -ga ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
end-of-line ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
vi-forward-char forward-char
vi-end-of-line end-of-line
vi-add-eol vi-forward-char
) vi-end-of-line
vi-add-eol
)
}
# Widgets that accept the entire suggestion and execute it # Widgets that accept the entire suggestion and execute it
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 # Widgets that accept the suggestion as far as the cursor moves
ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=( (( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && {
forward-word typeset -ga ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
emacs-forward-word ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
vi-forward-word forward-word
vi-forward-word-end emacs-forward-word
vi-forward-blank-word vi-forward-word
vi-forward-blank-word-end vi-forward-word-end
vi-find-next-char vi-forward-blank-word
vi-find-next-char-skip 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) # Widgets that should be ignored (globbing supported but must be escaped)
ZSH_AUTOSUGGEST_IGNORE_WIDGETS=( # Only relevant for zsh versions older than 5.4
orig-\* (( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && {
beep typeset -ga ZSH_AUTOSUGGEST_IGNORE_WIDGETS
run-help ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
set-local-history orig-\*
which-command beep
yank run-help
yank-pop set-local-history
) which-command
yank
yank-pop
)
}
# Max size of buffer to trigger autosuggestion. Leave undefined for no upper bound. # 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 # 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

24
src/fetch.zsh Normal file
View File

@@ -0,0 +1,24 @@
#--------------------------------------------------------------------#
# Fetch Suggestion #
#--------------------------------------------------------------------#
# Loops through all specified strategies and returns a suggestion
# from the first strategy to provide one.
#
_zsh_autosuggest_fetch_suggestion() {
typeset -g suggestion
local -a strategies
local strategy
# Ensure we are working with an array
strategies=(${=ZSH_AUTOSUGGEST_STRATEGY})
for strategy in $strategies; do
# Try to get a suggestion from this strategy
_zsh_autosuggest_strategy_$strategy "$1"
# Break once we've found a suggestion
[[ -n "$suggestion" ]] && break
done
}

View File

@@ -5,6 +5,8 @@
# Precmd hooks for initializing the library and starting pty's # Precmd hooks for initializing the library and starting pty's
autoload -Uz add-zsh-hook autoload -Uz add-zsh-hook
autoload -Uz add-zle-hook-widget
autoload -Uz is-at-least
# Asynchronous suggestions are generated in a pty # Asynchronous suggestions are generated in a pty
zmodload zsh/zpty zmodload zsh/zpty

View File

@@ -7,13 +7,22 @@
_zsh_autosuggest_start() { _zsh_autosuggest_start() {
add-zsh-hook -d precmd _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. # Re-bind widgets on every precmd to ensure we wrap other wrappers.
# Specifically, highlighting breaks if our widgets are wrapped by # Specifically, highlighting breaks if our widgets are wrapped by
# zsh-syntax-highlighting widgets. This also allows modifications # zsh-syntax-highlighting widgets. This also allows modifications
# to the widget list variables to take effect on the next precmd. # 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 if [[ -n "${ZSH_AUTOSUGGEST_USE_ASYNC+x}" ]]; then
_zsh_autosuggest_async_start _zsh_autosuggest_async_start

View File

@@ -1,12 +1,12 @@
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
# Default Suggestion Strategy # # History Suggestion Strategy #
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
# Suggests the most recent history item that matches the given # Suggests the most recent history item that matches the given
# prefix. # prefix.
# #
_zsh_autosuggest_strategy_default() { _zsh_autosuggest_strategy_history() {
# Reset options to defaults and enable LOCAL_OPTIONS # Reset options to defaults and enable LOCAL_OPTIONS
emulate -L zsh emulate -L zsh

View File

@@ -39,54 +39,21 @@ _zsh_autosuggest_clear() {
_zsh_autosuggest_modify() { _zsh_autosuggest_modify() {
local -i retval local -i retval
# Only available in zsh >= 5.4 # Save the contents of the postdisplay
local -i KEYS_QUEUED_COUNT
# Save the contents of the buffer/postdisplay
local orig_buffer="$BUFFER"
local orig_postdisplay="$POSTDISPLAY" local orig_postdisplay="$POSTDISPLAY"
# Clear suggestion while waiting for next one # Clear suggestion while original widget runs
unset POSTDISPLAY unset POSTDISPLAY
# Original widget may modify the buffer # Original widget may modify the buffer
_zsh_autosuggest_invoke_original_widget $@ _zsh_autosuggest_invoke_original_widget $@
retval=$? retval=$?
# Don't fetch a new suggestion if there's more input to be read immediately # Restore postdisplay to be used in redraw
if (( $PENDING > 0 )) || (( $KEYS_QUEUED_COUNT > 0 )); then POSTDISPLAY="$orig_postdisplay"
POSTDISPLAY="$orig_postdisplay"
return $retval
fi
# Optimize if manually typing in the suggestion # Run redraw to fetch a suggestion if needed
if (( $#BUFFER > $#orig_buffer )); then _zsh_autosuggest_redraw
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
return $retval return $retval
} }
@@ -97,13 +64,15 @@ _zsh_autosuggest_fetch() {
_zsh_autosuggest_async_request "$BUFFER" _zsh_autosuggest_async_request "$BUFFER"
else else
local suggestion local suggestion
_zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY "$BUFFER" _zsh_autosuggest_fetch_suggestion "$BUFFER"
_zsh_autosuggest_suggest "$suggestion" _zsh_autosuggest_suggest "$suggestion"
fi fi
} }
# Offer a suggestion # Offer a suggestion
_zsh_autosuggest_suggest() { _zsh_autosuggest_suggest() {
emulate -L zsh
local suggestion="$1" local suggestion="$1"
if [[ -n "$suggestion" ]] && (( $#BUFFER )); then if [[ -n "$suggestion" ]] && (( $#BUFFER )); then
@@ -186,28 +155,90 @@ _zsh_autosuggest_partial_accept() {
return $retval return $retval
} }
for action in clear modify fetch suggest accept partial_accept execute enable disable toggle; do _zsh_autosuggest_redraw() {
eval "_zsh_autosuggest_widget_$action() { emulate -L zsh
local -i retval
_zsh_autosuggest_highlight_reset typeset -g _ZSH_AUTOSUGGEST_LAST_BUFFER
_zsh_autosuggest_$action \$@ # Only available in zsh >= 5.4
retval=\$? 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 # Buffer hasn't changed
}" [[ "$BUFFER" = "$orig_buffer" ]] && return 0
done
zle -N autosuggest-fetch _zsh_autosuggest_widget_fetch local ignore_widgets
zle -N autosuggest-suggest _zsh_autosuggest_widget_suggest ignore_widgets=(
zle -N autosuggest-accept _zsh_autosuggest_widget_accept $ZSH_AUTOSUGGEST_CLEAR_WIDGETS
zle -N autosuggest-clear _zsh_autosuggest_widget_clear $ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
zle -N autosuggest-execute _zsh_autosuggest_widget_execute $ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
zle -N autosuggest-enable _zsh_autosuggest_widget_enable $ZSH_AUTOSUGGEST_IGNORE_WIDGETS
zle -N autosuggest-disable _zsh_autosuggest_widget_disable )
zle -N autosuggest-toggle _zsh_autosuggest_widget_toggle
# 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
}

View File

@@ -1,6 +1,6 @@
# 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.4.3 # v0.5.0
# Copyright (c) 2013 Thiago de Arruda # Copyright (c) 2013 Thiago de Arruda
# Copyright (c) 2016-2018 Eric Freese # Copyright (c) 2016-2018 Eric Freese
# #
@@ -31,6 +31,8 @@
# Precmd hooks for initializing the library and starting pty's # Precmd hooks for initializing the library and starting pty's
autoload -Uz add-zsh-hook autoload -Uz add-zsh-hook
autoload -Uz add-zle-hook-widget
autoload -Uz is-at-least
# Asynchronous suggestions are generated in a pty # Asynchronous suggestions are generated in a pty
zmodload zsh/zpty zmodload zsh/zpty
@@ -42,69 +44,94 @@ zmodload zsh/zpty
# Color to use when highlighting suggestion # Color to use when highlighting suggestion
# Uses format of `region_highlight` # Uses format of `region_highlight`
# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets # 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 # 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-
ZSH_AUTOSUGGEST_STRATEGY=default # Strategies to use to fetch a suggestion
# Will try each strategy in order until a suggestion is returned
(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && {
typeset -ga ZSH_AUTOSUGGEST_STRATEGY
ZSH_AUTOSUGGEST_STRATEGY=(history)
}
# Widgets that clear the suggestion # Widgets that clear the suggestion
ZSH_AUTOSUGGEST_CLEAR_WIDGETS=( (( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && {
history-search-forward typeset -ga ZSH_AUTOSUGGEST_CLEAR_WIDGETS
history-search-backward ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
history-beginning-search-forward history-search-forward
history-beginning-search-backward history-search-backward
history-substring-search-up history-beginning-search-forward
history-substring-search-down history-beginning-search-backward
up-line-or-beginning-search history-substring-search-up
down-line-or-beginning-search history-substring-search-down
up-line-or-history up-line-or-beginning-search
down-line-or-history down-line-or-beginning-search
accept-line up-line-or-history
) down-line-or-history
accept-line
)
}
# Widgets that accept the entire suggestion # Widgets that accept the entire suggestion
ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=( (( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && {
forward-char typeset -ga ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
end-of-line ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
vi-forward-char forward-char
vi-end-of-line end-of-line
vi-add-eol vi-forward-char
) vi-end-of-line
vi-add-eol
)
}
# Widgets that accept the entire suggestion and execute it # Widgets that accept the entire suggestion and execute it
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 # Widgets that accept the suggestion as far as the cursor moves
ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=( (( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && {
forward-word typeset -ga ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
emacs-forward-word ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
vi-forward-word forward-word
vi-forward-word-end emacs-forward-word
vi-forward-blank-word vi-forward-word
vi-forward-blank-word-end vi-forward-word-end
vi-find-next-char vi-forward-blank-word
vi-find-next-char-skip 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) # Widgets that should be ignored (globbing supported but must be escaped)
ZSH_AUTOSUGGEST_IGNORE_WIDGETS=( # Only relevant for zsh versions older than 5.4
orig-\* (( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && {
beep typeset -ga ZSH_AUTOSUGGEST_IGNORE_WIDGETS
run-help ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
set-local-history orig-\*
which-command beep
yank run-help
yank-pop set-local-history
) which-command
yank
yank-pop
)
}
# Max size of buffer to trigger autosuggestion. Leave undefined for no upper bound. # 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 # 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 # # Utility Functions #
@@ -206,11 +233,33 @@ _zsh_autosuggest_bind_widget() {
}" }"
# Create the bound widget # Create the bound widget
zle -N $widget _zsh_autosuggest_bound_${bind_count}_$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 # 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 local ignore_widgets
@@ -221,22 +270,15 @@ _zsh_autosuggest_bind_widgets() {
autosuggest-\* autosuggest-\*
$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\* $ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS $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 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 modify
_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
done done
} }
@@ -320,54 +362,21 @@ _zsh_autosuggest_clear() {
_zsh_autosuggest_modify() { _zsh_autosuggest_modify() {
local -i retval local -i retval
# Only available in zsh >= 5.4 # Save the contents of the postdisplay
local -i KEYS_QUEUED_COUNT
# Save the contents of the buffer/postdisplay
local orig_buffer="$BUFFER"
local orig_postdisplay="$POSTDISPLAY" local orig_postdisplay="$POSTDISPLAY"
# Clear suggestion while waiting for next one # Clear suggestion while original widget runs
unset POSTDISPLAY unset POSTDISPLAY
# Original widget may modify the buffer # Original widget may modify the buffer
_zsh_autosuggest_invoke_original_widget $@ _zsh_autosuggest_invoke_original_widget $@
retval=$? retval=$?
# Don't fetch a new suggestion if there's more input to be read immediately # Restore postdisplay to be used in redraw
if (( $PENDING > 0 )) || (( $KEYS_QUEUED_COUNT > 0 )); then POSTDISPLAY="$orig_postdisplay"
POSTDISPLAY="$orig_postdisplay"
return $retval
fi
# Optimize if manually typing in the suggestion # Run redraw to fetch a suggestion if needed
if (( $#BUFFER > $#orig_buffer )); then _zsh_autosuggest_redraw
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
return $retval return $retval
} }
@@ -378,13 +387,15 @@ _zsh_autosuggest_fetch() {
_zsh_autosuggest_async_request "$BUFFER" _zsh_autosuggest_async_request "$BUFFER"
else else
local suggestion local suggestion
_zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY "$BUFFER" _zsh_autosuggest_fetch_suggestion "$BUFFER"
_zsh_autosuggest_suggest "$suggestion" _zsh_autosuggest_suggest "$suggestion"
fi fi
} }
# Offer a suggestion # Offer a suggestion
_zsh_autosuggest_suggest() { _zsh_autosuggest_suggest() {
emulate -L zsh
local suggestion="$1" local suggestion="$1"
if [[ -n "$suggestion" ]] && (( $#BUFFER )); then if [[ -n "$suggestion" ]] && (( $#BUFFER )); then
@@ -467,40 +478,102 @@ _zsh_autosuggest_partial_accept() {
return $retval return $retval
} }
for action in clear modify fetch suggest accept partial_accept execute enable disable toggle; do _zsh_autosuggest_redraw() {
eval "_zsh_autosuggest_widget_$action() { emulate -L zsh
local -i retval
_zsh_autosuggest_highlight_reset typeset -g _ZSH_AUTOSUGGEST_LAST_BUFFER
_zsh_autosuggest_$action \$@ # Only available in zsh >= 5.4
retval=\$? 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 # Buffer hasn't changed
}" [[ "$BUFFER" = "$orig_buffer" ]] && return 0
done
zle -N autosuggest-fetch _zsh_autosuggest_widget_fetch local ignore_widgets
zle -N autosuggest-suggest _zsh_autosuggest_widget_suggest ignore_widgets=(
zle -N autosuggest-accept _zsh_autosuggest_widget_accept $ZSH_AUTOSUGGEST_CLEAR_WIDGETS
zle -N autosuggest-clear _zsh_autosuggest_widget_clear $ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
zle -N autosuggest-execute _zsh_autosuggest_widget_execute $ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
zle -N autosuggest-enable _zsh_autosuggest_widget_enable $ZSH_AUTOSUGGEST_IGNORE_WIDGETS
zle -N autosuggest-disable _zsh_autosuggest_widget_disable )
zle -N autosuggest-toggle _zsh_autosuggest_widget_toggle
# 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
}
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
# Default Suggestion Strategy # # History Suggestion Strategy #
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
# Suggests the most recent history item that matches the given # Suggests the most recent history item that matches the given
# prefix. # prefix.
# #
_zsh_autosuggest_strategy_default() { _zsh_autosuggest_strategy_history() {
# Reset options to defaults and enable LOCAL_OPTIONS # Reset options to defaults and enable LOCAL_OPTIONS
emulate -L zsh emulate -L zsh
@@ -577,6 +650,30 @@ _zsh_autosuggest_strategy_match_prev_cmd() {
typeset -g suggestion="$history[$histkey]" typeset -g suggestion="$history[$histkey]"
} }
#--------------------------------------------------------------------#
# Fetch Suggestion #
#--------------------------------------------------------------------#
# Loops through all specified strategies and returns a suggestion
# from the first strategy to provide one.
#
_zsh_autosuggest_fetch_suggestion() {
typeset -g suggestion
local -a strategies
local strategy
# Ensure we are working with an array
strategies=(${=ZSH_AUTOSUGGEST_STRATEGY})
for strategy in $strategies; do
# Try to get a suggestion from this strategy
_zsh_autosuggest_strategy_$strategy "$1"
# Break once we've found a suggestion
[[ -n "$suggestion" ]] && break
done
}
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
# Async # # Async #
#--------------------------------------------------------------------# #--------------------------------------------------------------------#
@@ -595,9 +692,12 @@ _zsh_autosuggest_async_server() {
sleep 1 # Block for long enough for the signal to come through sleep 1 # Block for long enough for the signal to come through
} }
# Output only newlines (not carriage return + newline) # Don't add any extra carriage returns
stty -onlcr stty -onlcr
# Don't translate carriage returns to newlines
stty -icrnl
# Silence any error messages # Silence any error messages
exec 2>/dev/null exec 2>/dev/null
@@ -610,7 +710,7 @@ _zsh_autosuggest_async_server() {
# Run suggestion search in the background # Run suggestion search in the background
( (
local suggestion local suggestion
_zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY "$query" _zsh_autosuggest_fetch_suggestion "$query"
echo -n -E "$suggestion"$'\0' echo -n -E "$suggestion"$'\0'
) & ) &
@@ -691,13 +791,22 @@ _zsh_autosuggest_async_start() {
_zsh_autosuggest_start() { _zsh_autosuggest_start() {
add-zsh-hook -d precmd _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. # Re-bind widgets on every precmd to ensure we wrap other wrappers.
# Specifically, highlighting breaks if our widgets are wrapped by # Specifically, highlighting breaks if our widgets are wrapped by
# zsh-syntax-highlighting widgets. This also allows modifications # zsh-syntax-highlighting widgets. This also allows modifications
# to the widget list variables to take effect on the next precmd. # 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 if [[ -n "${ZSH_AUTOSUGGEST_USE_ASYNC+x}" ]]; then
_zsh_autosuggest_async_start _zsh_autosuggest_async_start