diff --git a/.rubocop.yml b/.rubocop.yml index 9e0792f..97facac 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -2,29 +2,29 @@ # Enabled: true AllCops: - TargetRubyVersion: 2.3 - Include: - - '**/Rakefile' - - '**/config.ru' - - '**/Gemfile' + TargetRubyVersion: 2.3 + Include: + - '**/Rakefile' + - '**/config.ru' + - '**/Gemfile' Metrics/LineLength: - Max: 120 + Max: 120 Style/Documentation: - Enabled: false + Enabled: false Style/DotPosition: - EnforcedStyle: trailing + EnforcedStyle: trailing Style/FrozenStringLiteralComment: - Enabled: false + Enabled: false Style/Lambda: - Enabled: false + Enabled: false Style/MultilineMethodCallIndentation: - EnforcedStyle: indented + EnforcedStyle: indented Style/TrailingUnderscoreVariable: - Enabled: false + Enabled: false diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0f8e6..fb15b88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,21 @@ # Changelog +## 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 (#) -- Fix problems with multi-line suggestions (#) +- 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 (#) +- Avoid wrapping any zle-* widgets (#206) - Remove support for deprecated options from v0.0.x -- Handle history entries that begin with dashes (#) +- Handle history entries that begin with dashes - Gracefully handle being sourced multiple times (#126) - Add enable/disable/toggle widgets to disable/enable suggestions (#219) diff --git a/Makefile b/Makefile index d5d162c..5402b7f 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,6 @@ 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 \ diff --git a/README.md b/README.md index 4df4e90..8aedb31 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ It suggests commands as you type, based on command history. 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 + git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions ``` 2. Add the following to your `.zshrc`: @@ -33,7 +33,7 @@ It suggests commands as you type, based on command history. 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 + git clone https://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: diff --git a/VERSION b/VERSION index fb7a04c..5aff472 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.4.0 +v0.4.1 diff --git a/spec/integrations/bracketed_paste_magic_spec.rb b/spec/integrations/bracketed_paste_magic_spec.rb index f01b0e0..64092ad 100644 --- a/spec/integrations/bracketed_paste_magic_spec.rb +++ b/spec/integrations/bracketed_paste_magic_spec.rb @@ -23,14 +23,5 @@ describe 'pasting using bracketed-paste-magic' do expect(session.content).to eq("echo #{'a' * 60}") end end - - it 'shows a suggestion after a non-modifying keystroke' do - with_history('echo hello') do - session.paste_string('echo') - sleep 1 - session.send_keys('left') - wait_for { session.content }.to eq('echo hello') - end - end end end diff --git a/spec/integrations/rebound_bracket_spec.rb b/spec/integrations/rebound_bracket_spec.rb new file mode 100644 index 0000000..8b420f0 --- /dev/null +++ b/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 diff --git a/spec/special_characters_spec.rb b/spec/special_characters_spec.rb deleted file mode 100644 index ce7810b..0000000 --- a/spec/special_characters_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -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 diff --git a/spec/strategies/default_spec.rb b/spec/strategies/default_spec.rb index 94f3450..89321f3 100644 --- a/spec/strategies/default_spec.rb +++ b/spec/strategies/default_spec.rb @@ -1,3 +1,5 @@ +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 @@ -5,4 +7,6 @@ describe 'the default suggestion strategy' do wait_for { session.content }.to eq('ls bar') end end + + include_examples 'special characters' end diff --git a/spec/strategies/match_prev_cmd_spec.rb b/spec/strategies/match_prev_cmd_spec.rb index 21be712..f1596ba 100644 --- a/spec/strategies/match_prev_cmd_spec.rb +++ b/spec/strategies/match_prev_cmd_spec.rb @@ -1,3 +1,5 @@ +require 'strategies/special_characters_helper' + describe 'the match_prev_cmd strategy' do let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd'] } @@ -14,4 +16,6 @@ describe 'the match_prev_cmd strategy' do wait_for { session.content }.to eq('ls bar') end end + + include_examples 'special characters' end diff --git a/spec/strategies/special_characters_helper.rb b/spec/strategies/special_characters_helper.rb new file mode 100644 index 0000000..8771861 --- /dev/null +++ b/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 diff --git a/src/async.zsh b/src/async.zsh index 124c9ac..1d1e76d 100644 --- a/src/async.zsh +++ b/src/async.zsh @@ -63,7 +63,7 @@ _zsh_autosuggest_async_pty_create() { typeset -h REPLY # If we won't get a fd back from zpty, try to guess it - if [ $_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD -eq 0 ]; then + 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. diff --git a/src/bind.zsh b/src/bind.zsh index d8629f1..ed9a977 100644 --- a/src/bind.zsh +++ b/src/bind.zsh @@ -10,14 +10,14 @@ _zsh_autosuggest_incr_bind_count() { _ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=1 fi - bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] + typeset -gi bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] } _zsh_autosuggest_get_bind_count() { if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then - bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] + typeset -gi bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] else - bind_count=0 + typeset -gi bind_count=0 fi } @@ -88,13 +88,13 @@ _zsh_autosuggest_bind_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 + if [[ -n ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]]; then _zsh_autosuggest_bind_widget $widget clear - elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then + elif [[ -n ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]]; then _zsh_autosuggest_bind_widget $widget accept - elif [ ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]; then + elif [[ -n ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]]; then _zsh_autosuggest_bind_widget $widget execute - elif [ ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]; then + 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 @@ -106,13 +106,13 @@ _zsh_autosuggest_bind_widgets() { # 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 + (( $# )) || return local original_widget_name="$1" shift - if [ $widgets[$original_widget_name] ]; then + if (( ${+widgets[$original_widget_name]} )); then zle $original_widget_name -- $@ fi } diff --git a/src/config.zsh b/src/config.zsh index c7fc55a..ba694c0 100644 --- a/src/config.zsh +++ b/src/config.zsh @@ -42,6 +42,7 @@ 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 diff --git a/src/highlight.zsh b/src/highlight.zsh index a8ff08a..273c03d 100644 --- a/src/highlight.zsh +++ b/src/highlight.zsh @@ -7,7 +7,7 @@ _zsh_autosuggest_highlight_reset() { typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT - if [ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]; then + if [[ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]]; then region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}") unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT fi @@ -17,8 +17,8 @@ _zsh_autosuggest_highlight_reset() { _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" + 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 diff --git a/src/start.zsh b/src/start.zsh index 6fa8ce9..6f48ab6 100644 --- a/src/start.zsh +++ b/src/start.zsh @@ -15,7 +15,7 @@ _zsh_autosuggest_start() { # 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 + if [[ -n "${ZSH_AUTOSUGGEST_USE_ASYNC+x}" ]]; then _zsh_autosuggest_async_start fi } diff --git a/src/strategies/default.zsh b/src/strategies/default.zsh index 60c0494..17bf65d 100644 --- a/src/strategies/default.zsh +++ b/src/strategies/default.zsh @@ -7,19 +7,9 @@ # _zsh_autosuggest_strategy_default() { - # 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 - local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}" + local prefix="$1" # Get the history items that match # - (r) subscript flag makes the pattern match on values - suggestion="${history[(r)$prefix*]}" - + typeset -g suggestion="${history[(r)${(b)prefix}*]}" } diff --git a/src/strategies/match_prev_cmd.zsh b/src/strategies/match_prev_cmd.zsh index ee26346..8a84728 100644 --- a/src/strategies/match_prev_cmd.zsh +++ b/src/strategies/match_prev_cmd.zsh @@ -21,18 +21,18 @@ # `HIST_EXPIRE_DUPS_FIRST`. _zsh_autosuggest_strategy_match_prev_cmd() { - local prefix="${1//(#m)[\\()\[\]|*?~]/\\$MATCH}" + 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*]}) + history_match_keys=(${(k)history[(R)${(b)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))]}")" + local prev_cmd="${history[$((HISTCMD-1))]}" # Iterate up to the first 200 history event numbers that match $prefix for key in "${(@)history_match_keys[1,200]}"; do @@ -48,5 +48,5 @@ _zsh_autosuggest_strategy_match_prev_cmd() { done # Give back the matched history entry - suggestion="$history[$histkey]" + typeset -g suggestion="$history[$histkey]" } diff --git a/src/util.zsh b/src/util.zsh deleted file mode 100644 index 1f55d36..0000000 --- a/src/util.zsh +++ /dev/null @@ -1,11 +0,0 @@ - -#--------------------------------------------------------------------# -# Utility Functions # -#--------------------------------------------------------------------# - -_zsh_autosuggest_escape_command() { - setopt localoptions EXTENDED_GLOB - - # Escape special chars in the string (requires EXTENDED_GLOB) - echo -E "${1//(#m)[\"\'\\()\[\]|*?~]/\\$MATCH}" -} diff --git a/src/widgets.zsh b/src/widgets.zsh index aa3f248..8a31133 100644 --- a/src/widgets.zsh +++ b/src/widgets.zsh @@ -13,14 +13,14 @@ _zsh_autosuggest_disable() { _zsh_autosuggest_enable() { unset _ZSH_AUTOSUGGEST_DISABLED - if [ $#BUFFER -gt 0 ]; then + if (( $#BUFFER )); then _zsh_autosuggest_fetch fi } # Toggle suggestions (enable/disable) _zsh_autosuggest_toggle() { - if [ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]; then + if [[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]]; then _zsh_autosuggest_enable else _zsh_autosuggest_disable @@ -39,7 +39,7 @@ _zsh_autosuggest_clear() { _zsh_autosuggest_modify() { local -i retval - # Only added to zsh very recently + # Only available in zsh >= 5.4 local -i KEYS_QUEUED_COUNT # Save the contents of the buffer/postdisplay @@ -54,35 +54,35 @@ _zsh_autosuggest_modify() { retval=$? # Don't fetch a new suggestion if there's more input to be read immediately - if [[ $PENDING > 0 ]] || [[ $KEYS_QUEUED_COUNT > 0 ]]; then + if (( $PENDING > 0 )) || (( $KEYS_QUEUED_COUNT > 0 )); then return $retval fi # Optimize if manually typing in the suggestion - if [ $#BUFFER -gt $#orig_buffer ]; then + 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 + 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 + if [[ "$BUFFER" = "$orig_buffer" ]]; then POSTDISPLAY="$orig_postdisplay" return $retval fi # Bail out if suggestions are disabled - if [ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]; then + if [[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]]; then return $? fi # Get a new suggestion if the buffer is not empty after modification - if [ $#BUFFER -gt 0 ]; then - if [ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" -o $#BUFFER -le "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]; then + if (( $#BUFFER > 0 )); then + if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then _zsh_autosuggest_fetch fi fi @@ -105,7 +105,7 @@ _zsh_autosuggest_fetch() { _zsh_autosuggest_suggest() { local suggestion="$1" - if [ -n "$suggestion" ] && [ $#BUFFER -gt 0 ]; then + if [[ -n "$suggestion" ]] && (( $#BUFFER )); then POSTDISPLAY="${suggestion#$BUFFER}" else unset POSTDISPLAY @@ -118,12 +118,12 @@ _zsh_autosuggest_accept() { # When vicmd keymap is active, the cursor can't move all the way # to the end of the buffer - if [ "$KEYMAP" = "vicmd" ]; then + 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 + if [[ $CURSOR = $max_cursor_pos ]]; then # Add the suggestion to the buffer BUFFER="$BUFFER$POSTDISPLAY" @@ -165,7 +165,7 @@ _zsh_autosuggest_partial_accept() { retval=$? # If we've moved past the end of the original buffer - if [ $CURSOR -gt $#original_buffer ]; then + if (( $CURSOR > $#original_buffer )); then # Set POSTDISPLAY to text right of the cursor POSTDISPLAY="$RBUFFER" diff --git a/zsh-autosuggestions.zsh b/zsh-autosuggestions.zsh index 0d389ec..fadbac7 100644 --- a/zsh-autosuggestions.zsh +++ b/zsh-autosuggestions.zsh @@ -1,6 +1,6 @@ # Fish-like fast/unobtrusive autosuggestions for zsh. # https://github.com/zsh-users/zsh-autosuggestions -# v0.4.0 +# v0.4.1 # Copyright (c) 2013 Thiago de Arruda # Copyright (c) 2016-2017 Eric Freese # @@ -78,6 +78,7 @@ 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 @@ -100,17 +101,6 @@ 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 # #--------------------------------------------------------------------# @@ -141,14 +131,14 @@ _zsh_autosuggest_incr_bind_count() { _ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=1 fi - bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] + typeset -gi bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] } _zsh_autosuggest_get_bind_count() { if ((${+_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]})); then - bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] + typeset -gi bind_count=$_ZSH_AUTOSUGGEST_BIND_COUNTS[$1] else - bind_count=0 + typeset -gi bind_count=0 fi } @@ -219,13 +209,13 @@ _zsh_autosuggest_bind_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 + if [[ -n ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]]; then _zsh_autosuggest_bind_widget $widget clear - elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then + elif [[ -n ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]]; then _zsh_autosuggest_bind_widget $widget accept - elif [ ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]; then + elif [[ -n ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]]; then _zsh_autosuggest_bind_widget $widget execute - elif [ ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]; then + 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 @@ -237,13 +227,13 @@ _zsh_autosuggest_bind_widgets() { # 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 + (( $# )) || return local original_widget_name="$1" shift - if [ $widgets[$original_widget_name] ]; then + if (( ${+widgets[$original_widget_name]} )); then zle $original_widget_name -- $@ fi } @@ -256,7 +246,7 @@ _zsh_autosuggest_invoke_original_widget() { _zsh_autosuggest_highlight_reset() { typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT - if [ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]; then + if [[ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]]; then region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}") unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT fi @@ -266,8 +256,8 @@ _zsh_autosuggest_highlight_reset() { _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" + 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 @@ -288,14 +278,14 @@ _zsh_autosuggest_disable() { _zsh_autosuggest_enable() { unset _ZSH_AUTOSUGGEST_DISABLED - if [ $#BUFFER -gt 0 ]; then + if (( $#BUFFER )); then _zsh_autosuggest_fetch fi } # Toggle suggestions (enable/disable) _zsh_autosuggest_toggle() { - if [ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]; then + if [[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]]; then _zsh_autosuggest_enable else _zsh_autosuggest_disable @@ -314,7 +304,7 @@ _zsh_autosuggest_clear() { _zsh_autosuggest_modify() { local -i retval - # Only added to zsh very recently + # Only available in zsh >= 5.4 local -i KEYS_QUEUED_COUNT # Save the contents of the buffer/postdisplay @@ -329,35 +319,35 @@ _zsh_autosuggest_modify() { retval=$? # Don't fetch a new suggestion if there's more input to be read immediately - if [[ $PENDING > 0 ]] || [[ $KEYS_QUEUED_COUNT > 0 ]]; then + if (( $PENDING > 0 )) || (( $KEYS_QUEUED_COUNT > 0 )); then return $retval fi # Optimize if manually typing in the suggestion - if [ $#BUFFER -gt $#orig_buffer ]; then + 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 + 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 + if [[ "$BUFFER" = "$orig_buffer" ]]; then POSTDISPLAY="$orig_postdisplay" return $retval fi # Bail out if suggestions are disabled - if [ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]; then + if [[ -n "${_ZSH_AUTOSUGGEST_DISABLED+x}" ]]; then return $? fi # Get a new suggestion if the buffer is not empty after modification - if [ $#BUFFER -gt 0 ]; then - if [ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" -o $#BUFFER -le "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]; then + if (( $#BUFFER > 0 )); then + if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then _zsh_autosuggest_fetch fi fi @@ -380,7 +370,7 @@ _zsh_autosuggest_fetch() { _zsh_autosuggest_suggest() { local suggestion="$1" - if [ -n "$suggestion" ] && [ $#BUFFER -gt 0 ]; then + if [[ -n "$suggestion" ]] && (( $#BUFFER )); then POSTDISPLAY="${suggestion#$BUFFER}" else unset POSTDISPLAY @@ -393,12 +383,12 @@ _zsh_autosuggest_accept() { # When vicmd keymap is active, the cursor can't move all the way # to the end of the buffer - if [ "$KEYMAP" = "vicmd" ]; then + 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 + if [[ $CURSOR = $max_cursor_pos ]]; then # Add the suggestion to the buffer BUFFER="$BUFFER$POSTDISPLAY" @@ -440,7 +430,7 @@ _zsh_autosuggest_partial_accept() { retval=$? # If we've moved past the end of the original buffer - if [ $CURSOR -gt $#original_buffer ]; then + if (( $CURSOR > $#original_buffer )); then # Set POSTDISPLAY to text right of the cursor POSTDISPLAY="$RBUFFER" @@ -488,21 +478,11 @@ zle -N autosuggest-toggle _zsh_autosuggest_widget_toggle # _zsh_autosuggest_strategy_default() { - # 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 - local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}" + local prefix="$1" # Get the history items that match # - (r) subscript flag makes the pattern match on values - suggestion="${history[(r)$prefix*]}" - + typeset -g suggestion="${history[(r)${(b)prefix}*]}" } #--------------------------------------------------------------------# @@ -527,18 +507,18 @@ _zsh_autosuggest_strategy_default() { # `HIST_EXPIRE_DUPS_FIRST`. _zsh_autosuggest_strategy_match_prev_cmd() { - local prefix="${1//(#m)[\\()\[\]|*?~]/\\$MATCH}" + 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*]}) + history_match_keys=(${(k)history[(R)${(b)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))]}")" + local prev_cmd="${history[$((HISTCMD-1))]}" # Iterate up to the first 200 history event numbers that match $prefix for key in "${(@)history_match_keys[1,200]}"; do @@ -554,7 +534,7 @@ _zsh_autosuggest_strategy_match_prev_cmd() { done # Give back the matched history entry - suggestion="$history[$histkey]" + typeset -g suggestion="$history[$histkey]" } #--------------------------------------------------------------------# @@ -621,7 +601,7 @@ _zsh_autosuggest_async_pty_create() { typeset -h REPLY # If we won't get a fd back from zpty, try to guess it - if [ $_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD -eq 0 ]; then + 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. @@ -682,7 +662,7 @@ _zsh_autosuggest_start() { # 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 + if [[ -n "${ZSH_AUTOSUGGEST_USE_ASYNC+x}" ]]; then _zsh_autosuggest_async_start fi }