Compare commits

...
Author SHA1 Message Date
Cursor Agentand陈大猫 92296bdff3 test(terminal): expect ESC+CR when Shift+Enter broadcast falls back
Non-preserving Kitty targets now receive the new default Alt+Enter
encoding instead of a bare newline.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
2026-10-20 02:45:16 +00:00
Cursor Agentand陈大猫 507c58c33a fix(terminal): detect Alt+Enter line breaks without a control regex
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
2026-10-20 02:45:16 +00:00
Cursor AgentandGOUKI9999 d2dd48706c fix(terminal): do not treat ESC+CR Shift+Enter as command submission
getShiftEnterSubmittedInput classified every CR-terminated value as a
submit. The ESC+CR default (legacy Alt+Enter) therefore recorded a
command and fired onCommandSubmitted on each Shift+Enter.

Co-authored-by: GOUKI9999 <11640942+GOUKI9999@users.noreply.github.com>
2026-10-20 02:37:22 +00:00
GOUKI9999 eca31d3c88 feat(terminal): default Shift+Enter text to the legacy Alt+Enter encoding 2026-10-20 02:35:37 +00:00
11 changed files with 35 additions and 16 deletions

No files matched your search

+1 -1
View File
@@ -712,7 +712,7 @@ Highlight the focused split pane:
'Send configured text instead of normal Enter when pressing Shift+Enter in the terminal.',
'settings.terminal.behavior.shiftEnterNewlineText': 'Text to send',
'settings.terminal.behavior.shiftEnterNewlineText.desc':
'Use \\n for newline, \\t for tab, \\e for Escape, and \\\\ for backslash.',
'Use \\n for newline, \\t for tab, \\e for Escape, and \\\\ for backslash. Defaults to \\e\\r (Escape + Enter, the legacy Alt+Enter encoding), which most TUI CLIs treat as a newline.',
'settings.terminal.behavior.shiftEnterForceText': 'Send text in Win32 input mode',
'settings.terminal.behavior.shiftEnterForceText.desc':
'Also send the text above when a local Windows ConPTY session negotiates Win32 input mode. Needed for Node/Bun CLIs (Claude Code, CodeBuddy) that cannot read modifier keys from console input records.',
+1 -1
View File
@@ -627,7 +627,7 @@ Resalta el panel dividido enfocado:
'Envía el texto configurado en lugar del Enter normal al presionar Shift+Enter en la terminal.',
'settings.terminal.behavior.shiftEnterNewlineText': 'Texto a enviar',
'settings.terminal.behavior.shiftEnterNewlineText.desc':
'Usa \\n para nueva línea, \\t para tabulación, \\e para Escape y \\\\ para barra invertida.',
'Usa \\n para nueva línea, \\t para tabulación, \\e para Escape y \\\\ para barra invertida. Por defecto \\e\\r (Escape + Enter, la codificación clásica de Alt+Enter), que la mayoría de las CLI TUI interpretan como nueva línea.',
'settings.terminal.behavior.shiftEnterForceText': 'Enviar texto también en modo de entrada Win32',
'settings.terminal.behavior.shiftEnterForceText.desc':
'Envía también el texto anterior cuando una sesión ConPTY local de Windows negocia el modo de entrada Win32. Necesario para CLI escritas en Node/Bun (Claude Code, CodeBuddy) que no pueden leer modificadores desde los registros de entrada de la consola.',
+1 -1
View File
@@ -663,7 +663,7 @@ export const ruCoreMessages: Messages = {
'Отправлять настроенный текст вместо обычного Enter при нажатии Shift+Enter в терминале.',
'settings.terminal.behavior.shiftEnterNewlineText': 'Отправляемый текст',
'settings.terminal.behavior.shiftEnterNewlineText.desc':
'Используйте \\n для перевода строки, \\t для табуляции, \\e для Escape и \\\\ для обратной косой черты.',
'Используйте \\n для перевода строки, \\t для табуляции, \\e для Escape и \\\\ для обратной косой черты. По умолчанию \\e\\r (Escape + Enter, классическая кодировка Alt+Enter), которую большинство TUI-CLI распознают как перевод строки.',
'settings.terminal.behavior.shiftEnterForceText': 'Отправлять текст и в режиме ввода Win32',
'settings.terminal.behavior.shiftEnterForceText.desc':
'Отправлять указанный выше текст даже когда локальная сессия Windows ConPTY согласует режим ввода Win32. Нужно для CLI на Node/Bun (Claude Code, CodeBuddy), которые не читают модификаторы из записей ввода консоли.',
+1 -1
View File
@@ -352,7 +352,7 @@ export const zhCNTerminalMessages: Messages = {
'在终端中按 Shift+Enter 时发送配置的文本,而不是普通回车。',
'settings.terminal.behavior.shiftEnterNewlineText': '发送内容',
'settings.terminal.behavior.shiftEnterNewlineText.desc':
'使用 \\n 表示换行,\\t 表示 Tab,\\e 表示 ESC,\\\\ 表示反斜杠。',
'使用 \\n 表示换行,\\t 表示 Tab,\\e 表示 ESC,\\\\ 表示反斜杠。默认 \\e\\r(ESC+回车,传统 Alt+Enter 编码),大多数 TUI CLI 会将其识别为换行。',
'settings.terminal.behavior.shiftEnterForceText': '在 Win32 输入模式下也发送文本',
'settings.terminal.behavior.shiftEnterForceText.desc':
'本机 Windows ConPTY 会话协商 Win32 输入模式时,仍然发送上面的文本。Node/Bun 写的 CLI(Claude Code、CodeBuddy)读不到控制台输入记录里的修饰键,需要这个开关才能区分 Shift+Enter。',
+1 -1
View File
@@ -352,7 +352,7 @@ export const zhTWTerminalMessages: Messages = {
'在終端中按 Shift+Enter 時傳送設定的文字,而不是一般 Enter。',
'settings.terminal.behavior.shiftEnterNewlineText': '傳送內容',
'settings.terminal.behavior.shiftEnterNewlineText.desc':
'使用 \\n 表示換行,\\t 表示 Tab,\\e 表示 ESC,\\\\ 表示反斜線。',
'使用 \\n 表示換行,\\t 表示 Tab,\\e 表示 ESC,\\\\ 表示反斜線。預設 \\e\\r(ESC+Enter,傳統 Alt+Enter 編碼),大多數 TUI CLI 會將其識別為換行。',
'settings.terminal.behavior.shiftEnterForceText': '在 Win32 輸入模式下也傳送文字',
'settings.terminal.behavior.shiftEnterForceText.desc':
'本機 Windows ConPTY 工作階段協商 Win32 輸入模式時,仍然傳送上面的文字。Node/Bun 寫的 CLI(Claude Code、CodeBuddy)讀不到主控台輸入記錄中的修飾鍵,需要這個開關才能區分 Shift+Enter。',
@@ -224,9 +224,9 @@ export const TerminalBehaviorSettings: React.FC<TerminalBehaviorSettingsProps> =
description={t("settings.terminal.behavior.shiftEnterNewlineText.desc")}
>
<Input
value={terminalSettings.shiftEnterNewlineText ?? "\\n"}
value={terminalSettings.shiftEnterNewlineText ?? "\\e\\r"}
onChange={(e) => updateTerminalSetting("shiftEnterNewlineText", e.target.value)}
placeholder="\\n"
placeholder="\\e\\r"
className="w-56 font-mono"
spellCheck={false}
/>
@@ -541,7 +541,7 @@ test("Shift+Enter broadcast uses CSI-u only after the target negotiated a preser
applicationCursorMode: false,
encodedKeys: new Set<string>(),
}), {
data: "\n",
data: "\u001b\r",
kittyEncoded: false,
urgentInterrupt: false,
});
@@ -552,7 +552,7 @@ test("Shift+Enter broadcast uses CSI-u only after the target negotiated a preser
applicationCursorMode: false,
encodedKeys: new Set<string>(),
}), {
data: "\n",
data: "\u001b\r",
kittyEncoded: false,
urgentInterrupt: false,
});
@@ -26,8 +26,8 @@ const keyEvent = (overrides: Partial<KeyboardEvent> = {}) => ({
...overrides,
}) as KeyboardEvent;
test("shift enter text defaults to newline", () => {
assert.equal(resolveShiftEnterText(), "\n");
test("shift enter text defaults to the legacy Alt+Enter encoding (ESC + CR)", () => {
assert.equal(resolveShiftEnterText(), "\u001b\r");
});
test("shift enter text decodes newline, tab, carriage return, and backslash escapes", () => {
@@ -71,6 +71,20 @@ test("shift enter submitted input detects single command text with a line ending
assert.equal(getShiftEnterSubmittedInput("foo\nbar\n"), null);
});
test("Alt+Enter ESC+CR is a non-submitting logical line break", () => {
assert.equal(getShiftEnterSubmittedInput("\u001b\r"), null);
assert.equal(getShiftEnterSubmittedInput("echo hi\u001b\r"), null);
assert.equal(getShiftEnterSubmittedInput("echo hi\u001b\r\n"), null);
assert.deepEqual(getShiftEnterSubmittedInput("echo hi\r"), {
text: "echo hi",
lineEnding: "\r",
});
assert.deepEqual(getShiftEnterSubmittedInput("\u001b\n"), {
text: "\u001b",
lineEnding: "\n",
});
});
test("shift enter handler only matches plain Shift+Enter keydown", () => {
assert.equal(shouldSendShiftEnterText(keyEvent()), true);
assert.equal(shouldSendShiftEnterText(keyEvent({ type: "keyup" })), false);
@@ -1,6 +1,6 @@
import type { TerminalSettings } from "../../../domain/models";
export const DEFAULT_SHIFT_ENTER_TEXT = "\\n";
export const DEFAULT_SHIFT_ENTER_TEXT = "\\e\\r";
/** Kitty CSI-u encoding for Shift+Enter (keycode 13, modifier shift → 2). */
export const SHIFT_ENTER_CSI_U_SEQUENCE = "\u001b[13;2u";
@@ -109,10 +109,15 @@ export type ShiftEnterSubmittedInput = {
lineEnding: "\r\n" | "\r" | "\n";
};
/** ESC immediately before a terminating CR is the legacy Alt+Enter line break. */
function isAltEnterLineBreak(text: string): boolean {
return text.endsWith("\u001b\r") || text.endsWith("\u001b\r\n");
}
export function getShiftEnterSubmittedInput(
text: string,
): ShiftEnterSubmittedInput | null {
if (isShiftEnterLineContinuationText(text)) return null;
if (isShiftEnterLineContinuationText(text) || isAltEnterLineBreak(text)) return null;
const match = text.match(/^([^\r\n]*)(\r\n|\r|\n)$/);
if (!match) return null;
return {
+1 -1
View File
@@ -522,7 +522,7 @@ const DEFAULT_TERMINAL_SETTINGS: TerminalSettings = {
altAsMeta: false,
optionArrowWordJump: false,
shiftEnterNewlineEnabled: true,
shiftEnterNewlineText: '\\n',
shiftEnterNewlineText: '\\e\\r',
shiftEnterForceText: false,
kittyKeyboardProtocolEnabled: false,
scrollOnInput: true,
+2 -2
View File
@@ -93,7 +93,7 @@ test("normalizeTerminalSettings enables Shift+Enter newline by default", () => {
const settings = normalizeTerminalSettings();
assert.equal(settings.shiftEnterNewlineEnabled, true);
assert.equal(settings.shiftEnterNewlineText, "\\n");
assert.equal(settings.shiftEnterNewlineText, "\\e\\r");
});
test("normalizeTerminalSettings disables Kitty keyboard protocol by default", () => {
@@ -114,7 +114,7 @@ test("normalizeTerminalSettings preserves Shift+Enter text", () => {
test("normalizeTerminalSettings falls back when Shift+Enter text is not a string", () => {
assert.equal(
normalizeTerminalSettings({ shiftEnterNewlineText: null as never }).shiftEnterNewlineText,
"\\n",
"\\e\\r",
);
});