@@ -19,6 +19,9 @@ import kotlinx.coroutines.CoroutineScope
1919import kotlinx.coroutines.Dispatchers
2020import kotlinx.coroutines.GlobalScope
2121import kotlinx.coroutines.launch
22+ import kotlinx.coroutines.newSingleThreadContext
23+ import kotlinx.coroutines.sync.Mutex
24+ import kotlinx.coroutines.withContext
2225import kotlinx.serialization.json.*
2326import processing.app.*
2427import processing.app.syntax.JEditTextArea
@@ -34,13 +37,14 @@ import java.io.InputStreamReader
3437import java.net.URL
3538import javax.swing.JMenu
3639import javax.swing.JMenuItem
40+ import kotlin.jvm.optionals.getOrNull
3741
3842
3943class p5jsEditor (base : Base , path : String? , state : EditorState ? , mode : Mode ? ): Editor(base, path, state, mode) {
4044
4145 val scope = CoroutineScope (Dispatchers .Default )
4246 val isWindows = System .getProperty(" os.name" ).lowercase().contains(" windows" )
43- val shell = System .getenv( " SHELL " )
47+ var sketchProcess : Process ? = null
4448
4549 init {
4650 scope.launch {
@@ -96,15 +100,15 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
96100 }
97101
98102 statusNotice(" Installing Node via pnpm…" )
99- runCommand(" pnpm env use --global lts" , onFinished = {
103+ runCommand(" pnpm env use --global lts" ) {
100104 statusNotice(" Installing Node dependencies…" )
101- })
105+ }
102106 }
103107
104108 // --dangerously-allow-all-builds allows electron in particular to install properly
105- runCommand(" pnpm install --dangerously-allow-all-builds" , onFinished = {
109+ runCommand(" pnpm install --dangerously-allow-all-builds" ) {
106110 statusNotice(" All done! Enjoy p5.js mode." )
107- })
111+ }
108112 }
109113 }
110114
@@ -144,10 +148,10 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
144148 runCommand(" pnpm install --dangerously-allow-all-builds --force" )
145149 }
146150
147- runCommand(" pnpm app:pack" , onFinished = {
151+ runCommand(" pnpm app:pack" ) {
148152 Platform .openFolder(sketch.folder)
149153 statusNotice(Language .text(" export.notice.exporting.done" ))
150- })
154+ }
151155 }
152156
153157// override fun handleSaveAs(): Boolean {
@@ -181,11 +185,11 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
181185 }
182186
183187 override fun internalCloseRunner () {
184- processes.forEach { it. destroy() }
188+ sketchProcess?. destroy()
185189 }
186190
187191 override fun deactivateRun () {
188- processes.forEach { it. destroy() }
192+ sketchProcess?. destroy()
189193 toolbar.deactivateRun()
190194 }
191195
@@ -254,27 +258,31 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
254258
255259 }
256260
257- // TODO: state is maintained => turn into class
258- val processes = mutableListOf<Process >()
259261 fun runCommand (action : String , directory : File = sketch.folder, onFinished : () -> Unit = {}) {
260- // Wait for previous processes to finish
261- processes.forEach { it.waitFor() }
262+ try {
263+ // TODO: Get rid of magic strings. Better way to distinguish “endless” processes and processes we wait for?
264+ if (action == " pnpm sketch:start" ) {
265+ sketchProcess?.destroy()
266+ }
262267
263- val processBuilder = ProcessBuilder ()
268+ val processBuilder = ProcessBuilder ()
264269
265- // Set the command based on the operating system
266- val command = if (isWindows) {
267- listOf (" cmd" , " /c" , action)
268- } else {
269- listOf (shell, " -ci" , action)
270- }
270+ // Set the command based on the operating system
271+ val shell = System .getenv(" SHELL" )
272+ val command = if (isWindows) {
273+ listOf (" cmd" , " /c" , action)
274+ } else {
275+ listOf (shell, " -ci" , action)
276+ }
271277
272- processBuilder.command(command)
273- processBuilder.directory(directory)
278+ processBuilder.command(command)
279+ processBuilder.directory(directory)
274280
275- try {
276281 val process = processBuilder.start()
277- processes.add(process)
282+
283+ if (action == " pnpm sketch:start" ) {
284+ sketchProcess = process;
285+ }
278286
279287 // Handle output stream
280288 val reader = BufferedReader (InputStreamReader (process.inputStream))
@@ -294,15 +302,15 @@ class p5jsEditor(base: Base, path: String?, state: EditorState?, mode: Mode?): E
294302 println (line)
295303 }
296304
297- // Wait for the process to complete
298305 val exitCode = process.waitFor()
299- processes.remove(process)
300- onFinished()
306+
301307 if (exitCode != 0 ) {
302- throw RuntimeException (" $action failed with exit code $exitCode ." )
308+ throw RuntimeException (" Command failed with non-zero exit code $exitCode ." )
303309 }
310+
311+ onFinished()
304312 } catch (e: Exception ) {
305- throw RuntimeException (" Failed to run $action . " , e )
313+ statusError (" Failed to run ` $action `: ${e.message} " )
306314 }
307315 }
308316}
0 commit comments