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>
2.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build & Test Commands
# Build everything
gradle build
# Run all tests
gradle test
# Run tests for a specific module
gradle :parser:test
gradle :layout:test
gradle :renderer-pdf:test
gradle :app:test
# Run a single test class
gradle :parser:test --tests ChordProParserTest
# Run a single test method
gradle :parser:test --tests "ChordProParserTest.parse complete song"
# Build and run CLI
gradle :cli:run --args="build -d /path/to/project"
gradle :cli:run --args="validate -d /path/to/project"
# Launch GUI
gradle :gui:run
Requires Java 21 (configured in gradle.properties). Kotlin 2.1.10, Gradle 9.3.1.
Architecture
Pipeline: Parse → Measure → Paginate → Render
SongbookPipeline (in app) orchestrates the full flow:
ConfigParserreadssongbook.yaml→BookConfigChordProParserreads.choprofiles →SongobjectsValidatorchecks config and songsMeasurementEnginecalculates each song's height in mm usingFontMetricsTocGeneratorestimates TOC page count and creates entriesPaginationEnginearranges songs into pages (greedy spread packing)PdfBookRenderergenerates the PDF via OpenPDF
Module dependency graph:
model ← parser
model ← layout
model ← renderer-pdf
parser, layout, renderer-pdf ← app
app ← cli (Clikt)
app, parser ← gui (Compose Desktop)
model is the foundation with no dependencies — all data classes, the FontMetrics interface, and the BookRenderer interface live here. The FontMetrics abstraction decouples layout from rendering: PdfFontMetrics is the real implementation (in renderer-pdf), StubFontMetrics is used in layout tests.
Pagination constraint: Songs spanning 2 pages must start on a left (even) page. The PaginationEngine inserts filler images or blank pages to enforce this.
Key Types
Song→ sections →SongLine→LineSegment(chord?, text)— chord is placed above the text segmentPageContent— sealed class:SongPage,FillerImage,BlankPageSectionType— enum:VERSE,CHORUS,BRIDGE,REPEATBuildResult— returned bySongbookPipeline.build()with success/errors/counts
Song Format
ChordPro-compatible .chopro files: directives in {braces}, chords in [brackets] inline with lyrics, comments with #. See songs/ for examples.
Test Patterns
Tests use kotlin.test annotations with Kotest assertions (shouldBe, shouldHaveSize, etc.) on JUnit 5. Layout tests use StubFontMetrics to avoid PDF font dependencies. App integration tests create temp directories with song files and config.
Package
All code under de.pfadfinder.songbook.* — subpackages match module names (.model, .parser, .layout, .renderer.pdf, .app, .cli, .gui).