Fish-like autosuggestions for zsh
Find a file
Roman Perepelitsa 167d52e7d8 Fix bugs in async code
1. Insert `-` in `echo -nE "$suggestion"`. This is necessary to prevent
   `"$suggestion"` from being treated as an option for `echo`.
2. Close file descriptors only in `_zsh_autosuggest_async_response` to
   ensure that each file descriptor is closed only once.

It's the second bug that prompted the fix. The original code in some
cases could close the same file descriptor twice. The code relied on
an invalid assumption that `_zsh_autosuggest_async_response` cannot
fire after the file descriptor is closed. Here's a demo that shows
this assumption being violated:

    () {
      emulate -L zsh

      function callback1() {
        zle -I
        emulate -L zsh -o xtrace
        : "$@"
        zle -F $fd1
        exec {fd1}>&-
        zle -F $fd2
        exec {fd2}>&-
      }

      function callback2() {
        zle -I
        emulate -L zsh -o xtrace
        : "$@"
      }

      exec {fd1} </dev/null
      exec {fd2} </dev/null
      zle -F $fd1 callback1
      zle -F $fd2 callback2
    }

And here's the output I get if the code is pasted into an interactive zsh:

    +callback1:3> : 12
    +callback1:4> zle -F 12
    +callback1:6> zle -F 13
    +callback2:3> : 13

Note that `callback2` fires after its file descriptor has been closed
by `callback1`.

This bug was the culprit of several issues filed against powerlevel10k.
In a nutshell:

