rudimentary error reporting

This commit is contained in:
liquidex 2024-08-19 23:56:11 +02:00
parent 6eab20bb25
commit 1c0fa7197c
5 changed files with 90 additions and 10 deletions

View file

@ -28,11 +28,51 @@ export class BrushEditor extends HTMLElement {
}), }),
); );
}); });
this.errorHeader = this.appendChild(document.createElement("h1"));
this.errorHeader.classList.add("error-header");
this.errorArea = this.appendChild(document.createElement("pre"));
this.errorArea.classList.add("errors");
} }
get code() { get code() {
return this.textArea.textContent; return this.textArea.textContent;
} }
resetErrors() {
this.errorHeader.textContent = "";
this.errorArea.textContent = "";
}
renderHakuResult(phase, result) {
this.resetErrors();
console.log(result);
if (result.status != "error") return;
this.errorHeader.textContent = `${phase} failed`;
if (result.errorKind == "diagnostics") {
// This is kind of wooden; I'd prefer if the error spans were rendered inline in text,
// but I haven't integrated anything for syntax highlighting yet that would let me
// do that.
this.errorArea.textContent = result.diagnostics
.map(
(diagnostic) => `${diagnostic.start}..${diagnostic.end}: ${diagnostic.message}`,
)
.join("\n");
} else if (result.errorKind == "plain") {
this.errorHeader.textContent = result.message;
} else if (result.errorKind == "exception") {
// TODO: This should show a stack trace.
this.errorArea.textContent = `an exception occurred: ${result.message}`;
} else {
console.warn(`unknown error kind: ${result.errorKind}`);
this.errorHeader.textContent = "(unknown error kind)";
}
}
} }
customElements.define("rkgk-brush-editor", BrushEditor); customElements.define("rkgk-brush-editor", BrushEditor);

View file

@ -60,6 +60,10 @@ button, textarea, input {
font-family: inherit; font-family: inherit;
} }
pre, code {
font-family: "Fira Code", monospace;
}
/* Main container layout */ /* Main container layout */
main { main {
@ -215,7 +219,24 @@ rkgk-brush-editor {
height: 100%; height: 100%;
margin: 0; margin: 0;
resize: none; resize: none;
font-family: "Fira Code", monospace; white-space: pre-wrap;
}
&>.errors:empty, &>.error-header:empty {
display: none;
}
&>.error-header {
margin-top: 1em;
margin-bottom: 0;
font-size: 1rem;
color: var(--color-error);
}
&>.errors {
margin: 0;
color: var(--color-error);
white-space: pre-wrap;
} }
} }

View file

@ -183,7 +183,20 @@ function readUrl() {
canvasRenderer.addEventListener(".paint", async (event) => { canvasRenderer.addEventListener(".paint", async (event) => {
plotQueue.push({ x: event.x, y: event.y }); plotQueue.push({ x: event.x, y: event.y });
currentUser.renderBrushToChunks(wall, event.x, event.y);
if (currentUser.isBrushOk) {
brushEditor.resetErrors();
let result = currentUser.renderBrushToChunks(wall, event.x, event.y);
console.log(result);
if (result.status == "error") {
brushEditor.renderHakuResult(
result.phase == "eval" ? "Evaluation" : "Rendering",
result.result,
);
}
}
}); });
canvasRenderer.addEventListener(".viewportUpdate", () => reticleRenderer.render()); canvasRenderer.addEventListener(".viewportUpdate", () => reticleRenderer.render());
@ -191,10 +204,10 @@ function readUrl() {
updateUrl(session, canvasRenderer.viewport), updateUrl(session, canvasRenderer.viewport),
); );
currentUser.setBrush(brushEditor.code); brushEditor.renderHakuResult("Compilation", currentUser.setBrush(brushEditor.code));
brushEditor.addEventListener(".codeChanged", async () => { brushEditor.addEventListener(".codeChanged", async () => {
flushPlotQueue(); flushPlotQueue();
currentUser.setBrush(brushEditor.code); brushEditor.renderHakuResult("Compilation", currentUser.setBrush(brushEditor.code));
session.sendSetBrush(brushEditor.code); session.sendSetBrush(brushEditor.code);
}); });

View file

@ -22,7 +22,7 @@ export class User {
} }
renderBrushToChunks(wall, x, y) { renderBrushToChunks(wall, x, y) {
this.painter.renderBrushToWall(this.haku, x, y, wall); return this.painter.renderBrushToWall(this.haku, x, y, wall);
} }
} }

View file

@ -5,7 +5,8 @@ export class Painter {
renderBrushToWall(haku, centerX, centerY, wall) { renderBrushToWall(haku, centerX, centerY, wall) {
let evalResult = haku.evalBrush(); let evalResult = haku.evalBrush();
if (evalResult.status != "ok") return evalResult; if (evalResult.status != "ok")
return { status: "error", phase: "eval", result: evalResult };
let left = centerX - this.paintArea / 2; let left = centerX - this.paintArea / 2;
let top = centerY - this.paintArea / 2; let top = centerY - this.paintArea / 2;
@ -21,7 +22,10 @@ export class Painter {
let chunk = wall.getOrCreateChunk(chunkX, chunkY); let chunk = wall.getOrCreateChunk(chunkX, chunkY);
let renderResult = haku.renderValue(chunk.pixmap, x, y); let renderResult = haku.renderValue(chunk.pixmap, x, y);
if (renderResult.status != "ok") return renderResult; if (renderResult.status != "ok") {
haku.resetVm();
return { status: "error", phase: "render", result: renderResult };
}
} }
} }
haku.resetVm(); haku.resetVm();
@ -32,5 +36,7 @@ export class Painter {
chunk.syncFromPixmap(); chunk.syncFromPixmap();
} }
} }
return { status: "ok" };
} }
} }