Better column support, redefine keys.
- Fix transposition bug (wrap around past G->A) - Better chord parsing and handling (bass transposed correctly) - Add column and page break support.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import std/logging, std/os, std/strutils
|
||||
import std/[logging, options, os, strutils]
|
||||
import zero_functional
|
||||
|
||||
import ./ast
|
||||
@@ -8,6 +8,7 @@ type
|
||||
chart: ChordChart
|
||||
currentKey: ChordChartPitch
|
||||
sourceKey: ChordChartPitch
|
||||
currentSection: ChordChartNode
|
||||
|
||||
const DEFAULT_STYLESHEET* = """
|
||||
<style>
|
||||
@@ -19,9 +20,19 @@ const DEFAULT_STYLESHEET* = """
|
||||
|
||||
html { font-family: sans-serif; }
|
||||
|
||||
.page-contents {
|
||||
column-width: 336px;
|
||||
column-width: 3.5in;
|
||||
}
|
||||
|
||||
.column-break { margin-bottom: auto; }
|
||||
|
||||
h2 { font-size: 1.25em; }
|
||||
|
||||
section { margin-top: 1em; }
|
||||
section {
|
||||
break-inside: avoid;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.125rem;
|
||||
@@ -54,18 +65,30 @@ h3 {
|
||||
@media screen {
|
||||
body { margin: 1em; }
|
||||
}
|
||||
|
||||
@media print {
|
||||
.page-contents { column-count: 2; }
|
||||
}
|
||||
</style>
|
||||
"""
|
||||
|
||||
proc transpose(ctx: FormatContext, chord: ChordChartChord): string =
|
||||
let distance = ctx.currentKey - ctx.sourceKey
|
||||
if distance != 0: return $(chord.rootPitch + distance) & chord.flavor
|
||||
else: return chord.original
|
||||
|
||||
if distance != 0:
|
||||
result = $(chord.rootPitch + distance)
|
||||
if chord.flavor.isSome: result &= chord.flavor.get
|
||||
if chord.bassPitch.isSome: result &= "/" & $(chord.bassPitch.get + distance)
|
||||
#debug "transposed " & $ctx.sourceKey & " -> " & $ctx.currentKey &
|
||||
# " (distance " & $distance & ")\p\tchord: " & $chord & " to " & result
|
||||
|
||||
else: result = chord.original
|
||||
|
||||
proc toHtml(ctx: var FormatContext, node: ChordChartNode, indent: string): string =
|
||||
result = ""
|
||||
case node.kind
|
||||
of ccnkSection:
|
||||
ctx.currentSection = node
|
||||
result &= indent & "<section>\p" &
|
||||
indent & " " & "<h3>" & node.sectionName & "</h3>\p"
|
||||
|
||||
@@ -75,6 +98,7 @@ proc toHtml(ctx: var FormatContext, node: ChordChartNode, indent: string): strin
|
||||
result &= contents.join("\p")
|
||||
|
||||
result &= indent & "</section>"
|
||||
ctx.currentSection = EMPTY_CHORD_CHART_NODE
|
||||
|
||||
of ccnkLine:
|
||||
result &= indent & "<div class=line>\p"
|
||||
@@ -87,11 +111,11 @@ proc toHtml(ctx: var FormatContext, node: ChordChartNode, indent: string): strin
|
||||
if node.spaceAfter: result&=" space-after"
|
||||
result &= "'>"
|
||||
|
||||
if node.chord.original.len > 0:
|
||||
result &= "<span class=chord>" & ctx.transpose(node.chord) & "</span>"
|
||||
if node.chord.isSome:
|
||||
result &= "<span class=chord>" & ctx.transpose(node.chord.get) & "</span>"
|
||||
|
||||
result &= "<span class=lyric>"
|
||||
if node.word.len > 0: result &= node.word
|
||||
if node.word.isSome: result &= node.word.get
|
||||
else: result &= " "
|
||||
result &= "</span>"
|
||||
|
||||
@@ -100,16 +124,32 @@ proc toHtml(ctx: var FormatContext, node: ChordChartNode, indent: string): strin
|
||||
of ccnkNote:
|
||||
result &= indent & "<div class=note>" & node.note & "</div>"
|
||||
|
||||
of ccnkColBreak: discard #FIXME
|
||||
of ccnkPageBreak: discard #FIXME
|
||||
of ccnkColBreak:
|
||||
result &= "<div class=column-break />"
|
||||
|
||||
of ccnkPageBreak:
|
||||
result &= "</div><div class=page-contents>"
|
||||
|
||||
of ccnkTransposeKey:
|
||||
ctx.currentKey = ctx.currentKey + node.transposeSteps
|
||||
let headingVal = indent & "<h4 class=note>Key Change: " & $ctx.currentKey & "</h4>"
|
||||
if ctx.currentSection.kind == ccnkNone: result &= headingVal
|
||||
else:
|
||||
result &= "</section><section>" & headingVal & "</section><section>"
|
||||
|
||||
of ccnkRedefineKey:
|
||||
ctx.sourceKey = ctx.currentKey + node.transposeSteps
|
||||
let oldKey = ctx.sourceKey
|
||||
ctx.sourceKey = node.newKey
|
||||
ctx.currentKey = ctx.sourceKey
|
||||
|
||||
if oldKey != ctx.currentKey:
|
||||
let headingVal = indent & "<h4 class=note>Key Change: " & $ctx.currentKey & "</h4>"
|
||||
if ctx.currentSection.kind == ccnkNone: result &= headingVal
|
||||
else:
|
||||
result &= "</section><section>" & headingVal & "</section><section>"
|
||||
|
||||
of ccnkNone: discard
|
||||
|
||||
proc toHtml*(
|
||||
cc: ChordChart,
|
||||
stylesheets = @[DEFAULT_STYLESHEET],
|
||||
@@ -118,7 +158,8 @@ proc toHtml*(
|
||||
var ctx = FormatContext(
|
||||
chart: cc,
|
||||
currentKey: cc.metadata.key,
|
||||
sourceKey: cc.metadata.key)
|
||||
sourceKey: cc.metadata.key,
|
||||
currentSection: EMPTY_CHORD_CHART_NODE)
|
||||
|
||||
result = """<!doctype html>
|
||||
<html>
|
||||
@@ -142,10 +183,18 @@ proc toHtml*(
|
||||
# Title
|
||||
result &= indent & "<h1>" & cc.metadata.title & "</h1>\p"
|
||||
|
||||
result &= indent & "<h2>Key: " & $cc.metadata.key
|
||||
if cc.metadata.contains("bpm"): result &= " " & cc.metadata["bpm"] & "bpm"
|
||||
result &= "</h2>\p"
|
||||
var metadataPieces = @["Key: " & $cc.metadata.key]
|
||||
if cc.metadata.contains("time signature"):
|
||||
metadataPieces.add(cc.metadata["time signature"])
|
||||
if cc.metadata.contains("bpm"):
|
||||
metadataPieces.add(cc.metadata["bpm"] & "bpm")
|
||||
if cc.metadata.contains("tempo"):
|
||||
metadataPieces.add(cc.metadata["tempo"])
|
||||
|
||||
result &= indent & "<h2>" & metadataPieces.join(" | ") & "</h2>\p"
|
||||
|
||||
result &= "<div class=page-contents>"
|
||||
result &= join(cc.nodes --> map(ctx.toHtml(it, indent & " ")), "\p")
|
||||
result &= "</div>"
|
||||
|
||||
result &= " </body>\p</html>"
|
||||
|
||||
Reference in New Issue
Block a user