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 +}