#!/usr/bin/env python #!/usr/bin/python # The idea is to convert from Chord Pro (chopro, chordpro, cho) format to HTML. # This should be runnable from the command line and make files. # This is pretty simple. So, garbage in will produce garbage out. # BUG FIXED: when lines started with a chord (unwanted indent - blank td's) (see StormyWeather.chopro) # TODO # Do something more sophisticated with blank lines (not just blindly
). # other directives? define? # vertical bar (needed? [|] already works. Do we also need ['|]? Nah.) # BUG: title directive must be first line in the file (so we can include it in the head title tag. # 2011-07-12 - elb import sys import re chord = re.compile(r'\[[^]]*\]') lyric = re.compile(r'^[^[]*\[|\][^[]*\[|\][^[]*$') # This could be better. # Ideally each stanza should be a paragraph # Each line (except the last) in each stanza should end with a
. # That seems to require keeping a bunch of context. # Or maybe we could switch it all around and use a state machine? aChord = re.compile(r'\[([^]]*)\]') inLyric = False def lyricLine(theLine): global inLyric if empty.match(theLine): if inLyric: inLyric = False return'

' return '' if inLyric: return '
' + re.sub(aChord, r'\1', theLine.rstrip()) else: inLyric = True return '

' + re.sub(aChord, r'\1', theLine.rstrip()) def lineVerbatim(theLine): return theLine.rstrip() empty = re.compile(r'\s*$') def xlyricLine(theLine): """Convert a line of lyrics into a two line table. The first row (line) should contain the chords (and vertical bars). The second row should contain the lyrics. If there are no chords, just one row with one cell. >>> lineAsTable("one [A]two [B#]three") '' '' '' '
B# 
one  two  three 
' """ if empty.match(theLine): return'
' if (not chord.search(theLine)): return '
%s 
' % theLine l = re.split(chord, theLine) c = re.split(lyric, theLine) if (0 == len(l[0]) and 0 == len(c[0])): l = l[1:] c = c[1:] ourTable = '\n' ourLine = '' for i in c: if 0 < len(i): ourLine += '' % i else: ourLine += '' ourTable += '%s\n' % ourLine ourLine = '' for i in l: i = re.sub(r' $', ' ', i) ourLine += '' % i ourTable += '%s\n' % ourLine return ourTable + '
%s 
%s
' def printHead(theTitle): print ''' %s ''' % (theTitle) def addGadgets(theKey): if "?" == theKey: return False print '''

''' % (theKey, theKey) return True def main(argv=None): if argv is None: argv = sys.argv global inLyric directive = re.compile(r'\s*{([a-z_]+):\s*([^}]+)}') noargDirective = re.compile(r'\s*{([a-z_]+)}') comment = re.compile(r'\s*#') gadgetsAdded = False print '\n' lineOut = lyricLine #lineAsTable for line in sys.stdin: if (directive.match(line)): m = directive.match(line) #if re.match(r'^t(itle)?$', m.group(1)): if 'title' == m.group(1) or 't' == m.group(1): printHead(m.group(2)) print '' print '

%s

' % ('title', m.group(2)) elif 'subtitle' == m.group(1) or 'st' == m.group(1): print '

%s

' % ('subtitle', m.group(2)) elif 'comment' == m.group(1) or 'c' == m.group(1): print '

%s

' % ('annotation', m.group(2)) elif 'key' == m.group(1): # This is awkward. Make it better somehow. if not gadgetsAdded: gadgetsAdded = addGadgets(m.group(2)) if gadgetsAdded: print '

in %s

' % ('annotation', m.group(2)) else: print '

in %s

' % ('annotation', m.group(2)) else: print '

in %s

' % ('annotation', m.group(2)) else: print '

%s

' % (m.group(1), m.group(2)) elif (noargDirective.match(line)): m = noargDirective.match(line) if re.match(r'start_of_chorus|soc', m.group(1)): print '
' if re.match(r'start_of_bridge|sob', m.group(1)): print '
' if re.match(r'start_of_tab|sot', m.group(1)): sys.stdout.write('
') lineOut = lineVerbatim if re.match(r'end_of_|eoc|eot|eob', m.group(1)): if re.match(r'end_of_tab|eot', m.group(1)): lineOut = lyricLine #lineAsTable if inLyric: inLyric = False print '

' print '
' elif comment.match(line): print "" % (line.rstrip()) else: print lineOut(line.rstrip()) print '' print '' if __name__ == '__main__': sys.exit(main())