@oxecli/oxe 1.0.101 → 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 -26
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -750,46 +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
|
-
// Rebuild the transient row(s) and gap above the new frame, then park the
|
|
774
|
-
// physical cursor at the transient row so the running spinner keeps
|
|
775
|
-
// drawing THERE instead of inside the prompt box.
|
|
776
|
-
process.stdout.write("\n".repeat(wasRel) + frame);
|
|
777
|
-
process.stdout.write(`\x1b[${totalRows - 1 + wasRel}A\r`);
|
|
778
|
-
dockSetFrame(frame, totalRows);
|
|
779
801
|
docked = true;
|
|
780
802
|
dockGap = false;
|
|
781
803
|
dockTransient = true;
|
|
782
804
|
dockRel = wasRel;
|
|
783
805
|
dockCaretBelow = 0;
|
|
784
|
-
return;
|
|
785
806
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
dockSetFrame(frame, totalRows);
|
|
791
|
-
dockEnterDocked();
|
|
792
|
-
dockCaretBelow = cursorRow;
|
|
807
|
+
else {
|
|
808
|
+
dockEnterDocked();
|
|
809
|
+
dockCaretBelow = cursorRow;
|
|
810
|
+
}
|
|
793
811
|
}
|
|
794
812
|
/** Commit content at the box top, pushing the box down, preserving exactly one
|
|
795
813
|
* blank row between the content and the box. */
|