@oxecli/oxe 1.0.62 → 1.0.64
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/ui.js +53 -14
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -529,6 +529,7 @@ export class Spinner {
|
|
|
529
529
|
render = null;
|
|
530
530
|
enabled;
|
|
531
531
|
lastRendered = "";
|
|
532
|
+
lastLen = 0;
|
|
532
533
|
constructor(enabled = true) {
|
|
533
534
|
this.enabled = enabled;
|
|
534
535
|
}
|
|
@@ -549,6 +550,7 @@ export class Spinner {
|
|
|
549
550
|
this.frame = 0;
|
|
550
551
|
this.rows = 0;
|
|
551
552
|
this.lastRendered = "";
|
|
553
|
+
this.lastLen = 0;
|
|
552
554
|
this.timer = setInterval(() => {
|
|
553
555
|
this.frame++;
|
|
554
556
|
this.draw();
|
|
@@ -570,21 +572,35 @@ export class Spinner {
|
|
|
570
572
|
return;
|
|
571
573
|
this.lastRendered = rendered;
|
|
572
574
|
const newRows = Math.max(1, displayRows(rendered));
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
575
|
+
if (newRows === 1) {
|
|
576
|
+
// Overwrite in place: NEVER erase the whole line (the \x1b[2K erase-to-blank
|
|
577
|
+
// followed by a full redraw is what caused the flicker/flash). We just
|
|
578
|
+
// re-emit from the start; identical glyphs stay put, only the changed
|
|
579
|
+
// cells (spinner frame, trailing timer) actually change on screen. Pad
|
|
580
|
+
// with spaces so a shorter line clears any previously longer text.
|
|
581
|
+
const plain = stripAnsi(rendered);
|
|
582
|
+
const pad = Math.max(0, this.lastLen - plain.length);
|
|
583
|
+
process.stdout.write("\r" + rendered + " ".repeat(pad) + "\r");
|
|
584
|
+
this.lastLen = plain.length;
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
// Multi-row wrapped text: fall back to an erase-based redraw.
|
|
588
|
+
const clearRows = Math.max(this.rows, newRows, 1);
|
|
589
|
+
for (let i = 0; i < clearRows; i++) {
|
|
590
|
+
process.stdout.write("\r\x1b[2K");
|
|
591
|
+
if (i < clearRows - 1)
|
|
592
|
+
process.stdout.write("\n");
|
|
593
|
+
}
|
|
594
|
+
if (clearRows > 1)
|
|
595
|
+
process.stdout.write(`\x1b[${clearRows - 1}A\r`);
|
|
596
|
+
else
|
|
597
|
+
process.stdout.write("\r");
|
|
598
|
+
process.stdout.write(rendered);
|
|
599
|
+
if (newRows > 1)
|
|
600
|
+
process.stdout.write(`\x1b[${newRows - 1}A\r`);
|
|
601
|
+
else
|
|
602
|
+
process.stdout.write("\r");
|
|
578
603
|
}
|
|
579
|
-
if (clearRows > 1)
|
|
580
|
-
process.stdout.write(`\x1b[${clearRows - 1}A\r`);
|
|
581
|
-
else
|
|
582
|
-
process.stdout.write("\r");
|
|
583
|
-
process.stdout.write(rendered);
|
|
584
|
-
if (newRows > 1)
|
|
585
|
-
process.stdout.write(`\x1b[${newRows - 1}A\r`);
|
|
586
|
-
else
|
|
587
|
-
process.stdout.write("\r");
|
|
588
604
|
this.rows = newRows;
|
|
589
605
|
}
|
|
590
606
|
stop() {
|
|
@@ -949,6 +965,10 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
949
965
|
let bracketedPasteBuffer = "";
|
|
950
966
|
let pasteBurst = false;
|
|
951
967
|
let pasteBurstTimer = null;
|
|
968
|
+
// Accumulator for modifier-prefixed CSI sequences (e.g. Shift+Enter sent as
|
|
969
|
+
// `\x1b[27;2;13~`), which Node's readline splits into several keypress
|
|
970
|
+
// events instead of one, so they must be reassembled here.
|
|
971
|
+
let modSeq = "";
|
|
952
972
|
readline.emitKeypressEvents(process.stdin);
|
|
953
973
|
if (process.stdin.isTTY) {
|
|
954
974
|
process.stdin.setRawMode(true);
|
|
@@ -1297,6 +1317,25 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1297
1317
|
}, 500);
|
|
1298
1318
|
};
|
|
1299
1319
|
const onKeypress = (str, key) => {
|
|
1320
|
+
// Reassemble a modifier-prefixed CSI sequence that readline splits up,
|
|
1321
|
+
// e.g. Shift+Enter arriving as `\x1b[27;2;` + "1" + "3" + "~".
|
|
1322
|
+
if (key?.sequence === "\x1b[27;2;") {
|
|
1323
|
+
modSeq = "\x1b[27;2;";
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
if (modSeq) {
|
|
1327
|
+
modSeq += str || key?.sequence || "";
|
|
1328
|
+
if (modSeq.endsWith("~")) {
|
|
1329
|
+
const full = modSeq;
|
|
1330
|
+
modSeq = "";
|
|
1331
|
+
// `\x1b[27;2;13~` is Shift+Enter (modifier 2 = shift, key 13 = Enter).
|
|
1332
|
+
if (full === "\x1b[27;2;13~") {
|
|
1333
|
+
insert("\n");
|
|
1334
|
+
repaint();
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1300
1339
|
if (consumeBracketedPaste(str, key))
|
|
1301
1340
|
return;
|
|
1302
1341
|
if (pasteBurst && str && str.length === 1 && !key?.ctrl && !key?.meta) {
|