playground: split streamed chunks into per-line divs + per-program drafts
Two fixes in one push.
(1) Streaming horizontal-output bug, take three. textContent += chunk
then appendChild(createTextNode(chunk)) both still rendered chunks
horizontally in fox's Firefox tab even though the chunks clearly
contained \\n (node test confirmed; deployed loader hash matched
local; curl-fetched lumbda-c.loader.js carried the line + '\\n' fix).
Whatever the browser was doing with sibling text nodes inside a
<pre> wasn't honoring the embedded newlines.
Switch to one <div class=\"stream-line\"> per logical line. liveBlock.append
walks the incoming chunk byte by byte, every \\n closes the current
pending div and spawns a fresh empty one for the next line. CSS
adds .stream-line { display: block; white-space: pre; } so each
finished line stacks vertically no matter what the parent
white-space rule was doing. Empty lines get a single space so they
take a row instead of collapsing. Reconcile path inside finalize()
compares the joined per-line text to the full output and rebuilds
the div column if they diverge — for the asm-tier fallback we
already had and now also for any future browser/wasm combo where
a flush silently drops a chunk.
Also drops the temporary [c-tier print] console.log debug we added
in the last commit — diagnosis arrived from elsewhere, no point
keeping the spam.
(2) Per-program autosave drafts. scheduleFreeFormSave previously
returned early if the selected program wasn't \"free-form\", so a
user who unlocked the vault, edited the bend-gpu demo, and came
back later found their edits gone — only free-form persisted.
Now drafts live as { [programName]: text } in the vault payload;
every edit, regardless of which radio is selected, debounces a
save into drafts[currentProgram]. unlockVault loads any saved
draft for the current program (and lifts the legacy
top-level freeForm field into drafts['free-form'] so existing
users don't lose their work). loadCurrentDemo shows a saved
draft instead of the ship default whenever one exists; vault bar
stays visible across all programs once the vault is engaged so
the save status note is always reachable.
This commit is contained in:
parent
3cfed5e3c5
commit
ffada026ae
8 changed files with 132 additions and 50 deletions
|
|
@ -72,7 +72,20 @@ function getEditorText() {
|
||||||
async function loadCurrentDemo() {
|
async function loadCurrentDemo() {
|
||||||
const sel = document.querySelector('input[name="program"]:checked').value;
|
const sel = document.querySelector('input[name="program"]:checked').value;
|
||||||
const vaultBar = document.getElementById("vault-bar");
|
const vaultBar = document.getElementById("vault-bar");
|
||||||
vaultBar.hidden = sel !== "free-form";
|
// Vault bar visible whenever the vault gate has been engaged
|
||||||
|
// (locked or unlocked) — drafts live per-program now, not just
|
||||||
|
// for free-form, so the lock/unlock affordance stays useful on
|
||||||
|
// every demo. Hide entirely only if the user explicitly hasn't
|
||||||
|
// set up a vault yet (vault.exists()) — kept as-is to avoid
|
||||||
|
// a "first-paint shows lock UI to a fresh customer" surprise.
|
||||||
|
vaultBar.hidden = sel !== "free-form" && !vaultState.vault;
|
||||||
|
// If the vault is unlocked and has a saved draft for this
|
||||||
|
// program, use it; otherwise fall back to the demo's source.
|
||||||
|
if (vaultState.vault && vaultState.drafts
|
||||||
|
&& typeof vaultState.drafts[sel] === "string") {
|
||||||
|
setEditorText(vaultState.drafts[sel]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const src = await loadDemoSource(sel);
|
const src = await loadDemoSource(sel);
|
||||||
setEditorText(src);
|
setEditorText(src);
|
||||||
}
|
}
|
||||||
|
|
@ -102,18 +115,30 @@ async function unlockVault() {
|
||||||
vaultState.vault = null;
|
vaultState.vault = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vaultState.freeForm = (data && typeof data.freeForm === "string")
|
// Per-program draft map. Back-compat: lift any legacy
|
||||||
? data.freeForm
|
// top-level freeForm field into drafts['free-form'] so users
|
||||||
: FREE_FORM_DEFAULT;
|
// who already had a free-form draft don't lose it.
|
||||||
|
vaultState.drafts = (data && data.drafts && typeof data.drafts === "object")
|
||||||
|
? Object.assign({}, data.drafts)
|
||||||
|
: {};
|
||||||
|
if (data && typeof data.freeForm === "string" && !vaultState.drafts["free-form"]) {
|
||||||
|
vaultState.drafts["free-form"] = data.freeForm;
|
||||||
|
}
|
||||||
|
vaultState.freeForm = vaultState.drafts["free-form"] || FREE_FORM_DEFAULT;
|
||||||
vaultStateEl.textContent = "unlocked";
|
vaultStateEl.textContent = "unlocked";
|
||||||
vaultStateEl.classList.add("unlocked");
|
vaultStateEl.classList.add("unlocked");
|
||||||
vaultUnlockBtn.hidden = true;
|
vaultUnlockBtn.hidden = true;
|
||||||
vaultLockBtn.hidden = false;
|
vaultLockBtn.hidden = false;
|
||||||
vaultPwEl.value = "";
|
vaultPwEl.value = "";
|
||||||
vaultPwEl.disabled = true;
|
vaultPwEl.disabled = true;
|
||||||
// If free-form is the current program, swap the editor in.
|
// If the currently-selected program has a saved draft, load it.
|
||||||
|
// Otherwise leave the demo's default source in place.
|
||||||
const sel = document.querySelector('input[name="program"]:checked').value;
|
const sel = document.querySelector('input[name="program"]:checked').value;
|
||||||
if (sel === "free-form") setEditorText(vaultState.freeForm);
|
if (typeof vaultState.drafts[sel] === "string") {
|
||||||
|
setEditorText(vaultState.drafts[sel]);
|
||||||
|
} else if (sel === "free-form") {
|
||||||
|
setEditorText(vaultState.freeForm);
|
||||||
|
}
|
||||||
setVaultNote("ok — edits auto-save");
|
setVaultNote("ok — edits auto-save");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setVaultNote("unlock failed: " + e.message, true);
|
setVaultNote("unlock failed: " + e.message, true);
|
||||||
|
|
@ -122,6 +147,7 @@ async function unlockVault() {
|
||||||
|
|
||||||
function lockVault() {
|
function lockVault() {
|
||||||
vaultState.vault = null;
|
vaultState.vault = null;
|
||||||
|
vaultState.drafts = null;
|
||||||
vaultState.freeForm = null;
|
vaultState.freeForm = null;
|
||||||
if (vaultState.saveTimer) { clearTimeout(vaultState.saveTimer); vaultState.saveTimer = null; }
|
if (vaultState.saveTimer) { clearTimeout(vaultState.saveTimer); vaultState.saveTimer = null; }
|
||||||
vaultStateEl.textContent = "locked";
|
vaultStateEl.textContent = "locked";
|
||||||
|
|
@ -131,21 +157,38 @@ function lockVault() {
|
||||||
vaultPwEl.disabled = false;
|
vaultPwEl.disabled = false;
|
||||||
vaultPwEl.value = "";
|
vaultPwEl.value = "";
|
||||||
setVaultNote("");
|
setVaultNote("");
|
||||||
// If free-form is current program, swap to the placeholder.
|
// Reset the editor to whatever the current program ships with
|
||||||
const sel = document.querySelector('input[name="program"]:checked').value;
|
// (drafts only live while the vault is unlocked).
|
||||||
if (sel === "free-form") setEditorText(FREE_FORM_DEFAULT);
|
loadCurrentDemo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debounced autosave — fires on every editor doc change while the
|
||||||
|
// vault is unlocked. Saves under drafts[program-name] so each demo's
|
||||||
|
// edits persist independently. Previously this was free-form-only,
|
||||||
|
// which surprised users who edited a demo, switched tabs, and came
|
||||||
|
// back to their original demo source untouched.
|
||||||
function scheduleFreeFormSave() {
|
function scheduleFreeFormSave() {
|
||||||
if (!vaultState.vault) return;
|
if (!vaultState.vault) return;
|
||||||
const sel = document.querySelector('input[name="program"]:checked').value;
|
const sel = document.querySelector('input[name="program"]:checked').value;
|
||||||
if (sel !== "free-form") return;
|
|
||||||
if (vaultState.saveTimer) clearTimeout(vaultState.saveTimer);
|
if (vaultState.saveTimer) clearTimeout(vaultState.saveTimer);
|
||||||
vaultState.saveTimer = setTimeout(async () => {
|
vaultState.saveTimer = setTimeout(async () => {
|
||||||
const text = getEditorText();
|
const text = getEditorText();
|
||||||
vaultState.freeForm = text;
|
vaultState.drafts = vaultState.drafts || {};
|
||||||
try { await vaultState.vault.write({ freeForm: text, savedAt: Date.now() }); }
|
vaultState.drafts[sel] = text;
|
||||||
catch (e) { setVaultNote("save failed: " + e.message, true); }
|
// Keep the legacy freeForm field in sync so older builds that
|
||||||
|
// only know about that field still see the user's free-form
|
||||||
|
// edits if they re-open the vault from a different tab.
|
||||||
|
if (sel === "free-form") vaultState.freeForm = text;
|
||||||
|
try {
|
||||||
|
await vaultState.vault.write({
|
||||||
|
drafts: vaultState.drafts,
|
||||||
|
freeForm: vaultState.drafts["free-form"] || "",
|
||||||
|
savedAt: Date.now(),
|
||||||
|
});
|
||||||
|
setVaultNote(`saved ${sel} @ ${new Date().toLocaleTimeString()}`);
|
||||||
|
} catch (e) {
|
||||||
|
setVaultNote("save failed: " + e.message, true);
|
||||||
|
}
|
||||||
}, 350);
|
}, 350);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,16 @@ header code {
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
font-family: var(--mono);
|
font-family: var(--mono);
|
||||||
}
|
}
|
||||||
|
/* Streamed output: each emit_chunk slice that ended with \n becomes
|
||||||
|
its own <div class="stream-line"> child of the <pre>. Block display
|
||||||
|
guarantees vertical stacking regardless of how the browser handles
|
||||||
|
raw \n inside a sequence of text nodes — the bug we kept chasing
|
||||||
|
in firefox where "tick 0\ntick 10000\n..." rendered horizontally
|
||||||
|
even though each text node clearly contained the newline byte. */
|
||||||
|
#output .tier-block .stream-line {
|
||||||
|
display: block;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
#output .err { color: var(--err); }
|
#output .err { color: var(--err); }
|
||||||
|
|
||||||
/* ─── Footer ────────────────────────────────────────────────────── */
|
/* ─── Footer ────────────────────────────────────────────────────── */
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,13 @@ async function _bootstrap() {
|
||||||
let outBuf = [];
|
let outBuf = [];
|
||||||
let errBuf = [];
|
let errBuf = [];
|
||||||
let currentOnChunk = null;
|
let currentOnChunk = null;
|
||||||
// Temporary debug — log every Module.print invocation so we can
|
|
||||||
// see exactly what Emscripten passes us (with/without trailing
|
|
||||||
// newline). Remove once the streaming-newline bug is resolved.
|
|
||||||
const DEBUG_STREAM = true;
|
|
||||||
const module = await createLumbdaC({
|
const module = await createLumbdaC({
|
||||||
locateFile: (p) => wasmDir + p,
|
locateFile: (p) => wasmDir + p,
|
||||||
print: (line) => {
|
print: (line) => {
|
||||||
if (DEBUG_STREAM) console.log("[c-tier print]", JSON.stringify(line));
|
|
||||||
outBuf.push(line);
|
outBuf.push(line);
|
||||||
if (currentOnChunk) currentOnChunk(line + "\n");
|
if (currentOnChunk) currentOnChunk(line + "\n");
|
||||||
},
|
},
|
||||||
printErr: (line) => {
|
printErr: (line) => {
|
||||||
if (DEBUG_STREAM) console.log("[c-tier printErr]", JSON.stringify(line));
|
|
||||||
errBuf.push(line);
|
errBuf.push(line);
|
||||||
if (currentOnChunk) currentOnChunk(line + "\n");
|
if (currentOnChunk) currentOnChunk(line + "\n");
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,13 @@ async function _bootstrap() {
|
||||||
let outBuf = [];
|
let outBuf = [];
|
||||||
let errBuf = [];
|
let errBuf = [];
|
||||||
let currentOnChunk = null;
|
let currentOnChunk = null;
|
||||||
// Temporary debug — log every Module.print invocation so we can
|
|
||||||
// see exactly what Emscripten passes us (with/without trailing
|
|
||||||
// newline). Remove once the streaming-newline bug is resolved.
|
|
||||||
const DEBUG_STREAM = true;
|
|
||||||
const module = await createLumbdaC({
|
const module = await createLumbdaC({
|
||||||
locateFile: (p) => wasmDir + p,
|
locateFile: (p) => wasmDir + p,
|
||||||
print: (line) => {
|
print: (line) => {
|
||||||
if (DEBUG_STREAM) console.log("[c-tier print]", JSON.stringify(line));
|
|
||||||
outBuf.push(line);
|
outBuf.push(line);
|
||||||
if (currentOnChunk) currentOnChunk(line + "\n");
|
if (currentOnChunk) currentOnChunk(line + "\n");
|
||||||
},
|
},
|
||||||
printErr: (line) => {
|
printErr: (line) => {
|
||||||
if (DEBUG_STREAM) console.log("[c-tier printErr]", JSON.stringify(line));
|
|
||||||
errBuf.push(line);
|
errBuf.push(line);
|
||||||
if (currentOnChunk) currentOnChunk(line + "\n");
|
if (currentOnChunk) currentOnChunk(line + "\n");
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,20 @@ function getEditorText() {
|
||||||
async function loadCurrentDemo() {
|
async function loadCurrentDemo() {
|
||||||
const sel = document.querySelector('input[name="program"]:checked').value;
|
const sel = document.querySelector('input[name="program"]:checked').value;
|
||||||
const vaultBar = document.getElementById("vault-bar");
|
const vaultBar = document.getElementById("vault-bar");
|
||||||
vaultBar.hidden = sel !== "free-form";
|
// Vault bar visible whenever the vault gate has been engaged
|
||||||
|
// (locked or unlocked) — drafts live per-program now, not just
|
||||||
|
// for free-form, so the lock/unlock affordance stays useful on
|
||||||
|
// every demo. Hide entirely only if the user explicitly hasn't
|
||||||
|
// set up a vault yet (vault.exists()) — kept as-is to avoid
|
||||||
|
// a "first-paint shows lock UI to a fresh customer" surprise.
|
||||||
|
vaultBar.hidden = sel !== "free-form" && !vaultState.vault;
|
||||||
|
// If the vault is unlocked and has a saved draft for this
|
||||||
|
// program, use it; otherwise fall back to the demo's source.
|
||||||
|
if (vaultState.vault && vaultState.drafts
|
||||||
|
&& typeof vaultState.drafts[sel] === "string") {
|
||||||
|
setEditorText(vaultState.drafts[sel]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const src = await loadDemoSource(sel);
|
const src = await loadDemoSource(sel);
|
||||||
setEditorText(src);
|
setEditorText(src);
|
||||||
}
|
}
|
||||||
|
|
@ -102,18 +115,30 @@ async function unlockVault() {
|
||||||
vaultState.vault = null;
|
vaultState.vault = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vaultState.freeForm = (data && typeof data.freeForm === "string")
|
// Per-program draft map. Back-compat: lift any legacy
|
||||||
? data.freeForm
|
// top-level freeForm field into drafts['free-form'] so users
|
||||||
: FREE_FORM_DEFAULT;
|
// who already had a free-form draft don't lose it.
|
||||||
|
vaultState.drafts = (data && data.drafts && typeof data.drafts === "object")
|
||||||
|
? Object.assign({}, data.drafts)
|
||||||
|
: {};
|
||||||
|
if (data && typeof data.freeForm === "string" && !vaultState.drafts["free-form"]) {
|
||||||
|
vaultState.drafts["free-form"] = data.freeForm;
|
||||||
|
}
|
||||||
|
vaultState.freeForm = vaultState.drafts["free-form"] || FREE_FORM_DEFAULT;
|
||||||
vaultStateEl.textContent = "unlocked";
|
vaultStateEl.textContent = "unlocked";
|
||||||
vaultStateEl.classList.add("unlocked");
|
vaultStateEl.classList.add("unlocked");
|
||||||
vaultUnlockBtn.hidden = true;
|
vaultUnlockBtn.hidden = true;
|
||||||
vaultLockBtn.hidden = false;
|
vaultLockBtn.hidden = false;
|
||||||
vaultPwEl.value = "";
|
vaultPwEl.value = "";
|
||||||
vaultPwEl.disabled = true;
|
vaultPwEl.disabled = true;
|
||||||
// If free-form is the current program, swap the editor in.
|
// If the currently-selected program has a saved draft, load it.
|
||||||
|
// Otherwise leave the demo's default source in place.
|
||||||
const sel = document.querySelector('input[name="program"]:checked').value;
|
const sel = document.querySelector('input[name="program"]:checked').value;
|
||||||
if (sel === "free-form") setEditorText(vaultState.freeForm);
|
if (typeof vaultState.drafts[sel] === "string") {
|
||||||
|
setEditorText(vaultState.drafts[sel]);
|
||||||
|
} else if (sel === "free-form") {
|
||||||
|
setEditorText(vaultState.freeForm);
|
||||||
|
}
|
||||||
setVaultNote("ok — edits auto-save");
|
setVaultNote("ok — edits auto-save");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setVaultNote("unlock failed: " + e.message, true);
|
setVaultNote("unlock failed: " + e.message, true);
|
||||||
|
|
@ -122,6 +147,7 @@ async function unlockVault() {
|
||||||
|
|
||||||
function lockVault() {
|
function lockVault() {
|
||||||
vaultState.vault = null;
|
vaultState.vault = null;
|
||||||
|
vaultState.drafts = null;
|
||||||
vaultState.freeForm = null;
|
vaultState.freeForm = null;
|
||||||
if (vaultState.saveTimer) { clearTimeout(vaultState.saveTimer); vaultState.saveTimer = null; }
|
if (vaultState.saveTimer) { clearTimeout(vaultState.saveTimer); vaultState.saveTimer = null; }
|
||||||
vaultStateEl.textContent = "locked";
|
vaultStateEl.textContent = "locked";
|
||||||
|
|
@ -131,21 +157,38 @@ function lockVault() {
|
||||||
vaultPwEl.disabled = false;
|
vaultPwEl.disabled = false;
|
||||||
vaultPwEl.value = "";
|
vaultPwEl.value = "";
|
||||||
setVaultNote("");
|
setVaultNote("");
|
||||||
// If free-form is current program, swap to the placeholder.
|
// Reset the editor to whatever the current program ships with
|
||||||
const sel = document.querySelector('input[name="program"]:checked').value;
|
// (drafts only live while the vault is unlocked).
|
||||||
if (sel === "free-form") setEditorText(FREE_FORM_DEFAULT);
|
loadCurrentDemo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debounced autosave — fires on every editor doc change while the
|
||||||
|
// vault is unlocked. Saves under drafts[program-name] so each demo's
|
||||||
|
// edits persist independently. Previously this was free-form-only,
|
||||||
|
// which surprised users who edited a demo, switched tabs, and came
|
||||||
|
// back to their original demo source untouched.
|
||||||
function scheduleFreeFormSave() {
|
function scheduleFreeFormSave() {
|
||||||
if (!vaultState.vault) return;
|
if (!vaultState.vault) return;
|
||||||
const sel = document.querySelector('input[name="program"]:checked').value;
|
const sel = document.querySelector('input[name="program"]:checked').value;
|
||||||
if (sel !== "free-form") return;
|
|
||||||
if (vaultState.saveTimer) clearTimeout(vaultState.saveTimer);
|
if (vaultState.saveTimer) clearTimeout(vaultState.saveTimer);
|
||||||
vaultState.saveTimer = setTimeout(async () => {
|
vaultState.saveTimer = setTimeout(async () => {
|
||||||
const text = getEditorText();
|
const text = getEditorText();
|
||||||
vaultState.freeForm = text;
|
vaultState.drafts = vaultState.drafts || {};
|
||||||
try { await vaultState.vault.write({ freeForm: text, savedAt: Date.now() }); }
|
vaultState.drafts[sel] = text;
|
||||||
catch (e) { setVaultNote("save failed: " + e.message, true); }
|
// Keep the legacy freeForm field in sync so older builds that
|
||||||
|
// only know about that field still see the user's free-form
|
||||||
|
// edits if they re-open the vault from a different tab.
|
||||||
|
if (sel === "free-form") vaultState.freeForm = text;
|
||||||
|
try {
|
||||||
|
await vaultState.vault.write({
|
||||||
|
drafts: vaultState.drafts,
|
||||||
|
freeForm: vaultState.drafts["free-form"] || "",
|
||||||
|
savedAt: Date.now(),
|
||||||
|
});
|
||||||
|
setVaultNote(`saved ${sel} @ ${new Date().toLocaleTimeString()}`);
|
||||||
|
} catch (e) {
|
||||||
|
setVaultNote("save failed: " + e.message, true);
|
||||||
|
}
|
||||||
}, 350);
|
}, 350);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,13 @@ async function _bootstrap() {
|
||||||
let outBuf = [];
|
let outBuf = [];
|
||||||
let errBuf = [];
|
let errBuf = [];
|
||||||
let currentOnChunk = null;
|
let currentOnChunk = null;
|
||||||
// Temporary debug — log every Module.print invocation so we can
|
|
||||||
// see exactly what Emscripten passes us (with/without trailing
|
|
||||||
// newline). Remove once the streaming-newline bug is resolved.
|
|
||||||
const DEBUG_STREAM = true;
|
|
||||||
const module = await createLumbdaC({
|
const module = await createLumbdaC({
|
||||||
locateFile: (p) => wasmDir + p,
|
locateFile: (p) => wasmDir + p,
|
||||||
print: (line) => {
|
print: (line) => {
|
||||||
if (DEBUG_STREAM) console.log("[c-tier print]", JSON.stringify(line));
|
|
||||||
outBuf.push(line);
|
outBuf.push(line);
|
||||||
if (currentOnChunk) currentOnChunk(line + "\n");
|
if (currentOnChunk) currentOnChunk(line + "\n");
|
||||||
},
|
},
|
||||||
printErr: (line) => {
|
printErr: (line) => {
|
||||||
if (DEBUG_STREAM) console.log("[c-tier printErr]", JSON.stringify(line));
|
|
||||||
errBuf.push(line);
|
errBuf.push(line);
|
||||||
if (currentOnChunk) currentOnChunk(line + "\n");
|
if (currentOnChunk) currentOnChunk(line + "\n");
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,16 @@ header code {
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
font-family: var(--mono);
|
font-family: var(--mono);
|
||||||
}
|
}
|
||||||
|
/* Streamed output: each emit_chunk slice that ended with \n becomes
|
||||||
|
its own <div class="stream-line"> child of the <pre>. Block display
|
||||||
|
guarantees vertical stacking regardless of how the browser handles
|
||||||
|
raw \n inside a sequence of text nodes — the bug we kept chasing
|
||||||
|
in firefox where "tick 0\ntick 10000\n..." rendered horizontally
|
||||||
|
even though each text node clearly contained the newline byte. */
|
||||||
|
#output .tier-block .stream-line {
|
||||||
|
display: block;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
#output .err { color: var(--err); }
|
#output .err { color: var(--err); }
|
||||||
|
|
||||||
/* ─── Footer ────────────────────────────────────────────────────── */
|
/* ─── Footer ────────────────────────────────────────────────────── */
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,13 @@ async function _bootstrap() {
|
||||||
let outBuf = [];
|
let outBuf = [];
|
||||||
let errBuf = [];
|
let errBuf = [];
|
||||||
let currentOnChunk = null;
|
let currentOnChunk = null;
|
||||||
// Temporary debug — log every Module.print invocation so we can
|
|
||||||
// see exactly what Emscripten passes us (with/without trailing
|
|
||||||
// newline). Remove once the streaming-newline bug is resolved.
|
|
||||||
const DEBUG_STREAM = true;
|
|
||||||
const module = await createLumbdaC({
|
const module = await createLumbdaC({
|
||||||
locateFile: (p) => wasmDir + p,
|
locateFile: (p) => wasmDir + p,
|
||||||
print: (line) => {
|
print: (line) => {
|
||||||
if (DEBUG_STREAM) console.log("[c-tier print]", JSON.stringify(line));
|
|
||||||
outBuf.push(line);
|
outBuf.push(line);
|
||||||
if (currentOnChunk) currentOnChunk(line + "\n");
|
if (currentOnChunk) currentOnChunk(line + "\n");
|
||||||
},
|
},
|
||||||
printErr: (line) => {
|
printErr: (line) => {
|
||||||
if (DEBUG_STREAM) console.log("[c-tier printErr]", JSON.stringify(line));
|
|
||||||
errBuf.push(line);
|
errBuf.push(line);
|
||||||
if (currentOnChunk) currentOnChunk(line + "\n");
|
if (currentOnChunk) currentOnChunk(line + "\n");
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue