diff --git a/packages/pi-coding-agent/src/modes/interactive/components/custom-editor.ts b/packages/pi-coding-agent/src/modes/interactive/components/custom-editor.ts index 74fcc7767..b6968460c 100644 --- a/packages/pi-coding-agent/src/modes/interactive/components/custom-editor.ts +++ b/packages/pi-coding-agent/src/modes/interactive/components/custom-editor.ts @@ -1,4 +1,4 @@ -import { Editor, type EditorOptions, type EditorTheme, type TUI } from "@gsd/pi-tui"; +import { Editor, type EditorOptions, type EditorTheme, type TUI, isKittyProtocolActive } from "@gsd/pi-tui"; import type { AppAction, KeybindingsManager } from "../../../core/keybindings.js"; /** @@ -69,6 +69,13 @@ export class CustomEditor extends Editor { // Check all other app actions for (const [action, handler] of this.actionHandlers) { if (action !== "interrupt" && action !== "exit" && this.keybindings.matches(data, action)) { + // When kitty protocol is not active, \x1b\r is ambiguous: + // it could be alt+enter (followUp) or shift+enter mapped via /terminal-setup. + // Prioritize newLine since that's what terminal-setup configures. + // Alt+enter followUp still works in kitty-protocol terminals. + if (action === "followUp" && !isKittyProtocolActive() && data === "\x1b\r") { + break; // Fall through to parent editor's newLine handling + } handler(); return; } diff --git a/packages/pi-tui/src/components/editor.ts b/packages/pi-tui/src/components/editor.ts index ae8c6bb77..35508bc55 100644 --- a/packages/pi-tui/src/components/editor.ts +++ b/packages/pi-tui/src/components/editor.ts @@ -182,7 +182,7 @@ export class Editor implements Component, Focusable { private undoStack = new UndoStack(); private textVersion = 0; private cachedText: string | null = null; - private layoutCache: { width: number; textVersion: number; lines: LayoutLine[] } | null = null; + private layoutCache: { width: number; textVersion: number; cursorLine: number; cursorCol: number; lines: LayoutLine[] } | null = null; private visualLineMapCache: { width: number; textVersion: number; lines: VisualLine[] } | null = null; public onSubmit?: (text: string) => void; @@ -243,12 +243,14 @@ export class Editor implements Component, Focusable { private getLayoutLines(width: number): LayoutLine[] { const cached = this.layoutCache; - if (cached && cached.width === width && cached.textVersion === this.textVersion) { + if (cached && cached.width === width && cached.textVersion === this.textVersion + && cached.cursorLine === this.state.cursorLine && cached.cursorCol === this.state.cursorCol) { return cached.lines; } const lines = this.layoutText(width); - this.layoutCache = { width, textVersion: this.textVersion, lines }; + this.layoutCache = { width, textVersion: this.textVersion, lines, + cursorLine: this.state.cursorLine, cursorCol: this.state.cursorCol }; return lines; }