@oxecli/oxe 1.0.63 → 1.0.65

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.
Files changed (2) hide show
  1. package/dist/ui.js +56 -8
  2. package/package.json +1 -1
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[>1u");
12
+ process.stdout.write("\x1b[<u\x1b[>1u");
13
13
  }
14
14
  process.stdin.resume();
15
15
  hideCursor();
@@ -902,10 +902,37 @@ export function renderBufferWithCursor(buffer, pasteSpans, prefix, label, cursor
902
902
  const totalRows = body.length + 2;
903
903
  return { frame, cursorRow, cursorCol, totalRows };
904
904
  }
905
+ /**
906
+ * Generic CSI Shift+Enter detection. The modifier encoding used by CSI-u,
907
+ * legacy and kitty/modifyOtherKeys is a bitmask + 1, where Shift is bit0
908
+ * (so modifier 2 = shift, 4 = shift+alt, 6 = shift+ctrl, ...). Enter has
909
+ * key code 13. Handles:
910
+ * CSI-u / legacy: ESC [ 13 ; M u and ESC [ 13 ; M ~
911
+ * modifyOtherKeys: ESC [ 27 ; M ; 13 ~
912
+ * application: ESC O M
913
+ */
914
+ function csiShiftEnter(seq) {
915
+ if (seq === "\x1bOM")
916
+ return true;
917
+ // modifyOtherKeys: ESC [ 27 ; M ; 13 ~
918
+ const mod = seq.match(/^\x1b\[27;(\d+);13[~_]$/);
919
+ if (mod) {
920
+ const m = parseInt(mod[1], 10);
921
+ return Number.isInteger(m) && ((m - 1) & 1) === 1;
922
+ }
923
+ // CSI-u / legacy: ESC [ 13 ; M u (or ~ or _)
924
+ const csi = seq.match(/^\x1b\[13;(\d+)[~u_]$/);
925
+ if (csi) {
926
+ const m = parseInt(csi[1], 10);
927
+ return Number.isInteger(m) && ((m - 1) & 1) === 1;
928
+ }
929
+ return false;
930
+ }
905
931
  export function isShiftEnterKey(str, key) {
906
932
  if (!key)
907
933
  return false;
908
934
  const seq = key.sequence || str || "";
935
+ // Shift modifier reported by readline on a return/enter/linefeed key.
909
936
  if (key.shift &&
910
937
  (key.name === "return" ||
911
938
  key.name === "enter" ||
@@ -914,13 +941,8 @@ export function isShiftEnterKey(str, key) {
914
941
  seq === "\n")) {
915
942
  return true;
916
943
  }
917
- if (seq === "\x1b[13;2u" ||
918
- seq === "\x1b[13;2~" ||
919
- seq === "\x1b[13;2_" ||
920
- seq === "\x1b[27;2;13~" ||
921
- seq === "\x1bOM") {
944
+ if (csiShiftEnter(seq))
922
945
  return true;
923
- }
924
946
  return false;
925
947
  }
926
948
  export const isNewlineKey = isShiftEnterKey;
@@ -965,11 +987,18 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
965
987
  let bracketedPasteBuffer = "";
966
988
  let pasteBurst = false;
967
989
  let pasteBurstTimer = null;
990
+ // Accumulator for modifier-prefixed CSI sequences (e.g. Shift+Enter sent as
991
+ // `\x1b[27;2;13~`), which Node's readline splits into several keypress
992
+ // events instead of one, so they must be reassembled here.
993
+ let modSeq = "";
968
994
  readline.emitKeypressEvents(process.stdin);
969
995
  if (process.stdin.isTTY) {
970
996
  process.stdin.setRawMode(true);
971
997
  process.stdout.write("\x1b[?2004h");
972
- process.stdout.write("\x1b[>1u");
998
+ // Enable CSI-u "disambiguate" so the terminal reports Shift+Enter as a
999
+ // distinct code (`ESC [ 13 ; 2 u`) instead of collapsing it into a plain
1000
+ // Enter. Pop any prior mode, then push flags=1 (disambiguate).
1001
+ process.stdout.write("\x1b[<u\x1b[>1u");
973
1002
  }
974
1003
  process.stdin.resume();
975
1004
  hideCursor();
@@ -1313,6 +1342,25 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
1313
1342
  }, 500);
1314
1343
  };
1315
1344
  const onKeypress = (str, key) => {
1345
+ // Reassemble a modifier-prefixed CSI sequence that readline splits up,
1346
+ // e.g. Shift+Enter arriving as `\x1b[27;2;` + "1" + "3" + "~".
1347
+ if (key?.sequence === "\x1b[27;" || key?.sequence === "\x1b[27;2;") {
1348
+ modSeq = key.sequence;
1349
+ return;
1350
+ }
1351
+ if (modSeq) {
1352
+ modSeq += str || key?.sequence || "";
1353
+ if (/[~u_]/.test(modSeq.slice(-1)) || modSeq.endsWith("~")) {
1354
+ const full = modSeq;
1355
+ modSeq = "";
1356
+ // e.g. `\x1b[27;2;13~` = Shift+Enter.
1357
+ if (csiShiftEnter(full)) {
1358
+ insert("\n");
1359
+ repaint();
1360
+ }
1361
+ }
1362
+ return;
1363
+ }
1316
1364
  if (consumeBracketedPaste(str, key))
1317
1365
  return;
1318
1366
  if (pasteBurst && str && str.length === 1 && !key?.ctrl && !key?.meta) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxecli/oxe",
3
- "version": "1.0.63",
3
+ "version": "1.0.65",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },