@hackerrank/astra-cli 0.1.33 → 0.1.34
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/package.json +1 -1
- package/src/repl.js +41 -35
package/package.json
CHANGED
package/src/repl.js
CHANGED
|
@@ -301,6 +301,7 @@ export class Screen {
|
|
|
301
301
|
this._busyResume = false;
|
|
302
302
|
this._prevScrollBottom = 0;
|
|
303
303
|
this._prevFooterTop = 0;
|
|
304
|
+
this._renderedRows = new Map();
|
|
304
305
|
this._inPaste = false;
|
|
305
306
|
this.promptLabel = PROMPT_PREFIX;
|
|
306
307
|
this._onData = this._onData.bind(this);
|
|
@@ -343,6 +344,7 @@ export class Screen {
|
|
|
343
344
|
this.out.off("resize", this._onResize);
|
|
344
345
|
if (this.inp.isTTY) this.inp.setRawMode(false);
|
|
345
346
|
this.out.write("\x1b[?2004l"); // disable bracketed paste mode
|
|
347
|
+
this.out.write("\x1b[?25h"); // ensure the cursor is restored on exit
|
|
346
348
|
this.out.write("\x1b[r"); // reset scroll region
|
|
347
349
|
this.out.write(`\x1b[${this.rows};1H\n`); // move below footer
|
|
348
350
|
}
|
|
@@ -369,61 +371,63 @@ export class Screen {
|
|
|
369
371
|
|
|
370
372
|
/** Unified redraw of footer divider, multi-line prompt, and status lines without overwriting. */
|
|
371
373
|
redraw() {
|
|
372
|
-
|
|
374
|
+
const scrollChanged = this._prevScrollBottom !== this.scrollBottom;
|
|
375
|
+
if (scrollChanged) {
|
|
373
376
|
this.out.write(`\x1b[1;${this.scrollBottom}r`);
|
|
374
377
|
this._prevScrollBottom = this.scrollBottom;
|
|
378
|
+
// Prompt wrapping can move the footer. Clear the old pinned region once;
|
|
379
|
+
// ordinary input and spinner frames use the row diff below instead.
|
|
380
|
+
if (this._prevFooterTop && this._prevFooterTop !== this.footerTop) {
|
|
381
|
+
for (let row = this._prevFooterTop; row <= this.rows; row++) {
|
|
382
|
+
this.out.write(`\x1b[${row};1H\x1b[2K`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
this._prevFooterTop = this.footerTop;
|
|
386
|
+
// A resize or prompt-height change moves pinned rows. Their old
|
|
387
|
+
// coordinates are no longer meaningful, so repaint them once.
|
|
388
|
+
this._renderedRows.clear();
|
|
375
389
|
}
|
|
376
390
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
this.out.write(`\x1b[${r};1H\x1b[2K`);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Draw top divider rule at footerTop
|
|
385
|
-
this.out.write(`\x1b[${this.footerTop};1H`);
|
|
386
|
-
this.out.write(this.footer[0] || "");
|
|
391
|
+
const rows = new Map();
|
|
392
|
+
const put = (row, text) => {
|
|
393
|
+
if (row >= 1 && row <= this.rows) rows.set(row, text || "");
|
|
394
|
+
};
|
|
387
395
|
|
|
388
|
-
|
|
389
|
-
// transition from moving the input or status rows and causing terminal flicker.
|
|
396
|
+
put(this.footerTop, this.footer[0]);
|
|
390
397
|
if (this._busy) {
|
|
391
|
-
this.out.write(`\x1b[${this.loaderRow};1H`);
|
|
392
398
|
const frame = SPINNER_FRAMES[this._busyFrame % SPINNER_FRAMES.length];
|
|
393
|
-
this.
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Draw the input below the reserved loader row.
|
|
397
|
-
if (!this._busy) {
|
|
399
|
+
put(this.loaderRow, C.cyan(frame + " ") + C.dim(this._busyLabel + "…"));
|
|
400
|
+
} else {
|
|
398
401
|
const visual = computeVisualLines(this.buf, this.promptLabel || PROMPT_PREFIX, this.cols);
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
const row = this.promptRow + i;
|
|
402
|
-
this.out.write(`\x1b[${row};1H`);
|
|
403
|
-
this.out.write(visibleLines[i].text);
|
|
402
|
+
for (const [i, line] of visual.slice(-this.promptLines).entries()) {
|
|
403
|
+
put(this.promptRow + i, line.text);
|
|
404
404
|
}
|
|
405
405
|
}
|
|
406
|
-
|
|
407
|
-
// Draw status lines below the prompt
|
|
408
406
|
for (let i = 1; i < FOOTER_LINES; i++) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
407
|
+
put(this.statusStartRow + i - 1, this.footer[i]);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Update only changed rows. Clearing a row before immediately redrawing it
|
|
411
|
+
// caused a visible blank frame on every keystroke and spinner tick.
|
|
412
|
+
const changed = new Set([...this._renderedRows.keys(), ...rows.keys()]);
|
|
413
|
+
let output = "";
|
|
414
|
+
for (const row of [...changed].sort((a, b) => a - b)) {
|
|
415
|
+
const next = rows.get(row) || "";
|
|
416
|
+
if (this._renderedRows.get(row) !== next) {
|
|
417
|
+
output += `\x1b[${row};1H\x1b[2K${next}`;
|
|
413
418
|
}
|
|
414
419
|
}
|
|
420
|
+
this._renderedRows = rows;
|
|
415
421
|
|
|
416
|
-
// Place cursor at the end of input
|
|
417
422
|
if (!this._busy) {
|
|
418
423
|
const visual = computeVisualLines(this.buf, this.promptLabel || PROMPT_PREFIX, this.cols);
|
|
419
424
|
const visibleLines = visual.slice(-this.promptLines);
|
|
420
425
|
const lastLine = visibleLines[visibleLines.length - 1] || { visibleLength: 0 };
|
|
421
|
-
const cursorRow = this.promptRow +
|
|
426
|
+
const cursorRow = this.promptRow + visibleLines.length - 1;
|
|
422
427
|
const cursorCol = Math.min(this.cols, lastLine.visibleLength + 1);
|
|
423
|
-
|
|
424
|
-
} else {
|
|
425
|
-
this.out.write("\x1b[u"); // restore cursor
|
|
428
|
+
output += `\x1b[${cursorRow};${cursorCol}H`;
|
|
426
429
|
}
|
|
430
|
+
if (output) this.out.write(output);
|
|
427
431
|
}
|
|
428
432
|
|
|
429
433
|
drawFooter() {
|
|
@@ -437,6 +441,7 @@ export class Screen {
|
|
|
437
441
|
/** Start the minimal loading state on the prompt row. */
|
|
438
442
|
startBusy(label = "working") {
|
|
439
443
|
this._busy = true;
|
|
444
|
+
this.out.write("\x1b[?25l"); // spinner updates must not move a visible cursor
|
|
440
445
|
this._busyLabel = label;
|
|
441
446
|
this._busyFrame = 0;
|
|
442
447
|
this.redraw();
|
|
@@ -453,6 +458,7 @@ export class Screen {
|
|
|
453
458
|
if (this._busyTimer) { clearInterval(this._busyTimer); this._busyTimer = null; }
|
|
454
459
|
this._busy = false;
|
|
455
460
|
this._busyResume = false;
|
|
461
|
+
this.out.write("\x1b[?25h");
|
|
456
462
|
this.redraw();
|
|
457
463
|
}
|
|
458
464
|
|