function renderChordpro(text) {
const song = [];
const chords = [];
+ let chorus = null; // content of the chorus being parsed, if any
let verseLines = [];
let verseHasChords = false;
const flushVerse = () => {
if (verseLines.length === 0)
return;
- song.push(html`<p class="verse${verseHasChords ? ' chords' : ''}">${verseLines}</p>`);
+ (chorus ?? song).push(html`<p class="verse${verseHasChords ? ' chords' : ''}">${verseLines}</p>`);
verseLines = [];
verseHasChords = false;
};
+ const endChorus = () => {
+ if (chorus === null)
+ return;
+ song.push(html`<div class="chorus">${chorus}</div>`);
+ chorus = null;
+ };
+
for (let line of text.split('\n')) {
line = line.trim();
if (line.startsWith('#'))
const m = re_directive.exec(line);
if (m) {
flushVerse();
- const [, directive, value] = m;
- const handler = directive_handlers[directive];
- if (handler)
- song.push(handler(value ?? '', chords));
- else
- console.warn('unknown directive:', line);
+ const [, directive, value = ''] = m;
+ const target = chorus ?? song;
+ if (['start_of_chorus', 'soc'].includes(directive)) {
+ endChorus();
+ chorus = [];
+ } else if (['end_of_chorus', 'eoc'].includes(directive)) {
+ endChorus();
+ } else {
+ const handler = directive_handlers[directive];
+ if (handler)
+ target.push(handler(value, chords));
+ else
+ console.warn('unknown directive:', line);
+ }
} else if (line === '') {
flushVerse();
} else {
}
}
flushVerse();
+ endChorus();
if (chords.length > 0)
song.push(html`<div class="diagrams">${chords.map(chordDiagram)}</div>`);
white-space: pre-line;
}
+.chorus {
+ border-left: 3px solid #39F;
+ padding-left: 0.7em;
+}
+
/* A segment is one chord and the lyrics up to the next chord, stacked as two
rows. Its width is the wider of the two, so chords can never overlap each
other or the next segment. Line wrapping only happens between segments;