feat: support inline images within song pages (Closes #2)
Add {image: path} directive to embed images at any position within a song's
sections. SongLine gains an optional imagePath field; when set, the line
represents an inline image rather than chord/lyric content. The renderer
scales and centers images within the content width. MeasurementEngine
reserves 40mm height per inline image for layout calculations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit was merged in pull request #13.
This commit is contained in:
@@ -129,6 +129,13 @@ object ChordProParser {
|
||||
"end_of_repeat", "eor" -> {
|
||||
flushSection()
|
||||
}
|
||||
"image" -> if (value != null) {
|
||||
// Inline image within a song section
|
||||
if (currentType == null) {
|
||||
currentType = SectionType.VERSE
|
||||
}
|
||||
currentLines.add(SongLine(imagePath = value.trim()))
|
||||
}
|
||||
"start_of_notes", "son" -> {
|
||||
inNotesBlock = true
|
||||
}
|
||||
|
||||
@@ -577,4 +577,55 @@ class ChordProParserTest {
|
||||
song.notes[1] shouldBe "Paragraph two."
|
||||
song.notes[2] shouldBe "Paragraph three."
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse image directive within song section`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
{start_of_verse}
|
||||
[Am]Hello world
|
||||
{image: images/drawing.png}
|
||||
[C]Goodbye world
|
||||
{end_of_verse}
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 1
|
||||
song.sections[0].lines shouldHaveSize 3
|
||||
song.sections[0].lines[0].segments[0].chord shouldBe "Am"
|
||||
song.sections[0].lines[1].imagePath shouldBe "images/drawing.png"
|
||||
song.sections[0].lines[1].segments.shouldBeEmpty()
|
||||
song.sections[0].lines[2].segments[0].chord shouldBe "C"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse image directive outside section creates implicit verse`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
{image: images/landscape.jpg}
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 1
|
||||
song.sections[0].type shouldBe SectionType.VERSE
|
||||
song.sections[0].lines shouldHaveSize 1
|
||||
song.sections[0].lines[0].imagePath shouldBe "images/landscape.jpg"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse multiple image directives`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
{start_of_verse}
|
||||
{image: img1.png}
|
||||
Some text
|
||||
{image: img2.png}
|
||||
{end_of_verse}
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections[0].lines shouldHaveSize 3
|
||||
song.sections[0].lines[0].imagePath shouldBe "img1.png"
|
||||
song.sections[0].lines[0].segments.shouldBeEmpty()
|
||||
song.sections[0].lines[1].imagePath.shouldBeNull()
|
||||
song.sections[0].lines[1].segments[0].text shouldBe "Some text"
|
||||
song.sections[0].lines[2].imagePath shouldBe "img2.png"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user