@oxecli/oxe 1.0.65 → 1.0.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +5 -4
- package/dist/tools.js +16 -6
- package/dist/ui.js +277 -35
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -466,7 +466,10 @@ export class CLI {
|
|
|
466
466
|
this.story[this.story.length - 1]["type"] === "user") {
|
|
467
467
|
this.story.pop();
|
|
468
468
|
}
|
|
469
|
-
|
|
469
|
+
// Exit cleanly on: a second Ctrl+C, or a first Ctrl+C while idle
|
|
470
|
+
// (no active query). Only an in-flight query's first Ctrl+C keeps
|
|
471
|
+
// running so the agent can be interrupted without a stray key exiting.
|
|
472
|
+
if (this.interruptPending || !wasActive) {
|
|
470
473
|
this.saveSession(engine);
|
|
471
474
|
await engine.cleanupStoredResponses();
|
|
472
475
|
process.stdout.write("\nClosing terminal session. Goodbye!\n\n");
|
|
@@ -474,9 +477,7 @@ export class CLI {
|
|
|
474
477
|
}
|
|
475
478
|
this.interruptPending = true;
|
|
476
479
|
process.stdout.write("\n");
|
|
477
|
-
process.stdout.write(
|
|
478
|
-
? "\x1b[2mInterrupted agent. Press Ctrl+C again to exit, or type a new prompt.\x1b[0m\n"
|
|
479
|
-
: "\x1b[2mNo active query. Press Ctrl+C again to exit.\x1b[0m\n");
|
|
480
|
+
process.stdout.write("\x1b[2mInterrupted agent. Press Ctrl+C again to exit, or type a new prompt.\x1b[0m\n");
|
|
480
481
|
continue;
|
|
481
482
|
}
|
|
482
483
|
throw err;
|
package/dist/tools.js
CHANGED
|
@@ -72,9 +72,12 @@ function displayDiff(pathName, oldContent, newContent) {
|
|
|
72
72
|
const limit = kind === " " ? max_diff_context_lines : max_diff_lines;
|
|
73
73
|
const hidden = run.length - limit;
|
|
74
74
|
for (const r of run.slice(0, limit))
|
|
75
|
-
shown.push(truncateDiffLine(r.line));
|
|
75
|
+
shown.push({ kind, line: truncateDiffLine(r.line) });
|
|
76
76
|
if (hidden > 0) {
|
|
77
|
-
shown.push(
|
|
77
|
+
shown.push({
|
|
78
|
+
kind: "~",
|
|
79
|
+
line: `… (${hidden} ${hidden === 1 ? "line" : "lines"} of diff hidden) …`,
|
|
80
|
+
});
|
|
78
81
|
}
|
|
79
82
|
run = [];
|
|
80
83
|
};
|
|
@@ -87,9 +90,12 @@ function displayDiff(pathName, oldContent, newContent) {
|
|
|
87
90
|
}
|
|
88
91
|
flush();
|
|
89
92
|
// Build the lines, stripping the leading + / - / space marker for display.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
// Summary lines ("~") are already plain text and are kept whole.
|
|
94
|
+
const visible = shown.map(({ kind, line }) => {
|
|
95
|
+
if (kind === "~")
|
|
96
|
+
return { kind, body: line };
|
|
97
|
+
const k = line[0] === "+" ? "+" : line[0] === "-" ? "-" : " ";
|
|
98
|
+
return { kind: k, body: line.slice(1) };
|
|
93
99
|
});
|
|
94
100
|
// A "… (N lines hidden) …" summary line is neutral context.
|
|
95
101
|
const termW = terminalWidth();
|
|
@@ -110,7 +116,11 @@ function displayDiff(pathName, oldContent, newContent) {
|
|
|
110
116
|
pendingDiffOutput.push(`\x1b[90m${top}\x1b[0m`);
|
|
111
117
|
for (const v of visible) {
|
|
112
118
|
let line;
|
|
113
|
-
if (v.kind === "
|
|
119
|
+
if (v.kind === "~") {
|
|
120
|
+
const body = truncateStyled(v.body, innerW - 2);
|
|
121
|
+
line = `\x1b[2m ${body}\x1b[0m`;
|
|
122
|
+
}
|
|
123
|
+
else if (v.kind === "+") {
|
|
114
124
|
const body = truncateStyled(v.body, innerW - 2);
|
|
115
125
|
line = `\x1b[32m+ ${body}\x1b[0m`;
|
|
116
126
|
}
|
package/dist/ui.js
CHANGED
|
@@ -9,7 +9,7 @@ export function enableRawStdin() {
|
|
|
9
9
|
readline.emitKeypressEvents(process.stdin);
|
|
10
10
|
if (process.stdin.isTTY) {
|
|
11
11
|
process.stdin.setRawMode(true);
|
|
12
|
-
process.stdout.write("\x1b[
|
|
12
|
+
process.stdout.write("\x1b[?9001h\x1b[>1u");
|
|
13
13
|
}
|
|
14
14
|
process.stdin.resume();
|
|
15
15
|
hideCursor();
|
|
@@ -259,7 +259,7 @@ export function markdownToAnsi(text) {
|
|
|
259
259
|
const highlighted = highlightCodeLine(cline, codeLang);
|
|
260
260
|
out.push(`\x1b[90m│\x1b[0m ${highlighted}`);
|
|
261
261
|
}
|
|
262
|
-
out.push(`\x1b[90m╰${"─".repeat(barLen + plainLen(badge) +
|
|
262
|
+
out.push(`\x1b[90m╰${"─".repeat(barLen + plainLen(badge) + 1)}╯\x1b[0m`);
|
|
263
263
|
codeBuffer = [];
|
|
264
264
|
codeLang = "";
|
|
265
265
|
};
|
|
@@ -911,27 +911,63 @@ export function renderBufferWithCursor(buffer, pasteSpans, prefix, label, cursor
|
|
|
911
911
|
* modifyOtherKeys: ESC [ 27 ; M ; 13 ~
|
|
912
912
|
* application: ESC O M
|
|
913
913
|
*/
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
914
|
+
/**
|
|
915
|
+
* Parses a complete (reassembled) escape-sequence encoding of Enter and
|
|
916
|
+
* classifies it as a newline (Shift+Enter) or a submit (plain Enter).
|
|
917
|
+
*
|
|
918
|
+
* Return values:
|
|
919
|
+
* "newline" — Shift+Enter (insert a new row)
|
|
920
|
+
* "submit" — plain Enter (submit the prompt)
|
|
921
|
+
* null — not an Enter sequence
|
|
922
|
+
*
|
|
923
|
+
* Handles every encoding a terminal can produce:
|
|
924
|
+
* CSI-u: ESC [ 13 ; M u (M = xterm bitmask + 1)
|
|
925
|
+
* legacy / kitty: ESC [ 13 ; M ~ / ESC [ 13 ; M _
|
|
926
|
+
* modifyOtherKeys: ESC [ 27 ; M ; 13 ~
|
|
927
|
+
* application (SS3): ESC O M
|
|
928
|
+
* win32-input-mode: ESC [ G ; R ; C ; VK ; MOD u
|
|
929
|
+
* (VK = 13 for Enter, MOD = raw bitmask where
|
|
930
|
+
* bit0 = Shift)
|
|
931
|
+
*/
|
|
932
|
+
function parseEnterSequence(seq) {
|
|
933
|
+
if (!seq)
|
|
934
|
+
return null;
|
|
935
|
+
// win32-input-mode: ESC [ guard ; row ; col ; vk ; mod u
|
|
936
|
+
let m = seq.match(/^\x1b\[(\d+);(\d+);(\d+);(\d+);(\d+)u$/);
|
|
937
|
+
if (m) {
|
|
938
|
+
const vk = parseInt(m[4], 10);
|
|
939
|
+
if (vk !== 13)
|
|
940
|
+
return null;
|
|
941
|
+
const mod = parseInt(m[5], 10);
|
|
942
|
+
return mod & 1 ? "newline" : "submit";
|
|
922
943
|
}
|
|
923
|
-
//
|
|
924
|
-
|
|
925
|
-
if (
|
|
926
|
-
const
|
|
927
|
-
|
|
944
|
+
// modifyOtherKeys / kitty: ESC [ 27 ; M ; 13 ~ (or _)
|
|
945
|
+
m = seq.match(/^\x1b\[27;(\d+);13[~_]$/);
|
|
946
|
+
if (m) {
|
|
947
|
+
const mod = parseInt(m[1], 10);
|
|
948
|
+
if (mod > 0)
|
|
949
|
+
return (mod - 1) & 1 ? "newline" : "submit";
|
|
950
|
+
return null;
|
|
928
951
|
}
|
|
929
|
-
|
|
952
|
+
// CSI-u / legacy: ESC [ 13 ; M u (or ~ or _)
|
|
953
|
+
m = seq.match(/^\x1b\[13;(\d+)[~u_]$/);
|
|
954
|
+
if (m) {
|
|
955
|
+
const mod = parseInt(m[1], 10);
|
|
956
|
+
if (mod > 0)
|
|
957
|
+
return (mod - 1) & 1 ? "newline" : "submit";
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
// Application keypad Enter (SS3)
|
|
961
|
+
if (seq === "\x1bOM")
|
|
962
|
+
return "newline";
|
|
963
|
+
return null;
|
|
930
964
|
}
|
|
931
965
|
export function isShiftEnterKey(str, key) {
|
|
932
966
|
if (!key)
|
|
933
967
|
return false;
|
|
934
968
|
const seq = key.sequence || str || "";
|
|
969
|
+
if (parseEnterSequence(seq) === "newline")
|
|
970
|
+
return true;
|
|
935
971
|
// Shift modifier reported by readline on a return/enter/linefeed key.
|
|
936
972
|
if (key.shift &&
|
|
937
973
|
(key.name === "return" ||
|
|
@@ -941,8 +977,6 @@ export function isShiftEnterKey(str, key) {
|
|
|
941
977
|
seq === "\n")) {
|
|
942
978
|
return true;
|
|
943
979
|
}
|
|
944
|
-
if (csiShiftEnter(seq))
|
|
945
|
-
return true;
|
|
946
980
|
return false;
|
|
947
981
|
}
|
|
948
982
|
export const isNewlineKey = isShiftEnterKey;
|
|
@@ -952,6 +986,8 @@ export function isSubmitEnterKey(str, key) {
|
|
|
952
986
|
if (isShiftEnterKey(str, key))
|
|
953
987
|
return false;
|
|
954
988
|
const seq = key.sequence || str || "";
|
|
989
|
+
if (parseEnterSequence(seq) === "submit")
|
|
990
|
+
return true;
|
|
955
991
|
if ((key.name === "return" ||
|
|
956
992
|
seq === "\r" ||
|
|
957
993
|
seq === "\x1b[13u" ||
|
|
@@ -961,6 +997,115 @@ export function isSubmitEnterKey(str, key) {
|
|
|
961
997
|
}
|
|
962
998
|
return false;
|
|
963
999
|
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Maps a Windows virtual-key code + shift state to a printable character, or
|
|
1002
|
+
* null if the code isn't a printable character. US-layout approximation (the
|
|
1003
|
+
* common case); enough for a text prompt.
|
|
1004
|
+
*/
|
|
1005
|
+
function vkToChar(vk, shift) {
|
|
1006
|
+
if (vk >= 48 && vk <= 57) {
|
|
1007
|
+
const symbols = [")", "!", "@", "#", "$", "%", "^", "&", "*", "("];
|
|
1008
|
+
return shift ? symbols[vk - 48] : String(vk - 48);
|
|
1009
|
+
}
|
|
1010
|
+
if (vk >= 65 && vk <= 90) {
|
|
1011
|
+
return shift ? String.fromCharCode(vk) : String.fromCharCode(vk).toLowerCase();
|
|
1012
|
+
}
|
|
1013
|
+
if (vk === 186)
|
|
1014
|
+
return shift ? ":" : ";";
|
|
1015
|
+
if (vk === 187)
|
|
1016
|
+
return shift ? "+" : "=";
|
|
1017
|
+
if (vk === 188)
|
|
1018
|
+
return shift ? "<" : ",";
|
|
1019
|
+
if (vk === 189)
|
|
1020
|
+
return shift ? "_" : "-";
|
|
1021
|
+
if (vk === 190)
|
|
1022
|
+
return shift ? ">" : ".";
|
|
1023
|
+
if (vk === 191)
|
|
1024
|
+
return shift ? "?" : "/";
|
|
1025
|
+
if (vk === 192)
|
|
1026
|
+
return shift ? "~" : "`";
|
|
1027
|
+
if (vk === 219)
|
|
1028
|
+
return shift ? "{" : "[";
|
|
1029
|
+
if (vk === 220)
|
|
1030
|
+
return shift ? "|" : "\\";
|
|
1031
|
+
if (vk === 221)
|
|
1032
|
+
return shift ? "}" : "]";
|
|
1033
|
+
if (vk === 222)
|
|
1034
|
+
return shift ? '"' : "'";
|
|
1035
|
+
return null;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Decodes a complete win32-input-mode sequence (ESC [ G ; R ; C ; VK ; MOD u)
|
|
1039
|
+
* into a key action. Returns a descriptor for the prompt to execute, or null
|
|
1040
|
+
* if the sequence isn't a win32-input-mode sequence.
|
|
1041
|
+
*/
|
|
1042
|
+
function decodeWin32Key(seq) {
|
|
1043
|
+
const m = seq.match(/^\x1b\[(\d+);(\d+);(\d+);(\d+);(\d+)u$/);
|
|
1044
|
+
if (!m)
|
|
1045
|
+
return null;
|
|
1046
|
+
const vk = parseInt(m[4], 10);
|
|
1047
|
+
const mod = parseInt(m[5], 10);
|
|
1048
|
+
const shift = (mod & 1) === 1;
|
|
1049
|
+
const ctrl = (mod & 4) === 4;
|
|
1050
|
+
const alt = (mod & 2) === 2;
|
|
1051
|
+
const cmd = (c) => ({ type: "cmd", cmd: c });
|
|
1052
|
+
const text = (t) => ({ type: "text", text: t });
|
|
1053
|
+
// Control combos
|
|
1054
|
+
if (ctrl && vk === 67)
|
|
1055
|
+
return cmd("interrupt"); // Ctrl+C
|
|
1056
|
+
if (ctrl && vk === 68)
|
|
1057
|
+
return cmd("eof"); // Ctrl+D
|
|
1058
|
+
if (ctrl && vk === 90)
|
|
1059
|
+
return cmd("eof"); // Ctrl+Z
|
|
1060
|
+
if (ctrl && vk === 65)
|
|
1061
|
+
return cmd("home"); // Ctrl+A
|
|
1062
|
+
if (ctrl && vk === 69)
|
|
1063
|
+
return cmd("end"); // Ctrl+E
|
|
1064
|
+
if (ctrl && vk === 85)
|
|
1065
|
+
return cmd("clear-line"); // Ctrl+U
|
|
1066
|
+
if (ctrl && vk === 75)
|
|
1067
|
+
return cmd("kill-line"); // Ctrl+K
|
|
1068
|
+
if (ctrl && vk === 87)
|
|
1069
|
+
return cmd("delete-word"); // Ctrl+W
|
|
1070
|
+
switch (vk) {
|
|
1071
|
+
case 13: // Enter
|
|
1072
|
+
return shift ? cmd("newline") : cmd("submit");
|
|
1073
|
+
case 8: // Backspace
|
|
1074
|
+
return cmd(ctrl ? "delete-word" : "backspace");
|
|
1075
|
+
case 46: // Delete
|
|
1076
|
+
return cmd("delete");
|
|
1077
|
+
case 37: // Left
|
|
1078
|
+
return ctrl ? cmd("back-word") : cmd("left");
|
|
1079
|
+
case 39: // Right
|
|
1080
|
+
return ctrl ? cmd("forward-word") : cmd("right");
|
|
1081
|
+
case 38: // Up
|
|
1082
|
+
return cmd("up");
|
|
1083
|
+
case 40: // Down
|
|
1084
|
+
return cmd("down");
|
|
1085
|
+
case 36: // Home
|
|
1086
|
+
return cmd("home");
|
|
1087
|
+
case 35: // End
|
|
1088
|
+
return cmd("end");
|
|
1089
|
+
case 33: // PageUp
|
|
1090
|
+
return cmd("up");
|
|
1091
|
+
case 34: // PageDown
|
|
1092
|
+
return cmd("down");
|
|
1093
|
+
case 9: // Tab
|
|
1094
|
+
return cmd("tab");
|
|
1095
|
+
case 32: // Space
|
|
1096
|
+
return text(" ");
|
|
1097
|
+
case 27: // Escape
|
|
1098
|
+
return cmd("escape");
|
|
1099
|
+
default: {
|
|
1100
|
+
if (alt)
|
|
1101
|
+
return null; // Alt combos unsupported -> ignore
|
|
1102
|
+
const ch = vkToChar(vk, shift);
|
|
1103
|
+
if (ch)
|
|
1104
|
+
return text(ch);
|
|
1105
|
+
return cmd("ignore");
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
964
1109
|
export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
965
1110
|
return new Promise((resolve, reject) => {
|
|
966
1111
|
const isTTY = process.stdin.isTTY;
|
|
@@ -995,10 +1140,10 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
995
1140
|
if (process.stdin.isTTY) {
|
|
996
1141
|
process.stdin.setRawMode(true);
|
|
997
1142
|
process.stdout.write("\x1b[?2004h");
|
|
998
|
-
// Enable
|
|
999
|
-
//
|
|
1000
|
-
// Enter.
|
|
1001
|
-
process.stdout.write("\x1b[
|
|
1143
|
+
// Enable win32-input-mode (preferred by Windows Terminal) and CSI-u
|
|
1144
|
+
// disambiguation so Shift+Enter arrives as a distinct code instead of a
|
|
1145
|
+
// plain Enter. Harmless if a terminal doesn't support them.
|
|
1146
|
+
process.stdout.write("\x1b[?9001h\x1b[>1u");
|
|
1002
1147
|
}
|
|
1003
1148
|
process.stdin.resume();
|
|
1004
1149
|
hideCursor();
|
|
@@ -1021,13 +1166,14 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1021
1166
|
if (done)
|
|
1022
1167
|
return;
|
|
1023
1168
|
done = true;
|
|
1024
|
-
process.stdout.write("\x1b[?2004l");
|
|
1169
|
+
process.stdout.write("\x1b[?2004l\x1b[?9001l");
|
|
1025
1170
|
process.stdin.setRawMode(false);
|
|
1026
1171
|
if (pasteBurstTimer)
|
|
1027
1172
|
clearTimeout(pasteBurstTimer);
|
|
1028
1173
|
clearBox();
|
|
1029
1174
|
process.stdin.removeListener("keypress", onKeypress);
|
|
1030
1175
|
process.stdin.pause();
|
|
1176
|
+
showCursor();
|
|
1031
1177
|
if (isErr)
|
|
1032
1178
|
reject(value);
|
|
1033
1179
|
else
|
|
@@ -1341,26 +1487,122 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1341
1487
|
pasteBurstTimer = null;
|
|
1342
1488
|
}, 500);
|
|
1343
1489
|
};
|
|
1344
|
-
const
|
|
1345
|
-
//
|
|
1346
|
-
|
|
1347
|
-
if (
|
|
1348
|
-
|
|
1490
|
+
const handleRawSequence = (full) => {
|
|
1491
|
+
// Enter sequences (CSI-u, kitty, legacy, SS3, win32).
|
|
1492
|
+
const enter = parseEnterSequence(full);
|
|
1493
|
+
if (enter === "newline") {
|
|
1494
|
+
insert("\n");
|
|
1495
|
+
repaint();
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
if (enter === "submit") {
|
|
1499
|
+
if (buffer.trim())
|
|
1500
|
+
settle([buffer, pasteSpans], false);
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
// Other win32-input-mode keys (arrows, backspace, etc.).
|
|
1504
|
+
const dec = decodeWin32Key(full);
|
|
1505
|
+
if (!dec)
|
|
1506
|
+
return;
|
|
1507
|
+
if (dec.type === "text") {
|
|
1508
|
+
insert(dec.text);
|
|
1509
|
+
repaint();
|
|
1349
1510
|
return;
|
|
1350
1511
|
}
|
|
1512
|
+
switch (dec.cmd) {
|
|
1513
|
+
case "interrupt":
|
|
1514
|
+
settle(new Error("interrupt"), true);
|
|
1515
|
+
return;
|
|
1516
|
+
case "eof":
|
|
1517
|
+
settle(new Error("eof"), true);
|
|
1518
|
+
return;
|
|
1519
|
+
case "backspace":
|
|
1520
|
+
backspace();
|
|
1521
|
+
repaint();
|
|
1522
|
+
return;
|
|
1523
|
+
case "delete-word":
|
|
1524
|
+
deleteWordBefore();
|
|
1525
|
+
repaint();
|
|
1526
|
+
return;
|
|
1527
|
+
case "delete":
|
|
1528
|
+
deleteChar();
|
|
1529
|
+
repaint();
|
|
1530
|
+
return;
|
|
1531
|
+
case "left":
|
|
1532
|
+
moveLeft();
|
|
1533
|
+
repaint();
|
|
1534
|
+
return;
|
|
1535
|
+
case "right":
|
|
1536
|
+
moveRight();
|
|
1537
|
+
repaint();
|
|
1538
|
+
return;
|
|
1539
|
+
case "back-word": {
|
|
1540
|
+
const sp = buffer.slice(0, cursor).lastIndexOf(" ");
|
|
1541
|
+
cursor = sp === -1 ? 0 : sp + 1;
|
|
1542
|
+
repaint();
|
|
1543
|
+
return;
|
|
1544
|
+
}
|
|
1545
|
+
case "forward-word": {
|
|
1546
|
+
const sp = buffer.indexOf(" ", cursor);
|
|
1547
|
+
cursor = sp === -1 ? buffer.length : sp + 1;
|
|
1548
|
+
repaint();
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
case "up":
|
|
1552
|
+
moveUp();
|
|
1553
|
+
repaint();
|
|
1554
|
+
return;
|
|
1555
|
+
case "down":
|
|
1556
|
+
moveDown();
|
|
1557
|
+
repaint();
|
|
1558
|
+
return;
|
|
1559
|
+
case "home":
|
|
1560
|
+
cursor = 0;
|
|
1561
|
+
repaint();
|
|
1562
|
+
return;
|
|
1563
|
+
case "end":
|
|
1564
|
+
cursor = buffer.length;
|
|
1565
|
+
repaint();
|
|
1566
|
+
return;
|
|
1567
|
+
case "tab":
|
|
1568
|
+
insert(" ");
|
|
1569
|
+
repaint();
|
|
1570
|
+
return;
|
|
1571
|
+
case "clear-line":
|
|
1572
|
+
buffer = "";
|
|
1573
|
+
cursor = 0;
|
|
1574
|
+
pasteSpans = [];
|
|
1575
|
+
repaint();
|
|
1576
|
+
return;
|
|
1577
|
+
case "kill-line":
|
|
1578
|
+
buffer = buffer.slice(0, cursor);
|
|
1579
|
+
repaint();
|
|
1580
|
+
return;
|
|
1581
|
+
default:
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
const onKeypress = (str, key) => {
|
|
1586
|
+
// Reassemble modifier-prefixed / win32-input-mode CSI sequences, which
|
|
1587
|
+
// Node's readline splits into several keypress events (e.g. Shift+Enter
|
|
1588
|
+
// arriving as `\x1b[27;2;` + "1" + "3" + "~", or a win32-input-mode
|
|
1589
|
+
// sequence `\x1b[0;1;1;13;2u` arriving piecemeal). A "partial CSI" is
|
|
1590
|
+
// any ESC [ sequence readline left unterminated; we keep appending until
|
|
1591
|
+
// it ends in a terminator, then classify it.
|
|
1592
|
+
const seq = key?.sequence || str || "";
|
|
1351
1593
|
if (modSeq) {
|
|
1352
|
-
modSeq += str ||
|
|
1353
|
-
if (
|
|
1594
|
+
modSeq += str || seq || "";
|
|
1595
|
+
if (/^\x1b\[[\d;]*[a-zA-Z~_u]$/.test(modSeq)) {
|
|
1354
1596
|
const full = modSeq;
|
|
1355
1597
|
modSeq = "";
|
|
1356
|
-
|
|
1357
|
-
if (csiShiftEnter(full)) {
|
|
1358
|
-
insert("\n");
|
|
1359
|
-
repaint();
|
|
1360
|
-
}
|
|
1598
|
+
handleRawSequence(full);
|
|
1361
1599
|
}
|
|
1362
1600
|
return;
|
|
1363
1601
|
}
|
|
1602
|
+
if (/^\x1b\[[\d;]*$/.test(seq)) {
|
|
1603
|
+
modSeq = seq;
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1364
1606
|
if (consumeBracketedPaste(str, key))
|
|
1365
1607
|
return;
|
|
1366
1608
|
if (pasteBurst && str && str.length === 1 && !key?.ctrl && !key?.meta) {
|