history-substring-search.zsh
per-directory-history.plugin.zsh
zaw.zsh
+ zsh-autosuggestions.zsh
)
for file in $plugins; do
debug "PLUGIN: Trying to load ${file}"...
--- /dev/null
+[*]
+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
--- /dev/null
+[submodule "vendor/shunit2"]
+ path = vendor/shunit2
+ url = https://github.com/kward/shunit2
+[submodule "vendor/stub.sh"]
+ path = vendor/stub.sh
+ url = https://github.com/ericfreese/stub.sh
--- /dev/null
+# Changelog
+
+## 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.
--- /dev/null
+Fish-like fast/unobtrusive autosuggestions for zsh.
--- /dev/null
+Copyright (c) 2013 Thiago de Arruda
+Copyright (c) 2016 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.
--- /dev/null
+SRC_DIR := ./src
+VENDOR_DIR := ./vendor
+
+SRC_FILES := \
+ $(SRC_DIR)/config.zsh \
+ $(SRC_DIR)/deprecated.zsh \
+ $(SRC_DIR)/bind.zsh \
+ $(SRC_DIR)/highlight.zsh \
+ $(SRC_DIR)/widgets.zsh \
+ $(SRC_DIR)/suggestion.zsh \
+ $(SRC_DIR)/strategies/*.zsh \
+ $(SRC_DIR)/start.zsh
+
+HEADER_FILES := \
+ DESCRIPTION \
+ URL \
+ VERSION \
+ LICENSE
+
+PLUGIN_TARGET := zsh-autosuggestions.zsh
+
+SHUNIT2 := $(VENDOR_DIR)/shunit2/2.1.6
+STUB_SH := $(VENDOR_DIR)/stub.sh/stub.sh
+
+TEST_PREREQS := \
+ $(SHUNIT2) \
+ $(STUB_SH)
+
+all: $(PLUGIN_TARGET)
+
+$(PLUGIN_TARGET): $(HEADER_FILES) $(SRC_FILES)
+ cat $(HEADER_FILES) | sed -e 's/^/# /g' > $@
+ cat $(SRC_FILES) >> $@
+
+$(SHUNIT2):
+ git submodule update --init vendor/shunit2
+
+$(STUB_SH):
+ git submodule update --init vendor/stub.sh
+
+.PHONY: clean
+clean:
+ rm $(PLUGIN_TARGET)
+
+.PHONY: test
+test: all $(TEST_PREREQS)
+ script/test_runner.zsh $(TESTS)
--- /dev/null
+# zsh-autosuggestions
+
+_[Fish](http://fishshell.com/)-like fast/unobtrusive autosuggestions for zsh._
+
+It suggests commands as you type, based on command history.
+
+<a href="https://asciinema.org/a/37390" target="_blank"><img src="https://asciinema.org/a/37390.png" width="400" /></a>
+
+
+## Installation
+
+### Manual
+
+1. Clone this repository somewhere on your machine. This guide will assume `~/.zsh/zsh-autosuggestions`.
+
+ ```sh
+ git clone git://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.
+
+
+### Oh My Zsh
+
+1. Clone this repository into `$ZSH_CUSTOM/plugins` (by default `~/.oh-my-zsh/custom/plugins`)
+
+ ```sh
+ git clone git://github.com/zsh-users/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestions
+ ```
+
+2. Add the plugin to the list of plugins for Oh My Zsh to load:
+
+ ```sh
+ plugins=(zsh-autosuggestions)
+ ```
+
+3. Start a new terminal session.
+
+
+## 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 after sourcing the plugin. 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
+
+Set `ZSH_AUTOSUGGEST_STRATEGY` to choose the strategy for generating suggestions. There are currently two to choose from:
+
+- `default`: Chooses the most recent match.
+- `match_prev_cmd`: Chooses the most recent match whose preceding history item matches the most recently executed command ([more info](src/strategies/match_prev_cmd.zsh)). Note that this strategy won't work as expected with ZSH options that don't preserve the history order such as `HIST_IGNORE_ALL_DUPS` or `HIST_EXPIRE_DUPS_FIRST`.
+
+
+### 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.
+
+
+### Key Bindings
+
+This plugin provides three 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.
+
+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
+
+Testing is performed with [`shunit2`](https://github.com/kward/shunit2) (v2.1.6). Documentation can be found [here](http://shunit2.googlecode.com/svn/trunk/source/2.1/doc/shunit2.html).
+
+The test script lives at `script/test_runner.zsh`. To run the tests, run `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.
--- /dev/null
+https://github.com/zsh-users/zsh-autosuggestions
--- /dev/null
+#!/usr/bin/env zsh
+
+DIR="${0:a:h}"
+ROOT_DIR="$DIR/.."
+TEST_DIR="$ROOT_DIR/test"
+
+header() {
+ local message="$1"
+
+ cat <<-EOF
+
+#====================================================================#
+# $message
+#====================================================================#
+ EOF
+}
+
+# ZSH binary to use
+local zsh_bin="zsh"
+
+while getopts ":z:" opt; do
+ case $opt in
+ z)
+ zsh_bin="$OPTARG"
+ ;;
+ \?)
+ echo "Invalid option: -$OPTARG" >&2
+ exit 1
+ ;;
+ :)
+ echo "Option -$OPTARG requires an argument" >&2
+ exit 1
+ ;;
+ esac
+done
+
+shift $((OPTIND -1))
+
+# Test suites to run
+local -a tests
+if [ $#@ -gt 0 ]; then
+ tests=($@)
+else
+ tests=($TEST_DIR/**/*_test.zsh)
+fi
+
+local -i retval=0
+
+for suite in $tests; do
+ header "${suite#"$ROOT_DIR/"}"
+ "$zsh_bin" -f "$suite" || retval=$?
+done
+
+exit $retval
--- /dev/null
+
+#--------------------------------------------------------------------#
+# Widget Helpers #
+#--------------------------------------------------------------------#
+
+# Bind a single widget to an autosuggest widget, saving a reference to the original widget
+_zsh_autosuggest_bind_widget() {
+ local widget=$1
+ local autosuggest_action=$2
+ local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX
+
+ # Save a reference to the original widget
+ case $widgets[$widget] in
+ # Already bound
+ user:_zsh_autosuggest_(bound|orig)_*);;
+
+ # User-defined widget
+ user:*)
+ zle -N $prefix$widget ${widgets[$widget]#*:}
+ ;;
+
+ # Built-in widget
+ builtin)
+ eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
+ zle -N $prefix$widget _zsh_autosuggest_orig_$widget
+ ;;
+
+ # Completion widget
+ completion:*)
+ eval "zle -C $prefix${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
+ ;;
+ esac
+
+ # 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_${(q)widget}() {
+ _zsh_autosuggest_widget_$autosuggest_action $prefix${(q)widget} \$@
+ }"
+
+ # Create the bound widget
+ zle -N $widget _zsh_autosuggest_bound_$widget
+}
+
+# Map all configured widgets to the right autosuggest widgets
+_zsh_autosuggest_bind_widgets() {
+ local widget
+ local ignore_widgets
+
+ ignore_widgets=(
+ .\*
+ _\*
+ zle-line-\*
+ 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 [ ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]; then
+ _zsh_autosuggest_bind_widget $widget clear
+ elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then
+ _zsh_autosuggest_bind_widget $widget accept
+ elif [ ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]; then
+ _zsh_autosuggest_bind_widget $widget execute
+ elif [ ${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
+ [ $# -gt 0 ] || return
+
+ local original_widget_name="$1"
+
+ shift
+
+ if [ $widgets[$original_widget_name] ]; then
+ zle $original_widget_name -- $@
+ fi
+}
--- /dev/null
+
+#--------------------------------------------------------------------#
+# 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-
+
+ZSH_AUTOSUGGEST_STRATEGY=default
+
+# Widgets that clear the suggestion
+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-history
+ down-line-or-history
+ accept-line
+)
+
+# Widgets that accept the entire suggestion
+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=(
+)
+
+# Widgets that accept the suggestion as far as the cursor moves
+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
+ forward-word
+ vi-forward-word
+ vi-forward-word-end
+ vi-forward-blank-word
+ vi-forward-blank-word-end
+)
+
+# Widgets that should be ignored (globbing supported but must be escaped)
+ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
+ orig-\*
+ beep
+ run-help
+ set-local-history
+ which-command
+ yank
+)
+
+# Max size of buffer to trigger autosuggestion. Leave undefined for no upper bound.
+ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=
--- /dev/null
+
+#--------------------------------------------------------------------#
+# Handle Deprecated Variables/Widgets #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_deprecated_warning() {
+ >&2 echo "zsh-autosuggestions: $@"
+}
+
+_zsh_autosuggest_check_deprecated_config() {
+ if [ -n "$AUTOSUGGESTION_HIGHLIGHT_COLOR" ]; then
+ _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_COLOR is deprecated. Use ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE instead."
+ [ -z "$ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" ] && ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE=$AUTOSUGGESTION_HIGHLIGHT_STYLE
+ unset AUTOSUGGESTION_HIGHLIGHT_STYLE
+ fi
+
+ if [ -n "$AUTOSUGGESTION_HIGHLIGHT_CURSOR" ]; then
+ _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_CURSOR is deprecated."
+ unset AUTOSUGGESTION_HIGHLIGHT_CURSOR
+ fi
+
+ if [ -n "$AUTOSUGGESTION_ACCEPT_RIGHT_ARROW" ]; then
+ _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_ACCEPT_RIGHT_ARROW is deprecated. The right arrow now accepts the suggestion by default."
+ unset AUTOSUGGESTION_ACCEPT_RIGHT_ARROW
+ fi
+}
+
+_zsh_autosuggest_deprecated_start_widget() {
+ _zsh_autosuggest_deprecated_warning "The autosuggest-start widget is deprecated. For more info, see the README at https://github.com/zsh-users/zsh-autosuggestions."
+ zle -D autosuggest-start
+ eval "zle-line-init() {
+ $(echo $functions[${widgets[zle-line-init]#*:}] | sed -e 's/zle autosuggest-start//g')
+ }"
+}
+
+zle -N autosuggest-start _zsh_autosuggest_deprecated_start_widget
--- /dev/null
+
+#--------------------------------------------------------------------#
+# 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 -gt 0 ]; then
+ _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
+ region_highlight+=("$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT")
+ else
+ unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+ fi
+}
--- /dev/null
+
+#--------------------------------------------------------------------#
+# Start #
+#--------------------------------------------------------------------#
+
+# Start the autosuggestion widgets
+_zsh_autosuggest_start() {
+ _zsh_autosuggest_check_deprecated_config
+ _zsh_autosuggest_bind_widgets
+}
+
+autoload -Uz add-zsh-hook
+add-zsh-hook precmd _zsh_autosuggest_start
--- /dev/null
+
+#--------------------------------------------------------------------#
+# Default Suggestion Strategy #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix.
+#
+
+_zsh_autosuggest_strategy_default() {
+ fc -lnrm "$1*" 1 2>/dev/null | head -n 1
+}
--- /dev/null
+
+#--------------------------------------------------------------------#
+# 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() {
+ local prefix="$1"
+
+ # 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
+
+ # Echo the matched history entry
+ echo -E "$history[$histkey]"
+}
--- /dev/null
+
+#--------------------------------------------------------------------#
+# Suggestion #
+#--------------------------------------------------------------------#
+
+# Delegate to the selected strategy to determine a suggestion
+_zsh_autosuggest_suggestion() {
+ local escaped_prefix="$(_zsh_autosuggest_escape_command "$1")"
+ local strategy_function="_zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY"
+
+ if [ -n "$functions[$strategy_function]" ]; then
+ echo -E "$($strategy_function "$escaped_prefix")"
+ fi
+}
+
+_zsh_autosuggest_escape_command() {
+ setopt localoptions EXTENDED_GLOB
+
+ # Escape special chars in the string (requires EXTENDED_GLOB)
+ echo -E "${1//(#m)[\\()\[\]|*?~]/\\$MATCH}"
+}
--- /dev/null
+
+#--------------------------------------------------------------------#
+# Autosuggest Widget Implementations #
+#--------------------------------------------------------------------#
+
+# 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() {
+ local -i retval
+
+ # Save the contents of the buffer/postdisplay
+ local orig_buffer="$BUFFER"
+ local orig_postdisplay="$POSTDISPLAY"
+
+ # Clear suggestion while original widget runs
+ unset POSTDISPLAY
+
+ # Original widget may modify the buffer
+ _zsh_autosuggest_invoke_original_widget $@
+ retval=$?
+
+ # Don't fetch a new suggestion if the buffer hasn't changed
+ if [ "$BUFFER" = "$orig_buffer" ]; then
+ POSTDISPLAY="$orig_postdisplay"
+ return $retval
+ fi
+
+ # Get a new suggestion if the buffer is not empty after modification
+ local suggestion
+ if [ $#BUFFER -gt 0 ]; then
+ if [ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" -o $#BUFFER -lt "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]; then
+ suggestion="$(_zsh_autosuggest_suggestion "$BUFFER")"
+ fi
+ fi
+
+ # Add the suggestion to the POSTDISPLAY
+ if [ -n "$suggestion" ]; then
+ POSTDISPLAY="${suggestion#$BUFFER}"
+ fi
+
+ return $retval
+}
+
+# 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 -eq $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
+
+ # 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=$?
+
+ # If we've moved past the end of the original buffer
+ if [ $CURSOR -gt $#original_buffer ]; then
+ # Set POSTDISPLAY to text right of the cursor
+ POSTDISPLAY="$RBUFFER"
+
+ # Clip the buffer at the cursor
+ BUFFER="$LBUFFER"
+ else
+ # Restore the original buffer
+ BUFFER="$original_buffer"
+ fi
+
+ return $retval
+}
+
+for action in clear modify accept partial_accept execute; do
+ eval "_zsh_autosuggest_widget_$action() {
+ local -i retval
+
+ _zsh_autosuggest_highlight_reset
+
+ _zsh_autosuggest_$action \$@
+ retval=\$?
+
+ _zsh_autosuggest_highlight_apply
+
+ return \$retval
+ }"
+done
+
+zle -N autosuggest-accept _zsh_autosuggest_widget_accept
+zle -N autosuggest-clear _zsh_autosuggest_widget_clear
+zle -N autosuggest-execute _zsh_autosuggest_widget_execute
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+testInvokeOriginalWidgetDefined() {
+ stub_and_eval \
+ zle \
+ 'return 1'
+
+ _zsh_autosuggest_invoke_original_widget 'self-insert'
+
+ assertEquals \
+ '1' \
+ "$?"
+
+ assertTrue \
+ 'zle was not invoked' \
+ 'stub_called zle'
+
+ restore zle
+}
+
+testInvokeOriginalWidgetUndefined() {
+ stub_and_eval \
+ zle \
+ 'return 1'
+
+ _zsh_autosuggest_invoke_original_widget 'some-undefined-widget'
+
+ assertEquals \
+ '0' \
+ "$?"
+
+ assertFalse \
+ 'zle was invoked' \
+ 'stub_called zle'
+
+ restore zle
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+testHighlightDefaultStyle() {
+ assertEquals \
+ 'fg=8' \
+ "$ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
+}
+
+testHighlightApplyWithSuggestion() {
+ local orig_style=ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE
+ ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=4'
+
+ BUFFER='ec'
+ POSTDISPLAY='ho hello'
+ region_highlight=('0 2 fg=1')
+
+ _zsh_autosuggest_highlight_apply
+
+ assertEquals \
+ 'highlight did not use correct style' \
+ "0 2 fg=1 2 10 $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" \
+ "$region_highlight"
+
+ assertEquals \
+ 'higlight was not saved to be removed later' \
+ "2 10 $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" \
+ "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT"
+
+ ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE=orig_style
+}
+
+testHighlightApplyWithoutSuggestion() {
+ BUFFER='echo hello'
+ POSTDISPLAY=''
+ region_highlight=('0 4 fg=1')
+
+ _zsh_autosuggest_highlight_apply
+
+ assertEquals \
+ 'region_highlight was modified' \
+ '0 4 fg=1' \
+ "$region_highlight"
+
+ assertNull \
+ 'last highlight region was not cleared' \
+ "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT"
+}
+
+testHighlightReset() {
+ BUFFER='ec'
+ POSTDISPLAY='ho hello'
+ region_highlight=('0 1 fg=1' '2 10 fg=8' '1 2 fg=1')
+ _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT='2 10 fg=8'
+
+ _zsh_autosuggest_highlight_reset
+
+ assertEquals \
+ 'last highlight region was not removed' \
+ '0 1 fg=1 1 2 fg=1' \
+ "$region_highlight"
+
+ assertNull \
+ 'last highlight variable was not cleared' \
+ "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT"
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/../test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+testNoMatch() {
+ set_history <<-'EOF'
+ ls foo
+ ls bar
+ EOF
+
+ assertSuggestion \
+ 'foo' \
+ ''
+
+ assertSuggestion \
+ 'ls q' \
+ ''
+}
+
+testBasicMatches() {
+ set_history <<-'EOF'
+ ls foo
+ ls bar
+ EOF
+
+ assertSuggestion \
+ 'ls f' \
+ 'ls foo'
+
+ assertSuggestion \
+ 'ls b' \
+ 'ls bar'
+}
+
+testMostRecentMatch() {
+ set_history <<-'EOF'
+ ls foo
+ cd bar
+ ls baz
+ cd quux
+ EOF
+
+ assertSuggestion \
+ 'ls' \
+ 'ls baz'
+
+ assertSuggestion \
+ 'cd' \
+ 'cd quux'
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/../test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+
+ ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd
+}
+
+testNoMatch() {
+ set_history <<-'EOF'
+ ls foo
+ ls bar
+ EOF
+
+ assertSuggestion \
+ 'foo' \
+ ''
+
+ assertSuggestion \
+ 'ls q' \
+ ''
+}
+
+testBasicMatches() {
+ set_history <<-'EOF'
+ ls foo
+ ls bar
+ EOF
+
+ assertSuggestion \
+ 'ls f' \
+ 'ls foo'
+
+ assertSuggestion \
+ 'ls b' \
+ 'ls bar'
+}
+
+testMostRecentMatch() {
+ set_history <<-'EOF'
+ ls foo
+ cd bar
+ ls baz
+ cd quux
+ EOF
+
+ assertSuggestion \
+ 'ls' \
+ 'ls baz'
+
+ assertSuggestion \
+ 'cd' \
+ 'cd quux'
+}
+
+testMatchMostRecentAfterPreviousCmd() {
+ set_history <<-'EOF'
+ echo what
+ ls foo
+ ls bar
+ echo what
+ ls baz
+ ls quux
+ echo what
+ EOF
+
+ assertSuggestion \
+ 'ls' \
+ 'ls baz'
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+assertBackslashSuggestion() {
+ set_history <<-'EOF'
+ echo "hello\nworld"
+ EOF
+
+ assertSuggestion \
+ 'echo "hello\' \
+ 'echo "hello\nworld"'
+}
+
+assertDoubleBackslashSuggestion() {
+ set_history <<-'EOF'
+ echo "\\"
+ EOF
+
+ assertSuggestion \
+ 'echo "\\' \
+ 'echo "\\"'
+}
+
+assertTildeSuggestion() {
+ set_history <<-'EOF'
+ cd ~/something
+ EOF
+
+ assertSuggestion \
+ 'cd' \
+ 'cd ~/something'
+
+ assertSuggestion \
+ 'cd ~' \
+ 'cd ~/something'
+
+ assertSuggestion \
+ 'cd ~/s' \
+ 'cd ~/something'
+}
+
+assertTildeSuggestionWithExtendedGlob() {
+ setopt local_options extended_glob
+
+ assertTildeSuggestion
+}
+
+assertParenthesesSuggestion() {
+ set_history <<-'EOF'
+ echo "$(ls foo)"
+ EOF
+
+ assertSuggestion \
+ 'echo "$(' \
+ 'echo "$(ls foo)"'
+}
+
+assertSquareBracketsSuggestion() {
+ set_history <<-'EOF'
+ echo "$history[123]"
+ EOF
+
+ assertSuggestion \
+ 'echo "$history[' \
+ 'echo "$history[123]"'
+}
+
+assertHashSuggestion() {
+ set_history <<-'EOF'
+ echo "#yolo"
+ EOF
+
+ assertSuggestion \
+ 'echo "#' \
+ 'echo "#yolo"'
+}
+
+testSpecialCharsForAllStrategies() {
+ local strategies
+ strategies=(
+ "default"
+ "match_prev_cmd"
+ )
+
+ for s in $strategies; do
+ ZSH_AUTOSUGGEST_STRATEGY="$s"
+
+ assertBackslashSuggestion
+ assertDoubleBackslashSuggestion
+ assertTildeSuggestion
+ assertTildeSuggestionWithExtendedGlob
+ assertParenthesesSuggestion
+ assertSquareBracketsSuggestion
+ done
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+testEscapeCommand() {
+ assertEquals \
+ 'Did not escape single backslash' \
+ '\\' \
+ "$(_zsh_autosuggest_escape_command '\')"
+
+ assertEquals \
+ 'Did not escape two backslashes' \
+ '\\\\' \
+ "$(_zsh_autosuggest_escape_command '\\')"
+
+ assertEquals \
+ 'Did not escape parentheses' \
+ '\(\)' \
+ "$(_zsh_autosuggest_escape_command '()')"
+
+ assertEquals \
+ 'Did not escape square brackets' \
+ '\[\]' \
+ "$(_zsh_autosuggest_escape_command '[]')"
+
+ assertEquals \
+ 'Did not escape pipe' \
+ '\|' \
+ "$(_zsh_autosuggest_escape_command '|')"
+
+ assertEquals \
+ 'Did not escape star' \
+ '\*' \
+ "$(_zsh_autosuggest_escape_command '*')"
+
+ assertEquals \
+ 'Did not escape question mark' \
+ '\?' \
+ "$(_zsh_autosuggest_escape_command '?')"
+}
+
+run_tests "$0"
--- /dev/null
+DIR="${0:a:h}"
+ROOT_DIR="$DIR/.."
+VENDOR_DIR="$ROOT_DIR/vendor"
+
+# Use stub.sh for stubbing/mocking
+source "$VENDOR_DIR/stub.sh/stub.sh"
+
+#--------------------------------------------------------------------#
+# Helper Functions #
+#--------------------------------------------------------------------#
+
+# Source the autosuggestions plugin file
+source_autosuggestions() {
+ source "$ROOT_DIR/zsh-autosuggestions.zsh"
+}
+
+# Set history list from stdin
+set_history() {
+ # Make a tmp file in shunit's tmp dir
+ local tmp=$(mktemp "$SHUNIT_TMPDIR/hist.XXX")
+
+ # Write from stdin to the tmp file
+ > "$tmp"
+
+ # Write an extra line to simulate history active mode
+ # See https://github.com/zsh-users/zsh/blob/ca3bc0d95d7deab4f5381f12b15047de748c0814/Src/hist.c#L69-L82
+ echo >> "$tmp"
+
+ # Clear history and re-read from the tmp file
+ fc -P; fc -p; fc -R "$tmp"
+
+ rm "$tmp"
+}
+
+# Should be called at the bottom of every test suite file
+# Pass in the name of the test script ($0) for shunit
+run_tests() {
+ local test_script="$1"
+ shift
+
+ # Required for shunit to work with zsh
+ setopt localoptions shwordsplit
+ SHUNIT_PARENT="$test_script"
+
+ source "$VENDOR_DIR/shunit2/2.1.6/src/shunit2"
+}
+
+#--------------------------------------------------------------------#
+# Custom Assertions #
+#--------------------------------------------------------------------#
+
+assertSuggestion() {
+ local prefix="$1"
+ local expected_suggestion="$2"
+
+ assertEquals \
+ "Did not get correct suggestion for prefix:<$prefix> using strategy <$ZSH_AUTOSUGGEST_STRATEGY>" \
+ "$expected_suggestion" \
+ "$(_zsh_autosuggest_suggestion "$prefix")"
+}
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/../test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+setUp() {
+ BUFFER=''
+ POSTDISPLAY=''
+ CURSOR=0
+ KEYMAP='main'
+}
+
+tearDown() {
+ restore _zsh_autosuggest_invoke_original_widget
+}
+
+testCursorAtEnd() {
+ BUFFER='echo'
+ POSTDISPLAY=' hello'
+ CURSOR=4
+
+ stub _zsh_autosuggest_invoke_original_widget
+
+ _zsh_autosuggest_accept 'original-widget'
+
+ assertTrue \
+ 'original widget not invoked' \
+ 'stub_called _zsh_autosuggest_invoke_original_widget'
+
+ assertEquals \
+ 'BUFFER was not modified' \
+ 'echo hello' \
+ "$BUFFER"
+
+ assertEquals \
+ 'POSTDISPLAY was not cleared' \
+ '' \
+ "$POSTDISPLAY"
+}
+
+testCursorNotAtEnd() {
+ BUFFER='echo'
+ POSTDISPLAY=' hello'
+ CURSOR=2
+
+ stub _zsh_autosuggest_invoke_original_widget
+
+ _zsh_autosuggest_accept 'original-widget'
+
+ assertTrue \
+ 'original widget not invoked' \
+ 'stub_called _zsh_autosuggest_invoke_original_widget'
+
+ assertEquals \
+ 'BUFFER was modified' \
+ 'echo' \
+ "$BUFFER"
+
+ assertEquals \
+ 'POSTDISPLAY was modified' \
+ ' hello' \
+ "$POSTDISPLAY"
+}
+
+testViCursorAtEnd() {
+ BUFFER='echo'
+ POSTDISPLAY=' hello'
+ CURSOR=3
+ KEYMAP='vicmd'
+
+ stub _zsh_autosuggest_invoke_original_widget
+
+ _zsh_autosuggest_accept 'original-widget'
+
+ assertTrue \
+ 'original widget not invoked' \
+ 'stub_called _zsh_autosuggest_invoke_original_widget'
+
+ assertEquals \
+ 'BUFFER was not modified' \
+ 'echo hello' \
+ "$BUFFER"
+
+ assertEquals \
+ 'POSTDISPLAY was not cleared' \
+ '' \
+ "$POSTDISPLAY"
+}
+
+testViCursorNotAtEnd() {
+ BUFFER='echo'
+ POSTDISPLAY=' hello'
+ CURSOR=2
+ KEYMAP='vicmd'
+
+ stub _zsh_autosuggest_invoke_original_widget
+
+ _zsh_autosuggest_accept 'original-widget'
+
+ assertTrue \
+ 'original widget not invoked' \
+ 'stub_called _zsh_autosuggest_invoke_original_widget'
+
+ assertEquals \
+ 'BUFFER was modified' \
+ 'echo' \
+ "$BUFFER"
+
+ assertEquals \
+ 'POSTDISPLAY was modified' \
+ ' hello' \
+ "$POSTDISPLAY"
+}
+
+testRetval() {
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'return 1'
+
+ _zsh_autosuggest_widget_accept 'original-widget'
+
+ assertEquals \
+ 'Did not return correct value from original widget' \
+ '1' \
+ "$?"
+}
+
+testWidget() {
+ stub _zsh_autosuggest_highlight_reset
+ stub _zsh_autosuggest_accept
+ stub _zsh_autosuggest_highlight_apply
+
+ # Call the function pointed to by the widget since we can't call
+ # the widget itself when zle is not active
+ ${widgets[autosuggest-accept]#*:} 'original-widget'
+
+ assertTrue \
+ 'autosuggest-accept widget does not exist' \
+ 'zle -l autosuggest-accept'
+
+ assertTrue \
+ 'highlight_reset was not called' \
+ 'stub_called _zsh_autosuggest_highlight_reset'
+
+ assertTrue \
+ 'widget function was not called' \
+ 'stub_called _zsh_autosuggest_accept'
+
+ assertTrue \
+ 'highlight_apply was not called' \
+ 'stub_called _zsh_autosuggest_highlight_apply'
+
+ restore _zsh_autosuggest_highlight_reset
+ restore _zsh_autosuggest_accept
+ restore _zsh_autosuggest_highlight_apply
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/../test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+setUp() {
+ BUFFER=''
+ POSTDISPLAY=''
+}
+
+tearDown() {
+ restore _zsh_autosuggest_invoke_original_widget
+}
+
+testClear() {
+ BUFFER='ec'
+ POSTDISPLAY='ho hello'
+
+ _zsh_autosuggest_clear 'original-widget'
+
+ assertEquals \
+ 'BUFFER was modified' \
+ 'ec' \
+ "$BUFFER"
+
+ assertNull \
+ 'POSTDISPLAY was not cleared' \
+ "$POSTDISPLAY"
+}
+
+testRetval() {
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'return 1'
+
+ _zsh_autosuggest_widget_clear 'original-widget'
+
+ assertEquals \
+ 'Did not return correct value from original widget' \
+ '1' \
+ "$?"
+}
+
+testWidget() {
+ stub _zsh_autosuggest_highlight_reset
+ stub _zsh_autosuggest_clear
+ stub _zsh_autosuggest_highlight_apply
+
+ # Call the function pointed to by the widget since we can't call
+ # the widget itself when zle is not active
+ ${widgets[autosuggest-clear]#*:} 'original-widget'
+
+ assertTrue \
+ 'autosuggest-clear widget does not exist' \
+ 'zle -l autosuggest-clear'
+
+ assertTrue \
+ 'highlight_reset was not called' \
+ 'stub_called _zsh_autosuggest_highlight_reset'
+
+ assertTrue \
+ 'widget function was not called' \
+ 'stub_called _zsh_autosuggest_clear'
+
+ assertTrue \
+ 'highlight_apply was not called' \
+ 'stub_called _zsh_autosuggest_highlight_apply'
+
+ restore _zsh_autosuggest_highlight_reset
+ restore _zsh_autosuggest_clear
+ restore _zsh_autosuggest_highlight_apply
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/../test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+tearDown() {
+ restore _zsh_autosuggest_invoke_original_widget
+}
+
+testRetval() {
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'return 1'
+
+ _zsh_autosuggest_widget_execute 'original-widget'
+
+ assertEquals \
+ 'Did not return correct value from original widget' \
+ '1' \
+ "$?"
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/../test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+setUp() {
+ BUFFER=''
+ POSTDISPLAY=''
+ ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=''
+}
+
+tearDown() {
+ restore _zsh_autosuggest_invoke_original_widget
+ restore _zsh_autosuggest_suggestion
+}
+
+testModify() {
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'BUFFER+="e"'
+
+ stub_and_echo \
+ _zsh_autosuggest_suggestion \
+ 'echo hello'
+
+ _zsh_autosuggest_modify 'original-widget'
+
+ assertTrue \
+ 'original widget not invoked' \
+ 'stub_called _zsh_autosuggest_invoke_original_widget'
+
+ assertEquals \
+ 'BUFFER was not modified' \
+ 'e' \
+ "$BUFFER"
+
+ assertEquals \
+ 'POSTDISPLAY does not contain suggestion' \
+ 'cho hello' \
+ "$POSTDISPLAY"
+}
+
+testModifyBufferTooLarge() {
+
+ ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE='20'
+
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'BUFFER+="012345678901234567890"'
+
+ stub_and_echo \
+ _zsh_autosuggest_suggestion \
+ '012345678901234567890123456789'
+
+ _zsh_autosuggest_modify 'original-widget'
+
+ assertTrue \
+ 'original widget not invoked' \
+ 'stub_called _zsh_autosuggest_invoke_original_widget'
+
+ assertEquals \
+ 'BUFFER was not modified' \
+ '012345678901234567890' \
+ "$BUFFER"
+
+ assertEquals \
+ 'POSTDISPLAY does not contain suggestion' \
+ '' \
+ "$POSTDISPLAY"
+}
+
+testRetval() {
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'return 1'
+
+ _zsh_autosuggest_widget_modify 'original-widget'
+
+ assertEquals \
+ 'Did not return correct value from original widget' \
+ '1' \
+ "$?"
+}
+
+run_tests "$0"
--- /dev/null
+#!/usr/bin/env zsh
+
+source "${0:a:h}/../test_helper.zsh"
+
+oneTimeSetUp() {
+ source_autosuggestions
+}
+
+setUp() {
+ BUFFER=''
+ POSTDISPLAY=''
+ CURSOR=0
+}
+
+tearDown() {
+ restore _zsh_autosuggest_invoke_original_widget
+}
+
+testCursorMovesOutOfBuffer() {
+ BUFFER='ec'
+ POSTDISPLAY='ho hello'
+ CURSOR=1
+
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'CURSOR=5; LBUFFER="echo "; RBUFFER="hello"'
+
+ _zsh_autosuggest_partial_accept 'original-widget'
+
+ assertTrue \
+ 'original widget not invoked' \
+ 'stub_called _zsh_autosuggest_invoke_original_widget'
+
+ assertEquals \
+ 'BUFFER was not modified correctly' \
+ 'echo ' \
+ "$BUFFER"
+
+ assertEquals \
+ 'POSTDISPLAY was not modified correctly' \
+ 'hello' \
+ "$POSTDISPLAY"
+}
+
+testCursorStaysInBuffer() {
+ BUFFER='echo hello'
+ POSTDISPLAY=' world'
+ CURSOR=1
+
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'CURSOR=5; LBUFFER="echo "; RBUFFER="hello"'
+
+ _zsh_autosuggest_partial_accept 'original-widget'
+
+ assertTrue \
+ 'original widget not invoked' \
+ 'stub_called _zsh_autosuggest_invoke_original_widget'
+
+ assertEquals \
+ 'BUFFER was modified' \
+ 'echo hello' \
+ "$BUFFER"
+
+ assertEquals \
+ 'POSTDISPLAY was modified' \
+ ' world' \
+ "$POSTDISPLAY"
+}
+
+testRetval() {
+ stub_and_eval \
+ _zsh_autosuggest_invoke_original_widget \
+ 'return 1'
+
+ _zsh_autosuggest_widget_partial_accept 'original-widget'
+
+ assertEquals \
+ 'Did not return correct value from original widget' \
+ '1' \
+ "$?"
+}
+
+run_tests "$0"
--- /dev/null
+source ${0:A:h}/zsh-autosuggestions.zsh
--- /dev/null
+# Fish-like fast/unobtrusive autosuggestions for zsh.
+# https://github.com/zsh-users/zsh-autosuggestions
+# v0.3.3
+# Copyright (c) 2013 Thiago de Arruda
+# Copyright (c) 2016 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.
+
+#--------------------------------------------------------------------#
+# 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-
+
+ZSH_AUTOSUGGEST_STRATEGY=default
+
+# Widgets that clear the suggestion
+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-history
+ down-line-or-history
+ accept-line
+)
+
+# Widgets that accept the entire suggestion
+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=(
+)
+
+# Widgets that accept the suggestion as far as the cursor moves
+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
+)
+
+# Widgets that should be ignored (globbing supported but must be escaped)
+ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
+ orig-\*
+ beep
+ run-help
+ set-local-history
+ which-command
+ yank
+)
+
+# Max size of buffer to trigger autosuggestion. Leave undefined for no upper bound.
+ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=
+
+#--------------------------------------------------------------------#
+# Handle Deprecated Variables/Widgets #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_deprecated_warning() {
+ >&2 echo "zsh-autosuggestions: $@"
+}
+
+_zsh_autosuggest_check_deprecated_config() {
+ if [ -n "$AUTOSUGGESTION_HIGHLIGHT_COLOR" ]; then
+ _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_COLOR is deprecated. Use ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE instead."
+ [ -z "$ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" ] && ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE=$AUTOSUGGESTION_HIGHLIGHT_STYLE
+ unset AUTOSUGGESTION_HIGHLIGHT_STYLE
+ fi
+
+ if [ -n "$AUTOSUGGESTION_HIGHLIGHT_CURSOR" ]; then
+ _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_CURSOR is deprecated."
+ unset AUTOSUGGESTION_HIGHLIGHT_CURSOR
+ fi
+
+ if [ -n "$AUTOSUGGESTION_ACCEPT_RIGHT_ARROW" ]; then
+ _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_ACCEPT_RIGHT_ARROW is deprecated. The right arrow now accepts the suggestion by default."
+ unset AUTOSUGGESTION_ACCEPT_RIGHT_ARROW
+ fi
+}
+
+_zsh_autosuggest_deprecated_start_widget() {
+ _zsh_autosuggest_deprecated_warning "The autosuggest-start widget is deprecated. For more info, see the README at https://github.com/zsh-users/zsh-autosuggestions."
+ zle -D autosuggest-start
+ eval "zle-line-init() {
+ $(echo $functions[${widgets[zle-line-init]#*:}] | sed -e 's/zle autosuggest-start//g')
+ }"
+}
+
+zle -N autosuggest-start _zsh_autosuggest_deprecated_start_widget
+
+#--------------------------------------------------------------------#
+# Widget Helpers #
+#--------------------------------------------------------------------#
+
+# Bind a single widget to an autosuggest widget, saving a reference to the original widget
+_zsh_autosuggest_bind_widget() {
+ local widget=$1
+ local autosuggest_action=$2
+ local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX
+
+ # Save a reference to the original widget
+ case $widgets[$widget] in
+ # Already bound
+ user:_zsh_autosuggest_(bound|orig)_*);;
+
+ # User-defined widget
+ user:*)
+ zle -N $prefix$widget ${widgets[$widget]#*:}
+ ;;
+
+ # Built-in widget
+ builtin)
+ eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
+ zle -N $prefix$widget _zsh_autosuggest_orig_$widget
+ ;;
+
+ # Completion widget
+ completion:*)
+ eval "zle -C $prefix${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
+ ;;
+ esac
+
+ # 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_${(q)widget}() {
+ _zsh_autosuggest_widget_$autosuggest_action $prefix${(q)widget} \$@
+ }"
+
+ # Create the bound widget
+ zle -N $widget _zsh_autosuggest_bound_$widget
+}
+
+# Map all configured widgets to the right autosuggest widgets
+_zsh_autosuggest_bind_widgets() {
+ local widget
+ local ignore_widgets
+
+ ignore_widgets=(
+ .\*
+ _\*
+ zle-line-\*
+ 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 [ ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]; then
+ _zsh_autosuggest_bind_widget $widget clear
+ elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then
+ _zsh_autosuggest_bind_widget $widget accept
+ elif [ ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]; then
+ _zsh_autosuggest_bind_widget $widget execute
+ elif [ ${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
+ [ $# -gt 0 ] || return
+
+ 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 -gt 0 ]; then
+ _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 #
+#--------------------------------------------------------------------#
+
+# 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() {
+ local -i retval
+
+ # Save the contents of the buffer/postdisplay
+ local orig_buffer="$BUFFER"
+ local orig_postdisplay="$POSTDISPLAY"
+
+ # Clear suggestion while original widget runs
+ unset POSTDISPLAY
+
+ # Original widget may modify the buffer
+ _zsh_autosuggest_invoke_original_widget $@
+ retval=$?
+
+ # Don't fetch a new suggestion if the buffer hasn't changed
+ if [ "$BUFFER" = "$orig_buffer" ]; then
+ POSTDISPLAY="$orig_postdisplay"
+ return $retval
+ fi
+
+ # Get a new suggestion if the buffer is not empty after modification
+ local suggestion
+ if [ $#BUFFER -gt 0 ]; then
+ if [ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" -o $#BUFFER -lt "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]; then
+ suggestion="$(_zsh_autosuggest_suggestion "$BUFFER")"
+ fi
+ fi
+
+ # Add the suggestion to the POSTDISPLAY
+ if [ -n "$suggestion" ]; then
+ POSTDISPLAY="${suggestion#$BUFFER}"
+ fi
+
+ return $retval
+}
+
+# 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 -eq $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
+
+ # 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=$?
+
+ # If we've moved past the end of the original buffer
+ if [ $CURSOR -gt $#original_buffer ]; then
+ # Set POSTDISPLAY to text right of the cursor
+ POSTDISPLAY="$RBUFFER"
+
+ # Clip the buffer at the cursor
+ BUFFER="$LBUFFER"
+ else
+ # Restore the original buffer
+ BUFFER="$original_buffer"
+ fi
+
+ return $retval
+}
+
+for action in clear modify accept partial_accept execute; do
+ eval "_zsh_autosuggest_widget_$action() {
+ local -i retval
+
+ _zsh_autosuggest_highlight_reset
+
+ _zsh_autosuggest_$action \$@
+ retval=\$?
+
+ _zsh_autosuggest_highlight_apply
+
+ return \$retval
+ }"
+done
+
+zle -N autosuggest-accept _zsh_autosuggest_widget_accept
+zle -N autosuggest-clear _zsh_autosuggest_widget_clear
+zle -N autosuggest-execute _zsh_autosuggest_widget_execute
+
+#--------------------------------------------------------------------#
+# Suggestion #
+#--------------------------------------------------------------------#
+
+# Delegate to the selected strategy to determine a suggestion
+_zsh_autosuggest_suggestion() {
+ local escaped_prefix="$(_zsh_autosuggest_escape_command "$1")"
+ local strategy_function="_zsh_autosuggest_strategy_$ZSH_AUTOSUGGEST_STRATEGY"
+
+ if [ -n "$functions[$strategy_function]" ]; then
+ echo -E "$($strategy_function "$escaped_prefix")"
+ fi
+}
+
+_zsh_autosuggest_escape_command() {
+ setopt localoptions EXTENDED_GLOB
+
+ # Escape special chars in the string (requires EXTENDED_GLOB)
+ echo -E "${1//(#m)[\\()\[\]|*?~]/\\$MATCH}"
+}
+
+#--------------------------------------------------------------------#
+# Default Suggestion Strategy #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix.
+#
+
+_zsh_autosuggest_strategy_default() {
+ fc -lnrm "$1*" 1 2>/dev/null | head -n 1
+}
+
+#--------------------------------------------------------------------#
+# 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() {
+ local prefix="$1"
+
+ # 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
+
+ # Echo the matched history entry
+ echo -E "$history[$histkey]"
+}
+
+#--------------------------------------------------------------------#
+# Start #
+#--------------------------------------------------------------------#
+
+# Start the autosuggestion widgets
+_zsh_autosuggest_start() {
+ _zsh_autosuggest_check_deprecated_config
+ _zsh_autosuggest_bind_widgets
+}
+
+autoload -Uz add-zsh-hook
+add-zsh-hook precmd _zsh_autosuggest_start
--- /dev/null
+../external/zsh-autosuggestions/zsh-autosuggestions.zsh
\ No newline at end of file
# zstyle ':ganneff:config' plugins git-extras.plugin.zsh \
# history-substring-search.zsh \
# per-directory-history.plugin.zsh \
-# zaw.zsh
+# zaw.zsh \
+# zsh-autosuggestion.zsh
## oh-my-zsh plugins can also be loaded, in case you like one of it.
## Simply list their names here, and put their directories into