From 0b886d1beae38d217b8e5b4092555fadb1f9c96e Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Mon, 27 Jul 2026 23:28:43 -0400 Subject: [PATCH] Tighten up Device Attributes reply parsing This fixes an issue where `civis`/`cnorm` (hide/show cursor) escape sequences with `TERM=linux` were being parsed as requests to send a DA1 response, leading to repeated streams of `1;2c1;2c1;`... being shown in the terminal when using programs like `vim`, `tmux`, etc. where showing/hiding the cursor is common. The issue stems from the fact that under `TERM=linux`, the `civis`/`cnorm` escape sequences each end with a Linux console cursor size sequence (`CSI ? 1c`/`CSI ? 0c`) appended after the standard show/hide sequence. Since these cursor shape sequences match the `CSI c` pattern, they're handled as device attribute requests by `_csiHandleSendDeviceAttributes()`, which would respond to them with a DA1 sequence by default because `?` isn't a valid prefix. Example sequences: ``` $ TERM=xterm tput civis | xxd 00000000: 1b5b 3f32 356c .[?25l $ TERM=xterm tput cnorm | xxd 00000000: 1b5b 3f31 326c 1b5b 3f32 3568 .[?12l.[?25h $ TERM=linux tput civis | xxd 00000000: 1b5b 3f32 356c 1b5b 3f31 63 .[?25l.[?1c $ TERM=linux tput cnorm | xxd 00000000: 1b5b 3f32 3568 1b5b 3f30 63 .[?25h.[?0c ``` This commit updates the DA reply parsing to only accept valid prefixes (nothing, `>`, or `=`) and let everything else fall into the default case so it's ignored. --- lib/src/core/escape/parser.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/core/escape/parser.dart b/lib/src/core/escape/parser.dart index 0c7e74a9..075febad 100644 --- a/lib/src/core/escape/parser.dart +++ b/lib/src/core/escape/parser.dart @@ -329,12 +329,14 @@ class EscapeParser { /// https://terminalguide.namepad.de/seq/csi_sc/ void _csiHandleSendDeviceAttributes() { switch (_csi.prefix) { + case null: + return handler.sendPrimaryDeviceAttributes(); case Ascii.greaterThan: return handler.sendSecondaryDeviceAttributes(); case Ascii.equal: return handler.sendTertiaryDeviceAttributes(); default: - handler.sendPrimaryDeviceAttributes(); + handler.unknownCSI(_csi.finalByte); } }