1. `_zsh_autosuggest_async_request` opens a file.
2. `_zsh_autosuggest_async_request` closes the file descriptor.
3. powerlevel10k opens a file and gets the same file descriptor as above.
4. `_zsh_autosuggest_async_response` fires and closes the same file descriptor.
5. powerlevel10k encounters errors when trying to read from the file descriptor.
2023-07-26 13:06:13 +02:00
.circleci Fix circle ci build issues 2019-09-30 12:11:41 -06:00
.github/ISSUE_TEMPLATE Add issue templates 2019-07-02 21:03:58 -06:00
spec Fix flaky special char specs by not using with_history twice per test 2020-05-06 23:43:26 -06:00
src Fix bugs in async code 2023-07-26 13:06:13 +02:00
.editorconfig Set up circle ci 2017-02-26 14:26:41 -07:00
.rspec Lots of async changes 2017-02-16 19:19:30 -07:00
.rubocop.yml replace tabs in Rubocop config with spaces 2017-08-20 23:36:18 +01:00
.ruby-version Build docker image for running tests 2018-11-18 21:11:35 -07:00
CHANGELOG.md Update changelog for v0.7.0 release 2021-06-04 16:02:12 -06:00
DESCRIPTION Use add-zsh-hook to remove need to call autosuggest_start. 2016-02-07 15:35:43 -07:00
Dockerfile Build docker image for running tests 2018-11-18 21:11:35 -07:00
Gemfile Use pry-byebug instead of pry for more functionality 2017-03-03 18:43:10 -05:00
Gemfile.lock Use pry-byebug instead of pry for more functionality 2017-03-03 18:43:10 -05:00
INSTALL.md Update INSTALL.md 2021-03-09 11:08:18 +03:00
install_test_zsh.sh Enable tcsetpgrp to support job control 2019-04-09 13:14:34 -06:00
LICENSE Update license copyright year 2021-06-04 16:02:12 -06:00
Makefile Implement completion suggestion strategy (#111) 2019-04-11 09:53:55 -06:00
README.md Merge pull request #504 from zsh-users/ef/async-by-default 2020-01-29 20:54:46 -07:00
URL Update URL references after repo move to zsh-users 2016-02-25 13:04:32 -07:00
VERSION v0.7.0 2021-06-04 16:02:12 -06:00
zsh-autosuggestions.plugin.zsh Adjust plugin.zsh file to run on zsh 5.1 in mSYS2. 2016-05-11 17:02:41 +02:00
zsh-autosuggestions.zsh Fix bugs in async code 2023-07-26 13:06:13 +02:00
ZSH_VERSIONS Support new zsh version: 5.8 2021-06-04 14:42:16 -06:00

zsh-autosuggestions

Fish-like fast/unobtrusive autosuggestions for zsh.

It suggests commands as you type based on history and completions.

Requirements: Zsh v4.3.11 or later

CircleCI Chat on Gitter

Installation

See INSTALL.md.

Usage

As you type commands, you will see a completion offered after the cursor in a muted gray color. This color can be changed by setting the ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE variable. See configuration.

If you press the key (forward-char widget) or End (end-of-line widget) with the cursor at the end of the buffer, it will accept the suggestion, replacing the contents of the command line buffer with the suggestion.

If you invoke the forward-word widget, it will partially accept the suggestion up to the point that the cursor moves to.

Configuration

You may want to override the default global config variables. Default values of these variables can be found here.

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.

Suggestion Highlight Style

Set ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE to configure the style that the suggestion is shown with. The default is fg=8, which will set the foreground color to color 8 from the 256-color palette. If your terminal only supports 8 colors, you will need to use a number between 0 and 7.

Background color can also be set, and the suggestion can be styled bold, underlined, or standout. For example, this would show suggestions with bold, underlined, pink text on a cyan background:

ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#ff00ff,bg=cyan,bold,underline"

For more info, read the Character Highlighting section of the zsh manual: man zshzle or online.

Note: Some iTerm2 users have reported not being able to see the suggestions. If this affects you, the problem is likely caused by incorrect color settings. In order to correct this, go into iTerm2's setting, navigate to profile > colors and make sure that the colors for Basic Colors > Background and ANSI Colors > Bright Black are different.

Suggestion Strategy

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 three built-in strategies to choose from:

  • history: Chooses the most recent match from history.
  • completion: Chooses a suggestion based on what tab-completion would suggest. (requires zpty module)
  • match_prev_cmd: Like history, but chooses the most recent match whose preceding history item matches the most recently executed command (more info). 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.

For example, setting ZSH_AUTOSUGGEST_STRATEGY=(history completion) will first try to find a suggestion from your history, but, if it can't find a match, will find a suggestion from the completion engine.

Widget Mapping

This plugin works by triggering custom behavior when certain zle widgets are invoked. You can add and remove widgets from these arrays to change the behavior of this plugin:

  • ZSH_AUTOSUGGEST_CLEAR_WIDGETS: Widgets in this array will clear the suggestion when invoked.
  • ZSH_AUTOSUGGEST_ACCEPT_WIDGETS: Widgets in this array will accept the suggestion when invoked.
  • ZSH_AUTOSUGGEST_EXECUTE_WIDGETS: Widgets in this array will execute the suggestion when invoked.
  • ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS: Widgets in this array will partially accept the suggestion when invoked.
  • ZSH_AUTOSUGGEST_IGNORE_WIDGETS: Widgets in this array will not trigger any custom behavior.

Widgets that modify the buffer and are not found in any of these arrays will fetch a new suggestion after they are invoked.

Note: A widget shouldn't belong to more than one of the above arrays.

Disabling suggestion for large buffers

Set ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE to an integer value to disable autosuggestion for large buffers. The default is unset, which means that autosuggestion will be tried for any buffer size. Recommended value is 20. This can be useful when pasting large amount of text in the terminal, to avoid triggering autosuggestion for strings that are too long.

Asynchronous Mode

Suggestions are fetched asynchronously by default in zsh versions 5.0.8 and greater. To disable asynchronous suggestions and fetch them synchronously instead, unset ZSH_AUTOSUGGEST_USE_ASYNC after sourcing the plugin.

Alternatively, if you are using a version of zsh older than 5.0.8 and want to enable asynchronous mode, set the ZSH_AUTOSUGGEST_USE_ASYNC variable after sourcing the plugin (it can be set to anything). Note that there is a bug in versions of zsh older than 5.0.8 where ctrl + c will fail to reset the prompt immediately after fetching a suggestion asynchronously.

Disabling automatic widget re-binding

Set ZSH_AUTOSUGGEST_MANUAL_REBIND (it can be set to anything) to disable automatic widget re-binding on each precmd. This can be a big boost to performance, but you'll need to handle re-binding yourself if any of the widget lists change or if you or another plugin wrap any of the autosuggest widgets. To re-bind widgets, run _zsh_autosuggest_bind_widgets.

Ignoring history suggestions that match a pattern

Set ZSH_AUTOSUGGEST_HISTORY_IGNORE to a glob pattern to prevent offering suggestions for history entries that match the pattern. For example, set it to "cd *" to never suggest any cd commands from history. Or set to "?(#c50,)" to never suggest anything 50 characters or longer.

Note: This only affects the history and match_prev_cmd suggestion strategies.

Skipping completion suggestions for certain cases

Set ZSH_AUTOSUGGEST_COMPLETION_IGNORE to a glob pattern to prevent offering completion suggestions when the buffer matches that pattern. For example, set it to "git *" to disable completion suggestions for git subcommands.

Note: This only affects the completion suggestion strategy.

Key Bindings

This plugin provides a few widgets that you can use with bindkey:

  1. autosuggest-accept: Accepts the current suggestion.
  2. autosuggest-execute: Accepts and executes the current suggestion.
  3. autosuggest-clear: Clears the current suggestion.
  4. autosuggest-fetch: Fetches a suggestion (works even when suggestions are disabled).
  5. autosuggest-disable: Disables suggestions.
  6. autosuggest-enable: Re-enables suggestions.
  7. autosuggest-toggle: Toggles between enabled/disabled suggestions.

For example, this would bind ctrl + space to accept the current suggestion.

bindkey '^ ' autosuggest-accept

Troubleshooting

If you have a problem, please search through the list of issues on GitHub to see if someone else has already reported it.

Reporting an Issue

Before reporting an issue, please try temporarily disabling sections of your configuration and other plugins that may be conflicting with this plugin to isolate the problem.

When reporting an issue, please include:

  • The smallest, simplest .zshrc configuration that will reproduce the problem. See this comment for a good example of what this means.
  • The version of zsh you're using (zsh --version)
  • Which operating system you're running

Uninstallation

  1. Remove the code referencing this plugin from ~/.zshrc.

  2. Remove the git repository from your hard drive

    rm -rf ~/.zsh/zsh-autosuggestions # Or wherever you installed
    

Development

Build Process

Edit the source files in src/. Run make to build zsh-autosuggestions.zsh from those source files.

Pull Requests

Pull requests are welcome! If you send a pull request, please:

  • Request to merge into the develop branch (NOT master)
  • Match the existing coding conventions.
  • Include helpful comments to keep the barrier-to-entry low for people new to the project.
  • Write tests that cover your code as much as possible.

Testing

Tests are written in ruby using the rspec framework. They use tmux to drive a pseudoterminal, sending simulated keystrokes and making assertions on the terminal content.

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. It comes with ruby, the bundler dependencies, and all supported versions of zsh installed.

Pull the docker image with:

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 file):

docker run -it -e TEST_ZSH_BIN=zsh-<version> -v $PWD:/zsh-autosuggestions zsh-autosuggestions-test make test

License

This project is licensed under MIT license. For the full text of the license, see the LICENSE file.