From 6100617ba9a20b308191c1b4555f40ca1ca14448 Mon Sep 17 00:00:00 2001 From: triagent Date: Thu, 29 Oct 2026 09:50:33 +0000 Subject: [PATCH] fix(tui): treat Apple Terminal ESC+Return with Shift held as Shift+Enter --- packages/tui/src/terminal.ts | 16 ++++++++++++++-- packages/tui/test/terminal.test.ts | 12 ++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/tui/src/terminal.ts b/packages/tui/src/terminal.ts index 8e56022e9..287020c51 100644 --- a/packages/tui/src/terminal.ts +++ b/packages/tui/src/terminal.ts @@ -70,6 +70,8 @@ export function normalizeNativeShiftEnterInput( } export function normalizeAppleTerminalInput(data: string, isAppleTerminal: boolean, isShiftPressed: boolean): string { + // Apple Terminal sends ESC + Return for Shift+Enter in some versions, which would otherwise parse as Alt+Enter. + if (isAppleTerminal && data === "\x1b\r" && isShiftPressed) return NATIVE_SHIFT_ENTER_SEQUENCE; return normalizeNativeShiftEnterInput(data, isAppleTerminal, isShiftPressed); } @@ -396,8 +398,18 @@ export class ProcessTerminal implements Terminal { private forwardInputSequence(sequence: string): void { if (!this.inputHandler) return; - const shouldDetectNativeShiftEnter = - sequence === "\r" && (isAppleTerminalSession() || process.platform === "win32"); + if (isAppleTerminalSession()) { + const shouldDetectNativeShiftEnter = sequence === "\r" || sequence === "\x1b\r"; + this.inputHandler( + normalizeAppleTerminalInput( + sequence, + shouldDetectNativeShiftEnter, + shouldDetectNativeShiftEnter && isNativeModifierPressed("shift"), + ), + ); + return; + } + const shouldDetectNativeShiftEnter = sequence === "\r" && process.platform === "win32"; const input = normalizeNativeShiftEnterInput( sequence, shouldDetectNativeShiftEnter, diff --git a/packages/tui/test/terminal.test.ts b/packages/tui/test/terminal.test.ts index de3bc40eb..9e1e920f4 100644 --- a/packages/tui/test/terminal.test.ts +++ b/packages/tui/test/terminal.test.ts @@ -59,6 +59,18 @@ describe("normalizeAppleTerminalInput", () => { assert.equal(normalizeAppleTerminalInput("\r", true, false), "\r"); }); + it("rewrites Apple Terminal ESC + Return to CSI-u Shift+Enter when Shift is pressed", () => { + assert.equal(normalizeAppleTerminalInput("\x1b\r", true, true), "\x1b[13;2u"); + }); + + it("leaves Apple Terminal ESC + Return unchanged when Shift is not pressed", () => { + assert.equal(normalizeAppleTerminalInput("\x1b\r", true, false), "\x1b\r"); + }); + + it("leaves non-Apple Terminal ESC + Return unchanged when Shift is pressed", () => { + assert.equal(normalizeAppleTerminalInput("\x1b\r", false, true), "\x1b\r"); + }); + it("leaves non-Apple Terminal Return unchanged when Shift is pressed", () => { assert.equal(normalizeAppleTerminalInput("\r", false, true), "\r"); });