From 8a8dacca14234ba9cb730c5cdedd2a2225d3e924 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 22 Apr 2026 13:37:38 +0200 Subject: [PATCH] Demonstrate that unknown escape sequences leak as literal text The escape interpreter errors on anything outside the handful of sequences it understands (SGR, EL, OSC 8 hyperlinks), and view.go then renders the unparsed bytes as text cells. Co-Authored-By: Claude Opus 4.7 (1M context) --- pkg/gocui/escape_test.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pkg/gocui/escape_test.go b/pkg/gocui/escape_test.go index 382d27bad..3d9ab5b36 100644 --- a/pkg/gocui/escape_test.go +++ b/pkg/gocui/escape_test.go @@ -150,6 +150,29 @@ func TestParseOneColours(t *testing.T) { } } +func TestParseOneIgnoresUnknownSequences(t *testing.T) { + // These are the kinds of sequences ConPTY emits as session-init on Windows. A text-mode + // interpreter can't do anything meaningful with them, but it must silently consume them + // instead of leaking them into the view as literal text. + scenarios := []string{ + "\x1b[?9001h", // DEC private-mode set (?-prefix) + "\x1b[?25l", // hide cursor + "\x1b[?25h", // show cursor + "\x1b[2;J", // erase display (unusual 2;J variant) + "\x1b[H", // cursor home — final byte immediately after [ + "\x1b[5;1;H", // cursor position with multiple params + "\x1bc", // RIS — single-char ESC sequence + } + + for _, input := range scenarios { + ei := newEscapeInterpreter(OutputNormal) + /* EXPECTED: + parseEscRunes(t, ei, input) + ACTUAL: */ + parseEscRunesExpectingError(t, ei, input) + } +} + func parseEscRunes(t *testing.T, ei *escapeInterpreter, runes string) { t.Helper() for _, b := range []byte(runes) { @@ -158,3 +181,13 @@ func parseEscRunes(t *testing.T, ei *escapeInterpreter, runes string) { assert.NoError(t, err) } } + +func parseEscRunesExpectingError(t *testing.T, ei *escapeInterpreter, runes string) { + t.Helper() + for _, b := range []byte(runes) { + if _, err := ei.parseOne([]byte{b}); err != nil { + return + } + } + t.Errorf("expected a parse error for %q, got none", runes) +}