Merge pull request #1050 from Stefterv/feat-command-line

Setup a Command Line Interface
This commit is contained in:
Raphaël de Courville
2025-04-25 11:42:06 +02:00
committed by GitHub
6 changed files with 142 additions and 24 deletions
+4 -1
View File
@@ -47,7 +47,7 @@ sourceSets{
compose.desktop {
application {
mainClass = "processing.app.ui.Start"
mainClass = "processing.app.ProcessingKt"
jvmArgs(*listOf(
Pair("processing.version", rootProject.version),
@@ -97,6 +97,7 @@ compose.desktop {
dependencies {
implementation(project(":core"))
runtimeOnly(project(":java"))
implementation(libs.flatlaf)
@@ -121,6 +122,8 @@ dependencies {
testImplementation(libs.mockitoKotlin)
testImplementation(libs.junitJupiter)
testImplementation(libs.junitJupiterParams)
implementation(libs.clikt)
}
tasks.test {
+90
View File
@@ -0,0 +1,90 @@
package processing.app
import com.github.ajalt.clikt.command.SuspendingCliktCommand
import com.github.ajalt.clikt.command.main
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.help
import com.github.ajalt.clikt.parameters.arguments.multiple
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.help
import com.github.ajalt.clikt.parameters.options.option
import processing.app.ui.Start
class Processing: SuspendingCliktCommand("processing"){
val version by option("-v","--version")
.flag()
.help("Print version information")
val sketches by argument()
.multiple(default = emptyList())
.help("Sketches to open")
override fun help(context: Context) = "Start the Processing IDE"
override val invokeWithoutSubcommand = true
override suspend fun run() {
if(version){
println("processing-${Base.getVersionName()}-${Base.getRevision()}")
return
}
val subcommand = currentContext.invokedSubcommand
if (subcommand == null) {
Start.main(sketches.toTypedArray())
}
}
}
suspend fun main(args: Array<String>){
Processing()
.subcommands(
LSP(),
LegacyCLI(args)
)
.main(args)
}
class LSP: SuspendingCliktCommand("lsp"){
override fun help(context: Context) = "Start the Processing Language Server"
override suspend fun run(){
try {
// Indirect invocation since app does not depend on java mode
Class.forName("processing.mode.java.lsp.PdeLanguageServer")
.getMethod("main", Array<String>::class.java)
.invoke(null, *arrayOf<Any>(emptyList<String>()))
} catch (e: Exception) {
throw InternalError("Failed to invoke main method", e)
}
}
}
class LegacyCLI(val args: Array<String>): SuspendingCliktCommand( "cli"){
override fun help(context: Context) = "Legacy processing-java command line interface"
val help by option("--help").flag()
val build by option("--build").flag()
val run by option("--run").flag()
val present by option("--present").flag()
val sketch: String? by option("--sketch")
val force by option("--force").flag()
val output: String? by option("--output")
val export by option("--export").flag()
val noJava by option("--no-java").flag()
val variant: String? by option("--variant")
override suspend fun run(){
val cliArgs = args.filter { it != "cli" }
try {
if(build){
System.setProperty("java.awt.headless", "true")
}
// Indirect invocation since app does not depend on java mode
Class.forName("processing.mode.java.Commander")
.getMethod("main", Array<String>::class.java)
.invoke(null, *arrayOf<Any>(cliArgs.toTypedArray()))
} catch (e: Exception) {
throw InternalError("Failed to invoke main method", e)
}
}
}
@@ -86,30 +86,41 @@ public class InstallCommander implements Tool {
PrintWriter writer = PApplet.createWriter(file);
writer.print("#!/bin/sh\n\n");
writer.print("# Prevents processing-java from stealing focus, see:\n" +
"# https://github.com/processing/processing/issues/3996.\n" +
"OPTION_FOR_HEADLESS_RUN=\"\"\n" +
"for ARG in \"$@\"\n" +
"do\n" +
" if [ \"$ARG\" = \"--build\" ]; then\n" +
" OPTION_FOR_HEADLESS_RUN=\"-Djava.awt.headless=true\"\n" +
" fi\n" +
"done\n\n");
var resourcesDir = System.getProperty("compose.application.resources.dir");
if(resourcesDir != null) {
// Gradle based distributable
var appBinary = (resourcesDir
.split("\\.app")[0] + ".app/Contents/MacOS/Processing")
.replaceAll(" ", "\\\\ ");
writer.print(appBinary + " cli $@");
String javaRoot = Platform.getContentFile(".").getCanonicalPath();
} else {
// Ant based distributable
writer.print("# Prevents processing-java from stealing focus, see:\n" +
"# https://github.com/processing/processing/issues/3996.\n" +
"OPTION_FOR_HEADLESS_RUN=\"\"\n" +
"for ARG in \"$@\"\n" +
"do\n" +
" if [ \"$ARG\" = \"--build\" ]; then\n" +
" OPTION_FOR_HEADLESS_RUN=\"-Djava.awt.headless=true\"\n" +
" fi\n" +
"done\n\n");
StringList jarList = new StringList();
addJarList(jarList, new File(javaRoot));
addJarList(jarList, new File(javaRoot, "core/library"));
addJarList(jarList, new File(javaRoot, "modes/java/mode"));
String classPath = jarList.join(":").replaceAll(javaRoot + "\\/?", "");
String javaRoot = Platform.getContentFile(".").getCanonicalPath();
writer.println("cd \"" + javaRoot + "\" && " +
Platform.getJavaPath().replaceAll(" ", "\\\\ ") +
" -Djna.nosys=true" +
" $OPTION_FOR_HEADLESS_RUN" +
" -cp \"" + classPath + "\"" +
" processing.mode.java.Commander \"$@\"");
StringList jarList = new StringList();
addJarList(jarList, new File(javaRoot));
addJarList(jarList, new File(javaRoot, "core/library"));
addJarList(jarList, new File(javaRoot, "modes/java/mode"));
String classPath = jarList.join(":").replaceAll(javaRoot + "\\/?", "");
writer.println("cd \"" + javaRoot + "\" && " +
Platform.getJavaPath().replaceAll(" ", "\\\\ ") +
" -Djna.nosys=true" +
" $OPTION_FOR_HEADLESS_RUN" +
" -cp \"" + classPath + "\"" +
" processing.mode.java.Commander \"$@\"");
}
writer.flush();
writer.close();
file.setExecutable(true);
+14 -1
View File
@@ -1,12 +1,25 @@
import processing.core.PApplet;
import java.io.IOException;
public class Basic extends PApplet {
public void settings(){
size(500, 500);
try {
Runtime.getRuntime().exec("echo Hello World");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void draw(){
ellipse(width / 2f, height / 2f, 125f, 125f);
background(255);
fill(0);
ellipse(mouseX, mouseY, 125f, 125f);
println(frameRate);
}
+1
View File
@@ -27,6 +27,7 @@ lsp4j = { module = "org.eclipse.lsp4j:org.eclipse.lsp4j", version = "0.22.0" }
jsoup = { module = "org.jsoup:jsoup", version = "1.17.2" }
markdown = { module = "com.mikepenz:multiplatform-markdown-renderer-m2", version = "0.31.0" }
markdownJVM = { module = "com.mikepenz:multiplatform-markdown-renderer-jvm", version = "0.31.0" }
clikt = { module = "com.github.ajalt.clikt:clikt", version = "5.0.2" }
[plugins]
jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" }
@@ -21,7 +21,7 @@ import org.eclipse.lsp4j.services.LanguageClientAware;
import org.eclipse.lsp4j.services.LanguageClient;
class PdeLanguageServer implements LanguageServer, LanguageClientAware {
public class PdeLanguageServer implements LanguageServer, LanguageClientAware {
Map<File, PdeAdapter> adapters = new HashMap<>();
LanguageClient client = null;
PdeTextDocumentService textDocumentService = new PdeTextDocumentService(this);