Initial implementation of songbook toolset
Kotlin/JVM multi-module project for generating a scout songbook PDF from ChordPro-format text files. Includes ChordPro parser, layout engine with greedy spread packing for double-page songs, OpenPDF renderer, CLI (Clikt), Compose Desktop GUI, and 5 sample songs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17
cli/build.gradle.kts
Normal file
17
cli/build.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
id("songbook-conventions")
|
||||
application
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("de.pfadfinder.songbook.cli.MainKt")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":app"))
|
||||
implementation(project(":model"))
|
||||
implementation(project(":parser"))
|
||||
implementation("com.github.ajalt.clikt:clikt:5.0.3")
|
||||
implementation("io.github.microutils:kotlin-logging-jvm:3.0.5")
|
||||
implementation("ch.qos.logback:logback-classic:1.5.16")
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.pfadfinder.songbook.cli
|
||||
|
||||
import com.github.ajalt.clikt.core.CliktCommand
|
||||
import com.github.ajalt.clikt.core.Context
|
||||
import com.github.ajalt.clikt.core.ProgramResult
|
||||
import com.github.ajalt.clikt.parameters.options.default
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
import de.pfadfinder.songbook.app.SongbookPipeline
|
||||
import java.io.File
|
||||
|
||||
class BuildCommand : CliktCommand(name = "build") {
|
||||
override fun help(context: Context) = "Build the songbook PDF"
|
||||
|
||||
private val projectDir by option("-d", "--dir", help = "Project directory").default(".")
|
||||
|
||||
override fun run() {
|
||||
val dir = File(projectDir).absoluteFile
|
||||
echo("Building songbook from: ${dir.path}")
|
||||
|
||||
val pipeline = SongbookPipeline(dir)
|
||||
val result = pipeline.build()
|
||||
|
||||
if (result.success) {
|
||||
echo("Build successful!")
|
||||
echo(" Songs: ${result.songCount}")
|
||||
echo(" Pages: ${result.pageCount}")
|
||||
echo(" Output: ${result.outputFile?.absolutePath}")
|
||||
} else {
|
||||
echo("Build failed with ${result.errors.size} error(s):", err = true)
|
||||
for (error in result.errors) {
|
||||
val location = listOfNotNull(error.file, error.line?.toString()).joinToString(":")
|
||||
echo(" [$location] ${error.message}", err = true)
|
||||
}
|
||||
throw ProgramResult(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
15
cli/src/main/kotlin/de/pfadfinder/songbook/cli/Main.kt
Normal file
15
cli/src/main/kotlin/de/pfadfinder/songbook/cli/Main.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
package de.pfadfinder.songbook.cli
|
||||
|
||||
import com.github.ajalt.clikt.core.CliktCommand
|
||||
import com.github.ajalt.clikt.core.main
|
||||
import com.github.ajalt.clikt.core.subcommands
|
||||
|
||||
class SongbookCli : CliktCommand(name = "songbook") {
|
||||
override fun run() = Unit
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
SongbookCli()
|
||||
.subcommands(BuildCommand(), ValidateCommand())
|
||||
.main(args)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.pfadfinder.songbook.cli
|
||||
|
||||
import com.github.ajalt.clikt.core.CliktCommand
|
||||
import com.github.ajalt.clikt.core.Context
|
||||
import com.github.ajalt.clikt.core.ProgramResult
|
||||
import com.github.ajalt.clikt.parameters.options.default
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
import de.pfadfinder.songbook.app.SongbookPipeline
|
||||
import java.io.File
|
||||
|
||||
class ValidateCommand : CliktCommand(name = "validate") {
|
||||
override fun help(context: Context) = "Validate all song files"
|
||||
|
||||
private val projectDir by option("-d", "--dir", help = "Project directory").default(".")
|
||||
|
||||
override fun run() {
|
||||
val dir = File(projectDir).absoluteFile
|
||||
echo("Validating songbook in: ${dir.path}")
|
||||
|
||||
val pipeline = SongbookPipeline(dir)
|
||||
val errors = pipeline.validate()
|
||||
|
||||
if (errors.isEmpty()) {
|
||||
echo("All songs are valid!")
|
||||
} else {
|
||||
echo("Found ${errors.size} error(s):", err = true)
|
||||
for (error in errors) {
|
||||
val location = listOfNotNull(error.file, error.line?.toString()).joinToString(":")
|
||||
echo(" [$location] ${error.message}", err = true)
|
||||
}
|
||||
throw ProgramResult(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user