Skip to content

Commit 52dafba

Browse files
fix: re-apply dynamic modifier parsing for Shift+Enter after upstream sync
Upstream v0.1.21 reverted PR #70. Re-apply: - isShiftReturn() / isReturn() dynamic CSI modifier bit parsing - Kitty progressive enhancement (ESC[>1u) alongside xterm modifyOtherKeys - Clear input when key.return is true (safety net)
1 parent 75d68f4 commit 52dafba

3 files changed

Lines changed: 44 additions & 9 deletions

File tree

src/tests/promptInputKeys.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ test("parseTerminalInput keeps BS payload for meta+backspace", () => {
8080

8181
test("parseTerminalInput recognizes shifted return sequences", () => {
8282
const { input, key } = parseTerminalInput("\u001B\r");
83-
assert.equal(input, "\r");
83+
assert.equal(input, "");
8484
assert.equal(key.return, true);
8585
assert.equal(key.shift, true);
8686
assert.equal(key.meta, false);
@@ -108,8 +108,8 @@ test("parseTerminalInput recognizes alternate shifted return sequences", () => {
108108
});
109109

110110
test("terminal extended key helpers request and restore modifyOtherKeys mode", () => {
111-
assert.equal(enableTerminalExtendedKeys(), "\u001B[>4;1m");
112-
assert.equal(disableTerminalExtendedKeys(), "\u001B[>4;0m");
111+
assert.equal(enableTerminalExtendedKeys(), "\u001B[>4;1m\u001B[>1u");
112+
assert.equal(disableTerminalExtendedKeys(), "\u001B[>4;0m\u001B[<u");
113113
});
114114

115115
test("parseTerminalInput recognizes terminal focus events", () => {

src/ui/prompt/cursor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ function disableTerminalFocusReporting(): string {
4141
}
4242

4343
export function enableTerminalExtendedKeys(): string {
44-
return "\u001B[>4;1m";
44+
return "\u001B[>4;1m\u001B[>1u";
4545
}
4646

4747
export function disableTerminalExtendedKeys(): string {
48-
return "\u001B[>4;0m";
48+
return "\u001B[>4;0m\u001B[<u";
4949
}
5050

5151
export function getPromptCursorPlacement(

src/ui/prompt/useTerminalInput.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,42 @@ const BACKSPACE_BYTES = new Set(["\u007F", "\b"]);
2626
const FORWARD_DELETE_SEQUENCES = new Set(["\u001B[3~", "\u001B[P"]);
2727
const HOME_SEQUENCES = new Set(["\u001B[H", "\u001B[1~", "\u001B[7~", "\u001BOH"]);
2828
const END_SEQUENCES = new Set(["\u001B[F", "\u001B[4~", "\u001B[8~", "\u001BOF"]);
29-
const SHIFT_RETURN_SEQUENCES = new Set(["\u001B\r", "\u001B[13;2u", "\u001B[13;2~", "\u001B[27;2;13~"]);
29+
const SHIFT_RETURN_SEQUENCES = new Set([
30+
"\u001B\r",
31+
"\u001B[13;2u",
32+
"\u001B[13;1u",
33+
"\u001B[13;2~",
34+
"\u001B[13;1~",
35+
"\u001B[27;2;13~",
36+
"\u001B[27;1;13~",
37+
]);
38+
39+
const CSI_SHIFT_RETURN_RE = /^\u001B\[13;(\d+)[u~]$/;
40+
const CSI_EXTENDED_SHIFT_RETURN_RE = /^\u001B\[27;(\d+);13~$/;
41+
42+
function isShiftReturn(raw: string): boolean {
43+
if (SHIFT_RETURN_SEQUENCES.has(raw)) return true;
44+
let m: RegExpMatchArray | null;
45+
if ((m = raw.match(CSI_SHIFT_RETURN_RE)) !== null) {
46+
const mod = parseInt(m[1], 10);
47+
return (mod & 2) !== 0 || (mod & 1) !== 0;
48+
}
49+
if ((m = raw.match(CSI_EXTENDED_SHIFT_RETURN_RE)) !== null) {
50+
const mod = parseInt(m[1], 10);
51+
return (mod & 2) !== 0 || (mod & 1) !== 0;
52+
}
53+
return false;
54+
}
55+
56+
const CSI_RETURN_RE = /^\u001B\[13;(\d+)[u~]$/;
57+
const CSI_EXTENDED_RETURN_RE = /^\u001B\[27;(\d+);13~$/;
58+
59+
function isReturn(raw: string): boolean {
60+
if (raw === "\r") return true;
61+
if (SHIFT_RETURN_SEQUENCES.has(raw)) return true;
62+
if (META_RETURN_SEQUENCES.has(raw)) return true;
63+
return CSI_RETURN_RE.test(raw) || CSI_EXTENDED_RETURN_RE.test(raw);
64+
}
3065
const META_RETURN_SEQUENCES = new Set(["\u001B[13;3u", "\u001B[13;4u"]);
3166
const CTRL_LEFT_SEQUENCES = new Set(["\u001B[1;5D", "\u001B[5D"]);
3267
const CTRL_RIGHT_SEQUENCES = new Set(["\u001B[1;5C", "\u001B[5C"]);
@@ -113,10 +148,10 @@ export function parseTerminalInput(data: Buffer | string): { input: string; key:
113148
end: END_SEQUENCES.has(raw),
114149
pageDown: raw === "\u001B[6~",
115150
pageUp: raw === "\u001B[5~",
116-
return: raw === "\r" || SHIFT_RETURN_SEQUENCES.has(raw) || META_RETURN_SEQUENCES.has(raw),
151+
return: isReturn(raw),
117152
escape: raw === "\u001B",
118153
ctrl: CTRL_LEFT_SEQUENCES.has(raw) || CTRL_RIGHT_SEQUENCES.has(raw),
119-
shift: SHIFT_RETURN_SEQUENCES.has(raw),
154+
shift: isShiftReturn(raw),
120155
tab: raw === "\t" || raw === "\u001B[Z",
121156
backspace: BACKSPACE_BYTES.has(raw),
122157
delete: FORWARD_DELETE_SEQUENCES.has(raw),
@@ -162,7 +197,7 @@ export function parseTerminalInput(data: Buffer | string): { input: string; key:
162197
key.shift = true;
163198
}
164199

165-
if (key.tab || key.backspace || key.delete) {
200+
if (key.tab || key.backspace || key.delete || key.return) {
166201
input = "";
167202
}
168203

0 commit comments

Comments
 (0)