From fc8c034e607431138049de4d136d810bde0e9716 Mon Sep 17 00:00:00 2001 From: Eric Freese Date: Sat, 30 Jun 2018 18:15:38 -0600 Subject: [PATCH] Improve completion suggestions Just insert the first completion directly into the buffer and read the whole buffer from the zpty. --- src/strategies/completion.zsh | 95 +++++++++++------------------------ zsh-autosuggestions.zsh | 95 +++++++++++------------------------ 2 files changed, 56 insertions(+), 134 deletions(-) diff --git a/src/strategies/completion.zsh b/src/strategies/completion.zsh index 5f71d98..30139ba 100644 --- a/src/strategies/completion.zsh +++ b/src/strategies/completion.zsh @@ -2,18 +2,18 @@ #--------------------------------------------------------------------# # Completion Suggestion Strategy # #--------------------------------------------------------------------# -# Fetches suggestions from zsh's completion engine -# Based on https://github.com/Valodim/zsh-capture-completion +# Fetches a suggestion from the completion engine # -_zsh_autosuggest_capture_setup() { - zmodload zsh/zutil # For `zparseopts` +_zsh_autosuggest_capture_postcompletion() { + # Always insert the first completion into the buffer + compstate[insert]=1 - # Ensure completions have been initialized - if ! whence compdef >/dev/null; then - autoload -Uz compinit && compinit - fi + # Don't list completions + unset compstate[list] +} +_zsh_autosuggest_capture_completion_widget() { # 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 @@ -24,54 +24,26 @@ _zsh_autosuggest_capture_setup() { sleep 1 # Block for long enough for the signal to come through } - # Never group stuff! - zstyle ':completion:*' list-grouped false + local -a +h comppostfuncs + comppostfuncs=(_zsh_autosuggest_capture_postcompletion) - # No list separator, this saves some stripping later on - zstyle ':completion:*' list-separator '' + # Run the original widget wrapping `.complete-word` so we don't + # recursively try to fetch suggestions, since our pty is forked + # after autosuggestions is initialized. + zle -- ${(k)widgets[(r)completion:.complete-word:_main_complete]} - # Override compadd (this is our hook) - compadd () { - setopt localoptions norcexpandparam - - # Just delegate and leave if any of -O, -A or -D are given - if [[ ${@[1,(i)(-|--)]} == *-(O|A|D)\ * ]]; then - builtin compadd "$@" - return $? - fi - - # Capture completions by injecting -A parameter into the compadd call. - # This takes care of matching for us. - typeset -a __hits - builtin compadd -A __hits "$@" - - # Exit if no completion results - [[ -n $__hits ]] || return - - # Extract prefixes and suffixes from compadd call. we can't do zsh's cool - # -r remove-func magic, but it's better than nothing. - typeset -A apre hpre hsuf asuf - zparseopts -E P:=apre p:=hpre S:=asuf s:=hsuf - - # Print the first match - echo -nE - $'\0'$IPREFIX$apre$hpre$__hits[1]$dsuf$hsuf$asuf$'\0' - } + # The completion has been added, print the buffer as the suggestion + echo -nE - $'\0'$BUFFER$'\0' } -_zsh_autosuggest_capture_widget() { - _zsh_autosuggest_capture_setup - - zle complete-word -} - -zle -N autosuggest-capture-completion _zsh_autosuggest_capture_widget +zle -N autosuggest-capture-completion _zsh_autosuggest_capture_completion_widget _zsh_autosuggest_capture_buffer() { local BUFFERCONTENT="$1" - _zsh_autosuggest_capture_setup + zmodload zsh/parameter 2>/dev/null || return # For `$functions` - zmodload zsh/parameter # For `$functions` + bindkey '^I' autosuggest-capture-completion # Make vared completion work as if for a normal command line # https://stackoverflow.com/a/7057118/154703 @@ -86,12 +58,16 @@ _zsh_autosuggest_capture_buffer() { vared BUFFERCONTENT } -_zsh_autosuggest_capture_completion() { - zmodload zsh/zpty 2>/dev/null || return - - typeset -g completion +_zsh_autosuggest_strategy_completion() { + typeset -g suggestion local line REPLY + # Exit if we don't have completions + whence compdef >/dev/null || return + + # Exit if we don't have zpty + zmodload zsh/zpty 2>/dev/null || return + # Zle will be inactive if we are in async mode if zle; then zpty $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME zle autosuggest-capture-completion @@ -106,23 +82,8 @@ _zsh_autosuggest_capture_completion() { # On older versions of zsh, we sometimes get extra bytes after the # second null byte, so trim those off the end - completion="${${${(M)line:#*$'\0'*$'\0'*}#*$'\0'}%%$'\0'*}" + suggestion="${${${(M)line:#*$'\0'*$'\0'*}#*$'\0'}%%$'\0'*}" # Destroy the pty zpty -d $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME } - -_zsh_autosuggest_strategy_completion() { - typeset -g suggestion - local completion - - # Fetch the first completion result - _zsh_autosuggest_capture_completion "$1" - - [[ -z "$completion" ]] && return - - # Add the completion string to the buffer to build the full suggestion - local -i i=1 - while [[ "$completion" != "${1[$i,-1]}"* ]]; do ((i++)); done - suggestion="${1[1,$i-1]}$completion" -} diff --git a/zsh-autosuggestions.zsh b/zsh-autosuggestions.zsh index 41c659f..01ad86a 100644 --- a/zsh-autosuggestions.zsh +++ b/zsh-autosuggestions.zsh @@ -472,18 +472,18 @@ zle -N autosuggest-toggle _zsh_autosuggest_widget_toggle #--------------------------------------------------------------------# # Completion Suggestion Strategy # #--------------------------------------------------------------------# -# Fetches suggestions from zsh's completion engine -# Based on https://github.com/Valodim/zsh-capture-completion +# Fetches a suggestion from the completion engine # -_zsh_autosuggest_capture_setup() { - zmodload zsh/zutil # For `zparseopts` +_zsh_autosuggest_capture_postcompletion() { + # Always insert the first completion into the buffer + compstate[insert]=1 - # Ensure completions have been initialized - if ! whence compdef >/dev/null; then - autoload -Uz compinit && compinit - fi + # Don't list completions + unset compstate[list] +} +_zsh_autosuggest_capture_completion_widget() { # 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 @@ -494,54 +494,26 @@ _zsh_autosuggest_capture_setup() { sleep 1 # Block for long enough for the signal to come through } - # Never group stuff! - zstyle ':completion:*' list-grouped false + local -a +h comppostfuncs + comppostfuncs=(_zsh_autosuggest_capture_postcompletion) - # No list separator, this saves some stripping later on - zstyle ':completion:*' list-separator '' + # Run the original widget wrapping `.complete-word` so we don't + # recursively try to fetch suggestions, since our pty is forked + # after autosuggestions is initialized. + zle -- ${(k)widgets[(r)completion:.complete-word:_main_complete]} - # Override compadd (this is our hook) - compadd () { - setopt localoptions norcexpandparam - - # Just delegate and leave if any of -O, -A or -D are given - if [[ ${@[1,(i)(-|--)]} == *-(O|A|D)\ * ]]; then - builtin compadd "$@" - return $? - fi - - # Capture completions by injecting -A parameter into the compadd call. - # This takes care of matching for us. - typeset -a __hits - builtin compadd -A __hits "$@" - - # Exit if no completion results - [[ -n $__hits ]] || return - - # Extract prefixes and suffixes from compadd call. we can't do zsh's cool - # -r remove-func magic, but it's better than nothing. - typeset -A apre hpre hsuf asuf - zparseopts -E P:=apre p:=hpre S:=asuf s:=hsuf - - # Print the first match - echo -nE - $'\0'$IPREFIX$apre$hpre$__hits[1]$dsuf$hsuf$asuf$'\0' - } + # The completion has been added, print the buffer as the suggestion + echo -nE - $'\0'$BUFFER$'\0' } -_zsh_autosuggest_capture_widget() { - _zsh_autosuggest_capture_setup - - zle complete-word -} - -zle -N autosuggest-capture-completion _zsh_autosuggest_capture_widget +zle -N autosuggest-capture-completion _zsh_autosuggest_capture_completion_widget _zsh_autosuggest_capture_buffer() { local BUFFERCONTENT="$1" - _zsh_autosuggest_capture_setup + zmodload zsh/parameter 2>/dev/null || return # For `$functions` - zmodload zsh/parameter # For `$functions` + bindkey '^I' autosuggest-capture-completion # Make vared completion work as if for a normal command line # https://stackoverflow.com/a/7057118/154703 @@ -556,12 +528,16 @@ _zsh_autosuggest_capture_buffer() { vared BUFFERCONTENT } -_zsh_autosuggest_capture_completion() { - zmodload zsh/zpty 2>/dev/null || return - - typeset -g completion +_zsh_autosuggest_strategy_completion() { + typeset -g suggestion local line REPLY + # Exit if we don't have completions + whence compdef >/dev/null || return + + # Exit if we don't have zpty + zmodload zsh/zpty 2>/dev/null || return + # Zle will be inactive if we are in async mode if zle; then zpty $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME zle autosuggest-capture-completion @@ -576,27 +552,12 @@ _zsh_autosuggest_capture_completion() { # On older versions of zsh, we sometimes get extra bytes after the # second null byte, so trim those off the end - completion="${${${(M)line:#*$'\0'*$'\0'*}#*$'\0'}%%$'\0'*}" + suggestion="${${${(M)line:#*$'\0'*$'\0'*}#*$'\0'}%%$'\0'*}" # Destroy the pty zpty -d $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME } -_zsh_autosuggest_strategy_completion() { - typeset -g suggestion - local completion - - # Fetch the first completion result - _zsh_autosuggest_capture_completion "$1" - - [[ -z "$completion" ]] && return - - # Add the completion string to the buffer to build the full suggestion - local -i i=1 - while [[ "$completion" != "${1[$i,-1]}"* ]]; do ((i++)); done - suggestion="${1[1,$i-1]}$completion" -} - #--------------------------------------------------------------------# # History Suggestion Strategy # #--------------------------------------------------------------------#