From 07e52927ca7fd1c9056749efb00ffd559d07447a Mon Sep 17 00:00:00 2001 From: Stephan Max Date: Wed, 28 Jan 2026 08:26:06 +0100 Subject: [PATCH 1/2] Fix auto-install of pnpm and node on mode init --- p5js/src/main/kotlin/p5jsEditor.kt | 52 +++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/p5js/src/main/kotlin/p5jsEditor.kt b/p5js/src/main/kotlin/p5jsEditor.kt index 2f157fb65..bf028f406 100644 --- a/p5js/src/main/kotlin/p5jsEditor.kt +++ b/p5js/src/main/kotlin/p5jsEditor.kt @@ -63,24 +63,55 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?) : createIndexHtml() - // TODO: refactor into functions, pick up crucial information from stdout - statusNotice("Looking for pnpm…") + val stackedStatusNotice = createStackedStatusNotice() + stackedStatusNotice("Looking for pnpm…") try { - runCommand("pnpm -v") + val pnpmVersion = probeCommand("pnpm -v") + stackedStatusNotice("Found $pnpmVersion.") } catch (e: Exception) { - statusNotice("pnpm not found. Installing pnpm…") + stackedStatusNotice("Not found. Installing pnpm…") if (isWindows) { runCommand("powershell -command \"Invoke-WebRequest https://get.pnpm.io/install.ps1 -UseBasicParsing | Invoke-Expression\"") } else { runCommand("chmod u+x ${mode?.folder}/install.sh") runCommand("${mode?.folder}/install.sh") } + stackedStatusNotice("Done.") + } + + stackedStatusNotice("Looking for node…") + try { + val nodeVersion = probeCommand("node -v") + stackedStatusNotice("Found $nodeVersion.") + } catch (e: Exception) { + stackedStatusNotice("Not found. Installing node via pnpm…") - statusNotice("Installing Node via pnpm…") runCommand("pnpm env use --global lts") + + stackedStatusNotice("Done.") } - statusNotice("All done! Enjoy p5.js mode.") + stackedStatusNotice("Enjoy p5.js mode!") + } + } + + fun probeCommand(command: String): String { + val process = builder(command).start() + val exitCode = process.waitFor() + + if (exitCode != 0) { + throw RuntimeException("Command failed with non-zero exit code $exitCode.") + } + + val output = process.inputStream.bufferedReader().use { it.readText() } + return output + } + + fun createStackedStatusNotice(): (String) -> Unit { + var statusText = mutableListOf() + return fun(text: String) { + statusText.add(text) + statusNotice(statusText.joinToString(" ")) } } @@ -102,8 +133,7 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?) : if (sketch.isUntitled || sketch.isReadOnly) { Messages.showMessage("Save First", "Please first save the sketch."); } else { - // TODO: I’m sure this is not the best way to ensure that this runs async, so the ActionListener can return - // but works for now + // TODO: I’m sure this is not the best way to ensure that this runs async, so the ActionListener can return but works for now scope.launch { handleExport() } @@ -336,7 +366,6 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?) : } } - fun runCommand(action: String, directory: File = sketch.folder) { try { val processBuilder = builder(action, directory) @@ -358,15 +387,14 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?) : } } - private fun builder(action: String, directory: File): ProcessBuilder { + private fun builder(action: String, directory: File = sketch.folder): ProcessBuilder { val processBuilder = ProcessBuilder() // Set the command based on the operating system - val shell = System.getenv("SHELL") val command = if (isWindows) { listOf("cmd", "/c", action) } else { - listOf(shell, "-ci", action) + listOf(System.getenv("SHELL"), "-ci", action) } processBuilder.command(command) From b5c7d88b7ee970e3e4fd6023157d83b0fd4f3201 Mon Sep 17 00:00:00 2001 From: Stephan Max Date: Fri, 30 Jan 2026 11:57:32 +0100 Subject: [PATCH 2/2] Consider last line only when probing for command This ignores any user-defined output in an interactive shell that might precede the output of the command. --- p5js/src/main/kotlin/p5jsEditor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p5js/src/main/kotlin/p5jsEditor.kt b/p5js/src/main/kotlin/p5jsEditor.kt index bf028f406..5b35dcf82 100644 --- a/p5js/src/main/kotlin/p5jsEditor.kt +++ b/p5js/src/main/kotlin/p5jsEditor.kt @@ -103,7 +103,7 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?) : throw RuntimeException("Command failed with non-zero exit code $exitCode.") } - val output = process.inputStream.bufferedReader().use { it.readText() } + val output = process.inputStream.bufferedReader().use { it.readLines().last() } return output }