Terminate only OSC strings with BEL

DCS and APC end with ST. Stopping at a BEL in their payload framed just
the first half and left the rest to be typed into the query.

Reported by Copilot on #4926.
This commit is contained in:
Junegunn Choi
2026-09-27 21:02:34 +09:00
parent 993abd8a80
commit b05683edf0
2 changed files with 16 additions and 4 deletions
+11 -3
View File
@@ -363,13 +363,21 @@ func csiEnd(buffer []byte) int {
}
// stringEnd returns the length of the string sequence (DCS, OSC or APC) at the
// start of the buffer, or 0 if its terminator has not arrived. The terminator is
// ST, and BEL as well because xterm has always allowed it.
// start of the buffer, or 0 if its terminator has not arrived.
func stringEnd(buffer []byte) int {
if len(buffer) < 2 {
return 0
}
// Every one of them ends with ST. BEL ends an OSC as well, because xterm has
// always allowed it, but stopping at a BEL inside a DCS or APC payload would
// frame only its first half and leave the rest to be typed into the query.
bel := buffer[1] == ']'
for i := 2; i < len(buffer); i++ {
switch buffer[i] {
case '\a':
return i + 1
if bel {
return i + 1
}
case Esc.Byte():
if i+1 < len(buffer) && buffer[i+1] == '\\' {
return i + 2
+5 -1
View File
@@ -28,7 +28,8 @@ func TestUnknownCSISequence(t *testing.T) {
{"\x1b]11;rgb:4a4a/4a4a/4a4a\x1b\\", Invalid, 25}, // background color reply
{"\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}, // kitty graphics 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
// Left alone: this is how ALT-[ and ALT-] arrive
{"\x1b[a", Alt, 2},
@@ -71,6 +72,9 @@ func TestStringEnd(t *testing.T) {
want int
}{
{"\x1b]0;t\a", 6},
{"\x1bP\ax\x1b\\", 6}, // BEL in the payload ignored, ST ends it
{"\x1bP\a", 0}, // BEL does not terminate a DCS
{"\x1b_Gi=1\a", 0}, // nor an APC
{"\x1b]0;t\x1b\\", 7},
{"\x1b_G\x1b\\", 5},
{"\x1b]0;t", 0}, // no terminator