mirror of
https://github.com/processing/processing4.git
synced 2026-01-23 16:31:07 +01:00
Merge branch 'processing:main' into main
This commit is contained in:
@@ -1642,6 +1642,15 @@
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "catilac",
|
||||
"name": "Moon",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/15107?v=4",
|
||||
"profile": "https://softmoon.world",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"repoType": "github",
|
||||
|
||||
1
.github/workflows/release-gradle.yml
vendored
1
.github/workflows/release-gradle.yml
vendored
@@ -153,6 +153,7 @@ jobs:
|
||||
ORG_GRADLE_PROJECT_compose.desktop.mac.notarization.password: ${{ secrets.PROCESSING_APP_PASSWORD }}
|
||||
ORG_GRADLE_PROJECT_compose.desktop.mac.notarization.teamID: ${{ secrets.PROCESSING_TEAM_ID }}
|
||||
ORG_GRADLE_PROJECT_snapname: ${{ vars.SNAP_NAME }}
|
||||
ORG_GRADLE_PROJECT_snapconfinement: ${{ vars.SNAP_CONFINEMENT }}
|
||||
|
||||
- name: Sign files with Trusted Signing
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
@@ -313,6 +313,7 @@ _Note: due to GitHub's limitations, this repository's [Contributors](https://git
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/aj-m"><img src="https://avatars.githubusercontent.com/u/2524348?v=4?s=120" width="120px;" alt="Andrew"/><br /><sub><b>Andrew</b></sub></a><br /><a href="https://github.com/processing/processing4/commits?author=aj-m" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/pnngocdoan"><img src="https://avatars.githubusercontent.com/u/113954980?v=4?s=120" width="120px;" alt="Ngoc Doan"/><br /><sub><b>Ngoc Doan</b></sub></a><br /><a href="https://github.com/processing/processing4/commits?author=pnngocdoan" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/manoellribeiro"><img src="https://avatars.githubusercontent.com/u/59377764?v=4?s=120" width="120px;" alt="Manoel Ribeiro"/><br /><sub><b>Manoel Ribeiro</b></sub></a><br /><a href="https://github.com/processing/processing4/commits?author=manoellribeiro" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://softmoon.world"><img src="https://avatars.githubusercontent.com/u/15107?v=4?s=120" width="120px;" alt="Moon"/><br /><sub><b>Moon</b></sub></a><br /><a href="https://github.com/processing/processing4/commits?author=catilac" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -124,6 +124,7 @@ dependencies {
|
||||
testImplementation(libs.junitJupiterParams)
|
||||
|
||||
implementation(libs.clikt)
|
||||
implementation(libs.kotlinxSerializationJson)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
@@ -228,61 +229,44 @@ tasks.register<Exec>("packageCustomMsi"){
|
||||
|
||||
|
||||
tasks.register("generateSnapConfiguration"){
|
||||
val name = findProperty("snapname") ?: rootProject.name
|
||||
onlyIf { OperatingSystem.current().isLinux }
|
||||
|
||||
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
||||
dependsOn(distributable)
|
||||
|
||||
val name = findProperty("snapname") as String? ?: rootProject.name
|
||||
val arch = when (System.getProperty("os.arch")) {
|
||||
"amd64", "x86_64" -> "amd64"
|
||||
"aarch64" -> "arm64"
|
||||
else -> System.getProperty("os.arch")
|
||||
}
|
||||
|
||||
onlyIf { OperatingSystem.current().isLinux }
|
||||
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
||||
dependsOn(distributable)
|
||||
|
||||
val confinement = findProperty("snapconfinement") as String? ?: "strict"
|
||||
val dir = distributable.destinationDir.get()
|
||||
val content = """
|
||||
name: $name
|
||||
version: $version
|
||||
base: core22
|
||||
summary: A creative coding editor
|
||||
description: |
|
||||
Processing is a flexible software sketchbook and a programming language designed for learning how to code.
|
||||
confinement: strict
|
||||
|
||||
apps:
|
||||
processing:
|
||||
command: opt/processing/bin/Processing
|
||||
desktop: opt/processing/lib/processing-Processing.desktop
|
||||
environment:
|
||||
LD_LIBRARY_PATH: ${'$'}SNAP/opt/processing/lib/runtime/lib:${'$'}LD_LIBRARY_PATH
|
||||
LIBGL_DRIVERS_PATH: ${'$'}SNAP/usr/lib/${'$'}SNAPCRAFT_ARCH_TRIPLET/dri
|
||||
plugs:
|
||||
- desktop
|
||||
- desktop-legacy
|
||||
- wayland
|
||||
- x11
|
||||
- network
|
||||
- opengl
|
||||
- home
|
||||
- removable-media
|
||||
- audio-playback
|
||||
- audio-record
|
||||
- pulseaudio
|
||||
- gpio
|
||||
|
||||
parts:
|
||||
processing:
|
||||
plugin: dump
|
||||
source: deb/processing_$version-1_$arch.deb
|
||||
source-type: deb
|
||||
stage-packages:
|
||||
- openjdk-17-jre
|
||||
override-prime: |
|
||||
snapcraftctl prime
|
||||
rm -vf usr/lib/jvm/java-17-openjdk-*/lib/security/cacerts
|
||||
chmod -R +x opt/processing/lib/app/resources/jdk
|
||||
""".trimIndent()
|
||||
dir.file("../snapcraft.yaml").asFile.writeText(content)
|
||||
val base = layout.projectDirectory.file("linux/snapcraft.base.yml")
|
||||
|
||||
doFirst {
|
||||
|
||||
var content = base
|
||||
.asFile
|
||||
.readText()
|
||||
.replace("\$name", name)
|
||||
.replace("\$arch", arch)
|
||||
.replace("\$version", version as String)
|
||||
.replace("\$confinement", confinement)
|
||||
.let {
|
||||
if (confinement != "classic") return@let it
|
||||
// If confinement is not strict, remove the PLUGS section
|
||||
val start = it.indexOf("# PLUGS START")
|
||||
val end = it.indexOf("# PLUGS END")
|
||||
if (start != -1 && end != -1) {
|
||||
val before = it.substring(0, start)
|
||||
val after = it.substring(end + "# PLUGS END".length)
|
||||
return@let before + after
|
||||
}
|
||||
return@let it
|
||||
}
|
||||
dir.file("../snapcraft.yaml").asFile.writeText(content)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Exec>("packageSnap"){
|
||||
@@ -424,7 +408,6 @@ tasks.register<Copy>("renameWindres") {
|
||||
}
|
||||
tasks.register("includeProcessingResources"){
|
||||
dependsOn(
|
||||
"includeJdk",
|
||||
"includeCore",
|
||||
"includeJavaMode",
|
||||
"includeSharedAssets",
|
||||
@@ -433,6 +416,7 @@ tasks.register("includeProcessingResources"){
|
||||
"includeJavaModeResources",
|
||||
"renameWindres"
|
||||
)
|
||||
mustRunAfter("includeJdk")
|
||||
finalizedBy("signResources")
|
||||
}
|
||||
|
||||
@@ -539,6 +523,7 @@ afterEvaluate {
|
||||
dependsOn("includeProcessingResources")
|
||||
}
|
||||
tasks.named("createDistributable").configure {
|
||||
dependsOn("includeJdk")
|
||||
finalizedBy("setExecutablePermissions")
|
||||
}
|
||||
}
|
||||
|
||||
42
app/linux/snapcraft.base.yml
Normal file
42
app/linux/snapcraft.base.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
name: $name
|
||||
version: $version
|
||||
base: core22
|
||||
summary: A creative coding editor
|
||||
description: |
|
||||
Processing is a flexible software sketchbook and a programming language designed for learning how to code.
|
||||
confinement: $confinement
|
||||
|
||||
apps:
|
||||
processing:
|
||||
command: opt/processing/bin/Processing
|
||||
desktop: opt/processing/lib/processing-Processing.desktop
|
||||
environment:
|
||||
LD_LIBRARY_PATH: $SNAP/opt/processing/lib/runtime/lib:$LD_LIBRARY_PATH
|
||||
LIBGL_DRIVERS_PATH: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/dri
|
||||
# PLUGS START
|
||||
plugs:
|
||||
- desktop
|
||||
- desktop-legacy
|
||||
- wayland
|
||||
- x11
|
||||
- network
|
||||
- opengl
|
||||
- home
|
||||
- removable-media
|
||||
- audio-playback
|
||||
- audio-record
|
||||
- pulseaudio
|
||||
- gpio
|
||||
# PLUGS END
|
||||
|
||||
parts:
|
||||
processing:
|
||||
plugin: dump
|
||||
source: deb/processing_$version-1_$arch.deb
|
||||
source-type: deb
|
||||
stage-packages:
|
||||
- openjdk-17-jre
|
||||
override-prime: |
|
||||
snapcraftctl prime
|
||||
rm -vf usr/lib/jvm/java-17-openjdk-*/lib/security/cacerts
|
||||
chmod -R +x opt/processing/lib/app/resources/jdk
|
||||
@@ -166,18 +166,6 @@ public class Base {
|
||||
static private void createAndShowGUI(String[] args) {
|
||||
// these times are fairly negligible relative to Base.<init>
|
||||
// long t1 = System.currentTimeMillis();
|
||||
var preferences = java.util.prefs.Preferences.userRoot().node("org/processing/app");
|
||||
var installLocations = new ArrayList<>(List.of(preferences.get("installLocations", "").split(",")));
|
||||
var installLocation = System.getProperty("user.dir") + "^" + Base.getVersionName();
|
||||
|
||||
// Check if the installLocation is already in the list
|
||||
if (!installLocations.contains(installLocation)) {
|
||||
// Add the installLocation to the list
|
||||
installLocations.add(installLocation);
|
||||
|
||||
// Save the updated list back to preferences
|
||||
preferences.put("installLocations", String.join(",", installLocations));
|
||||
}
|
||||
// TODO: Cleanup old locations if no longer installed
|
||||
// TODO: Cleanup old locations if current version is installed in the same location
|
||||
|
||||
|
||||
@@ -105,6 +105,9 @@ public class Platform {
|
||||
"An unknown error occurred while trying to load\n" +
|
||||
"platform-specific code for your machine.", e);
|
||||
}
|
||||
|
||||
// Fix the issue where `java.home` points to the JRE instead of the JDK. processing/processing4#1163
|
||||
System.setProperty("java.home", getJavaHome().getAbsolutePath());
|
||||
}
|
||||
|
||||
|
||||
@@ -389,6 +392,7 @@ public class Platform {
|
||||
}
|
||||
|
||||
static public File getJavaHome() {
|
||||
// Get the build in JDK location from the Jetpack Compose resources
|
||||
var resourcesDir = System.getProperty("compose.application.resources.dir");
|
||||
if(resourcesDir != null) {
|
||||
var jdkFolder = new File(resourcesDir,"jdk");
|
||||
@@ -397,10 +401,13 @@ public class Platform {
|
||||
}
|
||||
}
|
||||
|
||||
// If the JDK is set in the environment, use that.
|
||||
var home = System.getProperty("java.home");
|
||||
if(home != null){
|
||||
return new File(home);
|
||||
}
|
||||
|
||||
// Otherwise try to use the Ant embedded JDK.
|
||||
if (Platform.isMacOS()) {
|
||||
//return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java";
|
||||
File[] plugins = getContentFile("../PlugIns").listFiles((dir, name) -> dir.isDirectory() &&
|
||||
|
||||
@@ -10,7 +10,12 @@ 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.api.Contributions
|
||||
import processing.app.api.Sketchbook
|
||||
import processing.app.ui.Start
|
||||
import java.io.File
|
||||
import java.util.prefs.Preferences
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class Processing: SuspendingCliktCommand("processing"){
|
||||
val version by option("-v","--version")
|
||||
@@ -29,6 +34,11 @@ class Processing: SuspendingCliktCommand("processing"){
|
||||
return
|
||||
}
|
||||
|
||||
thread {
|
||||
// Update the install locations in preferences
|
||||
updateInstallLocations()
|
||||
}
|
||||
|
||||
val subcommand = currentContext.invokedSubcommand
|
||||
if (subcommand == null) {
|
||||
Start.main(sketches.toTypedArray())
|
||||
@@ -40,7 +50,9 @@ suspend fun main(args: Array<String>){
|
||||
Processing()
|
||||
.subcommands(
|
||||
LSP(),
|
||||
LegacyCLI(args)
|
||||
LegacyCLI(args),
|
||||
Contributions(),
|
||||
Sketchbook()
|
||||
)
|
||||
.main(args)
|
||||
}
|
||||
@@ -49,6 +61,9 @@ class LSP: SuspendingCliktCommand("lsp"){
|
||||
override fun help(context: Context) = "Start the Processing Language Server"
|
||||
override suspend fun run(){
|
||||
try {
|
||||
// run in headless mode
|
||||
System.setProperty("java.awt.headless", "true")
|
||||
|
||||
// Indirect invocation since app does not depend on java mode
|
||||
Class.forName("processing.mode.java.lsp.PdeLanguageServer")
|
||||
.getMethod("main", Array<String>::class.java)
|
||||
@@ -68,10 +83,9 @@ class LegacyCLI(val args: Array<String>): SuspendingCliktCommand("cli") {
|
||||
|
||||
override suspend fun run() {
|
||||
try {
|
||||
if (arguments.contains("--build")) {
|
||||
System.setProperty("java.awt.headless", "true")
|
||||
}
|
||||
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, arguments.toTypedArray())
|
||||
@@ -80,3 +94,49 @@ class LegacyCLI(val args: Array<String>): SuspendingCliktCommand("cli") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateInstallLocations(){
|
||||
val preferences = Preferences.userRoot().node("org/processing/app")
|
||||
val installLocations = preferences.get("installLocations", "")
|
||||
.split(",")
|
||||
.dropLastWhile { it.isEmpty() }
|
||||
.filter { install ->
|
||||
try{
|
||||
val (path, version) = install.split("^")
|
||||
val file = File(path)
|
||||
if(!file.exists() || file.isDirectory){
|
||||
return@filter false
|
||||
}
|
||||
// call the path to check if it is a valid install location
|
||||
val process = ProcessBuilder(path, "--version")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
val exitCode = process.waitFor()
|
||||
if(exitCode != 0){
|
||||
return@filter false
|
||||
}
|
||||
val output = process.inputStream.bufferedReader().readText()
|
||||
return@filter output.contains(version)
|
||||
} catch (e: Exception){
|
||||
false
|
||||
}
|
||||
}
|
||||
.toMutableList()
|
||||
val command = ProcessHandle.current().info().command()
|
||||
if(command.isEmpty) {
|
||||
return
|
||||
}
|
||||
val installLocation = "${command.get()}^${Base.getVersionName()}"
|
||||
|
||||
|
||||
// Check if the installLocation is already in the list
|
||||
if (installLocations.contains(installLocation)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Add the installLocation to the list
|
||||
installLocations.add(installLocation)
|
||||
|
||||
// Save the updated list back to preferences
|
||||
preferences.put("installLocations", java.lang.String.join(",", installLocations))
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import processing.app.ui.WelcomeToBeta;
|
||||
import processing.core.PApplet;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Threaded class to check for updates in the background.
|
||||
* <p/>
|
||||
@@ -112,6 +113,7 @@ public class UpdateCheck {
|
||||
System.getProperty("os.arch"));
|
||||
|
||||
int latest = readInt(LATEST_URL + "?" + info);
|
||||
int revision = Base.getRevision();
|
||||
|
||||
String lastString = Preferences.get("update.last");
|
||||
long now = System.currentTimeMillis();
|
||||
@@ -125,18 +127,19 @@ public class UpdateCheck {
|
||||
Preferences.set("update.last", String.valueOf(now));
|
||||
|
||||
if (base.activeEditor != null) {
|
||||
// boolean offerToUpdateContributions = true;
|
||||
|
||||
if (latest > Base.getRevision()) {
|
||||
if (latest > revision) {
|
||||
System.out.println("You are running Processing revision 0" +
|
||||
Base.getRevision() + ", the latest build is 0" +
|
||||
revision + ", the latest build is 0" +
|
||||
latest + ".");
|
||||
// Assume the person is busy downloading the latest version
|
||||
// offerToUpdateContributions = !promptToVisitDownloadPage();
|
||||
promptToVisitDownloadPage();
|
||||
}
|
||||
if(latest < Base.getRevision()){
|
||||
WelcomeToBeta.showWelcomeToBeta();
|
||||
|
||||
int lastBetaWelcomeSeen = Preferences.getInteger("update.beta_welcome");
|
||||
if(latest < revision && revision != lastBetaWelcomeSeen ) {
|
||||
WelcomeToBeta.showWelcomeToBeta();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
144
app/src/processing/app/api/Contributions.kt
Normal file
144
app/src/processing/app/api/Contributions.kt
Normal file
@@ -0,0 +1,144 @@
|
||||
package processing.app.api
|
||||
|
||||
import com.github.ajalt.clikt.command.SuspendingCliktCommand
|
||||
import com.github.ajalt.clikt.core.Context
|
||||
import com.github.ajalt.clikt.core.subcommands
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import processing.app.Platform
|
||||
import processing.app.api.Sketch.Companion.getSketches
|
||||
import java.io.File
|
||||
|
||||
class Contributions: SuspendingCliktCommand(){
|
||||
override fun help(context: Context) = "Manage Processing contributions"
|
||||
override suspend fun run() {
|
||||
System.setProperty("java.awt.headless", "true")
|
||||
}
|
||||
init {
|
||||
subcommands(Examples())
|
||||
}
|
||||
|
||||
class Examples: SuspendingCliktCommand("examples") {
|
||||
override fun help(context: Context) = "Manage Processing examples"
|
||||
override suspend fun run() {
|
||||
}
|
||||
init {
|
||||
subcommands(ExamplesList())
|
||||
}
|
||||
}
|
||||
|
||||
class ExamplesList: SuspendingCliktCommand("list") {
|
||||
|
||||
|
||||
val serializer = Json {
|
||||
prettyPrint = true
|
||||
}
|
||||
|
||||
override fun help(context: Context) = "List all examples"
|
||||
override suspend fun run() {
|
||||
Platform.init()
|
||||
// TODO: Decouple modes listing from `Base` class, defaulting to Java mode for now
|
||||
// TODO: Allow the user to change the sketchbook location
|
||||
// TODO: Currently blocked since `Base.getSketchbookFolder()` is not available in headless mode
|
||||
val sketchbookFolder = Platform.getDefaultSketchbookFolder()
|
||||
val resourcesDir = System.getProperty("compose.application.resources.dir")
|
||||
|
||||
val javaMode = "$resourcesDir/modes/java"
|
||||
|
||||
val javaModeExamples = File("$javaMode/examples")
|
||||
.listFiles()
|
||||
?.map { getSketches(it)}
|
||||
?: emptyList()
|
||||
|
||||
val javaModeLibrariesExamples = File("$javaMode/libraries")
|
||||
.listFiles{ it.isDirectory }
|
||||
?.map { library ->
|
||||
val properties = library.resolve("library.properties")
|
||||
val name = findNameInProperties(properties) ?: library.name
|
||||
|
||||
val libraryExamples = getSketches(library.resolve("examples"))
|
||||
Sketch.Companion.Folder(
|
||||
type = "folder",
|
||||
name = name,
|
||||
path = library.absolutePath,
|
||||
mode = "java",
|
||||
children = libraryExamples?.children ?: emptyList(),
|
||||
sketches = libraryExamples?.sketches ?: emptyList()
|
||||
)
|
||||
} ?: emptyList()
|
||||
val javaModeLibraries = Sketch.Companion.Folder(
|
||||
type = "folder",
|
||||
name = "Libraries",
|
||||
path = "$javaMode/libraries",
|
||||
mode = "java",
|
||||
children = javaModeLibrariesExamples,
|
||||
sketches = emptyList()
|
||||
)
|
||||
|
||||
val contributedLibraries = sketchbookFolder.resolve("libraries")
|
||||
.listFiles{ it.isDirectory }
|
||||
?.map { library ->
|
||||
val properties = library.resolve("library.properties")
|
||||
val name = findNameInProperties(properties) ?: library.name
|
||||
// Get library name from library.properties if it exists
|
||||
val libraryExamples = getSketches(library.resolve("examples"))
|
||||
Sketch.Companion.Folder(
|
||||
type = "folder",
|
||||
name = name,
|
||||
path = library.absolutePath,
|
||||
mode = "java",
|
||||
children = libraryExamples?.children ?: emptyList(),
|
||||
sketches = libraryExamples?.sketches ?: emptyList()
|
||||
)
|
||||
} ?: emptyList()
|
||||
|
||||
val contributedLibrariesFolder = Sketch.Companion.Folder(
|
||||
type = "folder",
|
||||
name = "Contributed Libraries",
|
||||
path = sketchbookFolder.resolve("libraries").absolutePath,
|
||||
mode = "java",
|
||||
children = contributedLibraries,
|
||||
sketches = emptyList()
|
||||
)
|
||||
|
||||
val contributedExamples = sketchbookFolder.resolve("examples")
|
||||
.listFiles{ it.isDirectory }
|
||||
?.map {
|
||||
val properties = it.resolve("examples.properties")
|
||||
val name = findNameInProperties(properties) ?: it.name
|
||||
|
||||
val sketches = getSketches(it.resolve("examples"))
|
||||
Sketch.Companion.Folder(
|
||||
type = "folder",
|
||||
name,
|
||||
path = it.absolutePath,
|
||||
mode = "java",
|
||||
children = sketches?.children ?: emptyList(),
|
||||
sketches = sketches?.sketches ?: emptyList(),
|
||||
)
|
||||
}
|
||||
?: emptyList()
|
||||
val contributedExamplesFolder = Sketch.Companion.Folder(
|
||||
type = "folder",
|
||||
name = "Contributed Examples",
|
||||
path = sketchbookFolder.resolve("examples").absolutePath,
|
||||
mode = "java",
|
||||
children = contributedExamples,
|
||||
sketches = emptyList()
|
||||
)
|
||||
|
||||
val json = serializer.encodeToString(javaModeExamples + javaModeLibraries + contributedLibrariesFolder + contributedExamplesFolder)
|
||||
println(json)
|
||||
}
|
||||
|
||||
private fun findNameInProperties(properties: File): String? {
|
||||
if (!properties.exists()) return null
|
||||
|
||||
return properties.readLines().firstNotNullOfOrNull { line ->
|
||||
line.split("=", limit = 2)
|
||||
.takeIf { it.size == 2 && it[0].trim() == "name" }
|
||||
?.let { it[1].trim() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
app/src/processing/app/api/Sketch.kt
Normal file
50
app/src/processing/app/api/Sketch.kt
Normal file
@@ -0,0 +1,50 @@
|
||||
package processing.app.api
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.io.File
|
||||
|
||||
class Sketch {
|
||||
companion object{
|
||||
@Serializable
|
||||
data class Sketch(
|
||||
val type: String = "sketch",
|
||||
val name: String,
|
||||
val path: String,
|
||||
val mode: String = "java",
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Folder(
|
||||
val type: String = "folder",
|
||||
val name: String,
|
||||
val path: String,
|
||||
val mode: String = "java",
|
||||
val children: List<Folder> = emptyList(),
|
||||
val sketches: List<Sketch> = emptyList()
|
||||
)
|
||||
|
||||
fun getSketches(file: File, filter: (File) -> Boolean = { true }): Folder? {
|
||||
val name = file.name
|
||||
val (sketchesFolders, childrenFolders) = file.listFiles()?.filter (File::isDirectory)?.partition { isSketchFolder(it) } ?: return Folder(
|
||||
name = name,
|
||||
path = file.absolutePath,
|
||||
sketches = emptyList(),
|
||||
children = emptyList()
|
||||
)
|
||||
val children = childrenFolders.filter(filter).mapNotNull { getSketches(it) }
|
||||
val sketches = sketchesFolders.map { Sketch(name = it.name, path = it.absolutePath) }
|
||||
if(sketches.isEmpty() && children.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
return Folder(
|
||||
name = name,
|
||||
path = file.absolutePath,
|
||||
children = children,
|
||||
sketches = sketches
|
||||
)
|
||||
}
|
||||
fun isSketchFolder(file: File): Boolean {
|
||||
return file.isDirectory && file.listFiles().any { it.isFile && it.name.endsWith(".pde") }
|
||||
}
|
||||
}
|
||||
}
|
||||
50
app/src/processing/app/api/Sketchbook.kt
Normal file
50
app/src/processing/app/api/Sketchbook.kt
Normal file
@@ -0,0 +1,50 @@
|
||||
package processing.app.api
|
||||
|
||||
import com.github.ajalt.clikt.command.SuspendingCliktCommand
|
||||
import com.github.ajalt.clikt.core.Context
|
||||
import com.github.ajalt.clikt.core.subcommands
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import processing.app.Platform
|
||||
import processing.app.Preferences
|
||||
import processing.app.api.Sketch.Companion.getSketches
|
||||
import java.io.File
|
||||
|
||||
class Sketchbook: SuspendingCliktCommand() {
|
||||
|
||||
|
||||
override fun help(context: Context) = "Manage the sketchbook"
|
||||
override suspend fun run() {
|
||||
System.setProperty("java.awt.headless", "true")
|
||||
}
|
||||
init {
|
||||
subcommands(SketchbookList())
|
||||
}
|
||||
|
||||
|
||||
class SketchbookList: SuspendingCliktCommand("list") {
|
||||
val serializer = Json {
|
||||
prettyPrint = true
|
||||
}
|
||||
|
||||
override fun help(context: Context) = "List all sketches"
|
||||
override suspend fun run() {
|
||||
Platform.init()
|
||||
// TODO: Allow the user to change the sketchbook location
|
||||
// TODO: Currently blocked since `Base.getSketchbookFolder()` is not available in headless mode
|
||||
val sketchbookFolder = Platform.getDefaultSketchbookFolder()
|
||||
|
||||
val sketches = getSketches(sketchbookFolder) {
|
||||
!listOf(
|
||||
"android",
|
||||
"modes",
|
||||
"tools",
|
||||
"examples",
|
||||
"libraries"
|
||||
).contains(it.name)
|
||||
}
|
||||
val json = serializer.encodeToString(listOf(sketches))
|
||||
println(json)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import com.mikepenz.markdown.m2.markdownColor
|
||||
import com.mikepenz.markdown.m2.markdownTypography
|
||||
import com.mikepenz.markdown.model.MarkdownColors
|
||||
import com.mikepenz.markdown.model.MarkdownTypography
|
||||
import processing.app.Preferences
|
||||
import processing.app.Base.getRevision
|
||||
import processing.app.Base.getVersionName
|
||||
import processing.app.ui.theme.LocalLocale
|
||||
@@ -61,7 +62,10 @@ class WelcomeToBeta {
|
||||
val mac = SystemInfo.isMacFullWindowContentSupported
|
||||
SwingUtilities.invokeLater {
|
||||
JFrame(windowTitle).apply {
|
||||
val close = { dispose() }
|
||||
val close = {
|
||||
Preferences.set("update.beta_welcome", getRevision().toString())
|
||||
dispose()
|
||||
}
|
||||
rootPane.putClientProperty("apple.awt.transparentTitleBar", mac)
|
||||
rootPane.putClientProperty("apple.awt.fullWindowContent", mac)
|
||||
defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
|
||||
|
||||
@@ -76,6 +76,10 @@ theme.gradient.method = rgb
|
||||
# on how many people are using Processing)
|
||||
update.check = true
|
||||
|
||||
# default value for beta_welcome
|
||||
# -1 means no beta has been run
|
||||
update.beta_welcome = -1
|
||||
|
||||
# on windows, automatically associate .pde files with processing.exe
|
||||
platform.auto_file_type_associations = true
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ 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" }
|
||||
kotlinxSerializationJson = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.6.3" }
|
||||
|
||||
[plugins]
|
||||
jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" }
|
||||
|
||||
Reference in New Issue
Block a user