|
|
|
/*
|
|
|
|
Parse Latex song into chordpro
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
function megajoin(array){
|
|
|
|
for(x in array) {
|
|
|
|
if(array[x] instanceof Array) {
|
|
|
|
array[x] = array[x].join("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return array.join("");
|
|
|
|
}
|
|
|
|
function property(name, value){
|
|
|
|
if(value instanceof Array) {
|
|
|
|
value = value.join("");
|
|
|
|
}
|
|
|
|
return "{" + name +": " + value + "}";
|
|
|
|
}
|
|
|
|
function tab_property(name, base, frets, special, ukulele){
|
|
|
|
var content = "";
|
|
|
|
content += name.replace("/b/g", "&");
|
|
|
|
if(base > 0){
|
|
|
|
content += " base-fret ";
|
|
|
|
content += base;
|
|
|
|
}
|
|
|
|
content += " frets ";
|
|
|
|
content += frets.join("").toUpperCase();
|
|
|
|
if(special){
|
|
|
|
content += " special";
|
|
|
|
}
|
|
|
|
var define = "define";
|
|
|
|
if(ukulele){
|
|
|
|
define += "_ukulele";
|
|
|
|
}
|
|
|
|
return property(define, content);
|
|
|
|
}
|
|
|
|
function blockify(name, content, newline){
|
|
|
|
var start = "{start_of_"+name+"}";
|
|
|
|
var end = "{end_of_"+name+"}";
|
|
|
|
if(newline){
|
|
|
|
start += "\r\n";
|
|
|
|
end += "\r\n";
|
|
|
|
}
|
|
|
|
return start + content + end;
|
|
|
|
}
|
|
|
|
function blockify_param(name, param, content, newline){
|
|
|
|
if(param instanceof Array) {
|
|
|
|
param = param.join("");
|
|
|
|
}
|
|
|
|
var start = "{start_of_"+name + ": "+param+"}";
|
|
|
|
var end = "{end_of_"+name+"}";
|
|
|
|
if(newline){
|
|
|
|
start += "\r\n";
|
|
|
|
end += "\r\n";
|
|
|
|
}
|
|
|
|
return start + content + end;
|
|
|
|
}
|
|
|
|
function chordname_split(chordname){
|
|
|
|
return chordname.split(" - ").join(" ").split(" ").join("][").replace("/b/g", "&");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
start
|
|
|
|
= content:(language? newlines_merge columnsetting? newlines_merge song) {return content.join(""); }
|
|
|
|
|
|
|
|
|
|
|
|
// Basic characters
|
|
|
|
digits
|
|
|
|
= digits:[0-9]+ {return digits.join("")}
|
|
|
|
ndigits
|
|
|
|
= digits
|
|
|
|
/ "-" digits
|
|
|
|
digit
|
|
|
|
= digit:[0-9]
|
|
|
|
|
|
|
|
alpha
|
|
|
|
= chars:[a-zA-Z]+ {return chars.join("")}
|
|
|
|
|
|
|
|
slug
|
|
|
|
= chars:[a-zA-Z0-9-_]+ {return chars.join("")}
|
|
|
|
|
|
|
|
url
|
|
|
|
= chars:[a-zA-Z0-9-_$.+!*'(),/:]+ {return chars.join("")}
|
|
|
|
|
|
|
|
|
|
|
|
// Text patterns
|
|
|
|
inline_text
|
|
|
|
= content:inline_text_elt+ {return content.join("")}
|
|
|
|
|
|
|
|
inline_text_elt
|
|
|
|
= safe_text
|
|
|
|
/ inline_command
|
|
|
|
/ empty_command
|
|
|
|
/ ignored_command
|
|
|
|
/ equation
|
|
|
|
|
|
|
|
safe_text
|
|
|
|
= content:nonlatex_char+ {return content.join("")}
|
|
|
|
|
|
|
|
nonlatex_char
|
|
|
|
= [^\\\n\r{}$%\[\]~]
|
|
|
|
/ "~" { return " "}
|
|
|
|
|
|
|
|
inline_command
|
|
|
|
= "\\dots {" content:inline_text "}" {return "..." + content}
|
|
|
|
/ "\\shrp{" content:inline_text "}" {return "#" + content}
|
|
|
|
|
|
|
|
empty_command
|
|
|
|
= "\\" content:empty_command_name " "? "{}" {return content}
|
|
|
|
/ "\\" content:empty_command_name {return content}
|
|
|
|
/ "{\\" content:empty_command_name "}" {return content}
|
|
|
|
|
|
|
|
empty_command_name
|
|
|
|
= "oe" { return "œ"}
|
|
|
|
/ "ier"
|
|
|
|
/ "ieme"
|
|
|
|
/ "dots" { return "..."}
|
|
|
|
/ "ldots" { return "..."}
|
|
|
|
/ "og" { return "«"} // guillemets
|
|
|
|
/ "fg" { return "»"} // guillemets
|
|
|
|
/ "flt" { return "&"}
|
|
|
|
/ "shrp" { return "#"}
|
|
|
|
/ "&"
|
|
|
|
/ "_"
|
|
|
|
/ "%"
|
|
|
|
/ "#"
|
|
|
|
/ ","
|
|
|
|
/ "'"
|
|
|
|
/ " " { return " "}
|
|
|
|
/ removed_command_name { return ""}
|
|
|
|
|
|
|
|
removed_command_name
|
|
|
|
= "newline"
|
|
|
|
/ "MultiwordChords"
|
|
|
|
/ "Adlib"
|
|
|
|
|
|
|
|
ignored_command
|
|
|
|
= "\\" ignored_command_name "{" content:inline_text "}" {return content}
|
|
|
|
|
|
|
|
ignored_command_name
|
|
|
|
= "emph"
|
|
|
|
/ "Outro"
|
|
|
|
|
|
|
|
equation
|
|
|
|
= "$" eq:equation_content "$" {return eq}
|
|
|
|
|
|
|
|
equation_content
|
|
|
|
= "\\beta_1" { return "Beta1"}
|
|
|
|
/ "\\beta_2" { return "Beta2"}
|
|
|
|
/ "H_2O" { return "H20"}
|
|
|
|
/ "H_2" { return "H2"}
|
|
|
|
/ "O"
|
|
|
|
/ "CO_2" { return "CO2"}
|
|
|
|
/ "5m^2" { return "5m²"}
|
|
|
|
|
|
|
|
block_standalone_command
|
|
|
|
= "\\capo{" digits:digits "}" { return property("capo", digits)}
|
|
|
|
/ "\\meter{" num:digits "}{" denom:digits "}" { return property("meter", num + "/" + denom)}
|
|
|
|
/ "\\cover" { return ""}
|
|
|
|
/ "\\transposition{" digits:ndigits "}" {return property("transposition", digits)}
|
|
|
|
/ "\\lilypond" " "? "{" file:slug "}" { return property("partition", [file + ".ly"])}
|
|
|
|
/ "\\nolyrics{\\lilypond{" file:slug "}}" { return property("partition", [file + ".ly"])}
|
|
|
|
/ "\\rep{" digits:digits "}" {return property("repeat", digits)}
|
|
|
|
/ guitar_tab
|
|
|
|
/ ukulele_tab
|
|
|
|
|
|
|
|
guitar_tab
|
|
|
|
= "\\gtab{" name:inline_text "}{" base:basefret frets:([0-9xX]+) "}" { return tab_property(name, base, frets, false, false)}
|
|
|
|
/ "\\gtab*{" name:inline_text "}{" base:basefret frets:([0-9xX]+) ":"? "}" { return tab_property(name, base, frets, true, false)}
|
|
|
|
/ "\\gtab" "*"? "{" name:inline_text "}{}" { return ""}
|
|
|
|
|
|
|
|
ukulele_tab
|
|
|
|
= "\\utab{" name:inline_text "}{" base:basefret frets:([0-9xX]+) "}" { return tab_property(name, base, frets, false, true)}
|
|
|
|
/ "\\utab*{" name:inline_text "}{" base:basefret frets:([0-9xX]+) "}" { return tab_property(name, base, frets, true, true)}
|
|
|
|
|
|
|
|
basefret
|
|
|
|
= digits:digits ":" " "? { return digits; }
|
|
|
|
/ "" { return "0"}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
language
|
|
|
|
= "\\selectlanguage{" lang:alpha "}" {return property("language", lang);}
|
|
|
|
|
|
|
|
columnsetting
|
|
|
|
= "\\songcolumns{" num:digits "}" {return property("columns", num);}
|
|
|
|
|
|
|
|
song
|
|
|
|
= content:(begin_song properties newlines_merge song_blocks newlines_merge end_song newlines_discard scripture_block? newlines_discard) {return content.join(""); }
|
|
|
|
|
|
|
|
begin_song
|
|
|
|
= "\\beginsong{" title:inline_text "}" {return property("title", title);}
|
|
|
|
end_song
|
|
|
|
= "\\endsong" { return "";}
|
|
|
|
|
|
|
|
|
|
|
|
properties
|
|
|
|
= newlines_merge "[" newlines_merge props:property* "]" { return "\n" + props.join("\n")}
|
|
|
|
|
|
|
|
property
|
|
|
|
= "by={" value:inline_text "}" prop_separator* { return property("artist", value)}
|
|
|
|
/ "cov={" value:slug "}" prop_separator* { return property("cover", value)}
|
|
|
|
/ "album={" value:inline_text "}" prop_separator* { return property("album", value)}
|
|
|
|
/ "url={" value:url "}" prop_separator* { return property("url", value)}
|
|
|
|
/ "original={" value:inline_text "}" prop_separator* { return property("original", value)}
|
|
|
|
|
|
|
|
prop_separator
|
|
|
|
= ","
|
|
|
|
/ " "
|
|
|
|
/ "%"? newline
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// @
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
song_blocks
|
|
|
|
= content:(song_block newlines_merge)* {return megajoin(content)}
|
|
|
|
|
|
|
|
song_block
|
|
|
|
= block_standalone_command
|
|
|
|
/ verse
|
|
|
|
/ chorus
|
|
|
|
/ bridge
|
|
|
|
/ latex_comment_block
|
|
|
|
/ branching_block
|
|
|
|
/ textnote_block
|
|
|
|
/ musicnote_block
|
|
|
|
/ tablature_block
|
|
|
|
/ repeated_block
|
|
|
|
/ nolyrics_block
|
|
|
|
/ special_block
|
|
|
|
|
|
|
|
song_block_parts
|
|
|
|
= content:(song_block_part newlines_merge)* {return megajoin(content)}
|
|
|
|
|
|
|
|
song_block_part
|
|
|
|
= block_standalone_command
|
|
|
|
/ repeated_block_part
|
|
|
|
/ nolyrics_block_part
|
|
|
|
/ musicnote_block_part
|
|
|
|
/ textnote_block_part
|
|
|
|
/ special_block_part
|
|
|
|
/ paragraph_line
|
|
|
|
|
|
|
|
|
|
|
|
latex_comment_block
|
|
|
|
= "%" content:[^\r\n]* {return "#" + content.join("")}
|
|
|
|
|
|
|
|
branching_block
|
|
|
|
= "\\if" condition:[^\r\n]+ newlines {return "#if" + condition.join("") + "\r\n"}
|
|
|
|
/ "\\else" "%"? newlines {return "#else\r\n"}
|
|
|
|
/ "\\fi" "%"? newlines {return "#fi\r\n"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
repeated_block
|
|
|
|
= "\\begin{repeatedchords}" newlines c:song_blocks "\\end{repeatedchords}" newlines {return c}
|
|
|
|
|
|
|
|
repeated_block_part
|
|
|
|
= "\\begin{repeatedchords}" newlines c:song_block_parts "\\end{repeatedchords}" newlines {return c}
|
|
|
|
|
|
|
|
verse
|
|
|
|
= "\\begin{verse}" newlines c:song_block_parts "\\end{verse}" {return c}
|
|
|
|
/ "\\beginverse" newlines c:song_block_parts "\\endverse" {return c}
|
|
|
|
/ "\\begin{verse*}" newlines c:song_block_parts "\\end{verse*}" {return c}
|
|
|
|
|
|
|
|
chorus
|
|
|
|
= "\\begin{chorus}" newlines c:song_block_parts "\\end{chorus}" {return blockify("chorus", c, true)}
|
|
|
|
/ "\\beginchorus" newlines c:song_block_parts "\\endchorus" {return blockify("chorus", c, true)}
|
|
|
|
|
|
|
|
bridge
|
|
|
|
= "\\begin{bridge}" newlines c:song_block_parts "\\end{bridge}" {return blockify("bridge", c, true)}
|
|
|
|
|
|
|
|
nolyrics_block
|
|
|
|
= "{\\nolyrics " newlines c:song_block_parts "}" {return c}
|
|
|
|
/ "\\nolyrics" "{" c:song_block_parts "}" {return c}
|
|
|
|
|
|
|
|
nolyrics_block_part
|
|
|
|
= "{\\nolyrics " newlines c:song_block_parts "}" {return c}
|
|
|
|
/ "\\nolyrics" " "? "{" c:song_block_parts "}" {return c}
|
|
|
|
/ "\\nolyrics" {return ""}
|
|
|
|
|
|
|
|
musicnote_block
|
|
|
|
= "\\musicnote" " "* "{" c:song_block_parts "}" {return blockify("musicnote", c, true)}
|
|
|
|
/ "\\musicnote[" lang:alpha "]" " "* "{" c:song_block_parts "}" {return blockify_param("musicnote", lang, c, true)}
|
|
|
|
|
|
|
|
musicnote_block_part
|
|
|
|
= "\\musicnote" " "* "{" c:song_block_parts "}" {return c}
|
|
|
|
/ "\\musicnote[" lang:alpha "]" " "* "{" c:song_block_parts "}" {return c}
|
|
|
|
|
|
|
|
|
|
|
|
textnote_block
|
|
|
|
= "\\textnote" " "* "{" c:song_block_parts "}" {return blockify("textnote", c, false)}
|
|
|
|
/ "\\textnote[" lang:alpha "]" " "* "{" c:song_block_parts "}" {return blockify_param("textnote", lang, c, false)}
|
|
|
|
|
|
|
|
textnote_block_part
|
|
|
|
= "\\textnote" " "* "{" c:song_block_parts "}" {return c}
|
|
|
|
/ "\\textnote[" lang:alpha "]" " "* "{" c:song_block_parts "}" {return c}
|
|
|
|
/ "\\textbf" " "* "{" c:song_block_parts "}" {return "**" + c + "**"}
|
|
|
|
|
|
|
|
scripture_block
|
|
|
|
= "\\beginscripture{}" "%"? newlines c:song_block_parts "\\endscripture" "%"? {return blockify("scripture", c, true)}
|
|
|
|
/ "\\beginscripture{" comment:inline_text "}" newlines c:song_block_parts "\\endscripture" "%"? {return blockify_param("scripture", comment, c, true)}
|
|
|
|
|
|
|
|
special_block
|
|
|
|
= "\\Bridge" {return blockify("textnote", "Bridge", false)}
|
|
|
|
/ "\\image[" [^\]]+ "]{" [^}]+ "}" {return ""}
|
|
|
|
/ "\\MultiwordChords" { return ""}
|
|
|
|
|
|
|
|
special_block_part
|
|
|
|
= "\\Outro : " "{" newlines c:song_block_parts "}" {return c}
|
|
|
|
/ "\\ifrepeatchords" c:song_block_parts "\\fi" {return c}
|
|
|
|
/ "\\ifchorded" newline c:song_block_parts "\\fi" {return c}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Line
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
paragraph_line
|
|
|
|
= content:paragraph_line_elt+ paragraph_line_elt_comment? {return content.join("")}
|
|
|
|
/ paragraph_line_elt_comment
|
|
|
|
|
|
|
|
paragraph_line_elt_comment
|
|
|
|
= "%" newline { return ""}
|
|
|
|
/ "%" c:[^\r\n]+ newline { return "\r\n#" + c.join("")}
|
|
|
|
|
|
|
|
paragraph_line_elt
|
|
|
|
= inline_text
|
|
|
|
/ chord
|
|
|
|
/ command_in_paragraph
|
|
|
|
|
|
|
|
command_in_paragraph
|
|
|
|
= "\\emph{" c:paragraph_line "}" {return c}
|
|
|
|
/ "\\echo{" c:paragraph_line "}" {return property("echo", c)}
|
|
|
|
/ "\\" c:ignored_command_in_paragraph "{}"? { return c}
|
|
|
|
|
|
|
|
ignored_command_in_paragraph
|
|
|
|
= "Intro"
|
|
|
|
/ "Chorus"
|
|
|
|
/ "Bridge"
|
|
|
|
/ "Verse"
|
|
|
|
/ "Rythm"
|
|
|
|
/ "Outro"
|
|
|
|
/ "Solo"
|
|
|
|
/ "Pattern"
|
|
|
|
|
|
|
|
|
|
|
|
chord
|
|
|
|
= "\\[" chordname:inline_text "]" " "? "{" text:inline_text "}" {return "[" + chordname_split(chordname) + "]" + text}
|
|
|
|
/ "\\[" chordname:inline_text "]" {return "[" + chordname_split(chordname) + "]"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newlines_discard
|
|
|
|
= newlines {return ""; }
|
|
|
|
|
|
|
|
newlines_merge
|
|
|
|
= lines:newline* {return (lines.length>0)?"\r\n":""; }
|
|
|
|
|
|
|
|
newlines
|
|
|
|
= lines:newline* {return lines.join(""); }
|
|
|
|
|
|
|
|
newline
|
|
|
|
= " "* newline_char " "*
|
|
|
|
|
|
|
|
newline_char
|
|
|
|
= "\r\n"
|
|
|
|
/ "\r"
|
|
|
|
/ "\n"
|
|
|
|
|
|
|
|
|
|
|
|
tablature_block
|
|
|
|
= " "* "\\begin{tab}" content:tablature_block_line+ "\\end{tab}" {return "#Tabs\n# " +content.join("# ")}
|
|
|
|
|
|
|
|
tablature_block_line
|
|
|
|
= newlines t:tablature_command newlines { return t + "\r\n"}
|
|
|
|
|
|
|
|
tablature_command
|
|
|
|
= "\\single " chord:digit " " fret:digits { return "single chord:" + chord + " fret:" + fret}
|
|
|
|
/ "\\bar" { return "bar"}
|