Skip to content

Commit a8b9b2f

Browse files
committed
Add first round of error reporting
1 parent ea8e321 commit a8b9b2f

File tree

5 files changed

+72
-39
lines changed

5 files changed

+72
-39
lines changed

p5js/js/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
<!DOCTYPE html>
22
<html lang="en">
33
<head>
4-
<script src="./node_modules/p5/lib/p5.min.js"></script>
5-
<script src="./node_modules/p5.sound/dist/p5.sound.min.js"></script>
64
<meta charset="utf-8" />
75
<style>
86
html, body {
@@ -17,6 +15,8 @@
1715

1816
<body>
1917
<script src="renderer.js"></script>
18+
<script src="./node_modules/p5/lib/p5.min.js"></script>
19+
<script src="./node_modules/p5.sound/dist/p5.sound.min.js"></script>
2020
<script src="sketch.js"></script>
2121
</body>
22-
</html>
22+
</html>

p5js/js/main.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ const createWindow = () => {
99
autoHideMenuBar: true,
1010
alwaysOnTop: true,
1111
webPreferences: {
12+
contextIsolation: false,
1213
nodeIntegration: true,
13-
contextIsolation: false
14+
preload: path.join(__dirname, "preload.js")
1415
}
1516
});
1617

p5js/js/preload.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
const { contextBridge, ipcRenderer } = require("electron");
1+
const { ipcRenderer } = require("electron");
22

3-
contextBridge.exposeInMainWorld("electron", {
3+
window.pde = {
44
sendMessage: (message) => ipcRenderer.send("send-message", message)
5-
});
5+
};
6+
7+
// Force-disable security warning
8+
// https://www.electronjs.org/docs/latest/tutorial/security#:~:text=ELECTRON_DISABLE_SECURITY_WARNINGS
9+
window.ELECTRON_DISABLE_SECURITY_WARNINGS = true;

p5js/js/renderer.js

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,39 @@
1-
// TODO Beware of leakage into global scope!
2-
const fs = require("node:fs/promises");
3-
const p = require("node:path");
1+
const path = require('node:path');
42

5-
// const sharp = require("sharp");
3+
// Proxy calls to `console` and send output to main process
4+
const sendToMainHandler = {
5+
get(target, prop) {
6+
const consoleMethod = target[prop];
7+
// Only intercept methods, return properties
8+
if (typeof consoleMethod !== "function") {
9+
return Reflect.get(...arguments);
10+
}
11+
return new Proxy(consoleMethod, {
12+
apply(target, thisArg, args) {
13+
// API in preload.js
14+
pde.sendMessage(`console.${prop}: ${args.join(' ')}`);
15+
// Retain original behavior
16+
return Reflect.apply(...arguments);
17+
}
18+
});
19+
}
20+
};
21+
console = new Proxy(console, sendToMainHandler);
622

7-
let suffix = 0;
8-
9-
async function saveCnv(path) {
10-
const canvas = document.querySelector(".p5Canvas");
11-
const outPath = p.resolve(path, `out-${suffix.toString().padStart(5, "0")}.png`);
12-
13-
canvas.toBlob(async (blob) => {
14-
const buffer = Buffer.from(await blob.arrayBuffer());
15-
// await sharp(buffer).rotate(45).grayscale().toFile(outPath);
16-
await fs.writeFile(outPath, buffer);
17-
suffix++;
18-
});
19-
}
23+
// TODO: move error handling logic to Kotlin
24+
addEventListener("error", ({ message, filename, lineno, colno}) => {
25+
pde.sendMessage(
26+
["error", message, path.basename(filename), lineno, colno].join("|")
27+
);
28+
});
29+
addEventListener("unhandledrejection", ({ reason: { message, stack}}) => {
30+
const stackLinesWithFiles = stack.split("\n").slice(1);
31+
const potentialSourcesOfError = stackLinesWithFiles
32+
.map(line => /\/([^\/]+)\)/.exec(line)[1]);
33+
// TODO: improve stack trace parsing; first non-p5 file is suspected source of error
34+
const [filename, line, column] =
35+
potentialSourcesOfError.find(s => !s.startsWith("p5")).split(":");
36+
pde.sendMessage(
37+
["error", message, filename, line, column].join("|")
38+
);
39+
});

