Skip to content

Commit

Permalink
Fix bugs in handling of external widgets
Browse files Browse the repository at this point in the history
The old code would break the behavior of certain widgets that aren't ours.
  • Loading branch information
marlonrichert committed Jun 5, 2024
1 parent adfade3 commit bbbefed
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 89 deletions.
111 changes: 64 additions & 47 deletions Functions/Init/.autocomplete__async
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,18 @@ ${0}:precmd() {
}

.autocomplete:async:isearch-exit() {
.autocomplete__zle-flags $LASTWIDGET
unset _autocomplete__isearch
}

.autocomplete:async:save-state() {
typeset -g \
_autocomplete__curcontext=$context \
_autocomplete__curcontext=$curcontext \
_autocomplete__lbuffer="$LBUFFER" \
_autocomplete__rbuffer="$RBUFFER"
}

.autocomplete:async:same-state() {
[[ -v _autocomplete__curcontext && $_autocomplete__curcontext == $context &&
[[ -v _autocomplete__curcontext && _autocomplete__curcontext=$curcontext &&
-v _autocomplete__lbuffer && $_autocomplete__lbuffer == $LBUFFER &&
-v _autocomplete__rbuffer && $_autocomplete__rbuffer == $RBUFFER ]]
}
Expand All @@ -87,49 +86,62 @@ ${0}:precmd() {
_autocomplete__rbuffer
}

# function -T
.autocomplete:async:complete() {
.autocomplete__zle-flags $LASTWIDGET ||
if [[ -v _autocomplete__inserted ]]; then
unset _autocomplete__inserted
typeset -g curcontext=
builtin zstyle -s :autocomplete: default-context curcontext
fi
.autocomplete:async:save-state

.autocomplete__zle-flags ||
return 0

(( KEYS_QUEUED_COUNT || PENDING )) &&
return
{
# WORKAROUND: #549 Bug in zdharma/fast-syntax-highlighting.
[[ -v _FAST_MAIN_CACHE ]] &&
_zsh_highlight

typeset -g _autocomplete__region_highlight=( "$region_highlight[@]" )

if [[ -v ZSH_AUTOSUGGEST_IGNORE_WIDGETS ]] && (( ZSH_AUTOSUGGEST_IGNORE_WIDGETS[(I)$LASTWIDGET] )); then
unset POSTDISPLAY
fi

# Completion already started
[[ -v _autocomplete__lbuffer || -v _autocomplete__rbuffer ]] &&
return 0

# Don't get triggered by asynchronous widgets.
if [[ $LASTWIDGET == (autosuggest-suggest|.autocomplete:async:*:fd-widget) ]]; then
# Don't get activated by asynchronous widgets.
[[ $LASTWIDGET == (autosuggest-suggest|.autocomplete:async:*:fd-widget) ]] &&
return 0
fi

{
if (( REGION_ACTIVE )) ||
[[ -v _autocomplete__isearch && $LASTWIDGET == *(incremental|isearch)* ]]; then
builtin zle -Rc
return 0
fi

[[ $LASTWIDGET ==
(_complete_help|(|.)(describe-key-briefly|(|.)(|reverse-)menu-complete|what-cursor-position|where-is)) ]] &&
return
builtin zstyle -t ":autocomplete:${LASTWIDGET}:" ignore &&
return 0

local -Pa ignored=(
'_complete_help'
'(copy|insert)-*-word'
'describe-key-briefly'
'(|reverse-)menu-complete'
'what-cursor-position'
'where-is'
)
[[ ${LASTWIDGET##.} == (${(~j:|:)ignored}) ]] &&
return 0

[[ $KEYS == ([\ -+*]|$'\e\t') ]] &&
builtin zle -Rc

.autocomplete:async:wait
# WORKAROUND: #549 Bug in zdharma/fast-syntax-highlighting.
[[ -v _FAST_MAIN_CACHE ]] &&
_zsh_highlight

set +x
} 2>>| $_autocomplete__log
typeset -ga _autocomplete__region_highlight=( "$region_highlight[@]" )

if [[ -v ZSH_AUTOSUGGEST_IGNORE_WIDGETS ]] &&
(( ZSH_AUTOSUGGEST_IGNORE_WIDGETS[(I)$LASTWIDGET] )); then
unset POSTDISPLAY
fi

.autocomplete:async:wait
}

return 0
}
Expand All @@ -141,11 +153,10 @@ ${0}:precmd() {
return 0
}

# function -t
.autocomplete:async:wait() {
local fd=

.autocomplete:async:save-state

sysopen -r -o cloexec -u fd <(
local -F seconds=
builtin zstyle -s :autocomplete: delay seconds ||
Expand All @@ -164,28 +175,32 @@ ${0}:precmd() {
return 0
}

# function -T
.autocomplete:async:wait:fd-widget() {
{
local -i fd=$1
builtin zle -F $fd # Unhook ourselves immediately, so we don't get called more than once.
exec {fd}<&-
.autocomplete__zle-flags

if [[ -n $_autocomplete__zle_flags ]]; then
builtin zle -f $_autocomplete__zle_flags

[[ $_autocomplete__zle_flags == yank* ]] &&
return 0
fi

(( KEYS_QUEUED_COUNT || PENDING )) &&
return

{
if .autocomplete:async:same-state; then
.autocomplete:async:same-state &&
.autocomplete:async:start
else
.autocomplete:async:wait
fi
set +x
} 2>>| $_autocomplete__log
}
}
return 0
}

.autocomplete:async:start() {
.autocomplete:async:save-state

local fd=
sysopen -r -o cloexec -u fd <(
.autocomplete:async:start:inner 2>>| $_autocomplete__log
Expand Down Expand Up @@ -300,23 +315,25 @@ ${0}:precmd() {
} 2>>| $_autocomplete__log
}

# function -T
.autocomplete:async:complete:fd-widget() {
{
local -i fd=$1
{
builtin zle -F $fd # Unhook ourselves immediately, so we don't get called more than once.

if ! .autocomplete__zle-flags; then
.autocomplete:async:reset-state
return 0
fi
if [[ -n $_autocomplete__zle_flags ]]; then
builtin zle -f $_autocomplete__zle_flags

if ! .autocomplete:async:same-state; then
.autocomplete:async:start
[[ $_autocomplete__zle_flags == yank* ]] &&
return 0
fi

.autocomplete:async:reset-state
(( KEYS_QUEUED_COUNT || PENDING )) &&
return

.autocomplete:async:same-state ||
return 0

local -a reply=()
IFS=$'\0' read -rAu $fd
Expand All @@ -343,9 +360,9 @@ ${0}:precmd() {
builtin zle -R
fi
.autocomplete:async:reset-state
set +x

return 0
} 2>>| $_autocomplete__log
}
}

.autocomplete:async:sufficient-input() {
Expand Down
31 changes: 22 additions & 9 deletions Functions/Util/.autocomplete__zle-flags
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@
emulate -L zsh
setopt $_autocomplete__func_opts[@]

if (( YANK_ACTIVE )); then
local before
(( YANK_START <= CURSOR && YANK_END <= CURSOR )) &&
before=before
builtin zle -f yank$before
return 1 # Tell caller to abort.
fi

builtin zle -f kill
typeset -g _autocomplete__last_cutbuffer
typeset -g _autocomplete__zle_flags=
{
if (( YANK_ACTIVE )); then
_autocomplete__zle_flags=yank
(( YANK_END <= CURSOR )) &&
_autocomplete__zle_flags+=before

return 1 # Tell caller to abort.
fi

[[ $_autocomplete__last_cutbuffer != $CUTBUFFER ]] &&
_autocomplete__zle_flags=kill

return 0

} always {
[[ -n $_autocomplete__zle_flags ]] &&
builtin zle -f $_autocomplete__zle_flags
typeset -g _autocomplete__last_cutbuffer=$CUTBUFFER
}

return 0
72 changes: 40 additions & 32 deletions Functions/Widgets/.autocomplete__complete-word__post
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,51 @@ else
compstate[to_end]='always'
fi

compstate[insert]=
{
compstate[insert]=

if _autocomplete__should_insert_unambiguous; then
if [[ $WIDGETSTYLE == (|*-)menu(|-*) ]]; then
compstate[insert]='automenu-'
fi
compstate[insert]+='unambiguous'
unset _autocomplete__unambiguous
if _autocomplete__should_insert_unambiguous; then
if [[ $WIDGETSTYLE == (|*-)menu(|-*) ]]; then
compstate[insert]='automenu-'
fi
compstate[insert]+='unambiguous'
unset _autocomplete__unambiguous

return
fi
return
fi

if [[ $WIDGETSTYLE == (|*-)menu(|-*) ]]; then
if [[ $WIDGETSTYLE == (|*-)select(|-*) ]]; then
typeset -gi MENUSELECT=0
if [[ $WIDGET == (|*-)search(|-*) ]]; then
typeset -g MENUMODE=search-forward
if [[ $WIDGETSTYLE == (|*-)menu(|-*) ]]; then
if [[ $WIDGETSTYLE == (|*-)select(|-*) ]]; then
typeset -gi MENUSELECT=0
if [[ $WIDGET == (|*-)search(|-*) ]]; then
typeset -g MENUMODE=search-forward
fi
fi
compstate[insert]='menu:'
fi
if [[ $WIDGET == (|.)reverse-* || $WIDGETSTYLE == (|.)reverse-menu-complete ]]; then
compstate[insert]+='0'
else
compstate[insert]+='1'
fi
compstate[insert]='menu:'
fi
if [[ $WIDGET == (|.)reverse-* || $WIDGETSTYLE == (|.)reverse-menu-complete ]]; then
compstate[insert]+='0'
else
compstate[insert]+='1'
fi

local -Pa comptags=()
if [[ $compstate[old_list] == keep ]]; then
comptags=( $=_lastcomp[tags] )
else
comptags=( $=_comp_tags )
fi
local -Pa comptags=()
if [[ $compstate[old_list] == keep ]]; then
comptags=( $=_lastcomp[tags] )
else
comptags=( $=_comp_tags )
fi

local -a spacetags=()
builtin zstyle -a ":autocomplete:$WIDGET:" add-space spacetags ||
spacetags=( executables aliases functions builtins reserved-words commands )

[[ -n ${comptags:*spacetags} ]] &&
compstate[insert]+=' '

local -a spacetags=()
builtin zstyle -a ":autocomplete:$WIDGET:" add-space spacetags ||
spacetags=( executables aliases functions builtins reserved-words commands )
} always {
unset _autocomplete__inserted
[[ -n $compstate[insert] ]] &&
typeset -g _autocomplete__inserted

[[ -n ${comptags:*spacetags} ]] &&
compstate[insert]+=' '
}
1 change: 1 addition & 0 deletions Tests/complete-word.post.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Setup:
% source Tests/__init__.zsh
% typeset -gA compstate=() _lastcomp=()
% typeset -ga comptags=()
% typeset -g curcontext=
% zstyle ':autocomplete:*' add-space 'FOO' 'BAR'
% zstyle ':autocomplete:*' insert-unambiguous yes
%
Expand Down
3 changes: 2 additions & 1 deletion run-tests.zsh
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/bin/zsh -f
cd $( git rev-parse --show-toplevel )

git --version
typeset -p1 PWD VENDOR OSTYPE =zsh ZSH_VERSION ZSH_PATCHLEVEL
env -i HOME=$( mktemp -d ) PATH=$PATH FPATH=$FPATH zsh -f -- \
=clitest --list-run --progress dot --prompt '%' --color always \
--pre-flight 'git --version; print $PWD $VENDOR $OSTYPE =zsh $ZSH_VERSION $ZSH_PATCHLEVEL' \
-- $PWD/Tests/*.md

0 comments on commit bbbefed

Please sign in to comment.