playground streaming: per-line divs with inline display:block
Reapplies the per-line-div approach lost in the autosave revert
(c2d9eca) and pins display:block + white-space:pre as INLINE styles
on each div instead of relying on the .stream-line CSS rule. We
spent a long stretch chasing what looked like a deeper rendering
bug — turned out the previous .stream-line class rule in style.css
was loaded but the cached stylesheet bundle in fox's tab didn't
include it, so each div kept its default inline display and the
chunks still rendered horizontally even though the DOM had a clean
sibling-div column.
Each chunk now: walk byte-by-byte, accumulate text in a pending
div, every \n closes the pending div with display:block already
set and spawns a fresh sibling. Empty lines get a single space so
they still take a row. finalize() reconciles against the full eval
output (asm tier fallback) using the joined per-line text rather
than comparing pre.textContent.
This commit is contained in:
parent
c2d9eca476
commit
bc13b056ac
2 changed files with 98 additions and 26 deletions
|
|
@ -261,27 +261,63 @@ function startLiveBlock(tierName) {
|
|||
pre.textContent = "";
|
||||
block.appendChild(pre);
|
||||
outputEl.appendChild(block);
|
||||
|
||||
// Each chunk gets split on \n: every completed line becomes its
|
||||
// own block-level <div>, the trailing fragment without a newline
|
||||
// accumulates in a pending div that's updated in place until the
|
||||
// next \n closes it. display:block + white-space:pre set INLINE
|
||||
// so a stale cached stylesheet can't suppress the fix — we kept
|
||||
// chasing what turned out to be CSS not reloading.
|
||||
const makeLine = () => {
|
||||
const d = document.createElement("div");
|
||||
d.style.display = "block";
|
||||
d.style.whiteSpace = "pre";
|
||||
return d;
|
||||
};
|
||||
let pendingLine = makeLine();
|
||||
pre.appendChild(pendingLine);
|
||||
let pendingText = "";
|
||||
|
||||
return {
|
||||
append(chunk) {
|
||||
// Append a TextNode rather than `pre.textContent += chunk`
|
||||
// — the latter re-reads + restringifies + re-sets all
|
||||
// existing children on every chunk, which under a fast
|
||||
// C-tier loop (one chunk per (newline) printf) was
|
||||
// dropping line breaks and rendering "tick 0tick 10000…"
|
||||
// horizontally instead of stacking vertically. TextNode
|
||||
// append preserves every byte verbatim.
|
||||
pre.appendChild(document.createTextNode(chunk));
|
||||
if (!chunk) return;
|
||||
let start = 0;
|
||||
for (let i = 0; i < chunk.length; i++) {
|
||||
if (chunk.charCodeAt(i) === 10) {
|
||||
pendingText += chunk.slice(start, i);
|
||||
pendingLine.textContent = pendingText || " ";
|
||||
pendingText = "";
|
||||
pendingLine = makeLine();
|
||||
pre.appendChild(pendingLine);
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < chunk.length) {
|
||||
pendingText += chunk.slice(start);
|
||||
pendingLine.textContent = pendingText;
|
||||
}
|
||||
outputEl.scrollTop = outputEl.scrollHeight;
|
||||
},
|
||||
finalize(elapsedMs, kind, fullOutput) {
|
||||
if (kind === "cancelled") t.textContent = ` (cancelled @ ${elapsedMs.toFixed(0)} ms)`;
|
||||
else t.textContent = ` (${elapsedMs.toFixed(0)} ms)`;
|
||||
if (kind === "error") pre.className = "err";
|
||||
// If the streamed chunks miss anything (e.g. asm tier
|
||||
// which doesn't stream yet), reconcile with the full
|
||||
// output. No-op when streaming captured everything.
|
||||
if (fullOutput && pre.textContent !== fullOutput) {
|
||||
pre.textContent = fullOutput;
|
||||
// Reconcile against the full output if the streamed
|
||||
// per-line divs don't add up — e.g. asm-tier fallback
|
||||
// where streaming isn't wired yet. Otherwise the joined
|
||||
// per-line text should match the eval's full output.
|
||||
if (fullOutput) {
|
||||
const got = Array.from(pre.children).map((d) =>
|
||||
d.textContent === " " ? "" : d.textContent).join("\n");
|
||||
if (got !== fullOutput.replace(/\n$/, "")) {
|
||||
pre.textContent = "";
|
||||
const lines = fullOutput.split("\n");
|
||||
for (const ln of lines) {
|
||||
const d = makeLine();
|
||||
d.textContent = ln || " ";
|
||||
pre.appendChild(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue