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.
This commit is contained in:
Junegunn Choi
2026-09-27 21:16:03 +09:00
parent 9c667afb73
commit 78d45f26fb
2 changed files with 10 additions and 5 deletions
+8 -4
View File
@@ -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
+2 -1
View File
@@ -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},