Skip to content

Instantly share code, notes, and snippets.

@ozbeksu
Created May 13, 2026 08:21
Show Gist options
  • Select an option

  • Save ozbeksu/35acc1fe2701ec0d57bae3a6fce72900 to your computer and use it in GitHub Desktop.

Select an option

Save ozbeksu/35acc1fe2701ec0d57bae3a6fce72900 to your computer and use it in GitHub Desktop.
Kotlin Compose Desktop / Main.kt
package com.lambdastratum.appstream
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import clojure.java.api.Clojure
import clojure.lang.Keyword
import clojure.lang.PersistentVector
import clojure.lang.IPersistentMap
fun parseEdn(text: String): Any? {
val readString = Clojure.`var`("clojure.edn", "read-string")
return readString.invoke(text)
}
@Composable
fun RenderNode(node: Any?, showToast: (String) -> Unit) {
if (node !is PersistentVector || node.count() == 0) {
return
}
val type = node.nth(0).toString()
val maybeProps = if (node.count() > 1) node.nth(1) else null
val props = maybeProps as? IPersistentMap
val childrenStart = if (props != null) 2 else 1
when (type) {
":column" -> {
val gap = ((props?.valAt(Keyword.intern("gap")) as? Long) ?: 8L).toInt()
Column(
verticalArrangement = Arrangement.spacedBy(gap.dp)
) {
for (i in childrenStart until node.count()) {
RenderNode(node.nth(i), showToast)
}
}
}
":text" -> {
val size = ((props?.valAt(Keyword.intern("size")) as? Long) ?: 16L).toInt()
val content = node.nth(childrenStart).toString()
Text(
text = content,
fontSize = size.sp
)
}
":button" -> {
val label = props
?.valAt(Keyword.intern("label"))
?.toString()
?: "Button"
val toast = props
?.valAt(Keyword.intern("toast"))
?.toString()
?: "Clicked"
Button(
onClick = {
showToast(toast)
}
) {
Text(label)
}
}
":toast" -> {
val message = props
?.valAt(Keyword.intern("message"))
?.toString()
?: "Toast"
LaunchedEffect(message) {
showToast(message)
}
}
}
}
fun main() = application {
Window(
onCloseRequest = ::exitApplication,
title = "EDN Runtime Demo"
) {
MaterialTheme {
var ednText by remember {
mutableStateOf(
"""
[:column
{:gap 12}
[:text
{:size 24}
"Hello from EDN"]
[:button
{:label "Click Me"
:toast "Button clicked from EDN runtime"}]]
""".trimIndent()
)
}
var parsedTree by remember {
mutableStateOf<Any?>(null)
}
var toastMessage by remember {
mutableStateOf<String?>(null)
}
LaunchedEffect(ednText) {
try {
parsedTree = parseEdn(ednText)
} catch (e: Exception) {
parsedTree = null
}
}
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text("EDN Input")
Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField(
value = ednText,
onValueChange = {
ednText = it
},
modifier = Modifier.fillMaxSize()
)
}
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text("Rendered UI")
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp)
) {
RenderNode(parsedTree) {
toastMessage = it
}
}
}
}
}
toastMessage?.let { msg ->
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.BottomCenter
) {
Snackbar(
modifier = Modifier.padding(16.dp)
) {
Text(msg)
}
}
LaunchedEffect(msg) {
kotlinx.coroutines.delay(2000)
toastMessage = null
}
}
}
}
}
}
@ozbeksu

ozbeksu commented May 13, 2026

Copy link
Copy Markdown
Author
import org.jetbrains.compose.desktop.application.dsl.TargetFormat

plugins {
    alias(libs.plugins.kotlinMultiplatform)
    alias(libs.plugins.composeMultiplatform)
    alias(libs.plugins.composeCompiler)
    alias(libs.plugins.composeHotReload)
}

kotlin {
    jvm()

    sourceSets {
        commonMain.dependencies {
            implementation(libs.compose.runtime)
            implementation(libs.compose.foundation)
            implementation(libs.compose.material3)
            implementation(libs.compose.ui)
            implementation(libs.compose.components.resources)
            implementation(libs.compose.uiToolingPreview)
            implementation(libs.androidx.lifecycle.viewmodelCompose)
            implementation(libs.androidx.lifecycle.runtimeCompose)
        }
        commonTest.dependencies {
            implementation(libs.kotlin.test)
        }
        jvmMain.dependencies {
            implementation(compose.desktop.currentOs)
            implementation(libs.kotlinx.coroutinesSwing)
            implementation("org.clojure:clojure:1.12.5")
        }
    }
}


compose.desktop {
    application {
        mainClass = "com.lambdastratum.appstream.MainKt"

        nativeDistributions {
            targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
            packageName = "com.lambdastratum.appstream"
            packageVersion = "1.0.0"
        }
    }
}

build.gradle.kts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment