Commit Graph
2 Commits
Author SHA1 Message Date
Junegunn Choi b563e208d6 Check escape sequence bytes before counting them (#4929)
The parser decided how many bytes a key used before checking them, so a
key that arrived in the same read was lost or misread.

- Recognize F1-F8 and modified Delete, PageUp and PageDown when more input
  follows them, as with a paste or tmux send-keys. They required the
  sequence to be the whole buffer.
- After \e[ and a digit, do not consume a byte that cannot continue the
  sequence. ALT-[, 2 and Enter lost the Enter.
- Report Home and End for \e[7, \e[4 and \e[8 only before ~, $, ^ or @.
  ALT-[, 4 and x fired End and lost the x.
- Look for the end of a mouse report within its frame. A later M swallowed
  the keys before it, and repeated \e[< took quadratic time.
2026-10-08 21:34:46 +09:00
Junegunn Choi c009c106b9 Drop unrecognized escape sequences instead of typing them (#4926)
fzf consumed only the part of a sequence it recognized, and the rest was
typed into the query. CTRL-A sent as \e[97;5u became "97;5u", and CTRL-F
sent as \e[70;5u fired Home before typing ";5u". A BEL-terminated OSC
reply also aborted fzf, because the BEL that followed the typed payload
was read as CTRL-G.

Frame CSI and SS3 by their parameter and final byte ranges, OSC, DCS and
APC by their terminator. Drop the whole frame when the parser does not
recognize it, or recognizes only a prefix of it, and never consume past
it: the parser could count a key typed after it. rxvt ends keys with $,
as in \e[7$ and \e[23$, so $ after plain digits is a final byte. Elsewhere
it stays intermediate, as in DECRPM replies.

Take the second-chance read only when the sequence at the start of the
buffer is the only one and is unfinished. Otherwise it blocked until the
next key, holding back what followed, CTRL-G included. That read has no
time limit, so what it returns may be the next key, typed any time later.
It is never dropped with the frame.

Telling a terminal's sequence from an ALT key is the hard part, so these
keep what the parser made of them:

- An unterminated sequence, since that is how ALT-[, ALT-O, ALT-], ALT-P
  and ALT-_ arrive
- A CSI or SS3 of four bytes or fewer. It could be an ALT key and typed
  text, and rxvt sends keys of that size fzf does not know, such as \e[3^
- A string sequence whose payload does not start like a reply: digits and
  ';' for OSC, '>|', '!|', '[01]$r' or '[01]+r' for DCS, 'G' and a key
  for APC
- SOS and PM, which nothing sends

Within a string, an ESC ends it and introduces a sequence of its own, and
only OSC ends with BEL. The read loop does not wait for a string
terminator: that held ALT-], ALT-P and ALT-_ for ESCDELAY and let typed
bytes pile up until they looked like a sequence.
2026-10-08 20:17:03 +09:00