Skip to content

Commit 85566c8

Browse files
committed
CLI Compatibility
1 parent 7f2f2b6 commit 85566c8

File tree

7 files changed

+126
-43
lines changed

7 files changed

+126
-43
lines changed

app/src/processing/app/Processing.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.github.ajalt.clikt.parameters.arguments.multiple
1010
import com.github.ajalt.clikt.parameters.options.flag
1111
import com.github.ajalt.clikt.parameters.options.help
1212
import com.github.ajalt.clikt.parameters.options.option
13+
import processing.app.gradle.api.Sketch
1314
import processing.app.ui.Start
1415

1516
class Processing: SuspendingCliktCommand("processing"){
@@ -40,7 +41,8 @@ suspend fun main(args: Array<String>){
4041
Processing()
4142
.subcommands(
4243
LSP(),
43-
LegacyCLI(args)
44+
LegacyCLI(args),
45+
Sketch()
4446
)
4547
.main(args)
4648
}

app/src/processing/app/gradle/Exceptions.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class Exceptions {
5353
println("Thread : ${thread.name()}")
5454
println("Location : ${location.sourcePath()}:${location.lineNumber()}\n")
5555

56+
// TODO: Map to .pde file again
57+
// TODO: Communicate back to Editor
58+
5659
// Separate stack frames
5760
val userFrames = mutableListOf<StackFrame>()
5861
val processingFrames = mutableListOf<StackFrame>()

app/src/processing/app/gradle/GradleJob.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ import processing.app.Messages
2020
import java.io.InputStreamReader
2121
import java.io.PipedInputStream
2222
import java.io.PipedOutputStream
23+
import java.lang.IllegalStateException
2324

2425
// TODO: Move the error reporting to its own file
2526
// TODO: Move the output filtering to its own file
27+
// TODO: Remove dependency on Editor
2628
abstract class GradleJob{
2729
enum class State{
2830
NONE,
@@ -45,8 +47,7 @@ abstract class GradleJob{
4547
private val errorStream = PipedOutputStream()
4648

4749
fun start() {
48-
service?.jobs?.add(this)
49-
val folder = service?.folder ?: return
50+
val folder = service?.sketch?.folder ?: throw IllegalStateException("Sketch folder is not set")
5051
scope.launch {
5152
try {
5253
state.value = State.BUILDING
@@ -71,6 +72,7 @@ abstract class GradleJob{
7172
vm.value = null
7273
}
7374
}
75+
// TODO: I'm sure this can be done better
7476
scope.launch {
7577
try {
7678
InputStreamReader(PipedInputStream(outputStream)).buffered().use { reader ->
@@ -82,7 +84,7 @@ abstract class GradleJob{
8284
if (state.value != State.RUNNING) {
8385
return@forEach
8486
}
85-
service?.editor?.console?.out?.println(line)
87+
service?.out?.println(line)
8688
}
8789
}
8890
}catch (e: Exception){
@@ -104,7 +106,7 @@ abstract class GradleJob{
104106
line.contains("+[IMKClient subclass]: chose IMKClient_Modern") -> return@forEach
105107
line.contains("+[IMKInputSession subclass]: chose IMKInputSession_Modern") -> return@forEach
106108
line.startsWith("__MOVE__") -> return@forEach
107-
else -> service?.editor?.console?.err?.println(line)
109+
else -> service?.err?.println(line)
108110
}
109111
}
110112
}
@@ -155,7 +157,7 @@ abstract class GradleJob{
155157
val details = event.details.details?.replace(path ?: "", "")
156158
val solutions = event.solutions.joinToString("\n") { it.solution }
157159
val content = "$header\n$details\n$solutions"
158-
service?.editor?.console?.err?.println(content)
160+
service?.err?.println(content)
159161
}
160162
})
161163
}

app/src/processing/app/gradle/GradleService.kt

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,29 @@ package processing.app.gradle
22

33
import androidx.compose.runtime.mutableStateListOf
44
import androidx.compose.runtime.mutableStateOf
5-
import kotlinx.coroutines.CoroutineScope
6-
import kotlinx.coroutines.Dispatchers
7-
import kotlinx.coroutines.launch
85
import org.gradle.tooling.BuildLauncher
9-
import org.gradle.tooling.GradleConnector
10-
import org.gradle.tooling.ProjectConnection
116
import processing.app.Base
127
import processing.app.Language
138
import processing.app.Messages
9+
import processing.app.Mode
1410
import processing.app.Platform
1511
import processing.app.Preferences
12+
import processing.app.Sketch
1613
import processing.app.gradle.helpers.ActionGradleJob
17-
import processing.app.gradle.helpers.BackgroundGradleJob
1814
import processing.app.ui.Editor
1915
import java.io.*
20-
import javax.swing.SwingUtilities
21-
import javax.swing.event.DocumentEvent
22-
import javax.swing.event.DocumentListener
16+
import kotlin.io.path.createTempDirectory
2317
import kotlin.io.path.deleteIfExists
2418
import kotlin.io.path.writeText
2519

2620
// TODO: Test offline mode, gradle seems to be included as not needed to be downloaded.
2721
// TODO: Test running examples
2822
// TODO: Report failures to the console
23+
// TODO: Remove dependency on getting mode from Editor
24+
// TODO: Remove dependency on editor (editor is not mockable and not usable in the CLI, or move editor away from JFrame)
25+
// TODO: Highlight errors in the editor
2926

3027
// TODO: ---- FUTURE ----
31-
// TODO: Remove dependency on editor (editor is not mockable, or move editor away from JFrame)
3228
// TODO: Improve progress tracking
3329
// TODO: PoC new debugger/tweak mode
3430
// TODO: Allow for plugins to skip gradle entirely / new modes
@@ -39,48 +35,46 @@ import kotlin.io.path.writeText
3935
// It will create the necessary build files for gradle to run
4036
// Then it will kick off a new GradleJob to run the tasks
4137
// GradleJob manages the gradle build and connects the debugger
42-
class GradleService(val editor: Editor) {
43-
val folder: File get() = editor.sketch.folder
38+
class GradleService(
39+
// TODO: Move to a mode object after decoupling from Editor
40+
val mode: Mode,
41+
val editor: Editor?,
42+
) {
4443
val active = mutableStateOf(Preferences.getBoolean("run.use_gradle"))
4544

46-
val jobs = mutableStateListOf<GradleJob>()
47-
val workingDir = kotlin.io.path.createTempDirectory()
48-
val debugPort = (30_000..60_000).random()
45+
var sketch: Sketch? = null
4946

50-
private val scope = CoroutineScope(Dispatchers.IO)
47+
var out: PrintStream = System.out
48+
var err: PrintStream = System.err
5149

52-
// Hooks for java to check if the Gradle service is running since mutableStateOf is not accessible in java
53-
fun getEnabled(): Boolean {
54-
return active.value
55-
}
56-
fun setEnabled(active: Boolean) {
57-
this.active.value = active
58-
}
50+
val jobs = mutableStateListOf<GradleJob>()
51+
val workingDir = createTempDirectory()
52+
val debugPort = (30_000..60_000).random()
5953

6054
// TODO: Add support for present
6155
fun run(){
6256
stopActions()
63-
editor.console.clear()
6457

6558
val job = ActionGradleJob()
6659
job.service = this
6760
job.configure = {
6861
setup()
6962
forTasks("run")
7063
}
64+
jobs.add(job)
7165
job.start()
7266
}
7367

7468
fun export(){
7569
stopActions()
76-
editor.console.clear()
7770

7871
val job = ActionGradleJob()
7972
job.service = this
8073
job.configure = {
8174
setup()
8275
forTasks("runDistributable")
8376
}
77+
jobs.add(job)
8478
job.start()
8579
}
8680

@@ -95,7 +89,9 @@ class GradleService(val editor: Editor) {
9589
}
9690

9791
private fun setupGradle(): MutableList<String> {
98-
val unsaved = editor.sketch.code
92+
val sketch = sketch ?: throw IllegalStateException("Sketch is not set")
93+
94+
val unsaved = sketch.code
9995
.map { code ->
10096
val file = workingDir.resolve("unsaved/${code.fileName}")
10197
file.parent.toFile().mkdirs()
@@ -114,7 +110,7 @@ class GradleService(val editor: Editor) {
114110
val variables = mapOf(
115111
"group" to group,
116112
"version" to Base.getVersionName(),
117-
"sketchFolder" to folder.absolutePath,
113+
"sketchFolder" to sketch.folder.absolutePath,
118114
"sketchbook" to Base.getSketchbookFolder(),
119115
"workingDir" to workingDir.toAbsolutePath().toString(),
120116
"settings" to Platform.getSettingsFolder().absolutePath.toString(),
@@ -123,12 +119,12 @@ class GradleService(val editor: Editor) {
123119
"fullscreen" to false, // TODO: Implement
124120
"display" to 1, // TODO: Implement
125121
"external" to true,
126-
"editor.location" to editor.location.let { "${it.x},${it.y}" },
122+
"editor.location" to editor?.location?.let { "${it.x},${it.y}" },
127123
//"awt.disable" to false,
128124
//"window.color" to "0xFF000000", // TODO: Implement
129125
//"stop.color" to "0xFF000000", // TODO: Implement
130126
"stop.hide" to false, // TODO: Implement
131-
"sketch.folder" to folder.absolutePath,
127+
"sketch.folder" to sketch.folder.absolutePath,
132128
)
133129
val repository = Platform.getContentFile("repository").absolutePath.replace("""\""", """\\""")
134130

@@ -154,7 +150,7 @@ class GradleService(val editor: Editor) {
154150
}
155151

156152

157-
val buildGradle = folder.resolve("build.gradle.kts")
153+
val buildGradle = sketch.folder.resolve("build.gradle.kts")
158154
val generate = buildGradle.let {
159155
if(!it.exists()) return@let true
160156

@@ -164,15 +160,15 @@ class GradleService(val editor: Editor) {
164160
val version = contents.substringAfter("version=").substringBefore("\n")
165161
if(version != Base.getVersionName()) return@let true
166162

167-
val mode = contents.substringAfter("mode=").substringBefore(" ")
168-
if(editor.mode.title != mode) return@let true
163+
val modeTitle = contents.substringAfter("mode=").substringBefore(" ")
164+
if(this.mode.title != modeTitle) return@let true
169165

170166
return@let Base.DEBUG
171167
}
172168
if (generate) {
173-
Messages.log("build.gradle.kts outdated or not found in ${folder}, creating one")
169+
Messages.log("build.gradle.kts outdated or not found in ${sketch.folder}, creating one")
174170
val header = """
175-
// @processing-auto-generated mode=${editor.mode.title} version=${Base.getVersionName()}
171+
// @processing-auto-generated mode=${mode.title} version=${Base.getVersionName()}
176172
//
177173
""".trimIndent()
178174

@@ -193,14 +189,17 @@ class GradleService(val editor: Editor) {
193189
val content = "${header}\n${instructions}\n${configuration}"
194190
buildGradle.writeText(content)
195191
}
196-
val settingsGradle = folder.resolve("settings.gradle.kts")
192+
val settingsGradle = sketch.folder.resolve("settings.gradle.kts")
197193
if (!settingsGradle.exists()) {
198194
settingsGradle.createNewFile()
199195
}
200196

201197
val arguments = mutableListOf("--init-script", initGradle.toAbsolutePath().toString())
202198
if (!Base.DEBUG) arguments.add("--quiet")
203-
arguments.addAll(variables.entries.map { "-Pprocessing.${it.key}=${it.value}" })
199+
arguments.addAll(variables.entries
200+
.filter { it.value != null }
201+
.map { "-Pprocessing.${it.key}=${it.value}" }
202+
)
204203

205204
return arguments
206205
}
@@ -213,4 +212,12 @@ class GradleService(val editor: Editor) {
213212
arguments.addAll(extraArguments)
214213
withArguments(*arguments.toTypedArray())
215214
}
215+
216+
// Hooks for java to check if the Gradle service is running since mutableStateOf is not accessible in java
217+
fun getEnabled(): Boolean {
218+
return active.value
219+
}
220+
fun setEnabled(active: Boolean) {
221+
this.active.value = active
222+
}
216223
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package processing.app.gradle.api
2+
3+
import com.github.ajalt.clikt.command.SuspendingCliktCommand
4+
import com.github.ajalt.clikt.core.Context
5+
import com.github.ajalt.clikt.core.subcommands
6+
import com.github.ajalt.clikt.parameters.options.option
7+
import com.github.ajalt.clikt.parameters.options.required
8+
import processing.app.Base
9+
import processing.app.Platform
10+
import processing.app.Preferences
11+
import processing.app.contrib.ModeContribution
12+
import processing.app.gradle.GradleJob
13+
import processing.app.gradle.GradleService
14+
15+
class Sketch : SuspendingCliktCommand("sketch") {
16+
init {
17+
subcommands(
18+
Run()
19+
)
20+
}
21+
22+
override fun help(context: Context): String {
23+
return """Manage sketches in the Processing environment."""
24+
}
25+
26+
override suspend fun run() {
27+
System.setProperty("java.awt.headless", "true")
28+
}
29+
30+
class Run : SuspendingCliktCommand(name = "run") {
31+
val sketch by option("--sketch", help = "The sketch to run")
32+
.required()
33+
34+
override fun help(context: Context): String {
35+
return "Run the Processing sketch."
36+
}
37+
38+
override suspend fun run() {
39+
Base.setCommandLine()
40+
Platform.init()
41+
Preferences.init()
42+
Base.locateSketchbookFolder()
43+
44+
// TODO: Support modes other than Java
45+
val mode = ModeContribution.load(
46+
null, Platform.getContentFile("modes/java"),
47+
"processing.mode.java.JavaMode"
48+
).mode ?: throw IllegalStateException("Java mode not found")
49+
50+
System.setProperty("java.awt.headless", "false")
51+
52+
val service = GradleService(mode,null)
53+
service.sketch = processing.app.Sketch(sketch, mode)
54+
service.run()
55+
56+
// TODO: Use an async way to wait for the job to finish
57+
//Wait for the service to finish
58+
while (service.jobs.any { it.state.value != GradleJob.State.DONE }) {
59+
Thread.sleep(100)
60+
}
61+
}
62+
}
63+
}

app/src/processing/app/ui/Editor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ protected Editor(final Base base, String path, final EditorState state,
159159
this.base = base;
160160
this.state = state;
161161
this.mode = mode;
162-
this.service = new GradleService(this);
162+
this.service = new GradleService(this.mode,this);
163163

164164
// Make sure Base.getActiveEditor() never returns null
165165
base.checkFirstEditor(this);
@@ -2280,6 +2280,7 @@ protected void handleOpenInternal(String path) throws EditorException {
22802280
} catch (IOException e) {
22812281
throw new EditorException("Could not create the sketch.", e);
22822282
}
2283+
service.setSketch(sketch);
22832284

22842285
header.rebuild();
22852286
updateTitle();

app/src/processing/app/ui/EditorConsole.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public EditorConsole(Editor editor) {
8282
sketchOut = new PrintStream(new EditorConsoleStream(false));
8383
sketchErr = new PrintStream(new EditorConsoleStream(true));
8484

85+
if(editor.service != null){
86+
editor.service.setOut(sketchOut);
87+
editor.service.setErr(sketchErr);
88+
}
89+
8590
startTimer();
8691
}
8792

0 commit comments

Comments
 (0)