From 9c603bedb3970cfb1be1aef7b52ea6e3255a80e2 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Sat, 3 Oct 2026 15:06:08 +0900 Subject: [PATCH] Keep rxvt keys intact when checking the frame - Leave a short frame the parser rejects as it was. rxvt sends keys of that size fzf does not know, such as \e[3^ for CTRL-DELETE, and reporting them as ALT-[ typed "3^" into the query - Do not widen a parse that ends in an intermediate byte. rxvt ends keys with $, as in \e[7$ for SHIFT-HOME, and widening took the next typed key with it --- src/tui/light.go | 17 ++++++++--------- src/tui/light_csi_test.go | 14 ++++++++++---- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/tui/light.go b/src/tui/light.go index 8d8909af..f3921c36 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -348,6 +348,8 @@ func getEnv(name string, defaultValue int) int { func csiContinues(b byte) bool { return b >= 0x20 && b <= 0x3f } func csiFinal(b byte) bool { return b >= 0x40 && b <= 0x7e } +func csiIntermediate(b byte) bool { return b >= 0x20 && b <= 0x2f } + // csiEnd returns the length of the CSI sequence at the start of the buffer, or // 0 if it has no final byte yet or is malformed. func csiEnd(buffer []byte) int { @@ -645,18 +647,15 @@ func (r *LightRenderer) escSequence(sz *int) Event { if end == 0 { return ev } - // The same rule as the fall-through: four bytes or fewer could be ALT-[ - // or ALT-O and typed text + // Four bytes or fewer could be ALT-[ or ALT-O and typed text, and rxvt sends + // keys of that size fzf does not know, such as \e[3^ for CTRL-DELETE if end <= 4 { - if ev.Type == Invalid { - *sz = 2 - return AltKey(rune(r.buffer[1])) - } return ev } - // A key matched on a prefix, such as Home for \e[70;5u, or a sequence - // given up on partway - if end > *sz { + // A key matched on a prefix, such as Home for \e[70;5u, or a sequence given + // up on partway. rxvt ends keys with the intermediate byte $, as in \e[7$ + // for SHIFT-HOME, so a parse ending there is complete. + if end > *sz && !csiIntermediate(r.buffer[*sz-1]) { *sz = end return Event{Invalid, 0, nil} } diff --git a/src/tui/light_csi_test.go b/src/tui/light_csi_test.go index f9e76569..3b41ed92 100644 --- a/src/tui/light_csi_test.go +++ b/src/tui/light_csi_test.go @@ -49,10 +49,16 @@ func TestUnknownEscapeSequence(t *testing.T) { {"\x1b[ x", Alt, 2}, {"\x1bOx", Alt, 2}, {"\x1bO9A", Alt, 2}, - {"\x1b[2m", Alt, 2}, // the parser gives up on these itself - {"\x1b[3x", Alt, 2}, - {"\x1b[