fix: blank lines split implicit verses into separate sections (Closes #29)
This commit was merged in pull request #30.
This commit is contained in:
@@ -24,6 +24,7 @@ object ChordProParser {
|
||||
var currentType: SectionType? = null
|
||||
var currentLabel: String? = null
|
||||
var currentLines = mutableListOf<SongLine>()
|
||||
var explicitSection = false
|
||||
|
||||
// Notes block state
|
||||
var inNotesBlock = false
|
||||
@@ -42,6 +43,7 @@ object ChordProParser {
|
||||
currentType = null
|
||||
currentLabel = null
|
||||
currentLines = mutableListOf()
|
||||
explicitSection = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +74,13 @@ object ChordProParser {
|
||||
// Skip comments
|
||||
if (line.trimStart().startsWith("#")) continue
|
||||
|
||||
// Skip empty lines
|
||||
if (line.isBlank()) continue
|
||||
// Blank line: flush implicit sections, skip otherwise
|
||||
if (line.isBlank()) {
|
||||
if (currentType != null && !explicitSection) {
|
||||
flushSection()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Directive line
|
||||
if (line.trimStart().startsWith("{") && line.trimEnd().endsWith("}")) {
|
||||
@@ -109,6 +116,7 @@ object ChordProParser {
|
||||
flushSection()
|
||||
currentType = SectionType.VERSE
|
||||
currentLabel = value
|
||||
explicitSection = true
|
||||
}
|
||||
"end_of_verse", "eov" -> {
|
||||
flushSection()
|
||||
@@ -117,6 +125,7 @@ object ChordProParser {
|
||||
flushSection()
|
||||
currentType = SectionType.CHORUS
|
||||
currentLabel = value
|
||||
explicitSection = true
|
||||
}
|
||||
"end_of_chorus", "eoc" -> {
|
||||
flushSection()
|
||||
@@ -125,6 +134,7 @@ object ChordProParser {
|
||||
flushSection()
|
||||
currentType = SectionType.REPEAT
|
||||
currentLabel = value
|
||||
explicitSection = true
|
||||
}
|
||||
"end_of_repeat", "eor" -> {
|
||||
flushSection()
|
||||
|
||||
@@ -628,4 +628,145 @@ class ChordProParserTest {
|
||||
song.sections[0].lines[1].segments[0].text shouldBe "Some text"
|
||||
song.sections[0].lines[2].imagePath shouldBe "img2.png"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blank line splits implicit verses into separate sections`() {
|
||||
val input = """
|
||||
{title: Am Brunnen vor dem Tore}
|
||||
|
||||
Am [D]Brunnen vor dem Tore
|
||||
Ich [D]träumt in seinem Schatten
|
||||
|
||||
Ich musst auch heute wandern
|
||||
Da hab ich noch im Dunkeln
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 2
|
||||
song.sections[0].type shouldBe SectionType.VERSE
|
||||
song.sections[0].lines shouldHaveSize 2
|
||||
song.sections[0].lines[0].segments shouldHaveSize 2
|
||||
song.sections[0].lines[0].segments[0].chord.shouldBeNull()
|
||||
song.sections[0].lines[0].segments[0].text shouldBe "Am "
|
||||
song.sections[0].lines[0].segments[1].chord shouldBe "D"
|
||||
song.sections[0].lines[0].segments[1].text shouldBe "Brunnen vor dem Tore"
|
||||
song.sections[1].type shouldBe SectionType.VERSE
|
||||
song.sections[1].lines shouldHaveSize 2
|
||||
song.sections[1].lines[0].segments[0].text shouldBe "Ich musst auch heute wandern"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blank lines within explicit sections are ignored`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
{start_of_verse: Verse 1}
|
||||
Line one
|
||||
|
||||
Line two
|
||||
{end_of_verse}
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 1
|
||||
song.sections[0].type shouldBe SectionType.VERSE
|
||||
song.sections[0].label shouldBe "Verse 1"
|
||||
song.sections[0].lines shouldHaveSize 2
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blank lines between metadata do not create empty sections`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
|
||||
{lyricist: Someone}
|
||||
|
||||
{composer: Someone Else}
|
||||
|
||||
[Am]Hello world
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 1
|
||||
song.sections[0].type shouldBe SectionType.VERSE
|
||||
song.sections[0].lines shouldHaveSize 1
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `mixed explicit and implicit sections with blank lines`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
{start_of_chorus}
|
||||
[C]Chorus line
|
||||
|
||||
Still in chorus
|
||||
{end_of_chorus}
|
||||
|
||||
Implicit verse one
|
||||
|
||||
Implicit verse two
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 3
|
||||
song.sections[0].type shouldBe SectionType.CHORUS
|
||||
song.sections[0].lines shouldHaveSize 2
|
||||
song.sections[1].type shouldBe SectionType.VERSE
|
||||
song.sections[1].lines shouldHaveSize 1
|
||||
song.sections[1].lines[0].segments[0].text shouldBe "Implicit verse one"
|
||||
song.sections[2].type shouldBe SectionType.VERSE
|
||||
song.sections[2].lines shouldHaveSize 1
|
||||
song.sections[2].lines[0].segments[0].text shouldBe "Implicit verse two"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `multiple blank lines between implicit verses`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
First verse line
|
||||
|
||||
|
||||
Second verse line
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 2
|
||||
song.sections[0].type shouldBe SectionType.VERSE
|
||||
song.sections[0].lines shouldHaveSize 1
|
||||
song.sections[1].type shouldBe SectionType.VERSE
|
||||
song.sections[1].lines shouldHaveSize 1
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `three implicit verses separated by blank lines`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
[Am]Verse one line one
|
||||
Verse one line two
|
||||
|
||||
[C]Verse two line one
|
||||
Verse two line two
|
||||
|
||||
[G]Verse three line one
|
||||
Verse three line two
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 3
|
||||
song.sections.forEach { section ->
|
||||
section.type shouldBe SectionType.VERSE
|
||||
section.lines shouldHaveSize 2
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blank lines within explicit chorus are ignored`() {
|
||||
val input = """
|
||||
{title: Song}
|
||||
{start_of_chorus}
|
||||
Line one
|
||||
|
||||
Line two
|
||||
|
||||
Line three
|
||||
{end_of_chorus}
|
||||
""".trimIndent()
|
||||
val song = ChordProParser.parse(input)
|
||||
song.sections shouldHaveSize 1
|
||||
song.sections[0].type shouldBe SectionType.CHORUS
|
||||
song.sections[0].lines shouldHaveSize 3
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user