@oxecli/oxe 1.0.102 → 1.0.103
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 +44 -29
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -750,49 +750,64 @@ function dockRenderBox() {
|
|
|
750
750
|
/**
|
|
751
751
|
* Redraw the docked prompt box with the given buffer/caret, keeping whatever
|
|
752
752
|
* content already streams above it. Used to make the prompt field live-edit
|
|
753
|
-
* while a query runs.
|
|
754
|
-
*
|
|
755
|
-
*
|
|
756
|
-
*
|
|
757
|
-
* transient row, so streaming content is never pulled into the prompt
|
|
753
|
+
* while a query runs. Preserves exactly one blank row between the last content
|
|
754
|
+
* and the box. Rows that did not change (top border, hint row) are left
|
|
755
|
+
* untouched, so static parts never flicker on each keystroke. When a transient
|
|
756
|
+
* (thinking/working spinner) is parked above the box, the physical cursor stays
|
|
757
|
+
* on that transient row, so streaming content is never pulled into the prompt
|
|
758
|
+
* and the box does not drift.
|
|
758
759
|
*/
|
|
759
760
|
export function dockRenderPrompt(buffer, pasteSpans, prefix, label, hints) {
|
|
760
761
|
if (!docked || dockBoxRows < 1)
|
|
761
762
|
return;
|
|
762
|
-
// If a thinking/working spinner is currently parked above the box, typing
|
|
763
|
-
// must NOT disturb it. dockEraseBox() wipes that transient row and resets
|
|
764
|
-
// its state; the still-running spinner then keeps drawing at the physical
|
|
765
|
-
// caret (now inside the box), pulling streaming content into the prompt.
|
|
766
|
-
// Capture the transient before erasing so we can rebuild it above the frame
|
|
767
|
-
// and park the cursor back on the transient row, keeping the box intact.
|
|
768
763
|
const wasTransient = dockTransient;
|
|
769
764
|
const wasRel = dockRel;
|
|
765
|
+
const wasCaret = dockCaretBelow;
|
|
770
766
|
const { frame, cursorRow, cursorCol, totalRows } = renderBufferWithCursor(buffer, pasteSpans, prefix, label, buffer.length, hints);
|
|
771
|
-
|
|
767
|
+
const newLines = frame.split("\n");
|
|
768
|
+
const oldLines = dockFrameLines.length ? dockFrameLines : newLines;
|
|
769
|
+
// Move the caret to the box's top row (R). The physical cursor is either on
|
|
770
|
+
// the transient row (R - wasRel) or at the live caret (R + wasCaret).
|
|
771
|
+
if (wasTransient)
|
|
772
|
+
process.stdout.write(`\x1b[${wasRel}B\r`);
|
|
773
|
+
else if (wasCaret > 0)
|
|
774
|
+
process.stdout.write(`\x1b[${wasCaret}A\r`);
|
|
775
|
+
// In-place line diff: rewrite only lines that actually changed (the body),
|
|
776
|
+
// leaving unchanged rows (top border, hint row) untouched so they never
|
|
777
|
+
// flicker. Clear each rewritten row so a shorter line leaves no residue.
|
|
778
|
+
const maxLen = Math.max(oldLines.length, newLines.length);
|
|
779
|
+
for (let i = 0; i < maxLen; i++) {
|
|
780
|
+
if (newLines[i] !== oldLines[i]) {
|
|
781
|
+
process.stdout.write("\r\x1b[K" + (newLines[i] ?? ""));
|
|
782
|
+
}
|
|
783
|
+
if (i < maxLen - 1)
|
|
784
|
+
process.stdout.write("\n");
|
|
785
|
+
}
|
|
786
|
+
// Reposition the caret.
|
|
787
|
+
if (wasTransient) {
|
|
788
|
+
// Park back on the transient row so the running spinner keeps drawing there.
|
|
789
|
+
process.stdout.write(`\x1b[${maxLen - 1 + wasRel}A\r`);
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
const atLine = maxLen - 1;
|
|
793
|
+
if (atLine > cursorRow)
|
|
794
|
+
process.stdout.write(`\x1b[${atLine - cursorRow}A\r`);
|
|
795
|
+
else if (atLine < cursorRow)
|
|
796
|
+
process.stdout.write(`\x1b[${cursorRow - atLine}B\r`);
|
|
797
|
+
process.stdout.write(`\x1b[${cursorCol}C`);
|
|
798
|
+
}
|
|
799
|
+
dockSetFrame(frame, totalRows);
|
|
772
800
|
if (wasTransient) {
|
|
773
|
-
// dockEraseBox has left the transient row and gap still present above the
|
|
774
|
-
// box-top row (cleared but physically occupying rows R-2 and R-1). Write
|
|
775
|
-
// the frame at R and park the cursor back on the transient row (R-2) so the
|
|
776
|
-
// running spinner keeps drawing THERE instead of on/inside the box. Do NOT
|
|
777
|
-
// write any leading newlines: they would push the box down and add a blank
|
|
778
|
-
// row on every keystroke.
|
|
779
|
-
process.stdout.write(frame);
|
|
780
|
-
process.stdout.write(`\x1b[${totalRows - 1 + wasRel}A\r`);
|
|
781
|
-
dockSetFrame(frame, totalRows);
|
|
782
801
|
docked = true;
|
|
783
802
|
dockGap = false;
|
|
784
803
|
dockTransient = true;
|
|
785
804
|
dockRel = wasRel;
|
|
786
805
|
dockCaretBelow = 0;
|
|
787
|
-
return;
|
|
788
806
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
dockSetFrame(frame, totalRows);
|
|
794
|
-
dockEnterDocked();
|
|
795
|
-
dockCaretBelow = cursorRow;
|
|
807
|
+
else {
|
|
808
|
+
dockEnterDocked();
|
|
809
|
+
dockCaretBelow = cursorRow;
|
|
810
|
+
}
|
|
796
811
|
}
|
|
797
812
|
/** Commit content at the box top, pushing the box down, preserving exactly one
|
|
798
813
|
* blank row between the content and the box. */
|