changeset 467:e1ce8897030d

zsh: import df6f6f9ff41 of zsh-autosuggestions
author Augie Fackler <raf@durin42.com>
date Mon, 03 Dec 2018 22:37:29 -0500
parents f248cf012d9a
children bec91aeefddc
files .shell.d/99.zsh-autosuggestions.zsh .zfun/zsh-autosuggestions/.circleci/config.yml .zfun/zsh-autosuggestions/.editorconfig .zfun/zsh-autosuggestions/.rspec .zfun/zsh-autosuggestions/.rubocop.yml .zfun/zsh-autosuggestions/.ruby-version .zfun/zsh-autosuggestions/CHANGELOG.md .zfun/zsh-autosuggestions/DESCRIPTION .zfun/zsh-autosuggestions/Dockerfile .zfun/zsh-autosuggestions/Gemfile .zfun/zsh-autosuggestions/Gemfile.lock .zfun/zsh-autosuggestions/INSTALL.md .zfun/zsh-autosuggestions/LICENSE .zfun/zsh-autosuggestions/Makefile .zfun/zsh-autosuggestions/README.md .zfun/zsh-autosuggestions/URL .zfun/zsh-autosuggestions/VERSION .zfun/zsh-autosuggestions/ZSH_VERSIONS .zfun/zsh-autosuggestions/install_test_zsh.sh .zfun/zsh-autosuggestions/spec/async_spec.rb .zfun/zsh-autosuggestions/spec/integrations/bracketed_paste_magic_spec.rb .zfun/zsh-autosuggestions/spec/integrations/client_zpty_spec.rb .zfun/zsh-autosuggestions/spec/integrations/rebound_bracket_spec.rb .zfun/zsh-autosuggestions/spec/integrations/vi_mode_spec.rb .zfun/zsh-autosuggestions/spec/integrations/wrapped_widget_spec.rb .zfun/zsh-autosuggestions/spec/integrations/zle_input_stack_spec.rb .zfun/zsh-autosuggestions/spec/kill_ring_spec.rb .zfun/zsh-autosuggestions/spec/multi_line_spec.rb .zfun/zsh-autosuggestions/spec/options/async_zpty_name_spec.rb .zfun/zsh-autosuggestions/spec/options/buffer_max_size_spec.rb .zfun/zsh-autosuggestions/spec/options/highlight_style_spec.rb .zfun/zsh-autosuggestions/spec/options/original_widget_prefix_spec.rb .zfun/zsh-autosuggestions/spec/options/strategy_spec.rb .zfun/zsh-autosuggestions/spec/options/use_async_spec.rb .zfun/zsh-autosuggestions/spec/options/widget_lists_spec.rb .zfun/zsh-autosuggestions/spec/spec_helper.rb .zfun/zsh-autosuggestions/spec/strategies/default_spec.rb .zfun/zsh-autosuggestions/spec/strategies/match_prev_cmd_spec.rb .zfun/zsh-autosuggestions/spec/strategies/special_characters_helper.rb .zfun/zsh-autosuggestions/spec/terminal_session.rb .zfun/zsh-autosuggestions/spec/widgets/disable_spec.rb .zfun/zsh-autosuggestions/spec/widgets/enable_spec.rb .zfun/zsh-autosuggestions/spec/widgets/fetch_spec.rb .zfun/zsh-autosuggestions/spec/widgets/toggle_spec.rb .zfun/zsh-autosuggestions/src/async.zsh .zfun/zsh-autosuggestions/src/bind.zsh .zfun/zsh-autosuggestions/src/config.zsh .zfun/zsh-autosuggestions/src/features.zsh .zfun/zsh-autosuggestions/src/fetch.zsh .zfun/zsh-autosuggestions/src/highlight.zsh .zfun/zsh-autosuggestions/src/setup.zsh .zfun/zsh-autosuggestions/src/start.zsh .zfun/zsh-autosuggestions/src/strategies/default.zsh .zfun/zsh-autosuggestions/src/strategies/match_prev_cmd.zsh .zfun/zsh-autosuggestions/src/util.zsh .zfun/zsh-autosuggestions/src/widgets.zsh .zfun/zsh-autosuggestions/zsh-autosuggestions.plugin.zsh .zfun/zsh-autosuggestions/zsh-autosuggestions.zsh
diffstat 58 files changed, 2894 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/.shell.d/99.zsh-autosuggestions.zsh
@@ -0,0 +1,2 @@
+source ~/.zfun/zsh-autosuggestions/zsh-autosuggestions.zsh
+bindkey '^ ' autosuggest-accept
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/.circleci/config.yml
@@ -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
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/.editorconfig
@@ -0,0 +1,18 @@
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = tab
+indent_size = 4
+
+[*.md]
+indent_style = space
+
+[*.rb]
+indent_style = space
+indent_size = 2
+
+[*.yml]
+indent_style = space
+indent_size = 2
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/.rspec
@@ -0,0 +1,3 @@
+--color
+--require spec_helper
+--format documentation
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/.rubocop.yml
@@ -0,0 +1,30 @@
+# Rails:
+#   Enabled: true
+
+AllCops:
+  TargetRubyVersion: 2.3
+  Include:
+    - '**/Rakefile'
+    - '**/config.ru'
+    - '**/Gemfile'
+
+Metrics/LineLength:
+  Max: 120
+
+Style/Documentation:
+  Enabled: false
+
+Style/DotPosition:
+  EnforcedStyle: trailing
+
+Style/FrozenStringLiteralComment:
+  Enabled: false
+
+Style/Lambda:
+  Enabled: false
+
+Style/MultilineMethodCallIndentation:
+  EnforcedStyle: indented
+
+Style/TrailingUnderscoreVariable:
+  Enabled: false
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/.ruby-version
@@ -0,0 +1,1 @@
+2.5.3
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/CHANGELOG.md
@@ -0,0 +1,79 @@
+# 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
+- Avoid bell when accepting suggestions with `autosuggest-accept` (#228)
+- Don't fetch suggestions after [up,down]-line-or-beginning-search (#227, #241)
+- We are now running CI against new 5.5.1 version
+- Fix partial-accept in vi mode (#188)
+- Fix suggestion disappearing on fast movement after switching to `vicmd` mode (#290)
+- Fix issue rotating through kill ring with `yank-pop` (#301)
+- Fix issue creating new pty for async mode when previous pty is not properly cleaned up (#249)
+
+## v0.4.2
+- Fix bug in zsh versions older than 5.0.8 (#296)
+- Officially support back to zsh v4.3.11
+
+## v0.4.1
+- Switch to [[ and (( conditionals instead of [ (#257)
+- Avoid warnnestedvar warnings with `typeset -g` (#275)
+- Replace tabs with spaces in yaml (#268)
+- Clean up and fix escaping of special characters (#267)
+- Add `emacs-forward-word` to default list of partial accept widgets (#246)
+
+## v0.4.0
+- High-level integration tests using RSpec and tmux
+- Add continuous integration with Circle CI
+- Experimental support for asynchronous suggestions (#170)
+- Fix problems with multi-line suggestions (#225)
+- Optimize case where manually typing in suggestion
+- Avoid wrapping any zle-* widgets (#206)
+- Remove support for deprecated options from v0.0.x
+- Handle history entries that begin with dashes
+- Gracefully handle being sourced multiple times (#126)
+- Add enable/disable/toggle widgets to disable/enable suggestions (#219)
+
+
+## v0.3.3
+- Switch from $history array to fc builtin for better performance with large HISTFILEs (#164)
+- Fix tilde handling when extended_glob is set (#168)
+- Add config option for maximum buffer length to fetch suggestions for (#178)
+- Add config option for list of widgets to ignore (#184)
+- Don't fetch a new suggestion unless a modification widget actually modifies the buffer (#183)
+
+## v0.3.2
+- Test runner now supports running specific tests and choosing zsh binary
+- Return code from original widget is now correctly passed through (#135)
+- Add `vi-add-eol` to list of accept widgets (#143)
+- Escapes widget names within evals to fix problems with irregular widget names (#152)
+- Plugin now clears suggestion while within a completion menu (#149)
+- .plugin file no longer relies on symbolic link support, fixing issues on Windows (#156)
+
+## v0.3.1
+
+- Fixes issue with `vi-next-char` not accepting suggestion (#137).
+- Fixes global variable warning when WARN_CREATE_GLOBAL option enabled (#133).
+- Split out a separate test file for each widget.
+
+## v0.3.0
+
+- Adds `autosuggest-execute` widget (PR #124).
+- Adds concept of suggestion "strategies" for different ways of fetching suggestions.
+- Adds "match_prev_cmd" strategy (PR #131).
+- Uses git submodules for testing dependencies.
+- Lots of test cleanup.
+- Various bug fixes for zsh 5.0.x and `sh_word_split` option.
+
+
+## v0.2.17
+
+Start of changelog.
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/DESCRIPTION
@@ -0,0 +1,1 @@
+Fish-like fast/unobtrusive autosuggestions for zsh.
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/Dockerfile
@@ -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
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/Gemfile
@@ -0,0 +1,5 @@
+source 'https://rubygems.org'
+
+gem 'rspec'
+gem 'rspec-wait'
+gem 'pry-byebug'
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/Gemfile.lock
@@ -0,0 +1,41 @@
+GEM
+  remote: https://rubygems.org/
+  specs:
+    byebug (9.0.5)
+    coderay (1.1.1)
+    diff-lcs (1.3)
+    method_source (0.8.2)
+    pry (0.10.4)
+      coderay (~> 1.1.0)
+      method_source (~> 0.8.1)
+      slop (~> 3.4)
+    pry-byebug (3.4.0)
+      byebug (~> 9.0)
+      pry (~> 0.10)
+    rspec (3.5.0)
+      rspec-core (~> 3.5.0)
+      rspec-expectations (~> 3.5.0)
+      rspec-mocks (~> 3.5.0)
+    rspec-core (3.5.4)
+      rspec-support (~> 3.5.0)
+    rspec-expectations (3.5.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.5.0)
+    rspec-mocks (3.5.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.5.0)
+    rspec-support (3.5.0)
+    rspec-wait (0.0.9)
+      rspec (>= 3, < 4)
+    slop (3.6.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  pry-byebug
+  rspec
+  rspec-wait
+
+BUNDLED WITH
+   1.13.6
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/INSTALL.md
@@ -0,0 +1,77 @@
+## Installation
+
+### Manual (Git Clone)
+
+1. Clone this repository somewhere on your machine. This guide will assume `~/.zsh/zsh-autosuggestions`.
+
+    ```sh
+    git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
+    ```
+
+2. Add the following to your `.zshrc`:
+
+    ```sh
+    source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
+    ```
+
+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
+
+1. Clone this repository into `$ZSH_CUSTOM/plugins` (by default `~/.oh-my-zsh/custom/plugins`)
+
+    ```sh
+    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 (inside `~/.zshrc`):
+
+    ```sh
+    plugins=(zsh-autosuggestions)
+    ```
+
+3. Start a new terminal session.
+
+### Arch Linux
+
+1. Install [`zsh-autosuggestions`](https://www.archlinux.org/packages/community/any/zsh-autosuggestions/) from the `community` repository.
+
+    ```sh
+    pacman -S zsh-autosuggestions
+    ```
+
+    or, to use a package based on the `master` branch, install [`zsh-autosuggestions-git`](https://aur.archlinux.org/packages/zsh-autosuggestions-git/) from the [AUR](https://wiki.archlinux.org/index.php/Arch_User_Repository).
+
+2. Add the following to your `.zshrc`:
+
+    ```sh
+    source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
+    ```
+
+3. Start a new terminal session.
+
+### macOS via Homebrew
+1. Install the `zsh-autosuggestions` package using [Homebrew](https://brew.sh/).
+
+    ```sh
+    brew install zsh-autosuggestions
+    ```
+
+2. Add the following to your `.zshrc`:
+
+    ```sh
+    source /usr/local/share/zsh-autosuggestions/zsh-autosuggestions.zsh
+    ```
+
+3. Start a new terminal session.
+
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2013 Thiago de Arruda
+Copyright (c) 2016-2018 Eric Freese
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/Makefile
@@ -0,0 +1,37 @@
+SRC_DIR    := ./src
+
+SRC_FILES := \
+	$(SRC_DIR)/setup.zsh \
+	$(SRC_DIR)/config.zsh \
+	$(SRC_DIR)/util.zsh \
+	$(SRC_DIR)/features.zsh \
+	$(SRC_DIR)/bind.zsh \
+	$(SRC_DIR)/highlight.zsh \
+	$(SRC_DIR)/widgets.zsh \
+	$(SRC_DIR)/strategies/*.zsh \
+	$(SRC_DIR)/fetch.zsh \
+	$(SRC_DIR)/async.zsh \
+	$(SRC_DIR)/start.zsh
+
+HEADER_FILES := \
+	DESCRIPTION \
+	URL \
+	VERSION \
+	LICENSE
+
+PLUGIN_TARGET := zsh-autosuggestions.zsh
+
+all: $(PLUGIN_TARGET)
+
+$(PLUGIN_TARGET): $(HEADER_FILES) $(SRC_FILES)
+	cat $(HEADER_FILES) | sed -e 's/^/# /g' > $@
+	cat $(SRC_FILES) >> $@
+
+.PHONY: clean
+clean:
+	rm $(PLUGIN_TARGET)
+
+.PHONY: test
+test: all
+	@test -n "$$TEST_ZSH_BIN" && echo "Testing zsh binary: $(TEST_ZSH_BIN)" || true
+	bundle exec rspec $(TESTS)
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/README.md
@@ -0,0 +1,160 @@
+# zsh-autosuggestions
+
+_[Fish](http://fishshell.com/)-like fast/unobtrusive autosuggestions for zsh._
+
+It suggests commands as you type, based on command history.
+
+Requirements: Zsh v4.3.11 or later
+
+[![CircleCI](https://circleci.com/gh/zsh-users/zsh-autosuggestions.svg?style=svg)](https://circleci.com/gh/zsh-users/zsh-autosuggestions)
+
+<a href="https://asciinema.org/a/37390" target="_blank"><img src="https://asciinema.org/a/37390.png" width="400" /></a>
+
+
+## Installation
+
+See [INSTALL.md](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](#configuration).
+
+If you press the <kbd>→</kbd> key (`forward-char` widget) or <kbd>End</kbd> (`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](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).
+
+
+### Suggestion Highlight Style
+
+Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion is shown with. The default is `fg=8`.
+
+
+### 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 two built-in strategies to choose from:
+
+- `history`: Chooses the most recent match from history.
+- `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
+
+This plugin works by triggering custom behavior when certain [zle widgets](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#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 too long strings.
+
+### Enable Asynchronous Mode
+
+As of `v0.4.0`, suggestions can be fetched asynchronously using the `zsh/zpty` module. To enable this behavior, set the `ZSH_AUTOSUGGEST_USE_ASYNC` variable (it can be set to anything).
+
+
+### 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 <kbd>ctrl</kbd> + <kbd>space</kbd> to accept the current suggestion.
+
+```sh
+bindkey '^ ' autosuggest-accept
+```
+
+
+## Troubleshooting
+
+If you have a problem, please search through [the list of issues on GitHub](https://github.com/zsh-users/zsh-autosuggestions/issues) 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](https://github.com/zsh-users/zsh-autosuggestions/issues/102#issuecomment-180944764) 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
+
+    ```sh
+    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`](http://rspec.info/) framework. They use [`tmux`](https://tmux.github.io/) 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](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
+
+This project is licensed under [MIT license](http://opensource.org/licenses/MIT).
+For the full text of the license, see the [LICENSE](LICENSE) file.
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/URL
@@ -0,0 +1,1 @@
+https://github.com/zsh-users/zsh-autosuggestions
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/VERSION
@@ -0,0 +1,1 @@
+v0.5.0
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/ZSH_VERSIONS
@@ -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
new file mode 100755
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/install_test_zsh.sh
@@ -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
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/async_spec.rb
@@ -0,0 +1,84 @@
+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="] }
+
+  describe '`up-line-or-beginning-search`' do
+    let(:before_sourcing) do
+      -> do
+        session.
+          run_command('autoload -U up-line-or-beginning-search').
+          run_command('zle -N up-line-or-beginning-search').
+          send_string('bindkey "').
+          send_keys('C-v').send_keys('up').
+          send_string('" up-line-or-beginning-search').
+          send_keys('enter')
+      end
+    end
+
+    it 'should show previous history entries' do
+      with_history(
+        'echo foo',
+        'echo bar',
+        'echo baz'
+      ) do
+        session.clear_screen
+        3.times { session.send_keys('up') }
+        wait_for { session.content }.to eq("echo foo")
+      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
+    it 'should not cause error messages to be printed' do
+      session.run_command('$(exit)')
+
+      sleep 1
+
+      expect(session.content).to eq('$(exit)')
+    end
+  end
+end
+
+
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/integrations/bracketed_paste_magic_spec.rb
@@ -0,0 +1,27 @@
+describe 'pasting using bracketed-paste-magic' do
+  let(:before_sourcing) do
+    -> do
+      session.
+        run_command('autoload -Uz bracketed-paste-magic').
+        run_command('zle -N bracketed-paste bracketed-paste-magic')
+    end
+  end
+
+  context 'with suggestions disabled while pasting' do
+    before do
+      session.
+        run_command('bpm_init() { zle autosuggest-disable }').
+        run_command('bpm_finish() { zle autosuggest-enable }').
+        run_command('zstyle :bracketed-paste-magic paste-init bpm_init').
+        run_command('zstyle :bracketed-paste-magic paste-finish bpm_finish')
+    end
+
+    it 'does not show an incorrect suggestion' do
+      with_history('echo hello') do
+        session.paste_string("echo #{'a' * 60}")
+        sleep 1
+        expect(session.content).to eq("echo #{'a' * 60}")
+      end
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/integrations/client_zpty_spec.rb
@@ -0,0 +1,10 @@
+describe 'a running zpty command' do
+  let(:before_sourcing) { -> { session.run_command('zmodload zsh/zpty && zpty -b kitty cat') } }
+
+  it 'is not affected by running zsh-autosuggestions' do
+    sleep 1 # Give a little time for precmd hooks to run
+    session.run_command('zpty -t kitty; echo $?')
+
+    wait_for { session.content }.to end_with("\n0")
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/integrations/rebound_bracket_spec.rb
@@ -0,0 +1,13 @@
+describe 'rebinding [' do
+  context 'initialized before sourcing the plugin' do
+    before do
+      session.run_command("function [ { $commands[\\[] \"$@\" }")
+      session.clear_screen
+    end
+
+    it 'executes the custom behavior and the built-in behavior' do
+      session.send_string('asdf')
+      wait_for { session.content }.to eq('asdf')
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/integrations/vi_mode_spec.rb
@@ -0,0 +1,67 @@
+describe 'when using vi mode' do
+  let(:before_sourcing) do
+    -> do
+      session.run_command('bindkey -v')
+    end
+  end
+
+  describe 'moving the cursor after exiting insert mode' do
+    it 'should not clear the current suggestion' do
+      with_history('foobar foo') do
+        session.
+          send_string('foo').
+          send_keys('escape').
+          send_keys('h')
+
+        wait_for { session.content }.to eq('foobar foo')
+      end
+    end
+  end
+
+  describe '`vi-forward-word-end`' do
+    it 'should accept through the end of the current word' do
+      with_history('foobar foo') do
+        session.
+          send_string('foo').
+          send_keys('escape').
+          send_keys('e'). # vi-forward-word-end
+          send_keys('a'). # vi-add-next
+          send_string('baz')
+
+        wait_for { session.content }.to eq('foobarbaz')
+      end
+    end
+  end
+
+  describe '`vi-forward-word`' do
+    it 'should accept through the first character of the next word' do
+      with_history('foobar foo') do
+        session.
+          send_string('foo').
+          send_keys('escape').
+          send_keys('w'). # vi-forward-word
+          send_keys('a'). # vi-add-next
+          send_string('az')
+
+        wait_for { session.content }.to eq('foobar faz')
+      end
+    end
+  end
+
+  describe '`vi-find-next-char`' do
+    it 'should accept through the next occurrence of the character' do
+      with_history('foobar foo') do
+        session.
+          send_string('foo').
+          send_keys('escape').
+          send_keys('f'). # vi-find-next-char
+          send_keys('o').
+          send_keys('a'). # vi-add-next
+          send_string('b')
+
+        wait_for { session.content }.to eq('foobar fob')
+      end
+    end
+  end
+end
+
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/integrations/wrapped_widget_spec.rb
@@ -0,0 +1,39 @@
+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
+    end
+
+    it 'executes the custom behavior and the built-in behavior' do
+      with_history('foobar', 'foodar') do
+        session.send_string('food').send_keys('C-h')
+        wait_for { session.content }.to eq('foobar')
+      end
+    end
+  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
+
+    it 'executes the custom behavior and the built-in behavior' do
+      with_history('foobar', 'foodar') do
+        session.send_string('food').send_keys('C-h')
+        wait_for { session.content }.to eq('foobar')
+      end
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/integrations/zle_input_stack_spec.rb
@@ -0,0 +1,24 @@
+describe 'using `zle -U`' do
+  let(:before_sourcing) do
+    -> do
+      session.
+        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')
+    end
+  end
+
+  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
+    session.send_keys('C-b')
+    wait_for { session.content }.to eq('echo hello')
+  end
+
+  it 'shows a suggestion when the widget completes' do
+    with_history('echo hello world') do
+      session.send_keys('C-b')
+      wait_for { session.content(esc_seqs: true) }.to match(/\Aecho hello\e\[[0-9]+m world/)
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/kill_ring_spec.rb
@@ -0,0 +1,23 @@
+context 'with some items in the kill ring' do
+  before do
+    session.
+      send_string('echo foo').
+      send_keys('C-u').
+      send_string('echo bar').
+      send_keys('C-u')
+  end
+
+  describe '`yank-pop`' do
+    it 'should cycle through all items in the kill ring' do
+      session.send_keys('C-y')
+      wait_for { session.content }.to eq('echo bar')
+
+      session.send_keys('escape').send_keys('y')
+      wait_for { session.content }.to eq('echo foo')
+
+      session.send_keys('escape').send_keys('y')
+      wait_for { session.content }.to eq('echo bar')
+    end
+  end
+end
+
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/multi_line_spec.rb
@@ -0,0 +1,13 @@
+describe 'a multi-line suggestion' do
+  it 'should be displayed on multiple lines' do
+    with_history(-> {
+      session.send_string('echo "')
+      session.send_keys('enter')
+      session.send_string('"')
+      session.send_keys('enter')
+    }) do
+      session.send_keys('e')
+      wait_for { session.content }.to eq("echo \"\n\"")
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/options/async_zpty_name_spec.rb
@@ -0,0 +1,19 @@
+context 'when async suggestions are enabled' do
+  let(:options) { ["ZSH_AUTOSUGGEST_USE_ASYNC="] }
+
+  describe 'the zpty for async suggestions' do
+    it 'is created with the default name' do
+      session.run_command('zpty -t zsh_autosuggest_pty &>/dev/null; echo $?')
+      wait_for { session.content }.to end_with("\n0")
+    end
+
+    context 'when ZSH_AUTOSUGGEST_ASYNC_PTY_NAME is set' do
+      let(:options) { super() + ['ZSH_AUTOSUGGEST_ASYNC_PTY_NAME=foo_pty'] }
+
+      it 'is created with the specified name' do
+        session.run_command('zpty -t foo_pty &>/dev/null; echo $?')
+        wait_for { session.content }.to end_with("\n0")
+      end
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/options/buffer_max_size_spec.rb
@@ -0,0 +1,30 @@
+describe 'a suggestion' do
+  let(:term_opts) { { width: 200 } }
+  let(:long_command) { "echo #{'a' * 100}" }
+
+  around do |example|
+    with_history(long_command) { example.run }
+  end
+
+  it 'is provided for any buffer length' do
+    session.send_string(long_command[0...-1])
+    wait_for { session.content }.to eq(long_command)
+  end
+
+  context 'when ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE is specified' do
+    let(:buffer_max_size) { 10 }
+    let(:options) { ["ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=#{buffer_max_size}"] }
+
+    it 'is provided when the buffer is shorter than the specified length' do
+      session.send_string(long_command[0...(buffer_max_size - 1)])
+      wait_for { session.content }.to eq(long_command)
+    end
+
+    it 'is provided when the buffer is equal to the specified length' do
+      session.send_string(long_command[0...(buffer_max_size)])
+      wait_for { session.content }.to eq(long_command)
+    end
+
+    it 'is not provided when the buffer is longer than the specified length'
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/options/highlight_style_spec.rb
@@ -0,0 +1,7 @@
+describe 'a displayed suggestion' do
+  it 'is shown in the default style'
+
+  describe 'when ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE is set to a zle_highlight string' do
+    it 'is shown in the specified style'
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/options/original_widget_prefix_spec.rb
@@ -0,0 +1,7 @@
+describe 'an original zle widget' do
+  context 'is accessible with the default prefix'
+
+  context 'when ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX is set' do
+    it 'is accessible with the specified prefix'
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/options/strategy_spec.rb
@@ -0,0 +1,55 @@
+describe 'a suggestion for a given prefix' do
+  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" }' }
+
+  let(:after_sourcing) do
+    -> do
+      session.run_command(history_strategy)
+    end
+  end
+
+  it 'by default is determined by calling the `history` strategy function' do
+    session.send_string('h')
+    wait_for { session.content }.to eq('history')
+  end
+
+  context 'when ZSH_AUTOSUGGEST_STRATEGY is set to an array' 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
+
+  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
+
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/options/use_async_spec.rb
@@ -0,0 +1,7 @@
+describe 'suggestion fetching' do
+  it 'is performed synchronously'
+
+  context 'when ZSH_AUTOSUGGEST_USE_ASYNC is set' do
+    it 'is performed asynchronously'
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/options/widget_lists_spec.rb
@@ -0,0 +1,97 @@
+describe 'a zle widget' do
+  let(:widget) { 'my-widget' }
+  let(:before_sourcing) { -> { session.run_command("#{widget}() {}; zle -N #{widget}; bindkey ^B #{widget}") } }
+
+  context 'when added to ZSH_AUTOSUGGEST_ACCEPT_WIDGETS' do
+    let(:options) { ["ZSH_AUTOSUGGEST_ACCEPT_WIDGETS+=(#{widget})"] }
+
+    it 'accepts the suggestion when invoked' do
+      with_history('echo hello') do
+        session.send_string('e')
+        wait_for { session.content }.to eq('echo hello')
+        session.send_keys('C-b')
+        wait_for { session.content(esc_seqs: true) }.to eq('echo hello')
+      end
+    end
+  end
+
+  context 'when added to ZSH_AUTOSUGGEST_CLEAR_WIDGETS' do
+    let(:options) { ["ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(#{widget})"] }
+
+    it 'clears the suggestion when invoked' do
+      with_history('echo hello') do
+        session.send_string('e')
+        wait_for { session.content }.to eq('echo hello')
+        session.send_keys('C-b')
+        wait_for { session.content }.to eq('e')
+      end
+    end
+  end
+
+  context 'when added to ZSH_AUTOSUGGEST_EXECUTE_WIDGETS' do
+    let(:options) { ["ZSH_AUTOSUGGEST_EXECUTE_WIDGETS+=(#{widget})"] }
+
+    it 'executes the suggestion when invoked' do
+      with_history('echo hello') do
+        session.send_string('e')
+        wait_for { session.content }.to eq('echo hello')
+        session.send_keys('C-b')
+        wait_for { session.content }.to end_with("\nhello")
+      end
+    end
+  end
+
+  context 'when added to ZSH_AUTOSUGGEST_IGNORE_WIDGETS' do
+    let(:options) { ["ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(#{widget})"] }
+
+    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}")
+    end
+  end
+
+  context 'that moves the cursor forward' do
+    before { session.run_command("#{widget}() { zle forward-char }") }
+
+    context 'when added to ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS' do
+      let(:options) { ["ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(#{widget})"] }
+
+      it 'accepts the suggestion as far as the cursor is moved when invoked' 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(esc_seqs: true) }.to match(/\Aec\e\[[0-9]+mho hello/)
+        end
+      end
+    end
+  end
+
+  context 'that modifies the buffer' do
+    before { session.run_command("#{widget}() { BUFFER=\"foo\" }") }
+
+    context 'when not added to any of the widget lists' do
+      it 'modifies the buffer and fetches a new suggestion' do
+        with_history('foobar') do
+          session.send_keys('C-b')
+          wait_for { session.content }.to eq('foobar')
+        end
+      end
+    end
+  end
+end
+
+describe 'a modification to the widget lists' do
+  let(:widget) { 'my-widget' }
+  let(:before_sourcing) { -> { session.run_command("#{widget}() {}; zle -N #{widget}; bindkey ^B #{widget}") } }
+  before { session.run_command("ZSH_AUTOSUGGEST_ACCEPT_WIDGETS+=(#{widget})") }
+
+  it 'takes effect on the next cmd line' do
+    with_history('echo hello') do
+      session.send_string('e')
+      wait_for { session.content }.to eq('echo hello')
+      session.send_keys('C-b')
+      wait_for { session.content(esc_seqs: true) }.to eq('echo hello')
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/spec_helper.rb
@@ -0,0 +1,52 @@
+require 'pry'
+require 'rspec/wait'
+require 'terminal_session'
+
+RSpec.shared_context 'terminal session' do
+  let(:term_opts) { {} }
+  let(:session) { TerminalSession.new(term_opts) }
+  let(:before_sourcing) { -> {} }
+  let(:after_sourcing) { -> {} }
+  let(:options) { [] }
+
+  around do |example|
+    before_sourcing.call
+    session.run_command(options.join('; '))
+    session.run_command('source zsh-autosuggestions.zsh')
+    after_sourcing.call
+    session.clear_screen
+
+    example.run
+
+    session.destroy
+  end
+
+  def with_history(*commands, &block)
+    session.run_command('fc -p')
+
+    commands.each do |c|
+      c.respond_to?(:call) ? c.call : session.run_command(c)
+    end
+
+    session.clear_screen
+
+    yield block
+
+    session.send_keys('C-c')
+    session.run_command('fc -P')
+  end
+end
+
+RSpec.configure do |config|
+  config.expect_with :rspec do |expectations|
+    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+  end
+
+  config.mock_with :rspec do |mocks|
+    mocks.verify_partial_doubles = true
+  end
+
+  config.wait_timeout = 2
+
+  config.include_context 'terminal session'
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/strategies/default_spec.rb
@@ -0,0 +1,12 @@
+require 'strategies/special_characters_helper'
+
+describe 'the default suggestion strategy' do
+  it 'suggests the last matching history entry' do
+    with_history('ls foo', 'ls bar', 'echo baz') do
+      session.send_string('ls')
+      wait_for { session.content }.to eq('ls bar')
+    end
+  end
+
+  include_examples 'special characters'
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/strategies/match_prev_cmd_spec.rb
@@ -0,0 +1,21 @@
+require 'strategies/special_characters_helper'
+
+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
+    with_history(
+      'echo what',
+      'ls foo',
+      'echo what',
+      'ls bar',
+      'ls baz',
+      'echo what'
+    ) do
+      session.send_string('ls')
+      wait_for { session.content }.to eq('ls bar')
+    end
+  end
+
+  include_examples 'special characters'
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/strategies/special_characters_helper.rb
@@ -0,0 +1,62 @@
+shared_examples 'special characters' do
+  describe 'a special character in the buffer' do
+    it 'should be treated like any other character' do
+      with_history('echo "hello*"', 'echo "hello."') do
+        session.send_string('echo "hello*')
+        wait_for { session.content }.to eq('echo "hello*"')
+      end
+
+      with_history('echo "hello?"', 'echo "hello."') do
+        session.send_string('echo "hello?')
+        wait_for { session.content }.to eq('echo "hello?"')
+      end
+
+      with_history('echo "hello\nworld"') do
+        session.send_string('echo "hello\\')
+        wait_for { session.content }.to eq('echo "hello\nworld"')
+      end
+
+      with_history('echo "\\\\"') do
+        session.send_string('echo "\\\\')
+        wait_for { session.content }.to eq('echo "\\\\"')
+      end
+
+      with_history('echo ~/foo') do
+        session.send_string('echo ~')
+        wait_for { session.content }.to eq('echo ~/foo')
+      end
+
+      with_history('echo "$(ls foo)"') do
+        session.send_string('echo "$(')
+        wait_for { session.content }.to eq('echo "$(ls foo)"')
+      end
+
+      with_history('echo "$history[123]"') do
+        session.send_string('echo "$history[')
+        wait_for { session.content }.to eq('echo "$history[123]"')
+        session.send_string('123]')
+        wait_for { session.content }.to eq('echo "$history[123]"')
+      end
+
+      with_history('echo "#yolo"') do
+        session.send_string('echo "#')
+        wait_for { session.content }.to eq('echo "#yolo"')
+      end
+
+      with_history('echo "#foo"', 'echo $#abc') do
+        session.send_string('echo "#')
+        wait_for { session.content }.to eq('echo "#foo"')
+      end
+
+      with_history('echo "^A"', 'echo "^B"') do
+        session.send_string('echo "^A')
+        wait_for { session.content }.to eq('echo "^A"')
+      end
+
+      with_history('-foo() {}') do
+        session.send_string('-')
+        wait_for { session.content }.to eq('-foo() {}')
+      end
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/terminal_session.rb
@@ -0,0 +1,99 @@
+require 'securerandom'
+
+class TerminalSession
+  ZSH_BIN = ENV['TEST_ZSH_BIN'] || 'zsh'
+
+  def initialize(opts = {})
+    opts = {
+      width: 80,
+      height: 24,
+      prompt: '',
+      term: 'xterm-256color',
+      zsh_bin: ZSH_BIN
+    }.merge(opts)
+
+    @opts = opts
+
+    cmd="PS1=\"#{opts[:prompt]}\" TERM=#{opts[:term]} #{ZSH_BIN} -f"
+    tmux_command("new-session -d -x #{opts[:width]} -y #{opts[:height]} '#{cmd}'")
+  end
+
+  def zsh_version
+    @zsh_version ||= Gem::Version.new(`#{ZSH_BIN} -c 'echo -n $ZSH_VERSION'`)
+  end
+
+  def tmux_socket_name
+    @tmux_socket_name ||= SecureRandom.hex(6)
+  end
+
+  def run_command(command)
+    send_string(command)
+    send_keys('enter')
+
+    self
+  end
+
+  def send_string(str)
+    tmux_command("send-keys -t 0 -l -- '#{str.gsub("'", "\\'")}'")
+
+    self
+  end
+
+  def send_keys(*keys)
+    tmux_command("send-keys -t 0 #{keys.join(' ')}")
+
+    self
+  end
+
+  def paste_string(str)
+    tmux_command("set-buffer -- '#{str}'")
+    tmux_command("paste-buffer -dpr -t 0")
+
+    self
+  end
+
+  def content(esc_seqs: false)
+    cmd = 'capture-pane -p -t 0'
+    cmd += ' -e' if esc_seqs
+    tmux_command(cmd).strip
+  end
+
+  def clear_screen
+    send_keys('C-l')
+
+    i = 0
+    until content == opts[:prompt] || i > 20 do
+      sleep(0.1)
+      i = i + 1
+    end
+
+    self
+  end
+
+  def destroy
+    tmux_command('kill-session')
+  end
+
+  def cursor
+    tmux_command("display-message -t 0 -p '\#{cursor_x},\#{cursor_y}'").
+      strip.
+      split(',').
+      map(&:to_i)
+  end
+
+  def attach!
+    tmux_command('attach-session')
+  end
+
+  private
+
+  attr_reader :opts
+
+  def tmux_command(cmd)
+    out = `tmux -u -L #{tmux_socket_name} #{cmd}`
+
+    raise("tmux error running: '#{cmd}'") unless $?.success?
+
+    out
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/widgets/disable_spec.rb
@@ -0,0 +1,19 @@
+describe 'the `autosuggest-disable` widget' do
+  before do
+    session.run_command('bindkey ^B autosuggest-disable')
+  end
+
+  it 'disables suggestions and clears the suggestion' do
+    with_history('echo hello') do
+      session.send_string('echo')
+      wait_for { session.content }.to eq('echo hello')
+
+      session.send_keys('C-b')
+      wait_for { session.content }.to eq('echo')
+
+      session.send_string(' h')
+      sleep 1
+      expect(session.content).to eq('echo h')
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/widgets/enable_spec.rb
@@ -0,0 +1,42 @@
+describe 'the `autosuggest-enable` widget' do
+  before do
+    session.
+      run_command('typeset -g _ZSH_AUTOSUGGEST_DISABLED').
+      run_command('bindkey ^B autosuggest-enable')
+  end
+
+  it 'enables suggestions and fetches a suggestion' do
+    with_history('echo hello') do
+      session.send_string('e')
+      sleep 1
+      expect(session.content).to eq('e')
+
+      session.send_keys('C-b')
+      session.send_string('c')
+      wait_for { session.content }.to eq('echo hello')
+    end
+  end
+
+  context 'invoked on an empty buffer' do
+    it 'does not fetch a suggestion' do
+      with_history('echo hello') do
+        session.send_keys('C-b')
+        sleep 1
+        expect(session.content).to eq('')
+      end
+    end
+  end
+
+  context 'invoked on a non-empty buffer' do
+    it 'fetches a suggestion' do
+      with_history('echo hello') do
+        session.send_string('e')
+        sleep 1
+        expect(session.content).to eq('e')
+
+        session.send_keys('C-b')
+        wait_for { session.content }.to eq('echo hello')
+      end
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/widgets/fetch_spec.rb
@@ -0,0 +1,24 @@
+describe 'the `autosuggest-fetch` widget' do
+  context 'when suggestions are disabled' do
+    before do
+      session.
+        run_command('bindkey ^B autosuggest-disable').
+        run_command('bindkey ^F autosuggest-fetch').
+        send_keys('C-b')
+    end
+
+    it 'will fetch and display a suggestion' do
+      with_history('echo hello') do
+        session.send_string('echo h')
+        sleep 1
+        expect(session.content).to eq('echo h')
+
+        session.send_keys('C-f')
+        wait_for { session.content }.to eq('echo hello')
+
+        session.send_string('e')
+        wait_for { session.content }.to eq('echo hello')
+      end
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/spec/widgets/toggle_spec.rb
@@ -0,0 +1,26 @@
+describe 'the `autosuggest-toggle` widget' do
+  before do
+    session.run_command('bindkey ^B autosuggest-toggle')
+  end
+
+  it 'toggles suggestions' do
+    with_history('echo world', 'echo hello') do
+      session.send_string('echo')
+      wait_for { session.content }.to eq('echo hello')
+
+      session.send_keys('C-b')
+      wait_for { session.content }.to eq('echo')
+
+      session.send_string(' h')
+      sleep 1
+      expect(session.content).to eq('echo h')
+
+      session.send_keys('C-b')
+      wait_for { session.content }.to eq('echo hello')
+
+      session.send_keys('C-h')
+      session.send_string('w')
+      wait_for { session.content }.to eq('echo world')
+    end
+  end
+end
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/async.zsh
@@ -0,0 +1,109 @@
+
+#--------------------------------------------------------------------#
+# Async                                                              #
+#--------------------------------------------------------------------#
+
+# Zpty process is spawned running this function
+_zsh_autosuggest_async_server() {
+	emulate -R zsh
+
+	# There is a bug in zpty module (fixed in zsh/master) by which a
+	# zpty that exits will kill all zpty processes that were forked
+	# before it. Here we set up a zsh exit hook to SIGKILL the zpty
+	# process immediately, before it has a chance to kill any other
+	# zpty processes.
+	zshexit() {
+		kill -KILL $$
+		sleep 1 # Block for long enough for the signal to come through
+	}
+
+	# Don't add any extra carriage returns
+	stty -onlcr
+
+	# Don't translate carriage returns to newlines
+	stty -icrnl
+
+	# Silence any error messages
+	exec 2>/dev/null
+
+	local last_pid
+
+	while IFS='' read -r -d $'\0' query; do
+		# Kill last bg process
+		kill -KILL $last_pid &>/dev/null
+
+		# Run suggestion search in the background
+		(
+			local suggestion
+			_zsh_autosuggest_fetch_suggestion "$query"
+			echo -n -E "$suggestion"$'\0'
+		) &
+
+		last_pid=$!
+	done
+}
+
+_zsh_autosuggest_async_request() {
+	# Write the query to the zpty process to fetch a suggestion
+	zpty -w -n $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME "${1}"$'\0'
+}
+
+# Called when new data is ready to be read from the pty
+# First arg will be fd ready for reading
+# Second arg will be passed in case of error
+_zsh_autosuggest_async_response() {
+	setopt LOCAL_OPTIONS EXTENDED_GLOB
+
+	local suggestion
+
+	zpty -rt $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME suggestion '*'$'\0' 2>/dev/null
+	zle autosuggest-suggest -- "${suggestion%%$'\0'##}"
+}
+
+_zsh_autosuggest_async_pty_create() {
+	# With newer versions of zsh, REPLY stores the fd to read from
+	typeset -h REPLY
+
+	# If we won't get a fd back from zpty, try to guess it
+	if (( ! $_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD )); then
+		integer -l zptyfd
+		exec {zptyfd}>&1  # Open a new file descriptor (above 10).
+		exec {zptyfd}>&-  # Close it so it's free to be used by zpty.
+	fi
+
+	# Fork a zpty process running the server function
+	zpty -b $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME _zsh_autosuggest_async_server
+
+	# Store the fd so we can remove the handler later
+	if (( REPLY )); then
+		_ZSH_AUTOSUGGEST_PTY_FD=$REPLY
+	else
+		_ZSH_AUTOSUGGEST_PTY_FD=$zptyfd
+	fi
+
+	# Set up input handler from the zpty
+	zle -F $_ZSH_AUTOSUGGEST_PTY_FD _zsh_autosuggest_async_response
+}
+
+_zsh_autosuggest_async_pty_destroy() {
+	# Remove the input handler
+	zle -F $_ZSH_AUTOSUGGEST_PTY_FD &>/dev/null
+
+	# Destroy the zpty
+	zpty -d $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME &>/dev/null
+}
+
+_zsh_autosuggest_async_pty_recreate() {
+	_zsh_autosuggest_async_pty_destroy
+	_zsh_autosuggest_async_pty_create
+}
+
+_zsh_autosuggest_async_start() {
+	typeset -g _ZSH_AUTOSUGGEST_PTY_FD
+
+	_zsh_autosuggest_feature_detect_zpty_returns_fd
+	_zsh_autosuggest_async_pty_recreate
+
+	# We recreate the pty to get a fresh list of history events
+	add-zsh-hook precmd _zsh_autosuggest_async_pty_recreate
+}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/bind.zsh
@@ -0,0 +1,120 @@
+
+#--------------------------------------------------------------------#
+# Widget Helpers                                                     #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_incr_bind_count() {
+	if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then
+		((_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]++))
+	else
+		_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=1
+	fi
+
+	typeset -gi bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]
+}
+
+_zsh_autosuggest_get_bind_count() {
+	if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then
+		typeset -gi bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]
+	else
+		typeset -gi bind_count=0
+	fi
+}
+
+# Bind a single widget to an autosuggest widget, saving a reference to the original widget
+_zsh_autosuggest_bind_widget() {
+	typeset -gA _ZSH_AUTOSUGGEST_BIND_COUNTS
+
+	local widget=$1
+	local autosuggest_action=$2
+	local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX
+
+	local -i bind_count
+
+	# Save a reference to the original widget
+	case $widgets[$widget] in
+		# Already bound
+		user:_zsh_autosuggest_(bound|orig)_*);;
+
+		# User-defined widget
+		user:*)
+			_zsh_autosuggest_incr_bind_count $widget
+			zle -N $prefix${bind_count}-$widget ${widgets[$widget]#*:}
+			;;
+
+		# Built-in widget
+		builtin)
+			_zsh_autosuggest_incr_bind_count $widget
+			eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
+			zle -N $prefix${bind_count}-$widget _zsh_autosuggest_orig_$widget
+			;;
+
+		# Completion widget
+		completion:*)
+			_zsh_autosuggest_incr_bind_count $widget
+			eval "zle -C $prefix${bind_count}-${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
+			;;
+	esac
+
+	_zsh_autosuggest_get_bind_count $widget
+
+	# Pass the original widget's name explicitly into the autosuggest
+	# function. Use this passed in widget name to call the original
+	# widget instead of relying on the $WIDGET variable being set
+	# correctly. $WIDGET cannot be trusted because other plugins call
+	# zle without the `-w` flag (e.g. `zle self-insert` instead of
+	# `zle self-insert -w`).
+	eval "_zsh_autosuggest_bound_${bind_count}_${(q)widget}() {
+		_zsh_autosuggest_widget_$autosuggest_action $prefix$bind_count-${(q)widget} \$@
+	}"
+
+	# Create the bound widget
+	zle -N -- $widget _zsh_autosuggest_bound_${bind_count}_$widget
+}
+
+# Map all configured widgets to the right autosuggest widgets
+_zsh_autosuggest_bind_widgets() {
+	emulate -L zsh
+
+ 	local widget
+	local ignore_widgets
+
+	ignore_widgets=(
+		.\*
+		_\*
+		zle-\*
+		autosuggest-\*
+		$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
+		$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
+	)
+
+	# Find every widget we might want to bind and bind it appropriately
+	for widget in ${${(f)"$(builtin zle -la)"}:#${(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
+	done
+}
+
+# Given the name of an original widget and args, invoke it, if it exists
+_zsh_autosuggest_invoke_original_widget() {
+	# Do nothing unless called with at least one arg
+	(( $# )) || return 0
+
+	local original_widget_name="$1"
+
+	shift
+
+	if (( ${+widgets[$original_widget_name]} )); then
+		zle $original_widget_name -- $@
+	fi
+}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/config.zsh
@@ -0,0 +1,73 @@
+
+#--------------------------------------------------------------------#
+# Global Configuration Variables                                     #
+#--------------------------------------------------------------------#
+
+# 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'}
+
+# Prefix to use when saving original versions of bound widgets
+: ${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)
+
+# 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
+)
+
+# 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
+)
+
+# Widgets that accept the entire suggestion and execute it
+(( ! ${+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
+)
+
+# 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
+)
+
+# Max size of buffer to trigger autosuggestion. Leave null for no upper bound.
+: ${ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=}
+
+# Pty name for calculating autosuggestions asynchronously
+: ${ZSH_AUTOSUGGEST_ASYNC_PTY_NAME=zsh_autosuggest_pty}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/features.zsh
@@ -0,0 +1,19 @@
+
+#--------------------------------------------------------------------#
+# Feature Detection                                                  #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_feature_detect_zpty_returns_fd() {
+	typeset -g _ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD
+	typeset -h REPLY
+
+	zpty zsh_autosuggest_feature_detect '{ zshexit() { kill -KILL $$; sleep 1 } }'
+
+	if (( REPLY )); then
+		_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD=1
+	else
+		_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD=0
+	fi
+
+	zpty -d zsh_autosuggest_feature_detect
+}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/fetch.zsh
@@ -0,0 +1,23 @@
+
+#--------------------------------------------------------------------#
+# 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
+
+	# 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
+}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/highlight.zsh
@@ -0,0 +1,26 @@
+
+#--------------------------------------------------------------------#
+# Highlighting                                                       #
+#--------------------------------------------------------------------#
+
+# If there was a highlight, remove it
+_zsh_autosuggest_highlight_reset() {
+	typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+
+	if [[ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]]; then
+		region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}")
+		unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+	fi
+}
+
+# If there's a suggestion, highlight it
+_zsh_autosuggest_highlight_apply() {
+	typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+
+	if (( $#POSTDISPLAY )); then
+		typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
+		region_highlight+=("$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT")
+	else
+		unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+	fi
+}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/setup.zsh
@@ -0,0 +1,10 @@
+
+#--------------------------------------------------------------------#
+# Setup                                                              #
+#--------------------------------------------------------------------#
+
+# Precmd hooks for initializing the library and starting pty's
+autoload -Uz add-zsh-hook
+
+# Asynchronous suggestions are generated in a pty
+zmodload zsh/zpty
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/start.zsh
@@ -0,0 +1,24 @@
+
+#--------------------------------------------------------------------#
+# Start                                                              #
+#--------------------------------------------------------------------#
+
+# Start the autosuggestion widgets
+_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
+
+	if [[ -n "${ZSH_AUTOSUGGEST_USE_ASYNC+x}" ]]; then
+		_zsh_autosuggest_async_start
+	fi
+}
+
+# Start the autosuggestion widgets on the next precmd
+add-zsh-hook precmd _zsh_autosuggest_start
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/strategies/default.zsh
@@ -0,0 +1,25 @@
+
+#--------------------------------------------------------------------#
+# History Suggestion Strategy                                        #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix.
+#
+
+_zsh_autosuggest_strategy_history() {
+	# Reset options to defaults and enable LOCAL_OPTIONS
+	emulate -L zsh
+
+	# Enable globbing flags so that we can use (#m)
+	setopt EXTENDED_GLOB
+
+	# Escape backslashes and all of the glob operators so we can use
+	# this string as a pattern to search the $history associative array.
+	# - (#m) globbing flag enables setting references for match data
+	# TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
+	local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
+
+	# Get the history items that match
+	# - (r) subscript flag makes the pattern match on values
+	typeset -g suggestion="${history[(r)${prefix}*]}"
+}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/strategies/match_prev_cmd.zsh
@@ -0,0 +1,59 @@
+
+#--------------------------------------------------------------------#
+# Match Previous Command Suggestion Strategy                         #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix and whose preceding history item also matches the most
+# recently executed command.
+#
+# For example, suppose your history has the following entries:
+#   - pwd
+#   - ls foo
+#   - ls bar
+#   - pwd
+#
+# Given the history list above, when you type 'ls', the suggestion
+# will be 'ls foo' rather than 'ls bar' because your most recently
+# executed command (pwd) was previously followed by 'ls foo'.
+#
+# Note that this strategy won't work as expected with ZSH options that don't
+# preserve the history order such as `HIST_IGNORE_ALL_DUPS` or
+# `HIST_EXPIRE_DUPS_FIRST`.
+
+_zsh_autosuggest_strategy_match_prev_cmd() {
+	# Reset options to defaults and enable LOCAL_OPTIONS
+	emulate -L zsh
+
+	# Enable globbing flags so that we can use (#m)
+	setopt EXTENDED_GLOB
+
+	# TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
+	local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
+
+	# Get all history event numbers that correspond to history
+	# entries that match pattern $prefix*
+	local history_match_keys
+	history_match_keys=(${(k)history[(R)$prefix*]})
+
+	# By default we use the first history number (most recent history entry)
+	local histkey="${history_match_keys[1]}"
+
+	# Get the previously executed command
+	local prev_cmd="$(_zsh_autosuggest_escape_command "${history[$((HISTCMD-1))]}")"
+
+	# Iterate up to the first 200 history event numbers that match $prefix
+	for key in "${(@)history_match_keys[1,200]}"; do
+		# Stop if we ran out of history
+		[[ $key -gt 1 ]] || break
+
+		# See if the history entry preceding the suggestion matches the
+		# previous command, and use it if it does
+		if [[ "${history[$((key - 1))]}" == "$prev_cmd" ]]; then
+			histkey="$key"
+			break
+		fi
+	done
+
+	# Give back the matched history entry
+	typeset -g suggestion="$history[$histkey]"
+}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/util.zsh
@@ -0,0 +1,11 @@
+
+#--------------------------------------------------------------------#
+# Utility Functions                                                  #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_escape_command() {
+	setopt localoptions EXTENDED_GLOB
+
+	# Escape special chars in the string (requires EXTENDED_GLOB)
+	echo -E "${1//(#m)[\"\'\\()\[\]|*?~]/\\$MATCH}"
+}
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/src/widgets.zsh
@@ -0,0 +1,217 @@
+
+#--------------------------------------------------------------------#
+# Autosuggest Widget Implementations                                 #
+#--------------------------------------------------------------------#
+
+# Disable suggestions
+_zsh_autosuggest_disable() {
+	typeset -g _ZSH_AUTOSUGGEST_DISABLED
+	_zsh_autosuggest_clear
+}
+
+# Enable suggestions
+_zsh_autosuggest_enable() {
+	unset _ZSH_AUTOSUGGEST_DISABLED
+
+	if (( $#BUFFER )); then
+		_zsh_autosuggest_fetch
+	fi
+}
+
+# Toggle suggestions (enable/disable)
+_zsh_autosuggest_toggle() {
+	if [[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]]; then
+		_zsh_autosuggest_enable
+	else
+		_zsh_autosuggest_disable
+	fi
+}
+
+# Clear the suggestion
+_zsh_autosuggest_clear() {
+	# Remove the suggestion
+	unset POSTDISPLAY
+
+	_zsh_autosuggest_invoke_original_widget $@
+}
+
+# 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"
+	local orig_postdisplay="$POSTDISPLAY"
+
+	# Clear suggestion while waiting for next one
+	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
+
+	# 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
+
+	return $retval
+}
+
+# Fetch a new suggestion based on what's currently in the buffer
+_zsh_autosuggest_fetch() {
+	if zpty -t "$ZSH_AUTOSUGGEST_ASYNC_PTY_NAME" &>/dev/null; then
+		_zsh_autosuggest_async_request "$BUFFER"
+	else
+		local suggestion
+		_zsh_autosuggest_fetch_suggestion "$BUFFER"
+		_zsh_autosuggest_suggest "$suggestion"
+	fi
+}
+
+# Offer a suggestion
+_zsh_autosuggest_suggest() {
+	emulate -L zsh
+
+	local suggestion="$1"
+
+	if [[ -n "$suggestion" ]] && (( $#BUFFER )); then
+		POSTDISPLAY="${suggestion#$BUFFER}"
+	else
+		unset POSTDISPLAY
+	fi
+}
+
+# Accept the entire suggestion
+_zsh_autosuggest_accept() {
+	local -i max_cursor_pos=$#BUFFER
+
+	# When vicmd keymap is active, the cursor can't move all the way
+	# to the end of the buffer
+	if [[ "$KEYMAP" = "vicmd" ]]; then
+		max_cursor_pos=$((max_cursor_pos - 1))
+	fi
+
+	# Only accept if the cursor is at the end of the buffer
+	if [[ $CURSOR = $max_cursor_pos ]]; then
+		# Add the suggestion to the buffer
+		BUFFER="$BUFFER$POSTDISPLAY"
+
+		# Remove the suggestion
+		unset POSTDISPLAY
+
+		# Move the cursor to the end of the buffer
+		CURSOR=${#BUFFER}
+	fi
+
+	_zsh_autosuggest_invoke_original_widget $@
+}
+
+# Accept the entire suggestion and execute it
+_zsh_autosuggest_execute() {
+	# Add the suggestion to the buffer
+	BUFFER="$BUFFER$POSTDISPLAY"
+
+	# Remove the suggestion
+	unset POSTDISPLAY
+
+	# Call the original `accept-line` to handle syntax highlighting or
+	# other potential custom behavior
+	_zsh_autosuggest_invoke_original_widget "accept-line"
+}
+
+# Partially accept the suggestion
+_zsh_autosuggest_partial_accept() {
+	local -i retval cursor_loc
+
+	# Save the contents of the buffer so we can restore later if needed
+	local original_buffer="$BUFFER"
+
+	# Temporarily accept the suggestion.
+	BUFFER="$BUFFER$POSTDISPLAY"
+
+	# Original widget moves the cursor
+	_zsh_autosuggest_invoke_original_widget $@
+	retval=$?
+
+	# Normalize cursor location across vi/emacs modes
+	cursor_loc=$CURSOR
+	if [[ "$KEYMAP" = "vicmd" ]]; then
+		cursor_loc=$((cursor_loc + 1))
+	fi
+
+	# If we've moved past the end of the original buffer
+	if (( $cursor_loc > $#original_buffer )); then
+		# Set POSTDISPLAY to text right of the cursor
+		POSTDISPLAY="${BUFFER[$(($cursor_loc + 1)),$#BUFFER]}"
+
+		# Clip the buffer at the cursor
+		BUFFER="${BUFFER[1,$cursor_loc]}"
+	else
+		# Restore the original buffer
+		BUFFER="$original_buffer"
+	fi
+
+	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_highlight_reset
+
+		_zsh_autosuggest_$action \$@
+		retval=\$?
+
+		_zsh_autosuggest_highlight_apply
+
+		zle -R
+
+		return \$retval
+	}"
+done
+
+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
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/zsh-autosuggestions.plugin.zsh
@@ -0,0 +1,1 @@
+source ${0:A:h}/zsh-autosuggestions.zsh
new file mode 100644
--- /dev/null
+++ b/.zfun/zsh-autosuggestions/zsh-autosuggestions.zsh
@@ -0,0 +1,742 @@
+# Fish-like fast/unobtrusive autosuggestions for zsh.
+# https://github.com/zsh-users/zsh-autosuggestions
+# v0.5.0
+# Copyright (c) 2013 Thiago de Arruda
+# Copyright (c) 2016-2018 Eric Freese
+# 
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+# 
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+#--------------------------------------------------------------------#
+# Setup                                                              #
+#--------------------------------------------------------------------#
+
+# Precmd hooks for initializing the library and starting pty's
+autoload -Uz add-zsh-hook
+
+# Asynchronous suggestions are generated in a pty
+zmodload zsh/zpty
+
+#--------------------------------------------------------------------#
+# Global Configuration Variables                                     #
+#--------------------------------------------------------------------#
+
+# 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'}
+
+# Prefix to use when saving original versions of bound widgets
+: ${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)
+
+# 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
+)
+
+# 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
+)
+
+# Widgets that accept the entire suggestion and execute it
+(( ! ${+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
+)
+
+# 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
+)
+
+# Max size of buffer to trigger autosuggestion. Leave null for no upper bound.
+: ${ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=}
+
+# Pty name for calculating autosuggestions asynchronously
+: ${ZSH_AUTOSUGGEST_ASYNC_PTY_NAME=zsh_autosuggest_pty}
+
+#--------------------------------------------------------------------#
+# Utility Functions                                                  #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_escape_command() {
+	setopt localoptions EXTENDED_GLOB
+
+	# Escape special chars in the string (requires EXTENDED_GLOB)
+	echo -E "${1//(#m)[\"\'\\()\[\]|*?~]/\\$MATCH}"
+}
+
+#--------------------------------------------------------------------#
+# Feature Detection                                                  #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_feature_detect_zpty_returns_fd() {
+	typeset -g _ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD
+	typeset -h REPLY
+
+	zpty zsh_autosuggest_feature_detect '{ zshexit() { kill -KILL $$; sleep 1 } }'
+
+	if (( REPLY )); then
+		_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD=1
+	else
+		_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD=0
+	fi
+
+	zpty -d zsh_autosuggest_feature_detect
+}
+
+#--------------------------------------------------------------------#
+# Widget Helpers                                                     #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_incr_bind_count() {
+	if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then
+		((_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]++))
+	else
+		_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=1
+	fi
+
+	typeset -gi bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]
+}
+
+_zsh_autosuggest_get_bind_count() {
+	if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then
+		typeset -gi bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]
+	else
+		typeset -gi bind_count=0
+	fi
+}
+
+# Bind a single widget to an autosuggest widget, saving a reference to the original widget
+_zsh_autosuggest_bind_widget() {
+	typeset -gA _ZSH_AUTOSUGGEST_BIND_COUNTS
+
+	local widget=$1
+	local autosuggest_action=$2
+	local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX
+
+	local -i bind_count
+
+	# Save a reference to the original widget
+	case $widgets[$widget] in
+		# Already bound
+		user:_zsh_autosuggest_(bound|orig)_*);;
+
+		# User-defined widget
+		user:*)
+			_zsh_autosuggest_incr_bind_count $widget
+			zle -N $prefix${bind_count}-$widget ${widgets[$widget]#*:}
+			;;
+
+		# Built-in widget
+		builtin)
+			_zsh_autosuggest_incr_bind_count $widget
+			eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
+			zle -N $prefix${bind_count}-$widget _zsh_autosuggest_orig_$widget
+			;;
+
+		# Completion widget
+		completion:*)
+			_zsh_autosuggest_incr_bind_count $widget
+			eval "zle -C $prefix${bind_count}-${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
+			;;
+	esac
+
+	_zsh_autosuggest_get_bind_count $widget
+
+	# Pass the original widget's name explicitly into the autosuggest
+	# function. Use this passed in widget name to call the original
+	# widget instead of relying on the $WIDGET variable being set
+	# correctly. $WIDGET cannot be trusted because other plugins call
+	# zle without the `-w` flag (e.g. `zle self-insert` instead of
+	# `zle self-insert -w`).
+	eval "_zsh_autosuggest_bound_${bind_count}_${(q)widget}() {
+		_zsh_autosuggest_widget_$autosuggest_action $prefix$bind_count-${(q)widget} \$@
+	}"
+
+	# Create the bound widget
+	zle -N -- $widget _zsh_autosuggest_bound_${bind_count}_$widget
+}
+
+# Map all configured widgets to the right autosuggest widgets
+_zsh_autosuggest_bind_widgets() {
+	emulate -L zsh
+
+ 	local widget
+	local ignore_widgets
+
+	ignore_widgets=(
+		.\*
+		_\*
+		zle-\*
+		autosuggest-\*
+		$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
+		$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
+	)
+
+	# Find every widget we might want to bind and bind it appropriately
+	for widget in ${${(f)"$(builtin zle -la)"}:#${(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
+	done
+}
+
+# Given the name of an original widget and args, invoke it, if it exists
+_zsh_autosuggest_invoke_original_widget() {
+	# Do nothing unless called with at least one arg
+	(( $# )) || return 0
+
+	local original_widget_name="$1"
+
+	shift
+
+	if (( ${+widgets[$original_widget_name]} )); then
+		zle $original_widget_name -- $@
+	fi
+}
+
+#--------------------------------------------------------------------#
+# Highlighting                                                       #
+#--------------------------------------------------------------------#
+
+# If there was a highlight, remove it
+_zsh_autosuggest_highlight_reset() {
+	typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+
+	if [[ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]]; then
+		region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}")
+		unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+	fi
+}
+
+# If there's a suggestion, highlight it
+_zsh_autosuggest_highlight_apply() {
+	typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+
+	if (( $#POSTDISPLAY )); then
+		typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
+		region_highlight+=("$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT")
+	else
+		unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+	fi
+}
+
+#--------------------------------------------------------------------#
+# Autosuggest Widget Implementations                                 #
+#--------------------------------------------------------------------#
+
+# Disable suggestions
+_zsh_autosuggest_disable() {
+	typeset -g _ZSH_AUTOSUGGEST_DISABLED
+	_zsh_autosuggest_clear
+}
+
+# Enable suggestions
+_zsh_autosuggest_enable() {
+	unset _ZSH_AUTOSUGGEST_DISABLED
+
+	if (( $#BUFFER )); then
+		_zsh_autosuggest_fetch
+	fi
+}
+
+# Toggle suggestions (enable/disable)
+_zsh_autosuggest_toggle() {
+	if [[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]]; then
+		_zsh_autosuggest_enable
+	else
+		_zsh_autosuggest_disable
+	fi
+}
+
+# Clear the suggestion
+_zsh_autosuggest_clear() {
+	# Remove the suggestion
+	unset POSTDISPLAY
+
+	_zsh_autosuggest_invoke_original_widget $@
+}
+
+# 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"
+	local orig_postdisplay="$POSTDISPLAY"
+
+	# Clear suggestion while waiting for next one
+	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
+
+	# 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
+
+	return $retval
+}
+
+# Fetch a new suggestion based on what's currently in the buffer
+_zsh_autosuggest_fetch() {
+	if zpty -t "$ZSH_AUTOSUGGEST_ASYNC_PTY_NAME" &>/dev/null; then
+		_zsh_autosuggest_async_request "$BUFFER"
+	else
+		local suggestion
+		_zsh_autosuggest_fetch_suggestion "$BUFFER"
+		_zsh_autosuggest_suggest "$suggestion"
+	fi
+}
+
+# Offer a suggestion
+_zsh_autosuggest_suggest() {
+	emulate -L zsh
+
+	local suggestion="$1"
+
+	if [[ -n "$suggestion" ]] && (( $#BUFFER )); then
+		POSTDISPLAY="${suggestion#$BUFFER}"
+	else
+		unset POSTDISPLAY
+	fi
+}
+
+# Accept the entire suggestion
+_zsh_autosuggest_accept() {
+	local -i max_cursor_pos=$#BUFFER
+
+	# When vicmd keymap is active, the cursor can't move all the way
+	# to the end of the buffer
+	if [[ "$KEYMAP" = "vicmd" ]]; then
+		max_cursor_pos=$((max_cursor_pos - 1))
+	fi
+
+	# Only accept if the cursor is at the end of the buffer
+	if [[ $CURSOR = $max_cursor_pos ]]; then
+		# Add the suggestion to the buffer
+		BUFFER="$BUFFER$POSTDISPLAY"
+
+		# Remove the suggestion
+		unset POSTDISPLAY
+
+		# Move the cursor to the end of the buffer
+		CURSOR=${#BUFFER}
+	fi
+
+	_zsh_autosuggest_invoke_original_widget $@
+}
+
+# Accept the entire suggestion and execute it
+_zsh_autosuggest_execute() {
+	# Add the suggestion to the buffer
+	BUFFER="$BUFFER$POSTDISPLAY"
+
+	# Remove the suggestion
+	unset POSTDISPLAY
+
+	# Call the original `accept-line` to handle syntax highlighting or
+	# other potential custom behavior
+	_zsh_autosuggest_invoke_original_widget "accept-line"
+}
+
+# Partially accept the suggestion
+_zsh_autosuggest_partial_accept() {
+	local -i retval cursor_loc
+
+	# Save the contents of the buffer so we can restore later if needed
+	local original_buffer="$BUFFER"
+
+	# Temporarily accept the suggestion.
+	BUFFER="$BUFFER$POSTDISPLAY"
+
+	# Original widget moves the cursor
+	_zsh_autosuggest_invoke_original_widget $@
+	retval=$?
+
+	# Normalize cursor location across vi/emacs modes
+	cursor_loc=$CURSOR
+	if [[ "$KEYMAP" = "vicmd" ]]; then
+		cursor_loc=$((cursor_loc + 1))
+	fi
+
+	# If we've moved past the end of the original buffer
+	if (( $cursor_loc > $#original_buffer )); then
+		# Set POSTDISPLAY to text right of the cursor
+		POSTDISPLAY="${BUFFER[$(($cursor_loc + 1)),$#BUFFER]}"
+
+		# Clip the buffer at the cursor
+		BUFFER="${BUFFER[1,$cursor_loc]}"
+	else
+		# Restore the original buffer
+		BUFFER="$original_buffer"
+	fi
+
+	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_highlight_reset
+
+		_zsh_autosuggest_$action \$@
+		retval=\$?
+
+		_zsh_autosuggest_highlight_apply
+
+		zle -R
+
+		return \$retval
+	}"
+done
+
+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                                        #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix.
+#
+
+_zsh_autosuggest_strategy_history() {
+	# Reset options to defaults and enable LOCAL_OPTIONS
+	emulate -L zsh
+
+	# Enable globbing flags so that we can use (#m)
+	setopt EXTENDED_GLOB
+
+	# Escape backslashes and all of the glob operators so we can use
+	# this string as a pattern to search the $history associative array.
+	# - (#m) globbing flag enables setting references for match data
+	# TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
+	local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
+
+	# Get the history items that match
+	# - (r) subscript flag makes the pattern match on values
+	typeset -g suggestion="${history[(r)${prefix}*]}"
+}
+
+#--------------------------------------------------------------------#
+# Match Previous Command Suggestion Strategy                         #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix and whose preceding history item also matches the most
+# recently executed command.
+#
+# For example, suppose your history has the following entries:
+#   - pwd
+#   - ls foo
+#   - ls bar
+#   - pwd
+#
+# Given the history list above, when you type 'ls', the suggestion
+# will be 'ls foo' rather than 'ls bar' because your most recently
+# executed command (pwd) was previously followed by 'ls foo'.
+#
+# Note that this strategy won't work as expected with ZSH options that don't
+# preserve the history order such as `HIST_IGNORE_ALL_DUPS` or
+# `HIST_EXPIRE_DUPS_FIRST`.
+
+_zsh_autosuggest_strategy_match_prev_cmd() {
+	# Reset options to defaults and enable LOCAL_OPTIONS
+	emulate -L zsh
+
+	# Enable globbing flags so that we can use (#m)
+	setopt EXTENDED_GLOB
+
+	# TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
+	local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
+
+	# Get all history event numbers that correspond to history
+	# entries that match pattern $prefix*
+	local history_match_keys
+	history_match_keys=(${(k)history[(R)$prefix*]})
+
+	# By default we use the first history number (most recent history entry)
+	local histkey="${history_match_keys[1]}"
+
+	# Get the previously executed command
+	local prev_cmd="$(_zsh_autosuggest_escape_command "${history[$((HISTCMD-1))]}")"
+
+	# Iterate up to the first 200 history event numbers that match $prefix
+	for key in "${(@)history_match_keys[1,200]}"; do
+		# Stop if we ran out of history
+		[[ $key -gt 1 ]] || break
+
+		# See if the history entry preceding the suggestion matches the
+		# previous command, and use it if it does
+		if [[ "${history[$((key - 1))]}" == "$prev_cmd" ]]; then
+			histkey="$key"
+			break
+		fi
+	done
+
+	# Give back the matched history entry
+	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
+
+	# 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                                                              #
+#--------------------------------------------------------------------#
+
+# Zpty process is spawned running this function
+_zsh_autosuggest_async_server() {
+	emulate -R zsh
+
+	# There is a bug in zpty module (fixed in zsh/master) by which a
+	# zpty that exits will kill all zpty processes that were forked
+	# before it. Here we set up a zsh exit hook to SIGKILL the zpty
+	# process immediately, before it has a chance to kill any other
+	# zpty processes.
+	zshexit() {
+		kill -KILL $$
+		sleep 1 # Block for long enough for the signal to come through
+	}
+
+	# Don't add any extra carriage returns
+	stty -onlcr
+
+	# Don't translate carriage returns to newlines
+	stty -icrnl
+
+	# Silence any error messages
+	exec 2>/dev/null
+
+	local last_pid
+
+	while IFS='' read -r -d $'\0' query; do
+		# Kill last bg process
+		kill -KILL $last_pid &>/dev/null
+
+		# Run suggestion search in the background
+		(
+			local suggestion
+			_zsh_autosuggest_fetch_suggestion "$query"
+			echo -n -E "$suggestion"$'\0'
+		) &
+
+		last_pid=$!
+	done
+}
+
+_zsh_autosuggest_async_request() {
+	# Write the query to the zpty process to fetch a suggestion
+	zpty -w -n $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME "${1}"$'\0'
+}
+
+# Called when new data is ready to be read from the pty
+# First arg will be fd ready for reading
+# Second arg will be passed in case of error
+_zsh_autosuggest_async_response() {
+	setopt LOCAL_OPTIONS EXTENDED_GLOB
+
+	local suggestion
+
+	zpty -rt $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME suggestion '*'$'\0' 2>/dev/null
+	zle autosuggest-suggest -- "${suggestion%%$'\0'##}"
+}
+
+_zsh_autosuggest_async_pty_create() {
+	# With newer versions of zsh, REPLY stores the fd to read from
+	typeset -h REPLY
+
+	# If we won't get a fd back from zpty, try to guess it
+	if (( ! $_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD )); then
+		integer -l zptyfd
+		exec {zptyfd}>&1  # Open a new file descriptor (above 10).
+		exec {zptyfd}>&-  # Close it so it's free to be used by zpty.
+	fi
+
+	# Fork a zpty process running the server function
+	zpty -b $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME _zsh_autosuggest_async_server
+
+	# Store the fd so we can remove the handler later
+	if (( REPLY )); then
+		_ZSH_AUTOSUGGEST_PTY_FD=$REPLY
+	else
+		_ZSH_AUTOSUGGEST_PTY_FD=$zptyfd
+	fi
+
+	# Set up input handler from the zpty
+	zle -F $_ZSH_AUTOSUGGEST_PTY_FD _zsh_autosuggest_async_response
+}
+
+_zsh_autosuggest_async_pty_destroy() {
+	# Remove the input handler
+	zle -F $_ZSH_AUTOSUGGEST_PTY_FD &>/dev/null
+
+	# Destroy the zpty
+	zpty -d $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME &>/dev/null
+}
+
+_zsh_autosuggest_async_pty_recreate() {
+	_zsh_autosuggest_async_pty_destroy
+	_zsh_autosuggest_async_pty_create
+}
+
+_zsh_autosuggest_async_start() {
+	typeset -g _ZSH_AUTOSUGGEST_PTY_FD
+
+	_zsh_autosuggest_feature_detect_zpty_returns_fd
+	_zsh_autosuggest_async_pty_recreate
+
+	# We recreate the pty to get a fresh list of history events
+	add-zsh-hook precmd _zsh_autosuggest_async_pty_recreate
+}
+
+#--------------------------------------------------------------------#
+# Start                                                              #
+#--------------------------------------------------------------------#
+
+# Start the autosuggestion widgets
+_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
+
+	if [[ -n "${ZSH_AUTOSUGGEST_USE_ASYNC+x}" ]]; then
+		_zsh_autosuggest_async_start
+	fi
+}
+
+# Start the autosuggestion widgets on the next precmd
+add-zsh-hook precmd _zsh_autosuggest_start