Wait only when the parsed sequence is the only one in the buffer

The two checks could refer to different sequences. In \e[3;\a\e[ the first
looked unfinished and so did the trailing \e[, though the BEL had already
ended the first. The blocking read held back the CTRL-G abort.

Reported by Copilot on #4926.
This commit is contained in:
Junegunn Choi committed 2026-10-03 14:49:39 +09:00
1 parent 8bd6ba1830
commit c2cee734f4
2 files changed
+17 -17

No files matched your search

+7 -7
View File
@@ -444,12 +444,12 @@ func stringReply(buffer []byte) bool {
return false
}
// stillArriving reports whether the sequence that consumed sz bytes of the
// buffer may still be completed by more input. Both it and the buffer have to
// end unfinished: a complete sequence followed by ALT-[ is not waiting for
// anything, and an unfinished one followed by other bytes cannot complete.
func stillArriving(buffer []byte, sz int) bool {
return incompleteEscape(buffer[:min(sz, len(buffer))]) && incompleteEscape(buffer)
// stillArriving reports whether the sequence at the start of the buffer may
// still be completed by more input. It must be the only one in the buffer:
// whatever follows it, another sequence or a byte that ended it, means it is not
// waiting for anything.
func stillArriving(buffer []byte) bool {
return bytes.IndexByte(buffer[1:], Esc.Byte()) < 0 && incompleteEscape(buffer)
}
// incompleteEscape reports whether the buffer ends in an escape sequence that
@@ -589,7 +589,7 @@ func (r *LightRenderer) GetChar(cancellable bool) Event {
// Second chance, but only for an unfinished sequence. Re-reading
// otherwise blocks until the next keystroke, holding back whatever
// follows in the buffer.
if ev.Type == Invalid && stillArriving(r.buffer, sz) {
if ev.Type == Invalid && stillArriving(r.buffer) {
r.buffer, result, err = r.getBytes(true)
if err != nil {
return Event{Fatal, 0, nil}
+10 -10
View File
@@ -139,19 +139,19 @@ func TestStringEnd(t *testing.T) {
func TestStillArriving(t *testing.T) {
for _, c := range []struct {
buffer string
sz int
want bool
}{
{"\x1b[97;5u\a\x1b[", 7, false},
{"\x1b[97;5u\x1b[", 7, false},
{"\x1b[1;\a", 4, false}, // the BEL has already ended it
{"\x1b[1;", 4, true},
{"\x1b[", 2, true},
{"\x1bO1", 3, true},
{"\x1b[<0;1", 3, true},
{"\x1b[97;5u\a\x1b[", false},
{"\x1b[97;5u\x1b[", false},
{"\x1b[3;\a\x1b[", false}, // the BEL ended it, the trailing \e[ is another one
{"\x1b[1;\a", false}, // the BEL has already ended it
{"\x1b[1;", true},
{"\x1b[", true},
{"\x1bO1", true},
{"\x1b[<0;1", true},
} {
if got := stillArriving([]byte(c.buffer), c.sz); got != c.want {
t.Errorf("stillArriving(%q, %d) = %v, want %v", c.buffer, c.sz, got, c.want)
if got := stillArriving([]byte(c.buffer)); got != c.want {
t.Errorf("stillArriving(%q) = %v, want %v", c.buffer, got, c.want)
}
}
}