p5js/src/main/kotlin/p5jsEditor.kt

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package processing.p5js
22

33
import androidx.compose.foundation.layout.*
44
import androidx.compose.foundation.lazy.LazyColumn
5-
import androidx.compose.foundation.lazy.items
65
import androidx.compose.foundation.lazy.itemsIndexed
76
import androidx.compose.material.Button
87
import androidx.compose.material.Divider
@@ -19,15 +18,12 @@ import androidx.compose.ui.unit.dp
1918
import kotlinx.coroutines.CoroutineScope
2019
import kotlinx.coroutines.Dispatchers
2120
import kotlinx.coroutines.launch
22-
import kotlinx.serialization.json.Json
23-
import kotlinx.serialization.json.JsonObject
24-
import kotlinx.serialization.json.jsonArray
25-
import kotlinx.serialization.json.jsonObject
26-
import kotlinx.serialization.json.jsonPrimitive
21+
import kotlinx.serialization.json.*
2722
import processing.app.Base
2823
import processing.app.Formatter
24+
import processing.app.Messages
2925
import processing.app.Mode
30-
import processing.app.Platform
26+
import processing.app.SketchException
3127
import processing.app.syntax.JEditTextArea
3228
import processing.app.syntax.PdeTextArea
3329
import processing.app.syntax.PdeTextAreaDefaults
@@ -61,8 +57,6 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
6157
<!DOCTYPE html>
6258
<html lang="en">
6359
<head>
64-
<script src="./node_modules/p5/lib/p5.min.js"></script>
65-
<script src="./node_modules/p5.sound/dist/p5.sound.min.js"></script>
6660
<meta charset="utf-8" />
6761
<style>
6862
html, body {
@@ -77,6 +71,8 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
7771
7872
<body>
7973
<script src="renderer.js"></script>
74+
<script src="./node_modules/p5/lib/p5.min.js"></script>
75+
<script src="./node_modules/p5.sound/dist/p5.sound.min.js"></script>
8076
<script src="$name.js"></script>
8177
</body>
8278
</html>
@@ -200,10 +196,12 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
200196
npm, pnpm, npx
201197
}
202198

203-
val processes = mutableListOf<Process>()
204-
fun runNpmActions(directory: File, type: TYPE, actions: List<String>, onFinished: () -> Unit = {}) {
199+
private fun filenameToCodeIndex(filename: String) {
205200

201+
}
206202

203+
val processes = mutableListOf<Process>()
204+
fun runNpmActions(directory: File, type: TYPE, actions: List<String>, onFinished: () -> Unit = {}) {
207205
// Wait for previous processes to finish
208206
processes.forEach { it.waitFor() }
209207

@@ -224,21 +222,31 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
224222

225223
// Handle output stream
226224
val reader = BufferedReader(InputStreamReader(process.inputStream))
227-
var line: String?
225+
var line: String
226+
228227
while (reader.readLine().also { line = it } != null) {
228+
// TODO: so much refactoring!
229+
// Only check for errors when running the sketch
230+
if (type == TYPE.npx && line.startsWith("error")) {
231+
// TODO: more robust data exchange, double-check with @Stef
232+
// TODO: `statusError` does not do anything with column of a SketchException
233+
val ( msgType, msgText, msgFile, msgLine, msgCol ) = line.split("|")
234+
statusError(SketchException(msgText, 0, msgLine.toInt(), msgCol.toInt()))
235+
continue
236+
}
237+
229238
println(line)
230239
}
231240

232-
233241
// Wait for the process to complete
234242
val exitCode = process.waitFor()
235243
processes.remove(process)
236244
onFinished()
237245
if (exitCode != 0) {
238-
throw RuntimeException("npm install failed with exit code $exitCode")
246+
throw RuntimeException("$type ${actions.joinToString(" ")} failed with exit code $exitCode.")
239247
}
240248
} catch (e: Exception) {
241-
throw RuntimeException("Failed to run npm install", e)
249+
throw RuntimeException("Failed to run $type ${actions.joinToString(" ")}.", e)
242250
}
243251
}
244252
}

0 commit comments

Comments
 (0)