hammer-editor/base/build.gradle.kts
Adam Brown 4537909826
Add prose diff visualization to draft compare and conflict merge UIs (#525)
New ProseDiff module: word-level Myers diff (kotlin-multiplatform-diff)
over markdown text, with syntax stripped via the JetBrains parser and
offsets mapped back to source. Merges adjacent edits into single hunks,
emits anchors at each boundary for scroll sync, and includes a git-style
slider that aligns pure insert/delete blocks to line boundaries. Covers
plain-text diffing, prepared/reusable inputs, and an OffsetMap that maps
a position on one side to its counterpart.

Draft compare: highlights DELETED (red/strikethrough) and INSERTED
(green/underline) spans via non-destructive RichSpans in each pane's
rendered coordinate space, recomputed off-thread on a 500ms debounce.
Synchronized scrolling (compose-texteditor 2.0.7) drives either pane from
the other off raw scroll pixels with an echo guard. Both editor states are
hoisted so highlights and sync work in compact and expanded layouts and
survive theme changes. A DIFF toggle gates highlights and sync.
2026-05-30 09:49:33 -07:00

104 lines
No EOL
2.7 KiB
Kotlin

import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.android.kotlin.multiplatform.library)
alias(libs.plugins.jetbrains.kover)
alias(libs.plugins.buildconfig)
}
group = "com.darkrockstudios.apps.hammer"
version = libs.versions.app.get()
repositories {
mavenCentral()
}
kotlin {
androidLibrary {
namespace = "com.darkrockstudios.apps.hammer.base"
compileSdk = libs.versions.android.sdk.compile.get().toInt()
minSdk = libs.versions.android.sdk.min.get().toInt()
compilerOptions {
jvmTarget.set(JvmTarget.fromTarget(libs.versions.jvm.get()))
}
}
jvm("desktop")
iosArm64()
iosSimulatorArm64()
jvmToolchain(libs.versions.jvm.get().toInt())
applyDefaultHierarchyTemplate()
sourceSets {
all {
languageSettings {
optIn("kotlin.io.encoding.ExperimentalEncodingApi")
optIn("kotlin.uuid.ExperimentalUuidApi")
}
}
val commonMain by getting {
dependencies {
implementation(libs.serialization.core)
implementation(libs.coroutines.core)
implementation(libs.kotlinx.datetime)
implementation(libs.serialization.json)
//implementation("org.kotlincrypto.endians:endians:0.1.0")
//api("io.getstream:stream-result:1.1.0")
api(libs.korlibs.krypto)
//api("com.goncalossilva:murmurhash:0.4.0")
api(libs.cryptohash)
api(libs.korlibs.korio)
implementation(libs.okio)
implementation(libs.tomlkt)
implementation(libs.markdown)
implementation(libs.kotlin.multiplatform.diff)
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
implementation(libs.kotlin.reflect)
implementation(libs.okio)
}
}
}
}
buildConfig {
className("BuildMetadata")
useKotlinOutput { internalVisibility = false }
buildConfigField("String", "APP_VERSION", "\"${libs.versions.app.get()}\"")
buildConfigField("String", "DATA_VERSION", "\"${libs.versions.data.version.get()}\"")
}
val GIT_TASK_NAME = "install-git-hooks"
val gitDir = layout.projectDirectory.file("../.git").asFile
// In a git worktree `.git` is a file pointer rather than the hooks dir, so
// register a no-op — hooks are installed when the main checkout builds.
if (gitDir.isDirectory) {
tasks.register<Copy>(GIT_TASK_NAME) {
from(layout.projectDirectory.file("../.gitHooks/pre-commit"))
into(layout.projectDirectory.dir("../.git/hooks"))
doLast {
val file = layout.projectDirectory.file("../.git/hooks")
file.asFile.setExecutable(true)
}
}
} else {
tasks.register(GIT_TASK_NAME)
}
afterEvaluate {
val gitTask = tasks[GIT_TASK_NAME]
for (task in tasks) {
if (task != gitTask)
task.dependsOn(gitTask)
}
}