mirror of
https://github.com/zsh-users/zsh-autosuggestions.git
synced 2026-04-27 18:39:24 +02:00
Fix region_highlight entries leaking across accept/edit cycles
Before this change, the highlight module tracked only the most recent
plugin-owned entry in a scalar (_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT) and
relied on a parameter-expansion subtraction to remove it:
region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}")
That has two failure modes:
1. The tracked string is expanded as a zsh glob pattern. If the user's
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE contains characters like `#`
(e.g. `fg=#RRGGBB`), the entry is never removed and orphans
accumulate in region_highlight across redraws. See #789.
2. Only one entry can be tracked at a time. When apply is called
repeatedly without a successful reset (which happens under fast edits
and widget-wrapping interactions), every apply overwrites the tracked
reference and previous entries are orphaned.
Both manifest as stale suggestion colors bleeding onto accepted text,
typically in combination with zsh-syntax-highlighting (whose entries
interleave with ours in region_highlight).
Changes:
* Track every plugin-owned entry in an array
(_ZSH_AUTOSUGGEST_OWNED_HIGHLIGHTS).
* On zsh 5.9+, tag each entry with `memo=zsh-autosuggestions` and on
reset strip by memo in a single pass — robust regardless of how other
plugins manipulate region_highlight. This matches the mechanism
zsh-syntax-highlighting has used since 0.8.0.
* On zsh < 5.9, remove owned entries by literal string comparison
(loop, not pattern expansion) to avoid the `#`-as-glob issue.
* _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT is retained and kept in sync for
backwards compatibility with any external consumer.
Adds spec/highlight_spec.rb covering:
- round-trip with a hex-colored style (regression for #789)
- reset does not touch foreign region_highlight entries
- accumulated orphans from repeated apply calls are all cleaned up
Supersedes #790 (which used `shift -p region_highlight` — incorrect
when another plugin has appended the most-recent entry).
Fixes #789, #698.
This commit is contained in:
parent
85919cd1ff
commit
a98dd4abcf
4 changed files with 274 additions and 8 deletions
|
|
@ -3,14 +3,77 @@
|
|||
# Highlighting #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
# `is-at-least` is autoloaded in src/start.zsh, but we may be called
|
||||
# before start.zsh runs (e.g. another plugin triggering us). Safe to
|
||||
# autoload here too — it's idempotent.
|
||||
autoload -Uz is-at-least
|
||||
|
||||
# Array of every region_highlight entry this plugin has added. Using an
|
||||
# array (instead of a single scalar) ensures every entry we own can be
|
||||
# removed on reset even when:
|
||||
# * another plugin appends to region_highlight between our apply and
|
||||
# reset calls (e.g. zsh-syntax-highlighting),
|
||||
# * multiple apply calls occur without an intervening successful reset
|
||||
# (which can happen under rapid edits / widget wrapping edge cases).
|
||||
typeset -ga _ZSH_AUTOSUGGEST_OWNED_HIGHLIGHTS
|
||||
|
||||
# Returns 0 if this zsh supports the `memo=` attribute on region_highlight
|
||||
# entries (zsh 5.9+). The result is cached on first call.
|
||||
_zsh_autosuggest_highlight_memo_support() {
|
||||
typeset -g _ZSH_AUTOSUGGEST_MEMO_SUPPORT
|
||||
if [[ -z "$_ZSH_AUTOSUGGEST_MEMO_SUPPORT" ]]; then
|
||||
if is-at-least 5.9; then
|
||||
_ZSH_AUTOSUGGEST_MEMO_SUPPORT=1
|
||||
else
|
||||
_ZSH_AUTOSUGGEST_MEMO_SUPPORT=0
|
||||
fi
|
||||
fi
|
||||
(( _ZSH_AUTOSUGGEST_MEMO_SUPPORT ))
|
||||
}
|
||||
|
||||
# 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}")
|
||||
if (( $#_ZSH_AUTOSUGGEST_OWNED_HIGHLIGHTS == 0 )); then
|
||||
unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
|
||||
return
|
||||
fi
|
||||
|
||||
if _zsh_autosuggest_highlight_memo_support; then
|
||||
# Single pass: drop every region_highlight entry carrying our
|
||||
# memo tag. Order-independent and robust against interleaving
|
||||
# with other plugins' entries.
|
||||
local entry
|
||||
local -a kept=()
|
||||
for entry in $region_highlight; do
|
||||
[[ "$entry" != *memo=zsh-autosuggestions* ]] && kept+=("$entry")
|
||||
done
|
||||
region_highlight=("${kept[@]}")
|
||||
else
|
||||
# Fallback for zsh < 5.9: remove by literal string comparison.
|
||||
# We intentionally do NOT use `${(@)array:#$needle}` because
|
||||
# that treats $needle as a glob pattern — `#` in hex colors
|
||||
# (e.g. `fg=#RRGGBB`) would be interpreted as pattern-matching
|
||||
# syntax and the entry would never be removed.
|
||||
# See https://github.com/zsh-users/zsh-autosuggestions/issues/789
|
||||
local owned entry
|
||||
for owned in $_ZSH_AUTOSUGGEST_OWNED_HIGHLIGHTS; do
|
||||
local -a kept=()
|
||||
local removed=0
|
||||
for entry in $region_highlight; do
|
||||
if (( ! removed )) && [[ "$entry" == "$owned" ]]; then
|
||||
removed=1
|
||||
else
|
||||
kept+=("$entry")
|
||||
fi
|
||||
done
|
||||
region_highlight=("${kept[@]}")
|
||||
done
|
||||
fi
|
||||
|
||||
_ZSH_AUTOSUGGEST_OWNED_HIGHLIGHTS=()
|
||||
unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
|
||||
}
|
||||
|
||||
# If there's a suggestion, highlight it
|
||||
|
|
@ -18,8 +81,16 @@ _zsh_autosuggest_highlight_apply() {
|
|||
typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
|
||||
|
||||
if (( $#POSTDISPLAY )); then
|
||||
typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
|
||||
region_highlight+=("$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT")
|
||||
local entry="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
|
||||
if _zsh_autosuggest_highlight_memo_support; then
|
||||
entry+=" memo=zsh-autosuggestions"
|
||||
fi
|
||||
region_highlight+=("$entry")
|
||||
_ZSH_AUTOSUGGEST_OWNED_HIGHLIGHTS+=("$entry")
|
||||
|
||||
# Retained for backwards compatibility with anything reading
|
||||
# this variable externally.
|
||||
_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$entry"
|
||||
else
|
||||
unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
|
||||
fi
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue