From 78d45f26fbf58c242cff68a78b1d413e645720e9 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Sun, 27 Sep 2026 21:16:03 +0900 Subject: [PATCH] End a string sequence at an ESC that does not start ST An ESC inside a DCS, OSC or APC ends the string and introduces a sequence of its own. Giving up at that point left the payload to be typed into the query, and scanning on to a later ST would swallow that following sequence. https://vt100.net/emu/dec_ansi_parser Reported by Copilot on #4926. --- src/tui/light.go | 12 ++++++++---- src/tui/light_csi_test.go | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tui/light.go b/src/tui/light.go index 1bedbf17..0ded2917 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -379,12 +379,16 @@ func stringEnd(buffer []byte) int { return i + 1 } case Esc.Byte(): - if i+1 < len(buffer) && buffer[i+1] == '\\' { + if i+1 == len(buffer) { + return 0 // ST may still be arriving + } + if buffer[i+1] == '\\' { return i + 2 } - // A lone ESC is either a truncated payload or a terminator still - // arriving. Either way the sequence is not framed. - return 0 + // Any other ESC ends the string and introduces a sequence of its + // own, so frame only what precedes it and leave the ESC to be + // parsed again. Scanning past it would swallow that sequence too. + return i } } return 0 diff --git a/src/tui/light_csi_test.go b/src/tui/light_csi_test.go index 6d2831f0..fb790af4 100644 --- a/src/tui/light_csi_test.go +++ b/src/tui/light_csi_test.go @@ -29,7 +29,8 @@ func TestUnknownCSISequence(t *testing.T) { {"\x1b]0;a title\a", Invalid, 12}, // BEL terminated {"\x1bP>|kitty(0.48.2)\x1b\\", Invalid, 19}, // XTVERSION reply {"\x1b_Gi=1;OK\x1b\\", Invalid, 11}, - {"\x1bP\ax\x1b\\", Invalid, 6}, // BEL inside a DCS payload is not a terminator // kitty graphics reply + {"\x1bP\ax\x1b\\", Invalid, 6}, // BEL inside a DCS payload is not a terminator + {"\x1b]foo\x1bX\x1b\\", Invalid, 5}, // ESC aborts the string, consuming only "\e]foo" // kitty graphics reply // Left alone: this is how ALT-[ and ALT-] arrive {"\x1b[a", Alt, 2},