From b1c499b34066ba4481ccad14eedafe7b7b3f6469 Mon Sep 17 00:00:00 2001 From: JiXieShi Date: Sun, 24 May 2026 03:25:40 +0800 Subject: [PATCH] fix: TUI CSI u key parsing and console escape sequence order - TUI: Add parseCSIuBytes to handle CSI u sequences that bubbletea v1.3.6 returns as []byte (unknownCSISequenceMsg). Parses codepoint and modifier bits to reconstruct key string for hotkey routing. - Console: Reorder escape parser checks. Check 2-byte non-CSI sequences first, then CSI terminator only after ESC[ introducer. Fixes CSI u sequences being truncated at '[' byte (0x5b). Co-Authored-By: Claude Opus 4.7 --- internal/console/console.go | 6 ++++-- internal/tui/hotkeys.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/internal/console/console.go b/internal/console/console.go index 47a8a8d..ba2e86c 100644 --- a/internal/console/console.go +++ b/internal/console/console.go @@ -189,13 +189,15 @@ func RunConsole(appInst *apppkg.App) error { break } escBuf = append(escBuf, nb) - if nb >= 0x40 && nb <= 0x7e { + // 2-byte non-CSI: ESC + letter (not [) + if len(escBuf) == 2 && escBuf[1] != '[' { if flushESC(escBuf) { return nil } break } - if len(escBuf) == 2 && escBuf[1] != '[' { + // CSI terminator: final byte of ESC [ ... sequence + if len(escBuf) > 2 && escBuf[1] == '[' && nb >= 0x40 && nb <= 0x7e { if flushESC(escBuf) { return nil } diff --git a/internal/tui/hotkeys.go b/internal/tui/hotkeys.go index ef24c5d..c4038bb 100644 --- a/internal/tui/hotkeys.go +++ b/internal/tui/hotkeys.go @@ -1,6 +1,7 @@ package tui import ( + "strconv" "strings" tea "github.com/charmbracelet/bubbletea" @@ -146,3 +147,35 @@ func completionBase(line string) string { } return line[:i+1] } + +func parseCSIuBytes(b []byte) (string, bool) { + s := string(b) + if !strings.HasPrefix(s, "\x1b[") || !strings.HasSuffix(s, "u") { + return "", false + } + inner := s[2 : len(s)-1] + parts := strings.SplitN(inner, ";", 2) + if len(parts) != 2 { + return "", false + } + cp, err := strconv.Atoi(parts[0]) + if err != nil || cp < 'a' || cp > 'z' { + return "", false + } + mod, err := strconv.Atoi(parts[1]) + if err != nil { + return "", false + } + var seq []string + if mod&4 != 0 { + seq = append(seq, "ctrl") + } + if mod&2 != 0 { + seq = append(seq, "alt") + } + if mod&1 != 0 { + seq = append(seq, "shift") + } + seq = append(seq, string(rune(cp))) + return strings.Join(seq, "+"), true +}