From 8019a21475618b03127459e43b4825660208c3ac Mon Sep 17 00:00:00 2001 From: Bernhard Weichel Date: Sun, 14 Dec 2014 20:34:41 +0100 Subject: [PATCH 01/26] added abc mode --- demo/kitchen-sink/docs/abc.abc | 171 +++ lib/ace/ext/modelist.js | 1 + lib/ace/mode/_test/tokens_abc.json | 2207 +++++++++++++++++++++++++++ lib/ace/mode/abc.js | 58 + lib/ace/mode/abc_highlight_rules.js | 114 ++ lib/ace/snippets/abc.js | 7 + lib/ace/snippets/abc.snippets | 15 + 7 files changed, 2573 insertions(+) create mode 100644 demo/kitchen-sink/docs/abc.abc create mode 100644 lib/ace/mode/_test/tokens_abc.json create mode 100644 lib/ace/mode/abc.js create mode 100644 lib/ace/mode/abc_highlight_rules.js create mode 100644 lib/ace/snippets/abc.js create mode 100644 lib/ace/snippets/abc.snippets diff --git a/demo/kitchen-sink/docs/abc.abc b/demo/kitchen-sink/docs/abc.abc new file mode 100644 index 00000000..d8ac326e --- /dev/null +++ b/demo/kitchen-sink/docs/abc.abc @@ -0,0 +1,171 @@ +%abc-2.1 +H:This file contains some example English tunes +% note that the comments (like this one) are to highlight usages +% and would not normally be included in such detail +O:England % the origin of all tunes is England + +X:1 % tune no 1 +T:Dusty Miller, The % title +T:Binny's Jig % an alternative title +C:Trad. % traditional +R:DH % double hornpipe +M:3/4 % meter +K:G % key +B>cd BAG|FA Ac BA|B>cd BAG|DG GB AG:| +Bdd gfg|aA Ac BA|Bdd gfa|gG GB AG:| +BG G/2G/2G BG|FA Ac BA|BG G/2G/2G BG|DG GB AG:| +W:Hey, the dusty miller, and his dusty coat; +W:He will win a shilling, or he spend a groat. +W:Dusty was the coat, dusty was the colour; +W:Dusty was the kiss, that I got frae the miller. + +X:2 +T:Old Sir Simon the King +C:Trad. +S:Offord MSS % from Offord manuscript +N:see also Playford % reference note +M:9/8 +R:SJ % slip jig +N:originally in C % transcription note +K:G +D|GFG GAG G2D|GFG GAG F2D|EFE EFE EFG|A2G F2E D2:| +D|GAG GAB d2D|GAG GAB c2D|[1 EFE EFE EFG|[A2G] F2E D2:|\ % no line-break in score +M:12/8 % change of meter +[2 E2E EFE E2E EFG|\ % no line-break in score +M:9/8 % change of meter +A2G F2E D2|] + +X:3 +T:William and Nancy +T:New Mown Hay +T:Legacy, The +C:Trad. +O:England; Gloucs; Bledington % place of origin +B:Sussex Tune Book % can be found in these books +B:Mally's Cotswold Morris vol.1 2 +D:Morris On % can be heard on this record +P:(AB)2(AC)2A % play the parts in this order +M:6/8 +K:G +[P:A] D|"G"G2G GBd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| +[P:B] d|"G"e2d B2d|"C"gfe "G"d2d| "G"e2d B2d|"C"gfe "D7"d2c| + "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| +% changes of meter, using inline fields +[T:Slows][M:4/4][L:1/4][P:C]"G"d2|"C"e2 "G"d2|B2 d2|"Em"gf "A7"e2|"D7"d2 "G"d2|\ + "C"e2 "G"d2|[M:3/8][L:1/8] "G"B2 d |[M:6/8] "C"gfe "D7"d2c| + "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| + +X:4 +T:South Downs Jig +R:jig +S:Robert Harbron +M:6/8 +L:1/8 +K:G +|: d | dcA G3 | EFG AFE | DEF GAB | cde d2d | +dcA G3 | EFG AFE | DEF GAB | cAF G2 :| +B | Bcd e2c | d2B c2A | Bcd e2c | [M:9/8]d2B c2B A3 | +[M:6/8]DGF E3 | cBA FED | DEF GAB |1 cAF G2 :|2 cAF G3 |] + +X:5 +T:Atholl Brose +% in this example, which reproduces Highland Bagpipe gracing, +% the large number of grace notes mean that it is more convenient to be specific about +% score line-breaks (using the $ symbol), rather than using code line breaks to indicate them +I:linebreak $ +K:D +{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad| +{gcd}c<{e}A {gAGAG}A>e {ag}a>f {gef}e>d| +{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad| +{g}c/d/e {g}G>{d}B {gf}gG {dc}d>B:|$ +{g}ce {ag}a>e {gf}g>e| +{g}ce {ag}a2 {GdG}a>d| +{g}ce {ag}a>e {gf}g>f| +{gef}e>d {gf}g>d {gBd}B<{e}G {dc}d>B| +{g}ce {ag}a>e {gf}g>e| +{g}ce {ag}a2 {GdG}ad| +{g}c<{GdG}e {gf}ga {f}g>e {g}f>d| +{g}e/f/g {Gdc}d>c {gBd}B<{e}G {dc}d2|] + +X:6 +T:Untitled Reel +C:Trad. +K:D +eg|a2ab ageg|agbg agef|g2g2 fgag|f2d2 d2:|\ +ed|cecA B2ed|cAcA E2ed|cecA B2ed|c2A2 A2:| +K:G +AB|cdec BcdB|ABAF GFE2|cdec BcdB|c2A2 A2:| + +X:7 +T:Kitchen Girl +C:Trad. +K:D +[c4a4] [B4g4]|efed c2cd|e2f2 gaba|g2e2 e2fg| +a4 g4|efed cdef|g2d2 efed|c2A2 A4:| +K:G +ABcA BAGB|ABAG EDEG|A2AB c2d2|e3f edcB|ABcA BAGB| +ABAG EGAB|cBAc BAG2|A4 A4:| + +%abc-2.1 +%%pagewidth 21cm +%%pageheight 29.7cm +%%topspace 0.5cm +%%topmargin 1cm +%%botmargin 0cm +%%leftmargin 1cm +%%rightmargin 1cm +%%titlespace 0cm +%%titlefont Times-Bold 32 +%%subtitlefont Times-Bold 24 +%%composerfont Times 16 +%%vocalfont Times-Roman 14 +%%staffsep 60pt +%%sysstaffsep 20pt +%%musicspace 1cm +%%vocalspace 5pt +%%measurenb 0 +%%barsperstaff 5 +%%scale 0.7 +X: 1 +T: Canzonetta a tre voci +C: Claudio Monteverdi (1567-1643) +M: C +L: 1/4 +Q: "Andante mosso" 1/4 = 110 +%%score [1 2 3] +V: 1 clef=treble name="Soprano"sname="A" +V: 2 clef=treble name="Alto" sname="T" +V: 3 clef=bass middle=d name="Tenor" sname="B" +%%MIDI program 1 75 % recorder +%%MIDI program 2 75 +%%MIDI program 3 75 +K: Eb +% 1 - 4 +[V: 1] |:z4 |z4 |f2ec |_ddcc | +w: Son que-sti~i cre-spi cri-ni~e +w: Que-sti son gli~oc-chi che mi- +[V: 2] |:c2BG|AAGc|(F/G/A/B/)c=A|B2AA | +w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il vi-so e +w: Que-sti son~gli oc-chi che mi-ran - - - - do fi-so mi- +[V: 3] |:z4 |f2ec|_ddcf |(B/c/_d/e/)ff| +w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il +w: Que-sti son~gli oc-chi che mi-ran - - - - do +% 5 - 9 +[V: 1] cAB2 |cAAA |c3B|G2!fermata!Gz ::e4| +w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh, +w: ran-do fi-so, tut-to re-stai con-qui-so. +[V: 2] AAG2 |AFFF |A3F|=E2!fermata!Ez::c4| +w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh, +w: ran-do fi-so tut-to re-stai con-qui-so. +[V: 3] (ag/f/e2)|A_ddd|A3B|c2!fermata!cz ::A4| +w: vi - - - so ond' io ti-man-go~uc-ci-so. Deh, +w: fi - - - so tut-to re-stai con-qui-so. +% 10 - 15 +[V: 1] f_dec |B2c2|zAGF |\ +w: dim-me-lo ben mi-o, che que-sto\ +=EFG2 |1F2z2:|2F8|] % more notes +w: sol de-si-o_. % more lyrics +[V: 2] ABGA |G2AA|GF=EF |(GF3/2=E//D//E)|1F2z2:|2F8|] +w: dim-me-lo ben mi-o, che que-sto sol de-si - - - - o_. +[V: 3] _dBc>d|e2AF|=EFc_d|c4 |1F2z2:|2F8|] +w: dim-me-lo ben mi-o, che que-sto sol de-si-o_. \ No newline at end of file diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 3245d8a7..cba800ac 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -43,6 +43,7 @@ Mode.prototype.supportsFile = function(filename) { // todo firstlinematch var supportedModes = { ABAP: ["abap"], + ABC: ["abc"], ActionScript:["as"], ADA: ["ada|adb"], Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"], diff --git a/lib/ace/mode/_test/tokens_abc.json b/lib/ace/mode/_test/tokens_abc.json new file mode 100644 index 00000000..c65ae2a5 --- /dev/null +++ b/lib/ace/mode/_test/tokens_abc.json @@ -0,0 +1,2207 @@ +[[ + "start", + ["comment.line.percentage","%abc-2.1"] +],[ + "start", + ["information.keyword","H:"], + ["information.argument.string.unquoted","This file contains some example English tunes"] +],[ + "start", + ["comment.line.percentage","% note that the comments (like this one) are to highlight usages"] +],[ + "start", + ["comment.line.percentage","% and would not normally be included in such detail"] +],[ + "start", + ["information.keyword","O:"], + ["information.argument.string.unquoted","England "], + ["comment.line.percentage","% the origin of all tunes is England"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","1 "], + ["comment.line.percentage","% tune no 1"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Dusty Miller, The "], + ["comment.line.percentage","% title"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Binny's Jig "], + ["comment.line.percentage","% an alternative title"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad. "], + ["comment.line.percentage","% traditional"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","DH "], + ["comment.line.percentage","% double hornpipe"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","3/4 "], + ["comment.line.percentage","% meter"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G "], + ["comment.line.percentage","% key"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","a"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Hey, the dusty miller, and his dusty coat;"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","He will win a shilling, or he spend a groat."] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Dusty was the coat, dusty was the colour;"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Dusty was the kiss, that I got frae the miller."] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","2"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Old Sir Simon the King"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","S:"], + ["information.argument.string.unquoted","Offord MSS "], + ["comment.line.percentage","% from Offord manuscript"] +],[ + "start", + ["information.keyword","N:"], + ["information.argument.string.unquoted","see also Playford "], + ["comment.line.percentage","% reference note"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","9/8"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","SJ "], + ["comment.line.percentage","% slip jig"] +],[ + "start", + ["information.keyword","N:"], + ["information.argument.string.unquoted","originally in C "], + ["comment.line.percentage","% transcription note"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|[1"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["text","["], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text","] "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"], + ["text","\\ "], + ["comment.line.percentage","% no line-break in score"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","12/8 "], + ["comment.line.percentage","% change of meter"] +],[ + "start", + ["barline.keyword.operator","[2"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["text","\\ "], + ["comment.line.percentage","% no line-break in score"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","9/8 "], + ["comment.line.percentage","% change of meter"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","3"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","William and Nancy"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","New Mown Hay"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Legacy, The"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","O:"], + ["information.argument.string.unquoted","England; Gloucs; Bledington "], + ["comment.line.percentage","% place of origin"] +],[ + "start", + ["information.keyword","B:"], + ["information.argument.string.unquoted","Sussex Tune Book "], + ["comment.line.percentage","% can be found in these books"] +],[ + "start", + ["information.keyword","B:"], + ["information.argument.string.unquoted","Mally's Cotswold Morris vol.1 2"] +],[ + "start", + ["information.keyword","D:"], + ["information.argument.string.unquoted","Morris On "], + ["comment.line.percentage","% can be heard on this record"] +],[ + "start", + ["information.keyword","P:"], + ["information.argument.string.unquoted","(AB)2(AC)2A "], + ["comment.line.percentage","% play the parts in this order"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","6/8"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G "] +],[ + "start", + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","A]"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","B]"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["comment.line.percentage","% changes of meter, using inline fields"] +],[ + "start", + ["information.keyword.embedded","[T:"], + ["information.argument.string.unquoted","Slows]"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","4/4]"], + ["information.keyword.embedded","[L:"], + ["information.argument.string.unquoted","1/4]"], + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","C]"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"Em\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["string.quoted","\"A7\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["text","\\"] +],[ + "start", + ["text"," "], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","3/8]"], + ["information.keyword.embedded","[L:"], + ["information.argument.string.unquoted","1/8]"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","6/8]"], + ["text"," "], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","4"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","South Downs Jig"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","jig"] +],[ + "start", + ["information.keyword","S:"], + ["information.argument.string.unquoted","Robert Harbron"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","6/8"] +],[ + "start", + ["information.keyword","L:"], + ["information.argument.string.unquoted","1/8"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["barline.keyword.operator","|:"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","9/8]"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","6/8]"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","D"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator",":|2"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","5"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Atholl Brose"] +],[ + "start", + ["comment.line.percentage","% in this example, which reproduces Highland Bagpipe gracing,"] +],[ + "start", + ["comment.line.percentage","% the large number of grace notes mean that it is more convenient to be specific about"] +],[ + "start", + ["comment.line.percentage","% score line-breaks (using the $ symbol), rather than using code line breaks to indicate them"] +],[ + "start", + ["information.keyword","I:"], + ["information.argument.string.unquoted","linebreak $"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","f"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric",">"], + ["text","{"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator",":|"], + ["text","$"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["text"," {"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","g"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","6"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Untitled Reel"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","b"], + ["text"," "], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","b"], + ["pitch.constant.numeric","g"], + ["text"," "], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"], + ["text","\\"] +],[ + "start", + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","7"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Kitchen Girl"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["text","["], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","4"], + ["text","] ["], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","4"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","4"], + ["text","]"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","b"], + ["pitch.constant.numeric","a"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","4"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["comment.line.percentage","%abc-2.1"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","pagewidth 21cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","pageheight 29.7cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","topspace 0.5cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","topmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","botmargin 0cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","leftmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","rightmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","titlespace 0cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","titlefont Times-Bold 32"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","subtitlefont Times-Bold 24"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","composerfont Times 16"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","vocalfont Times-Roman 14"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","staffsep 60pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","sysstaffsep 20pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","musicspace 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","vocalspace 5pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","measurenb 0"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","barsperstaff 5"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","scale 0.7"] +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted"," 1"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted"," Canzonetta a tre voci"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted"," Claudio Monteverdi (1567-1643)"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted"," C"] +],[ + "start", + ["information.keyword","L:"], + ["information.argument.string.unquoted"," 1/4"] +],[ + "start", + ["information.keyword","Q:"], + ["information.argument.string.unquoted"," \"Andante mosso\" 1/4 = 110"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","score [1 2 3]"] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 1 clef=treble name=\"Soprano\"sname=\"A\""] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 2 clef=treble name=\"Alto\" sname=\"T\""] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 3 clef=bass middle=d name=\"Tenor\" sname=\"B\""] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 1 75 % recorder"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 2 75"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 3 75"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted"," Eb"] +],[ + "start", + ["comment.line.percentage","% 1 - 4"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son gli~oc-chi che mi-"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","/"], + ["text",")"], + ["pitch.constant.numeric","c"], + ["accent.constant.language","="], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e que - - - - sto~il vi-so e"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son~gli oc-chi che mi-ran - - - - do fi-so mi-"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","/"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","/"], + ["text",")"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e que - - - - sto~il"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son~gli oc-chi che mi-ran - - - - do"] +],[ + "start", + ["comment.line.percentage","% 5 - 9"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","z"], + ["text"," "], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," ran-do fi-so, tut-to re-stai con-qui-so."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","F"], + ["barline.keyword.operator","|"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","z"], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," ran-do fi-so tut-to re-stai con-qui-so."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," ("], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text",")"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","z"], + ["text"," "], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," vi - - - so ond' io ti-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," fi - - - so tut-to re-stai con-qui-so."] +],[ + "start", + ["comment.line.percentage","% 10 - 15"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["pitch.constant.numeric","f"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","z"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","\\"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto"], + ["text","\\"] +],[ + "start", + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"], + ["text"," "], + ["comment.line.percentage","% more notes"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," sol de-si-o_. "], + ["comment.line.percentage","% more lyrics"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","3/2"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","//"], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","//"], + ["pitch.constant.numeric","E"], + ["text",")"], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto sol de-si - - - - o_."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," "], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["barline.keyword.operator","|"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","c"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto sol de-si-o_."] +]] \ No newline at end of file diff --git a/lib/ace/mode/abc.js b/lib/ace/mode/abc.js new file mode 100644 index 00000000..b6eb237a --- /dev/null +++ b/lib/ace/mode/abc.js @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js + */ + +define(function (require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextMode = require("./text").Mode; + var ABCHighlightRules = require("./abc_highlight_rules").ABCHighlightRules; +// TODO: pick appropriate fold mode + var FoldMode = require("./folding/cstyle").FoldMode; + + var Mode = function () { + this.HighlightRules = ABCHighlightRules; + this.foldingRules = new FoldMode(); + }; + oop.inherits(Mode, TextMode); + + (function () { + // this.lineCommentStart = ""%.*""; + // this.blockComment = {start: ""/*"", end: ""*/""}; + // Extra logic goes here. + this.$id = "ace/mode/abc" + }).call(Mode.prototype); + + exports.Mode = Mode; +}); \ No newline at end of file diff --git a/lib/ace/mode/abc_highlight_rules.js b/lib/ace/mode/abc_highlight_rules.js new file mode 100644 index 00000000..6ffe9c9b --- /dev/null +++ b/lib/ace/mode/abc_highlight_rules.js @@ -0,0 +1,114 @@ +/* This file was partially autogenerated from https://github.com/jimhawkridge/SublimeABC + + Modifications + + - more classes to express the abc semantic + - added syntax highlighting for Zupfnoter conventions (https://github.com/bwl21/zupfnoter) + - separate note pitch and note duration - even if it looks the same + + ***********************************************************************************************/ + + +define(function (require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + var ABCHighlightRules = function () { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + start: [ + { + token: ['zupfnoter.information.comment.line.percentage', 'information.keyword', 'in formation.keyword.embedded'], + regex: '(%%%%)(hn\\.[a-z]*)(.*)', + comment: 'Instruction Comment' + }, + { + token: ['information.comment.line.percentage', 'information.keyword.embedded'], + regex: '(%%)(.*)', + comment: 'Instruction Comment' + }, + + { + token: 'comment.line.percentage', + regex: '%.*', + comment: 'Comments' + }, + + { + token: 'barline.keyword.operator', + regex: '[\\[:]*[|:][|\\]:]*(?:\\[?[0-9]+)?|\\[[0-9]+', + comment: 'Bar lines' + }, + { + token: ['information.keyword.embedded', 'information.argument.string.unquoted'], + regex: '(\\[[A-Za-z]:)([^\\]]*\\])', + comment: 'embedded Header lines' + }, + { + token: ['information.keyword', 'information.argument.string.unquoted'], + regex: '^([A-Za-z]:)([^%\\\\]*)', + comment: 'Header lines' + }, + { + token: ['text', 'entity.name.function', 'string.unquoted', 'text'], + regex: '(\\[)([A-Z]:)(.*?)(\\])', + comment: 'Inline fields' + }, + { + token: ['accent.constant.language', 'pitch.constant.numeric', 'duration.constant.numeric'], + regex: '([\\^=_]*)([A-Ga-gz][,\']*)([0-9]*/*[><0-9]*)', + comment: 'Notes' + }, + { + token: 'zupfnoter.jumptarget.string.quoted', + regex: '[\\"!]\\^\\:.*?[\\"!]', + comment: 'Zupfnoter jumptarget' + }, { + token: 'zupfnoter.goto.string.quoted', + regex: '[\\"!]\\^\\@.*?[\\"!]', + comment: 'Zupfnoter goto' + }, + { + token: 'zupfnoter.annotation.string.quoted', + regex: '[\\"!]\\^\\!.*?[\\"!]', + comment: 'Zupfnoter annoation' + }, + { + token: 'zupfnoter.annotationref.string.quoted', + regex: '[\\"!]\\^\\#.*?[\\"!]', + comment: 'Zupfnoter annotation reference' + }, + { + token: 'chordname.string.quoted', + regex: '[\\"!]\\^.*?[\\"!]', + comment: 'abc chord' + }, + { + token: 'string.quoted', + regex: '[\\"!].*?[\\"!]', + comment: 'abc annotation' + } + + ] + }; + + // this.embedRules(JsonHighlightRules, "json-") + + this.normalizeRules(); + }; + + ABCHighlightRules.metaData = { + fileTypes: ['abc'], + name: 'ABC', + scopeName: 'text.abcnotation' + }; + + + oop.inherits(ABCHighlightRules, TextHighlightRules); + + exports.ABCHighlightRules = ABCHighlightRules; +}); diff --git a/lib/ace/snippets/abc.js b/lib/ace/snippets/abc.js new file mode 100644 index 00000000..da0448ef --- /dev/null +++ b/lib/ace/snippets/abc.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./abc.snippets"); +exports.scope = "abc"; + +}); diff --git a/lib/ace/snippets/abc.snippets b/lib/ace/snippets/abc.snippets new file mode 100644 index 00000000..11e2d735 --- /dev/null +++ b/lib/ace/snippets/abc.snippets @@ -0,0 +1,15 @@ +snippet zupfnoter.goto + "^@${1:target}@${2:some_id},${3:some_id}" + +snippet zupfnoter.annotation + "^@!{1:text}@${2:some_id},${3:some_id}" + +snippet zupfnoter.annotationref + "^#${1:target}" + +snippet zupfnoter.target + "^:${1:target}" + + +snippet zupfnoter.print + %%%%hn.print {"startpos": 20, "t":"Sopran, Alt", "v":[1,2], "s":[[1,2]], "f":[1], "sf":[2], "j":[1]} From 7da354d5f33202ab0d7dd78263e5fa220f7f03b7 Mon Sep 17 00:00:00 2001 From: Bernhard Weichel Date: Sun, 14 Dec 2014 23:40:47 +0100 Subject: [PATCH 02/26] fixed Uncaught TypeError: undefined is not a functionapp_config.js:147 (anonymous function)app_config.js:146 setDefaultValuesmode_creator.js:6 --- lib/ace/lib/app_config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/lib/app_config.js b/lib/ace/lib/app_config.js index 84b9e70c..bc5518d7 100644 --- a/lib/ace/lib/app_config.js +++ b/lib/ace/lib/app_config.js @@ -141,11 +141,11 @@ var AppConfig = function() { opts[name].value = value; } }; - + this.setDefaultValues = function(path, optionHash) { Object.keys(optionHash).forEach(function(key) { this.setDefaultValue(path, key, optionHash[key]); - }); + }, this); }; this.warn = warn; From 95eed254393eeda6079a0386d87e0fe2a6807024 Mon Sep 17 00:00:00 2001 From: Bernhard Weichel Date: Sun, 14 Dec 2014 23:53:52 +0100 Subject: [PATCH 03/26] small fix in the snippets --- lib/ace/lib/app_config.js | 2 +- lib/ace/snippets/abc.snippets | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/lib/app_config.js b/lib/ace/lib/app_config.js index bc5518d7..ead26a98 100644 --- a/lib/ace/lib/app_config.js +++ b/lib/ace/lib/app_config.js @@ -141,7 +141,7 @@ var AppConfig = function() { opts[name].value = value; } }; - + this.setDefaultValues = function(path, optionHash) { Object.keys(optionHash).forEach(function(key) { this.setDefaultValue(path, key, optionHash[key]); diff --git a/lib/ace/snippets/abc.snippets b/lib/ace/snippets/abc.snippets index 11e2d735..65b0fd65 100644 --- a/lib/ace/snippets/abc.snippets +++ b/lib/ace/snippets/abc.snippets @@ -1,8 +1,8 @@ snippet zupfnoter.goto - "^@${1:target}@${2:some_id},${3:some_id}" + "^@${1:target}@${2:distance}" snippet zupfnoter.annotation - "^@!{1:text}@${2:some_id},${3:some_id}" + "^@!{1:text}@${2:x_offset},${3:y_offset}" snippet zupfnoter.annotationref "^#${1:target}" From b9a4f293eda9c829f30653f1700ebee8f425c81b Mon Sep 17 00:00:00 2001 From: Daniel Darabos Date: Sun, 21 Dec 2014 22:52:21 +0100 Subject: [PATCH 04/26] Fix getVScrollBarAlwaysVisible. By accident it was returning `$hScrollBarAlwaysVisible`. --- lib/ace/virtual_renderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index ae438ae8..484ebb5e 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -750,7 +750,7 @@ var VirtualRenderer = function(container, theme) { * @returns {Boolean} **/ this.getVScrollBarAlwaysVisible = function() { - return this.$hScrollBarAlwaysVisible; + return this.$vScrollBarAlwaysVisible; }; /** From 14850f5b9ecc935a72079c43adf1afd653d8bef1 Mon Sep 17 00:00:00 2001 From: Bernhard Weichel Date: Mon, 22 Dec 2014 16:55:40 +0100 Subject: [PATCH 05/26] Reduced size of sample document --- demo/kitchen-sink/docs/abc.abc | 154 +-------------------------------- 1 file changed, 2 insertions(+), 152 deletions(-) diff --git a/demo/kitchen-sink/docs/abc.abc b/demo/kitchen-sink/docs/abc.abc index d8ac326e..32548d3c 100644 --- a/demo/kitchen-sink/docs/abc.abc +++ b/demo/kitchen-sink/docs/abc.abc @@ -11,161 +11,11 @@ C:Trad. % traditional R:DH % double hornpipe M:3/4 % meter K:G % key -B>cd BAG|FA Ac BA|B>cd BAG|DG GB AG:| +%%score (1,2) +[P:1]B>cd "^G"BAG|FA Ac BA|B>cd BAG|DG GB AG:| Bdd gfg|aA Ac BA|Bdd gfa|gG GB AG:| BG G/2G/2G BG|FA Ac BA|BG G/2G/2G BG|DG GB AG:| W:Hey, the dusty miller, and his dusty coat; W:He will win a shilling, or he spend a groat. W:Dusty was the coat, dusty was the colour; W:Dusty was the kiss, that I got frae the miller. - -X:2 -T:Old Sir Simon the King -C:Trad. -S:Offord MSS % from Offord manuscript -N:see also Playford % reference note -M:9/8 -R:SJ % slip jig -N:originally in C % transcription note -K:G -D|GFG GAG G2D|GFG GAG F2D|EFE EFE EFG|A2G F2E D2:| -D|GAG GAB d2D|GAG GAB c2D|[1 EFE EFE EFG|[A2G] F2E D2:|\ % no line-break in score -M:12/8 % change of meter -[2 E2E EFE E2E EFG|\ % no line-break in score -M:9/8 % change of meter -A2G F2E D2|] - -X:3 -T:William and Nancy -T:New Mown Hay -T:Legacy, The -C:Trad. -O:England; Gloucs; Bledington % place of origin -B:Sussex Tune Book % can be found in these books -B:Mally's Cotswold Morris vol.1 2 -D:Morris On % can be heard on this record -P:(AB)2(AC)2A % play the parts in this order -M:6/8 -K:G -[P:A] D|"G"G2G GBd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| -[P:B] d|"G"e2d B2d|"C"gfe "G"d2d| "G"e2d B2d|"C"gfe "D7"d2c| - "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| -% changes of meter, using inline fields -[T:Slows][M:4/4][L:1/4][P:C]"G"d2|"C"e2 "G"d2|B2 d2|"Em"gf "A7"e2|"D7"d2 "G"d2|\ - "C"e2 "G"d2|[M:3/8][L:1/8] "G"B2 d |[M:6/8] "C"gfe "D7"d2c| - "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| - -X:4 -T:South Downs Jig -R:jig -S:Robert Harbron -M:6/8 -L:1/8 -K:G -|: d | dcA G3 | EFG AFE | DEF GAB | cde d2d | -dcA G3 | EFG AFE | DEF GAB | cAF G2 :| -B | Bcd e2c | d2B c2A | Bcd e2c | [M:9/8]d2B c2B A3 | -[M:6/8]DGF E3 | cBA FED | DEF GAB |1 cAF G2 :|2 cAF G3 |] - -X:5 -T:Atholl Brose -% in this example, which reproduces Highland Bagpipe gracing, -% the large number of grace notes mean that it is more convenient to be specific about -% score line-breaks (using the $ symbol), rather than using code line breaks to indicate them -I:linebreak $ -K:D -{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad| -{gcd}c<{e}A {gAGAG}A>e {ag}a>f {gef}e>d| -{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad| -{g}c/d/e {g}G>{d}B {gf}gG {dc}d>B:|$ -{g}ce {ag}a>e {gf}g>e| -{g}ce {ag}a2 {GdG}a>d| -{g}ce {ag}a>e {gf}g>f| -{gef}e>d {gf}g>d {gBd}B<{e}G {dc}d>B| -{g}ce {ag}a>e {gf}g>e| -{g}ce {ag}a2 {GdG}ad| -{g}c<{GdG}e {gf}ga {f}g>e {g}f>d| -{g}e/f/g {Gdc}d>c {gBd}B<{e}G {dc}d2|] - -X:6 -T:Untitled Reel -C:Trad. -K:D -eg|a2ab ageg|agbg agef|g2g2 fgag|f2d2 d2:|\ -ed|cecA B2ed|cAcA E2ed|cecA B2ed|c2A2 A2:| -K:G -AB|cdec BcdB|ABAF GFE2|cdec BcdB|c2A2 A2:| - -X:7 -T:Kitchen Girl -C:Trad. -K:D -[c4a4] [B4g4]|efed c2cd|e2f2 gaba|g2e2 e2fg| -a4 g4|efed cdef|g2d2 efed|c2A2 A4:| -K:G -ABcA BAGB|ABAG EDEG|A2AB c2d2|e3f edcB|ABcA BAGB| -ABAG EGAB|cBAc BAG2|A4 A4:| - -%abc-2.1 -%%pagewidth 21cm -%%pageheight 29.7cm -%%topspace 0.5cm -%%topmargin 1cm -%%botmargin 0cm -%%leftmargin 1cm -%%rightmargin 1cm -%%titlespace 0cm -%%titlefont Times-Bold 32 -%%subtitlefont Times-Bold 24 -%%composerfont Times 16 -%%vocalfont Times-Roman 14 -%%staffsep 60pt -%%sysstaffsep 20pt -%%musicspace 1cm -%%vocalspace 5pt -%%measurenb 0 -%%barsperstaff 5 -%%scale 0.7 -X: 1 -T: Canzonetta a tre voci -C: Claudio Monteverdi (1567-1643) -M: C -L: 1/4 -Q: "Andante mosso" 1/4 = 110 -%%score [1 2 3] -V: 1 clef=treble name="Soprano"sname="A" -V: 2 clef=treble name="Alto" sname="T" -V: 3 clef=bass middle=d name="Tenor" sname="B" -%%MIDI program 1 75 % recorder -%%MIDI program 2 75 -%%MIDI program 3 75 -K: Eb -% 1 - 4 -[V: 1] |:z4 |z4 |f2ec |_ddcc | -w: Son que-sti~i cre-spi cri-ni~e -w: Que-sti son gli~oc-chi che mi- -[V: 2] |:c2BG|AAGc|(F/G/A/B/)c=A|B2AA | -w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il vi-so e -w: Que-sti son~gli oc-chi che mi-ran - - - - do fi-so mi- -[V: 3] |:z4 |f2ec|_ddcf |(B/c/_d/e/)ff| -w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il -w: Que-sti son~gli oc-chi che mi-ran - - - - do -% 5 - 9 -[V: 1] cAB2 |cAAA |c3B|G2!fermata!Gz ::e4| -w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh, -w: ran-do fi-so, tut-to re-stai con-qui-so. -[V: 2] AAG2 |AFFF |A3F|=E2!fermata!Ez::c4| -w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh, -w: ran-do fi-so tut-to re-stai con-qui-so. -[V: 3] (ag/f/e2)|A_ddd|A3B|c2!fermata!cz ::A4| -w: vi - - - so ond' io ti-man-go~uc-ci-so. Deh, -w: fi - - - so tut-to re-stai con-qui-so. -% 10 - 15 -[V: 1] f_dec |B2c2|zAGF |\ -w: dim-me-lo ben mi-o, che que-sto\ -=EFG2 |1F2z2:|2F8|] % more notes -w: sol de-si-o_. % more lyrics -[V: 2] ABGA |G2AA|GF=EF |(GF3/2=E//D//E)|1F2z2:|2F8|] -w: dim-me-lo ben mi-o, che que-sto sol de-si - - - - o_. -[V: 3] _dBc>d|e2AF|=EFc_d|c4 |1F2z2:|2F8|] -w: dim-me-lo ben mi-o, che que-sto sol de-si-o_. \ No newline at end of file From ded43d9d6903456e3a4bc5743b2370289e8edb52 Mon Sep 17 00:00:00 2001 From: "Matthias S. Benkmann" Date: Sun, 7 Dec 2014 17:03:07 +0100 Subject: [PATCH 06/26] HTTP PUT support for static.py change host default to 127.0.0.1 for better security improved option parsing --- static.py | 114 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 41 deletions(-) diff --git a/static.py b/static.py index eb864596..ba3df3dd 100755 --- a/static.py +++ b/static.py @@ -33,6 +33,7 @@ import string import sys from os import path, stat, getcwd from wsgiref import util +from wsgiref.validate import validator from wsgiref.headers import Headers from wsgiref.simple_server import make_server from optparse import OptionParser @@ -84,6 +85,7 @@ class Cling(object): not_modified = StatusApp('304 Not Modified', "") moved_permanently = StatusApp('301 Moved Permanently') method_not_allowed = StatusApp('405 Method Not Allowed') + success_no_content = StatusApp('204 No Content', "") def __init__(self, root, **kw): """Just set the root and any other attribs passes via **kw.""" @@ -93,9 +95,6 @@ class Cling(object): def __call__(self, environ, start_response): """Respond to a request when called in the usual WSGI way.""" - if environ['REQUEST_METHOD'] not in ('GET', 'HEAD'): - headers = [('Allow', 'GET, HEAD')] - return self.method_not_allowed(environ, start_response, headers) path_info = environ.get('PATH_INFO', '') full_path = self._full_path(path_info) if not self._is_under_root(full_path): @@ -109,6 +108,17 @@ class Cling(object): return self.moved_permanently(environ, start_response, headers) else: full_path = self._full_path(path_info + self.index_file) + try: + sz = int(environ['CONTENT_LENGTH']) + except: + sz = 0 + if environ['REQUEST_METHOD'] == 'PUT' and path_info in self.puttable and sz > 0: + data = environ['wsgi.input'].read(sz) + with open(full_path, "wb") as f: f.write(data) + return self.success_no_content(environ, start_response) + if environ['REQUEST_METHOD'] not in ('GET', 'HEAD'): + headers = [('Allow', 'GET, HEAD')] + return self.method_not_allowed(environ, start_response, headers) content_type = self._guess_type(full_path) try: etag, last_modified = self._conditions(full_path, environ) @@ -191,52 +201,74 @@ def cling_wrap(package_name, dir_name, **kw): def command(): - parser = OptionParser(usage="%prog DIR [HOST][:][PORT]", - version="static 0.3.6") + usage = "%prog [--help] [-d DIR] [-l [HOST][:PORT]] [-p RELPATH[,RELPATH...]]" + parser = OptionParser(usage=usage, version="static 0.3.6") + parser.add_option("-d", "--dir", dest="rootdir", default=".", help="Root directory to serve. Defaults to '.' .", metavar="DIR") + parser.add_option("-l", "--listen", dest="listen", default="127.0.0.1:8888", help="Listen on this interface (given by its hostname or IP) and port. HOST defaults to 127.0.0.1. PORT defaults to 8888. Leave HOST empty to listen on all interfaces (SECURITY WARNING!).", metavar="[HOST][:PORT]") + parser.add_option("-p", "--puttable", dest="puttable", default="", help="Comma or space-separated list of request paths for which to permit PUT requests.", metavar="RELPATH[,RELPATH...]") + parser.add_option("--validate", dest="validate", action="store_true", default=False, help="Enable HTTP validation. You don't need this unless you're working on static.py itself.") + options, args = parser.parse_args() - if len(args) in (1, 2): - if len(args) == 2: - parts = args[1].split(":") - if len(parts) == 1: - host = parts[0] - port = None - elif len(parts) == 2: - host, port = parts - else: - sys.exit("Invalid host:port specification.") - elif len(args) == 1: - host, port = None, None - if not host: - host = '0.0.0.0' - if not port: - port = 8888 - try: - port = int(port) - except: - sys.exit("Invalid host:port specification.") - app = Cling(args[0]) - try: - make_server(host, port, app).serve_forever() - except KeyboardInterrupt, ki: - print "Cio, baby!" - except: - sys.exit("Problem initializing server.") - else: + if len(args) > 0: parser.print_help(sys.stderr) sys.exit(1) + parts = options.listen.split(":") + if len(parts) == 1: + try: # if the the listen argument consists only of a port number + port = int(parts[0]) + host = None + except: # could not parse as port number => must be a host IP or name + host = parts[0] + port = None + elif len(parts) == 2: + host, port = parts + else: + sys.exit("Invalid host:port specification.") -def test(): - from wsgiref.validate import validator - app = Cling(getcwd()) + if not host: + host = '0.0.0.0' + if not port: + port = 8888 try: - print "Serving " + getcwd() + " to http://localhost:8888" - make_server('0.0.0.0', 8888, validator(app)).serve_forever() + port = int(port) + if port <= 0 or port > 65535: raise ValueError + except: + sys.exit("Invalid host:port specification.") + + puttable = set(path.abspath(p) for p in options.puttable.replace(","," ").split()) + if puttable and host not in ('127.0.0.1', 'localhost'): + sys.exit("Permitting PUT access for non-localhost connections is unwise.") + + options.rootdir = path.abspath(options.rootdir) + + for p in puttable: + if not p.startswith(options.rootdir): + sys.exit("puttable path '%s' not under root '%s'" % (p, options.rootdir)) + if path.exists(p) and not path.isfile(p): + sys.exit("puttable path '%s' exists but is not a file" % p) + + # cut off root prefix from puttable paths + puttable = set(p[len(options.rootdir):] for p in puttable) + + app = Cling(options.rootdir, puttable=puttable) + + if options.validate: + app = validator(app) + + try: + print "Serving %s to http://%s:%d" % (options.rootdir, host, port) + if puttable: + print "The following paths (relative to server root) may be OVERWRITTEN via HTTP PUT.\nI HOPE EVERY USER ON THIS SYSTEM IS TRUSTED!" + for p in puttable: + print p + make_server(host, port, app).serve_forever() except KeyboardInterrupt, ki: - print "" - print "Ciao, baby!" + print "Cio, baby!" + except: + sys.exit("Problem initializing server: %s" % sys.exc_info()[1]) if __name__ == '__main__': - test() + command() From 8919b113d15069f40df01f8c56d0e800946c29b8 Mon Sep 17 00:00:00 2001 From: "Matthias S. Benkmann" Date: Sun, 7 Dec 2014 17:38:15 +0100 Subject: [PATCH 07/26] add server upload buttons and Ctrl-S bindings to mode_editor in combination with PUT support in ./static.py (or whatever other web server) this allows people to save both the highlighting rules and the demo documents right from the mode editor for a better workflow. --- demo/kitchen-sink/doclist.js | 19 +++++++++++++++++- lib/ace/lib/net.js | 13 ++++++++++++ tool/mode_creator.html | 4 +++- tool/mode_creator.js | 39 ++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/demo/kitchen-sink/doclist.js b/demo/kitchen-sink/doclist.js index b0198238..567c62cd 100644 --- a/demo/kitchen-sink/doclist.js +++ b/demo/kitchen-sink/doclist.js @@ -169,13 +169,30 @@ function loadDoc(name, callback) { }); } +// callback is called with the error message from PUT (if any) +function saveDoc(name, callback) { + var doc = fileCache[name]; + if (!doc || !doc.session) + return callback("Unknown document: " + name); + + var path = doc.path; + var parts = path.split("/"); + if (parts[0] == "docs") + path = "demo/kitchen-sink/" + path; + else if (parts[0] == "ace") + path = "lib/" + path; + + net.put(path, doc.session.getValue(), callback); +} + module.exports = { fileCache: fileCache, docs: sort(prepareDocList(docs)), ownSource: prepareDocList(ownSource), hugeDocs: prepareDocList(hugeDocs), initDoc: initDoc, - loadDoc: loadDoc + loadDoc: loadDoc, + saveDoc: saveDoc, }; module.exports.all = { "Mode Examples": module.exports.docs, diff --git a/lib/ace/lib/net.js b/lib/ace/lib/net.js index bba76df8..4c07ec2b 100644 --- a/lib/ace/lib/net.js +++ b/lib/ace/lib/net.js @@ -22,6 +22,19 @@ exports.get = function (url, callback) { xhr.send(null); }; +exports.put = function (url, data, callback) { + var xhr = new XMLHttpRequest(); + xhr.open('PUT', url, true); + xhr.onreadystatechange = function () { + //Do not explicitly handle errors, those should be + //visible via console output in the browser. + if (xhr.readyState === 4) { + callback(xhr.responseText); + } + }; + xhr.send(data); +}; + exports.loadScript = function(path, callback) { var head = dom.getDocumentHead(); var s = document.createElement('script'); diff --git a/tool/mode_creator.html b/tool/mode_creator.html index e2db56af..cd6b2461 100644 --- a/tool/mode_creator.html +++ b/tool/mode_creator.html @@ -19,7 +19,7 @@ border-bottom: solid 1px; } .separator-h { - padding: 0 20px; + padding: 0 10px; } #closeBtn { background: rgba(245, 146, 146, 0.5); @@ -59,6 +59,7 @@ + @@ -70,6 +71,7 @@ + diff --git a/tool/mode_creator.js b/tool/mode_creator.js index 6b1122cd..ee235eca 100644 --- a/tool/mode_creator.js +++ b/tool/mode_creator.js @@ -53,6 +53,7 @@ util.bindDropdown("doc", function(value) { doclist.loadDoc(value, function(session) { if (session) { editor2.setSession(session); + uploadEl2.disabled = session.getUndoManager().isClean(); } }); }); @@ -60,6 +61,7 @@ util.bindDropdown("doc", function(value) { var modeEl = document.getElementById("modeEl"); util.fillDropdown(modeEl, modelist.modes); var modeSessions = {}; +var savedLeadingComments = ""; util.bindDropdown(modeEl, function(value) { if (modeSessions[value]) { editor1.setSession(modeSessions[value]); @@ -68,7 +70,10 @@ util.bindDropdown(modeEl, function(value) { } var hp = "./lib/ace/mode/" + value + "_highlight_rules.js"; net.get(hp, function(text) { + uploadEl1.disabled = true; + savedLeadingComments = text; text = util.stripLeadingComments(text); + savedLeadingComments = savedLeadingComments.substr(0, savedLeadingComments.length - text.length); var session = new EditSession(text); session.setUndoManager(new UndoManager()); @@ -85,6 +90,40 @@ document.getElementById("syncToMode").onclick = function() { docEl.onchange(); run(); }; + +var uploadEl1 = document.getElementById("uploadToServer1"); +var uploadEl2 = document.getElementById("uploadToServer2"); +uploadEl1.onclick = function() { + var text = savedLeadingComments + editor1.getValue(); + var url = "./lib/ace/mode/" + modeEl.value + "_highlight_rules.js"; + net.put(url, text, function(text) { + if (text.trim().length > 0) + log(text); + else { + uploadEl1.disabled = true; + editor1.getSession().getUndoManager().markClean(); + } + }); +}; +editor1.commands.bindKey("Ctrl-S", uploadEl1.onclick); +uploadEl2.onclick = function() { + doclist.saveDoc(docEl.value, function(text) { + if (text.trim().length > 0) + log(text); + else { + uploadEl2.disabled = true; + editor2.getSession().getUndoManager().markClean(); + } + }); +}; +editor2.commands.bindKey("Ctrl-S", uploadEl2.onclick); +editor1.on('change', function() { + uploadEl1.disabled = false; +}); +editor2.on('change', function() { + uploadEl2.disabled = false; +}); + document.getElementById("perfTest").onclick = function() { var lines = editor2.session.doc.getAllLines(); if (!lines.length) From e7afb4f19ea7690523436e3f025cd0bf0f528490 Mon Sep 17 00:00:00 2001 From: "Matthias S. Benkmann" Date: Tue, 23 Dec 2014 15:51:23 +0100 Subject: [PATCH 08/26] support glob patterns for --puttable; reformat for ancient terminals --- static.py | 57 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/static.py b/static.py index ba3df3dd..913648e2 100755 --- a/static.py +++ b/static.py @@ -32,6 +32,7 @@ import time import string import sys from os import path, stat, getcwd +from fnmatch import fnmatch from wsgiref import util from wsgiref.validate import validator from wsgiref.headers import Headers @@ -86,6 +87,7 @@ class Cling(object): moved_permanently = StatusApp('301 Moved Permanently') method_not_allowed = StatusApp('405 Method Not Allowed') success_no_content = StatusApp('204 No Content', "") + server_error = StatusApp('500 Internal Server Error') def __init__(self, root, **kw): """Just set the root and any other attribs passes via **kw.""" @@ -112,10 +114,16 @@ class Cling(object): sz = int(environ['CONTENT_LENGTH']) except: sz = 0 - if environ['REQUEST_METHOD'] == 'PUT' and path_info in self.puttable and sz > 0: - data = environ['wsgi.input'].read(sz) - with open(full_path, "wb") as f: f.write(data) - return self.success_no_content(environ, start_response) + if environ['REQUEST_METHOD'] == 'PUT' and sz > 0: + for putglob in self.puttable: + if fnmatch(path_info, putglob): + data = environ['wsgi.input'].read(sz) + try: + with open(full_path, "wb") as f: f.write(data) + return self.success_no_content(environ, start_response) + except: + print sys.exc_info()[1] + return self.server_error(environ, start_response) if environ['REQUEST_METHOD'] not in ('GET', 'HEAD'): headers = [('Allow', 'GET, HEAD')] return self.method_not_allowed(environ, start_response, headers) @@ -201,12 +209,28 @@ def cling_wrap(package_name, dir_name, **kw): def command(): - usage = "%prog [--help] [-d DIR] [-l [HOST][:PORT]] [-p RELPATH[,RELPATH...]]" + usage = "%prog [--help] [-d DIR] [-l [HOST][:PORT]] [-p GLOB[,GLOB...]]" parser = OptionParser(usage=usage, version="static 0.3.6") - parser.add_option("-d", "--dir", dest="rootdir", default=".", help="Root directory to serve. Defaults to '.' .", metavar="DIR") - parser.add_option("-l", "--listen", dest="listen", default="127.0.0.1:8888", help="Listen on this interface (given by its hostname or IP) and port. HOST defaults to 127.0.0.1. PORT defaults to 8888. Leave HOST empty to listen on all interfaces (SECURITY WARNING!).", metavar="[HOST][:PORT]") - parser.add_option("-p", "--puttable", dest="puttable", default="", help="Comma or space-separated list of request paths for which to permit PUT requests.", metavar="RELPATH[,RELPATH...]") - parser.add_option("--validate", dest="validate", action="store_true", default=False, help="Enable HTTP validation. You don't need this unless you're working on static.py itself.") + parser.add_option("-d", "--dir", dest="rootdir", default=".", + help="Root directory to serve. Defaults to '.' .", metavar="DIR") + parser.add_option("-l", "--listen", dest="listen", default="127.0.0.1:8888", + help="Listen on this interface (given by its hostname or IP) and port."+ + " HOST defaults to 127.0.0.1. PORT defaults to 8888. "+ + "Leave HOST empty to listen on all interfaces (INSECURE!).", + metavar="[HOST][:PORT]") + parser.add_option("-p", "--puttable", dest="puttable", default="", + help="Comma or space-separated list of request paths for which to"+ + " permit PUT requests. Each path is a glob pattern that may "+ + "contain wildcard characters '*' and/or '?'. "+ + "'*' matches any sequence of characters, including the empty"+ + " string. '?' matches exactly 1 arbitrary character. "+ + "NOTE: Both '*' and '?' match slashes and dots. "+ + "I.e. --puttable=* makes every file under DIR writable!", + metavar="GLOB[,GLOB...]") + parser.add_option("--validate", dest="validate", action="store_true", + default=False, + help="Enable HTTP validation. You don't need this unless "+ + "you're developing static.py itself.") options, args = parser.parse_args() if len(args) > 0: @@ -236,17 +260,16 @@ def command(): except: sys.exit("Invalid host:port specification.") - puttable = set(path.abspath(p) for p in options.puttable.replace(","," ").split()) + puttable = set(path.abspath(p) for p in + options.puttable.replace(","," ").split()) if puttable and host not in ('127.0.0.1', 'localhost'): - sys.exit("Permitting PUT access for non-localhost connections is unwise.") + sys.exit("Permitting PUT access for non-localhost connections is unwise.") options.rootdir = path.abspath(options.rootdir) for p in puttable: - if not p.startswith(options.rootdir): - sys.exit("puttable path '%s' not under root '%s'" % (p, options.rootdir)) - if path.exists(p) and not path.isfile(p): - sys.exit("puttable path '%s' exists but is not a file" % p) + if not p.startswith(options.rootdir): + sys.exit("puttable path '%s' not under root '%s'" % (p, options.rootdir)) # cut off root prefix from puttable paths puttable = set(p[len(options.rootdir):] for p in puttable) @@ -259,7 +282,9 @@ def command(): try: print "Serving %s to http://%s:%d" % (options.rootdir, host, port) if puttable: - print "The following paths (relative to server root) may be OVERWRITTEN via HTTP PUT.\nI HOPE EVERY USER ON THIS SYSTEM IS TRUSTED!" + print("The following paths (relative to server root) may be "+ + "OVERWRITTEN via HTTP PUT.\n"+ + "I HOPE EVERY USER ON THIS SYSTEM IS TRUSTED!") for p in puttable: print p make_server(host, port, app).serve_forever() From eccc98b83b3c310860f69b6f78890b26bea3b254 Mon Sep 17 00:00:00 2001 From: "Matthias S. Benkmann" Date: Tue, 23 Dec 2014 16:33:56 +0100 Subject: [PATCH 09/26] net.put => net.request('PUT'; improved usability for "Save" buttons --- demo/kitchen-sink/doclist.js | 2 +- lib/ace/lib/net.js | 21 ++++++--------------- tool/mode_creator.html | 4 ++-- tool/mode_creator.js | 32 +++++++++++++++++++------------- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/demo/kitchen-sink/doclist.js b/demo/kitchen-sink/doclist.js index 567c62cd..abdc9a3e 100644 --- a/demo/kitchen-sink/doclist.js +++ b/demo/kitchen-sink/doclist.js @@ -182,7 +182,7 @@ function saveDoc(name, callback) { else if (parts[0] == "ace") path = "lib/" + path; - net.put(path, doc.session.getValue(), callback); + net.request('PUT', path, doc.session.getValue(), callback); } module.exports = { diff --git a/lib/ace/lib/net.js b/lib/ace/lib/net.js index 4c07ec2b..357fcb9d 100644 --- a/lib/ace/lib/net.js +++ b/lib/ace/lib/net.js @@ -9,22 +9,9 @@ define(function(require, exports, module) { "use strict"; var dom = require("./dom"); -exports.get = function (url, callback) { +exports.request = function (verb, url, data, callback) { var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.onreadystatechange = function () { - //Do not explicitly handle errors, those should be - //visible via console output in the browser. - if (xhr.readyState === 4) { - callback(xhr.responseText); - } - }; - xhr.send(null); -}; - -exports.put = function (url, data, callback) { - var xhr = new XMLHttpRequest(); - xhr.open('PUT', url, true); + xhr.open(verb, url, true); xhr.onreadystatechange = function () { //Do not explicitly handle errors, those should be //visible via console output in the browser. @@ -35,6 +22,10 @@ exports.put = function (url, data, callback) { xhr.send(data); }; +exports.get = function (url, callback) { + this.request('GET', url, null, callback); +}; + exports.loadScript = function(path, callback) { var head = dom.getDocumentHead(); var s = document.createElement('script'); diff --git a/tool/mode_creator.html b/tool/mode_creator.html index cd6b2461..b4c66715 100644 --- a/tool/mode_creator.html +++ b/tool/mode_creator.html @@ -59,7 +59,7 @@ - + @@ -71,7 +71,7 @@ - + diff --git a/tool/mode_creator.js b/tool/mode_creator.js index ee235eca..c78345ac 100644 --- a/tool/mode_creator.js +++ b/tool/mode_creator.js @@ -96,24 +96,14 @@ var uploadEl2 = document.getElementById("uploadToServer2"); uploadEl1.onclick = function() { var text = savedLeadingComments + editor1.getValue(); var url = "./lib/ace/mode/" + modeEl.value + "_highlight_rules.js"; - net.put(url, text, function(text) { - if (text.trim().length > 0) - log(text); - else { - uploadEl1.disabled = true; - editor1.getSession().getUndoManager().markClean(); - } + net.request('PUT', url, text, function(text) { + handle_put_result(text, editor1, uploadEl1); }); }; editor1.commands.bindKey("Ctrl-S", uploadEl1.onclick); uploadEl2.onclick = function() { doclist.saveDoc(docEl.value, function(text) { - if (text.trim().length > 0) - log(text); - else { - uploadEl2.disabled = true; - editor2.getSession().getUndoManager().markClean(); - } + handle_put_result(text, editor2, uploadEl2); }); }; editor2.commands.bindKey("Ctrl-S", uploadEl2.onclick); @@ -124,6 +114,22 @@ editor2.on('change', function() { uploadEl2.disabled = false; }); +function handle_put_result(text, editor, buttonEl) { + text = text.trim(); + if (text.length == 0) { + buttonEl.disabled = true; + editor.getSession().getUndoManager().markClean(); + } else { + if (text.indexOf("405") == 0) { + log("Write access to this file is disabled.\n"+ + "To enable saving your changes to disk, clone the Ace repository"+ + "\nand run the included static.py web server with the option\n"+ + "--puttable='lib/ace/mode/*_highlight_rules.js,demo/kitchen-sink/docs/*'"); + } else + log(text); + } +} + document.getElementById("perfTest").onclick = function() { var lines = editor2.session.doc.getAllLines(); if (!lines.length) From 07d01fda44ffb7d26e522ced7a8ab06a950e1096 Mon Sep 17 00:00:00 2001 From: Bernhard Weichel Date: Mon, 29 Dec 2014 22:10:03 +0100 Subject: [PATCH 10/26] fixed a few typos and added more snippets --- lib/ace/snippets/abc.snippets | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/ace/snippets/abc.snippets b/lib/ace/snippets/abc.snippets index 65b0fd65..5c3cd677 100644 --- a/lib/ace/snippets/abc.snippets +++ b/lib/ace/snippets/abc.snippets @@ -1,15 +1,31 @@ -snippet zupfnoter.goto - "^@${1:target}@${2:distance}" + +snippet zupfnoter.print + %%%%hn.print {"startpos": ${1:pos_y}, "t":"${2:title}", "v":[${3:voices}], "s":[[${4:syncvoices}1,2]], "f":[${5:flowlines}], "sf":[${6:subflowlines}], "j":[${7:jumplines}]} + +snippet zupfnoter.note + %%%%hn.note {"pos": [${1:pos_x},${2:pos_y}], "text": "${3:text}", "style": "${4:style}"} snippet zupfnoter.annotation - "^@!{1:text}@${2:x_offset},${3:y_offset}" + %%%%hn.annotation {"id": "${1:id}", "pos": [${2:pos}], "text": "${3:text}"} + +snippet zupfnoter.lyrics + %%%%hn.lyrics {"pos": [${1:x_pos},${2:y_pos}]} + +snippet zupfnoter.legend + %%%%hn.legend {"pos": [${1:x_pos},${2:y_pos}]} + -snippet zupfnoter.annotationref - "^#${1:target}" snippet zupfnoter.target "^:${1:target}" +snippet zupfnoter.goto + "^@${1:target}@${2:distance}" + +snippet zupfnoter.annotationref + "^#${1:target}" + +snippet zupfnoter.annotation + "^!${1:text}@${2:x_offset},${3:y_offset}" + -snippet zupfnoter.print - %%%%hn.print {"startpos": 20, "t":"Sopran, Alt", "v":[1,2], "s":[[1,2]], "f":[1], "sf":[2], "j":[1]} From 4603c34b1017fafc8773801f8350f19ab9f518ca Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 1 Jan 2015 01:58:19 +0400 Subject: [PATCH 11/26] workaround for webkit focus bug --- lib/ace/keyboard/textinput.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 605f5b8e..faf73a4a 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -102,6 +102,11 @@ var TextInput = function(parentNode, host) { function resetSelection(isEmpty) { if (inComposition) return; + + // this prevents infinite recursion on safari 8 + // see https://github.com/ajaxorg/ace/issues/2114 + inComposition = true; + if (inputHandler) { selectionStart = 0; selectionEnd = isEmpty ? 0 : text.value.length - 1; @@ -113,6 +118,8 @@ var TextInput = function(parentNode, host) { try { text.setSelectionRange(selectionStart, selectionEnd); } catch(e){} + + inComposition = false; } function resetValue() { From 0054bb87946e27d534b49fb1cdf1acf1b261a888 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 4 Jan 2015 02:13:28 +0400 Subject: [PATCH 12/26] cleanup --- demo/kitchen-sink/doclist.js | 20 ++++- lib/ace/lib/net.js | 10 +-- lib/ace/mode/abap_highlight_rules.js | 2 +- static.js | 113 +++++++++++++++++++++------ static.py | 11 ++- tool/mode_creator.html | 4 +- tool/mode_creator.js | 92 ++++++++++++---------- 7 files changed, 165 insertions(+), 87 deletions(-) diff --git a/demo/kitchen-sink/doclist.js b/demo/kitchen-sink/doclist.js index abdc9a3e..a4848d50 100644 --- a/demo/kitchen-sink/doclist.js +++ b/demo/kitchen-sink/doclist.js @@ -169,9 +169,8 @@ function loadDoc(name, callback) { }); } -// callback is called with the error message from PUT (if any) function saveDoc(name, callback) { - var doc = fileCache[name]; + var doc = fileCache[name] || name; if (!doc || !doc.session) return callback("Unknown document: " + name); @@ -182,9 +181,24 @@ function saveDoc(name, callback) { else if (parts[0] == "ace") path = "lib/" + path; - net.request('PUT', path, doc.session.getValue(), callback); + upload(path, doc.session.getValue(), callback); } +function upload(url, data, callback) { + url = net.qualifyURL(url); + if (!/https?:/.test(url)) + return callback(new Error("Unsupported url scheme")); + var xhr = new XMLHttpRequest(); + xhr.open("PUT", url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + callback(!/^2../.test(xhr.status)); + } + }; + xhr.send(data); +}; + + module.exports = { fileCache: fileCache, docs: sort(prepareDocList(docs)), diff --git a/lib/ace/lib/net.js b/lib/ace/lib/net.js index 357fcb9d..bba76df8 100644 --- a/lib/ace/lib/net.js +++ b/lib/ace/lib/net.js @@ -9,9 +9,9 @@ define(function(require, exports, module) { "use strict"; var dom = require("./dom"); -exports.request = function (verb, url, data, callback) { +exports.get = function (url, callback) { var xhr = new XMLHttpRequest(); - xhr.open(verb, url, true); + xhr.open('GET', url, true); xhr.onreadystatechange = function () { //Do not explicitly handle errors, those should be //visible via console output in the browser. @@ -19,11 +19,7 @@ exports.request = function (verb, url, data, callback) { callback(xhr.responseText); } }; - xhr.send(data); -}; - -exports.get = function (url, callback) { - this.request('GET', url, null, callback); + xhr.send(null); }; exports.loadScript = function(path, callback) { diff --git a/lib/ace/mode/abap_highlight_rules.js b/lib/ace/mode/abap_highlight_rules.js index 6b232c90..bab1e504 100644 --- a/lib/ace/mode/abap_highlight_rules.js +++ b/lib/ace/mode/abap_highlight_rules.js @@ -126,7 +126,7 @@ var AbapHighlightRules = function() { {token : "string", regex : "`", next : "start"}, {defaultToken : "string"} ] - } + }; }; oop.inherits(AbapHighlightRules, TextHighlightRules); diff --git a/static.js b/static.js index 4f7e7248..a711715e 100755 --- a/static.js +++ b/static.js @@ -10,37 +10,100 @@ var http = require("http") // compatibility with node 0.6 if (!fs.exists) - fs.exists = path.exists; + fs.exists = path.exists; -http.createServer(function(request, response) { +var allowSave = process.argv.indexOf("--allow-save") != -1; - var uri = url.parse(request.url).pathname - , filename = path.join(process.cwd(), uri); - - fs.exists(filename, function(exists) { - if(!exists) { - response.writeHead(404, {"Content-Type": "text/plain"}); - response.write("404 Not Found\n"); - response.end(); - return; +http.createServer(function(req, res) { + var uri = url.parse(req.url).pathname + , filename = path.join(process.cwd(), uri); + + if (req.method == "PUT") { + if (!allowSave) + return error(res, 404, "Saving not allowed pass --allow-save to enable"); + save(req, res, filename); } - if (fs.statSync(filename).isDirectory()) filename += '/index.html'; + fs.exists(filename, function(exists) { + if (!exists) + return error(res, 404, "404 Not Found\n"); - fs.readFile(filename, "binary", function(err, file) { - if(err) { - response.writeHead(500, {"Content-Type": "text/plain"}); - response.write(err + "\n"); - response.end(); - return; - } + if (fs.statSync(filename).isDirectory()) { + var files = fs.readdirSync(filename); + res.writeHead(200, {"Content-Type": "text/html"}); + + files.push(".", ".."); + var html = files.map(function(name) { + var href = uri + "/" + name; + href = href.replace(/[\/\\]+/g, "/").replace(/\/$/g, ""); + if (fs.statSync(filename + "/" + name + "/").isDirectory()) + href += "/"; + return "" + name + "
"; + }); - var contentType = mime.lookup(filename) || "text/plain"; - response.writeHead(200, {"Content-Type": contentType}); - response.write(file, "binary"); - response.end(); + res._hasBody && res.write(html.join("")); + res.end(); + return; + } + + fs.readFile(filename, "binary", function(err, file) { + if (err) { + res.writeHead(500, { "Content-Type": "text/plain" }); + res.write(err + "\n"); + res.end(); + return; + } + + var contentType = mime.lookup(filename) || "text/plain"; + res.writeHead(200, { "Content-Type": contentType }); + res.write(file, "binary"); + res.end(); + }); }); - }); }).listen(port, ip); -console.log("http://localhost:" + port); +function error(res, status, message, error) { + console.error(error || message); + res.writeHead(status, { "Content-Type": "text/plain" }); + res.write(message); + res.end(); +} + +function save(req, res, filePath) { + var data = ""; + req.on("data", function(chunk) { + data += chunk; + }); + req.on("error", function() { + error(res, 404, "Could't save file"); + }); + req.on("end", function() { + try { + fs.writeFileSync(filePath, data); + } + catch (e) { + return error(res, 404, "Could't save file", e); + } + res.statusCode = 200; + res.end("OK"); + }); +} + +function getLocalIps() { + var os = require("os"); + + var interfaces = os.networkInterfaces ? os.networkInterfaces() : {}; + var addresses = []; + for (var k in interfaces) { + for (var k2 in interfaces[k]) { + var address = interfaces[k][k2]; + if (address.family === "IPv4" && !address.internal) { + addresses.push(address.address); + } + } + } + return addresses; +} + +console.log("http://" + (ip == "0.0.0.0" ? getLocalIps()[0] : ip) + ":" + port); + diff --git a/static.py b/static.py index 913648e2..7a2faf91 100755 --- a/static.py +++ b/static.py @@ -263,13 +263,13 @@ def command(): puttable = set(path.abspath(p) for p in options.puttable.replace(","," ").split()) if puttable and host not in ('127.0.0.1', 'localhost'): - sys.exit("Permitting PUT access for non-localhost connections is unwise.") + print("Permitting PUT access for non-localhost connections may be unwise.") options.rootdir = path.abspath(options.rootdir) for p in puttable: - if not p.startswith(options.rootdir): - sys.exit("puttable path '%s' not under root '%s'" % (p, options.rootdir)) + if not p.startswith(options.rootdir): + sys.exit("puttable path '%s' not under root '%s'" % (p, options.rootdir)) # cut off root prefix from puttable paths puttable = set(p[len(options.rootdir):] for p in puttable) @@ -283,13 +283,12 @@ def command(): print "Serving %s to http://%s:%d" % (options.rootdir, host, port) if puttable: print("The following paths (relative to server root) may be "+ - "OVERWRITTEN via HTTP PUT.\n"+ - "I HOPE EVERY USER ON THIS SYSTEM IS TRUSTED!") + "OVERWRITTEN via HTTP PUT.") for p in puttable: print p make_server(host, port, app).serve_forever() except KeyboardInterrupt, ki: - print "Cio, baby!" + print "Ciao, baby!" except: sys.exit("Problem initializing server: %s" % sys.exc_info()[1]) diff --git a/tool/mode_creator.html b/tool/mode_creator.html index b4c66715..259ba64e 100644 --- a/tool/mode_creator.html +++ b/tool/mode_creator.html @@ -59,7 +59,7 @@ - + @@ -71,7 +71,7 @@ - + diff --git a/tool/mode_creator.js b/tool/mode_creator.js index c78345ac..e79c54c6 100644 --- a/tool/mode_creator.js +++ b/tool/mode_creator.js @@ -53,7 +53,8 @@ util.bindDropdown("doc", function(value) { doclist.loadDoc(value, function(session) { if (session) { editor2.setSession(session); - uploadEl2.disabled = session.getUndoManager().isClean(); + session.getUndoManager().markClean(); + updateSaveButtonState(null, editor2); } }); }); @@ -61,7 +62,7 @@ util.bindDropdown("doc", function(value) { var modeEl = document.getElementById("modeEl"); util.fillDropdown(modeEl, modelist.modes); var modeSessions = {}; -var savedLeadingComments = ""; + util.bindDropdown(modeEl, function(value) { if (modeSessions[value]) { editor1.setSession(modeSessions[value]); @@ -70,17 +71,18 @@ util.bindDropdown(modeEl, function(value) { } var hp = "./lib/ace/mode/" + value + "_highlight_rules.js"; net.get(hp, function(text) { - uploadEl1.disabled = true; - savedLeadingComments = text; - text = util.stripLeadingComments(text); - savedLeadingComments = savedLeadingComments.substr(0, savedLeadingComments.length - text.length); - var session = new EditSession(text); session.setUndoManager(new UndoManager()); + modeSessions[value] = session; - session.setMode("ace/mode/javascript"); + session.setMode("ace/mode/javascript", function() { + if (session.getLine(0).match(/^\s*\//)) + session.toggleFoldWidget(0); // fold licence comment + }); editor1.setSession(modeSessions[value]); + session.getUndoManager().markClean(); + updateSaveButtonState(null, editor1); schedule(); }); }); @@ -91,43 +93,47 @@ document.getElementById("syncToMode").onclick = function() { run(); }; -var uploadEl1 = document.getElementById("uploadToServer1"); -var uploadEl2 = document.getElementById("uploadToServer2"); -uploadEl1.onclick = function() { - var text = savedLeadingComments + editor1.getValue(); - var url = "./lib/ace/mode/" + modeEl.value + "_highlight_rules.js"; - net.request('PUT', url, text, function(text) { - handle_put_result(text, editor1, uploadEl1); - }); -}; -editor1.commands.bindKey("Ctrl-S", uploadEl1.onclick); -uploadEl2.onclick = function() { - doclist.saveDoc(docEl.value, function(text) { - handle_put_result(text, editor2, uploadEl2); - }); -}; -editor2.commands.bindKey("Ctrl-S", uploadEl2.onclick); -editor1.on('change', function() { - uploadEl1.disabled = false; -}); -editor2.on('change', function() { - uploadEl2.disabled = false; -}); +editor1.saveButton = document.getElementById("saveButton1"); +editor2.saveButton = document.getElementById("saveButton2"); +editor1.saveButton.editor = editor1; +editor2.saveButton.editor = editor2; -function handle_put_result(text, editor, buttonEl) { - text = text.trim(); - if (text.length == 0) { - buttonEl.disabled = true; - editor.getSession().getUndoManager().markClean(); - } else { - if (text.indexOf("405") == 0) { - log("Write access to this file is disabled.\n"+ - "To enable saving your changes to disk, clone the Ace repository"+ - "\nand run the included static.py web server with the option\n"+ - "--puttable='lib/ace/mode/*_highlight_rules.js,demo/kitchen-sink/docs/*'"); - } else - log(text); +editor1.saveButton.onclick = function() { + doclist.saveDoc({ + path: "./lib/ace/mode/" + modeEl.value + "_highlight_rules.js", + session: editor1.session + }, function(err) { + handleSaveResult(err, editor1); + }); +}; +editor1.commands.bindKey({ + win: "Ctrl-S", mac: "Cmd-s" +}, editor1.saveButton.onclick); +editor2.saveButton.onclick = function() { + doclist.saveDoc(docEl.value, function(err) { + handleSaveResult(err, editor2); + }); +}; +editor2.commands.bindKey({ + win: "Ctrl-S", mac: "Cmd-s" +}, editor2.saveButton.onclick); +function updateSaveButtonState(e, editor){ + editor.saveButton.disabled = editor.session.getUndoManager().isClean(); +} +editor1.on("input", updateSaveButtonState); +editor2.on("input", updateSaveButtonState); + +function handleSaveResult(err, editor) { + if (err) { + return log( + "Write access to this file is disabled.\n"+ + "To enable saving your changes to disk, clone the Ace repository\n"+ + "and run the included web server with the --allow-write option\n"+ + "`node static.js --allow-write` or `static.py --puttable=*`" + ); } + editor.session.getUndoManager().markClean(); + updateSaveButtonState(null, editor); } document.getElementById("perfTest").onclick = function() { From ad9aa35ffeec911285001189f7b37014efef18af Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 24 Dec 2014 02:44:30 +0400 Subject: [PATCH 13/26] Revert "Reduced size of sample document" --- demo/kitchen-sink/docs/abc.abc | 154 ++++++++++++++++++++++++++++++++- tool/add_mode.js | 2 +- 2 files changed, 153 insertions(+), 3 deletions(-) diff --git a/demo/kitchen-sink/docs/abc.abc b/demo/kitchen-sink/docs/abc.abc index 32548d3c..d8ac326e 100644 --- a/demo/kitchen-sink/docs/abc.abc +++ b/demo/kitchen-sink/docs/abc.abc @@ -11,11 +11,161 @@ C:Trad. % traditional R:DH % double hornpipe M:3/4 % meter K:G % key -%%score (1,2) -[P:1]B>cd "^G"BAG|FA Ac BA|B>cd BAG|DG GB AG:| +B>cd BAG|FA Ac BA|B>cd BAG|DG GB AG:| Bdd gfg|aA Ac BA|Bdd gfa|gG GB AG:| BG G/2G/2G BG|FA Ac BA|BG G/2G/2G BG|DG GB AG:| W:Hey, the dusty miller, and his dusty coat; W:He will win a shilling, or he spend a groat. W:Dusty was the coat, dusty was the colour; W:Dusty was the kiss, that I got frae the miller. + +X:2 +T:Old Sir Simon the King +C:Trad. +S:Offord MSS % from Offord manuscript +N:see also Playford % reference note +M:9/8 +R:SJ % slip jig +N:originally in C % transcription note +K:G +D|GFG GAG G2D|GFG GAG F2D|EFE EFE EFG|A2G F2E D2:| +D|GAG GAB d2D|GAG GAB c2D|[1 EFE EFE EFG|[A2G] F2E D2:|\ % no line-break in score +M:12/8 % change of meter +[2 E2E EFE E2E EFG|\ % no line-break in score +M:9/8 % change of meter +A2G F2E D2|] + +X:3 +T:William and Nancy +T:New Mown Hay +T:Legacy, The +C:Trad. +O:England; Gloucs; Bledington % place of origin +B:Sussex Tune Book % can be found in these books +B:Mally's Cotswold Morris vol.1 2 +D:Morris On % can be heard on this record +P:(AB)2(AC)2A % play the parts in this order +M:6/8 +K:G +[P:A] D|"G"G2G GBd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| +[P:B] d|"G"e2d B2d|"C"gfe "G"d2d| "G"e2d B2d|"C"gfe "D7"d2c| + "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| +% changes of meter, using inline fields +[T:Slows][M:4/4][L:1/4][P:C]"G"d2|"C"e2 "G"d2|B2 d2|"Em"gf "A7"e2|"D7"d2 "G"d2|\ + "C"e2 "G"d2|[M:3/8][L:1/8] "G"B2 d |[M:6/8] "C"gfe "D7"d2c| + "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| + +X:4 +T:South Downs Jig +R:jig +S:Robert Harbron +M:6/8 +L:1/8 +K:G +|: d | dcA G3 | EFG AFE | DEF GAB | cde d2d | +dcA G3 | EFG AFE | DEF GAB | cAF G2 :| +B | Bcd e2c | d2B c2A | Bcd e2c | [M:9/8]d2B c2B A3 | +[M:6/8]DGF E3 | cBA FED | DEF GAB |1 cAF G2 :|2 cAF G3 |] + +X:5 +T:Atholl Brose +% in this example, which reproduces Highland Bagpipe gracing, +% the large number of grace notes mean that it is more convenient to be specific about +% score line-breaks (using the $ symbol), rather than using code line breaks to indicate them +I:linebreak $ +K:D +{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad| +{gcd}c<{e}A {gAGAG}A>e {ag}a>f {gef}e>d| +{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad| +{g}c/d/e {g}G>{d}B {gf}gG {dc}d>B:|$ +{g}ce {ag}a>e {gf}g>e| +{g}ce {ag}a2 {GdG}a>d| +{g}ce {ag}a>e {gf}g>f| +{gef}e>d {gf}g>d {gBd}B<{e}G {dc}d>B| +{g}ce {ag}a>e {gf}g>e| +{g}ce {ag}a2 {GdG}ad| +{g}c<{GdG}e {gf}ga {f}g>e {g}f>d| +{g}e/f/g {Gdc}d>c {gBd}B<{e}G {dc}d2|] + +X:6 +T:Untitled Reel +C:Trad. +K:D +eg|a2ab ageg|agbg agef|g2g2 fgag|f2d2 d2:|\ +ed|cecA B2ed|cAcA E2ed|cecA B2ed|c2A2 A2:| +K:G +AB|cdec BcdB|ABAF GFE2|cdec BcdB|c2A2 A2:| + +X:7 +T:Kitchen Girl +C:Trad. +K:D +[c4a4] [B4g4]|efed c2cd|e2f2 gaba|g2e2 e2fg| +a4 g4|efed cdef|g2d2 efed|c2A2 A4:| +K:G +ABcA BAGB|ABAG EDEG|A2AB c2d2|e3f edcB|ABcA BAGB| +ABAG EGAB|cBAc BAG2|A4 A4:| + +%abc-2.1 +%%pagewidth 21cm +%%pageheight 29.7cm +%%topspace 0.5cm +%%topmargin 1cm +%%botmargin 0cm +%%leftmargin 1cm +%%rightmargin 1cm +%%titlespace 0cm +%%titlefont Times-Bold 32 +%%subtitlefont Times-Bold 24 +%%composerfont Times 16 +%%vocalfont Times-Roman 14 +%%staffsep 60pt +%%sysstaffsep 20pt +%%musicspace 1cm +%%vocalspace 5pt +%%measurenb 0 +%%barsperstaff 5 +%%scale 0.7 +X: 1 +T: Canzonetta a tre voci +C: Claudio Monteverdi (1567-1643) +M: C +L: 1/4 +Q: "Andante mosso" 1/4 = 110 +%%score [1 2 3] +V: 1 clef=treble name="Soprano"sname="A" +V: 2 clef=treble name="Alto" sname="T" +V: 3 clef=bass middle=d name="Tenor" sname="B" +%%MIDI program 1 75 % recorder +%%MIDI program 2 75 +%%MIDI program 3 75 +K: Eb +% 1 - 4 +[V: 1] |:z4 |z4 |f2ec |_ddcc | +w: Son que-sti~i cre-spi cri-ni~e +w: Que-sti son gli~oc-chi che mi- +[V: 2] |:c2BG|AAGc|(F/G/A/B/)c=A|B2AA | +w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il vi-so e +w: Que-sti son~gli oc-chi che mi-ran - - - - do fi-so mi- +[V: 3] |:z4 |f2ec|_ddcf |(B/c/_d/e/)ff| +w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il +w: Que-sti son~gli oc-chi che mi-ran - - - - do +% 5 - 9 +[V: 1] cAB2 |cAAA |c3B|G2!fermata!Gz ::e4| +w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh, +w: ran-do fi-so, tut-to re-stai con-qui-so. +[V: 2] AAG2 |AFFF |A3F|=E2!fermata!Ez::c4| +w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh, +w: ran-do fi-so tut-to re-stai con-qui-so. +[V: 3] (ag/f/e2)|A_ddd|A3B|c2!fermata!cz ::A4| +w: vi - - - so ond' io ti-man-go~uc-ci-so. Deh, +w: fi - - - so tut-to re-stai con-qui-so. +% 10 - 15 +[V: 1] f_dec |B2c2|zAGF |\ +w: dim-me-lo ben mi-o, che que-sto\ +=EFG2 |1F2z2:|2F8|] % more notes +w: sol de-si-o_. % more lyrics +[V: 2] ABGA |G2AA|GF=EF |(GF3/2=E//D//E)|1F2z2:|2F8|] +w: dim-me-lo ben mi-o, che que-sto sol de-si - - - - o_. +[V: 3] _dBc>d|e2AF|=EFc_d|c4 |1F2z2:|2F8|] +w: dim-me-lo ben mi-o, che que-sto sol de-si-o_. \ No newline at end of file diff --git a/tool/add_mode.js b/tool/add_mode.js index 2f70a14a..879b9204 100644 --- a/tool/add_mode.js +++ b/tool/add_mode.js @@ -9,7 +9,7 @@ function main(displayName, extRe) { var demoFileExt = extRe.split("|")[0] || name; var demoFileName = demoFileExt[0] == "^" ? demoFileExt.substr(1) : name + "." + demoFileExt; var demoFilePath = lib.AceRoot + "demo/kitchen-sink/docs/" + demoFileName; - fs.writeFileSync(demoFilePath, "TODO add a nice demo!", "utf8"); + fs.writeFileSync(demoFilePath, "TODO add a nice demo!\nTry to keep it short!", "utf8"); console.log("Created demo file at: " + path.normalize(demoFilePath)); /** mode **/ From f4ea1ccb6a8048097b6e79afa0930d6fa01b3aa8 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 5 Jan 2015 00:02:41 +0400 Subject: [PATCH 14/26] always call the callback form setMode --- lib/ace/edit_session.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 347c854a..b11ff05c 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -893,17 +893,17 @@ var EditSession = function(text, mode) { config.loadModule(["mode", path], function(m) { if (this.$modeId !== path) return cb && cb(); - if (this.$modes[path] && !options) - return this.$onChangeMode(this.$modes[path]); - if (m && m.Mode) { + if (this.$modes[path] && !options) { + this.$onChangeMode(this.$modes[path]); + } else if (m && m.Mode) { m = new m.Mode(options); if (!options) { this.$modes[path] = m; m.$id = path; } this.$onChangeMode(m); - cb && cb(); } + cb && cb(); }.bind(this)); // set mode to text until loading is finished From 72edcd332d07ce10d730b35272fc6c15de37264f Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 5 Jan 2015 00:34:25 +0400 Subject: [PATCH 15/26] tweak mode_creator --- tool/mode_creator.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/tool/mode_creator.js b/tool/mode_creator.js index e79c54c6..7a2aea59 100644 --- a/tool/mode_creator.js +++ b/tool/mode_creator.js @@ -53,7 +53,6 @@ util.bindDropdown("doc", function(value) { doclist.loadDoc(value, function(session) { if (session) { editor2.setSession(session); - session.getUndoManager().markClean(); updateSaveButtonState(null, editor2); } }); @@ -81,7 +80,6 @@ util.bindDropdown(modeEl, function(value) { }); editor1.setSession(modeSessions[value]); - session.getUndoManager().markClean(); updateSaveButtonState(null, editor1); schedule(); }); From a50833cfea3b81f08c03c66c01b961cf843e3647 Mon Sep 17 00:00:00 2001 From: Kevin Ushey Date: Mon, 5 Jan 2015 17:08:23 -0800 Subject: [PATCH 16/26] conform with upstream change Ref: https://github.com/codemirror/CodeMirror/commit/1e5ae06ba46ab8c7c41d295ebf25b1bfc6cfc39 --- lib/ace/keyboard/vim.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index ff054f96..a8bba7ec 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -2118,11 +2118,9 @@ dom.importCssString(".normal-mode .ace_cursor{\ newHead = copyCursor(origHead); } if (vim.visualMode) { - - if (!(vim.visualBlock && motion === "moveToEol")) { + if (!(vim.visualBlock && newHead.ch === Infinity)) { newHead = clipCursorToContent(cm, newHead, vim.visualBlock); } - if (newAnchor) { newAnchor = clipCursorToContent(cm, newAnchor, true); } From ced37c0c1974b57460164525aec759fe35e6f3fb Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 6 Jan 2015 15:45:55 +0400 Subject: [PATCH 17/26] update jshint --- lib/ace/mode/javascript/jshint.js | 2827 +++++++++++++++++++++-------- 1 file changed, 2107 insertions(+), 720 deletions(-) diff --git a/lib/ace/mode/javascript/jshint.js b/lib/ace/mode/javascript/jshint.js index 7d8352a8..c390116e 100644 --- a/lib/ace/mode/javascript/jshint.js +++ b/lib/ace/mode/javascript/jshint.js @@ -1416,6 +1416,7 @@ var Lexer = _dereq_("./lex.js").Lexer; var reg = _dereq_("./reg.js"); var state = _dereq_("./state.js").state; var style = _dereq_("./style.js"); +var options = _dereq_("./options.js"); // We build the application inside a function so that we produce only a singleton // variable. That function will be invoked immediately, and its return value is @@ -1424,8 +1425,7 @@ var style = _dereq_("./style.js"); var JSHINT = (function () { "use strict"; - var anonname, // The guessed name for anonymous functions. - api, // Extension API + var api, // Extension API // These are operators that should not be used with the ! operator. bang = { @@ -1444,153 +1444,6 @@ var JSHINT = (function () { "%" : true }, - // These are the JSHint boolean options. - boolOptions = { - asi : true, // if automatic semicolon insertion should be tolerated - bitwise : true, // if bitwise operators should not be allowed - boss : true, // if advanced usage of assignments should be allowed - browser : true, // if the standard browser globals should be predefined - camelcase : true, // if identifiers should be required in camel case - couch : true, // if CouchDB globals should be predefined - curly : true, // if curly braces around all blocks should be required - debug : true, // if debugger statements should be allowed - devel : true, // if logging globals should be predefined (console, alert, etc.) - dojo : true, // if Dojo Toolkit globals should be predefined - eqeqeq : true, // if === should be required - eqnull : true, // if == null comparisons should be tolerated - notypeof : true, // if should report typos in typeof comparisons - es3 : true, // if ES3 syntax should be allowed - es5 : true, // if ES5 syntax should be allowed (is now set per default) - esnext : true, // if es.next specific syntax should be allowed - moz : true, // if mozilla specific syntax should be allowed - evil : true, // if eval should be allowed - expr : true, // if ExpressionStatement should be allowed as Programs - forin : true, // if for in statements must filter - funcscope : true, // if only function scope should be used for scope tests - globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict') - immed : true, // if immediate invocations must be wrapped in parens - iterator : true, // if the `__iterator__` property should be allowed - jasmine : true, // Jasmine functions should be predefined - jquery : true, // if jQuery globals should be predefined - lastsemic : true, // if semicolons may be ommitted for the trailing - // statements inside of a one-line blocks. - laxbreak : true, // if line breaks should not be checked - laxcomma : true, // if line breaks should not be checked around commas - loopfunc : true, // if functions should be allowed to be defined within - // loops - mootools : true, // if MooTools globals should be predefined - multistr : true, // allow multiline strings - freeze : true, // if modifying native object prototypes should be disallowed - newcap : true, // if constructor names must be capitalized - noarg : true, // if arguments.caller and arguments.callee should be - // disallowed - node : true, // if the Node.js environment globals should be - // predefined - noempty : true, // if empty blocks should be disallowed - nonbsp : true, // if non-breaking spaces should be disallowed - nonew : true, // if using `new` for side-effects should be disallowed - nonstandard : true, // if non-standard (but widely adopted) globals should - // be predefined - phantom : true, // if PhantomJS symbols should be allowed - plusplus : true, // if increment/decrement should not be allowed - proto : true, // if the `__proto__` property should be allowed - prototypejs : true, // if Prototype and Scriptaculous globals should be - // predefined - qunit : true, // if the QUnit environment globals should be predefined - rhino : true, // if the Rhino environment globals should be predefined - shelljs : true, // if ShellJS globals should be predefined - typed : true, // if typed array globals should be predefined - undef : true, // if variables should be declared before used - scripturl : true, // if script-targeted URLs should be tolerated - strict : true, // require the "use strict"; pragma - sub : true, // if all forms of subscript notation are tolerated - supernew : true, // if `new function () { ... };` and `new Object;` - // should be tolerated - validthis : true, // if 'this' inside a non-constructor function is valid. - // This is a function scoped option only. - withstmt : true, // if with statements should be allowed - worker : true, // if Web Worker script symbols should be allowed - wsh : true, // if the Windows Scripting Host environment globals - // should be predefined - yui : true, // YUI variables should be predefined - mocha : true, // Mocha functions should be predefined - noyield : true, // allow generators without a yield - - // Obsolete options - onecase : true, // if one case switch statements should be allowed - regexp : true, // if the . should not be allowed in regexp literals - regexdash : true // if unescaped first/last dash (-) inside brackets - // should be tolerated - }, - - // These are the JSHint options that can take any value - // (we use this object to detect invalid options) - valOptions = { - maxlen : false, - indent : false, - maxerr : false, - predef : false, // predef is deprecated and being replaced by globals - globals : false, - quotmark : false, // 'single'|'double'|true - scope : false, - maxstatements: false, // {int} max statements per function - maxdepth : false, // {int} max nested block depth per function - maxparams : false, // {int} max params per function - maxcomplexity: false, // {int} max cyclomatic complexity per function - shadow : false, // if variable shadowing should be tolerated - // "inner" - check for variables defined in the same scope only - // "outer" - check for variables defined in outer scopes as well - // false - same as inner - // true - allow variable shadowing - unused : true, // warn if variables are unused. Available options: - // false - don't check for unused variables - // true - "vars" + check last function param - // "vars" - skip checking unused function params - // "strict" - "vars" + check all function params - latedef : false, // warn if the variable is used before its definition - // false - don't emit any warnings - // true - warn if any variable is used before its definition - // "nofunc" - warn for any variable but function declarations - ignore : false // start/end ignoring lines of code, bypassing the lexer - // start - start ignoring lines, including the current line - // end - stop ignoring lines, starting on the next line - // line - ignore warnings / errors for just a single line - // (this option does not bypass the lexer) - }, - - // These are JSHint boolean options which are shared with JSLint - // where the definition in JSHint is opposite JSLint - invertedOptions = { - bitwise : true, - forin : true, - newcap : true, - plusplus: true, - regexp : true, - undef : true, - - // Inverted and renamed, use JSHint name here - eqeqeq : true, - strict : true - }, - - // These are JSHint boolean options which are shared with JSLint - // where the name has been changed but the effect is unchanged - renamedOptions = { - eqeq : "eqeqeq", - windows: "wsh", - sloppy : "strict" - }, - - removedOptions = { - nomen: true, - onevar: true, - passfail: true, - white: true, - gcl: true, - smarttabs: true, - trailing: true - }, - declared, // Globals that were declared using /*global ... */ syntax. exported, // Variables that are used outside of the current file. @@ -1610,7 +1463,6 @@ var JSHINT = (function () { lex, member, membersOnly, - noreach, predefined, // Global variables defined by option scope, // The current scope @@ -1628,8 +1480,8 @@ var JSHINT = (function () { return true; } - if (valOptions[name] === undefined && boolOptions[name] === undefined) { - if (t.type !== "jslint" && !removedOptions[name]) { + if (options.validNames.indexOf(name) === -1) { + if (t.type !== "jslint" && !_.has(options.removed, name)) { error("E001", t, name); return false; } @@ -1694,7 +1546,24 @@ var JSHINT = (function () { }); } + function processenforceall() { + if (state.option.enforceall) { + for (var enforceopt in options.bool.enforcing) { + if (state.option[enforceopt] === undefined) { + state.option[enforceopt] = true; + } + } + for (var relaxopt in options.bool.relaxing) { + if (state.option[relaxopt] === undefined) { + state.option[relaxopt] = false; + } + } + } + } + function assume() { + processenforceall(); + if (state.option.esnext) { combine(predefined, vars.newEcmaIdentifiers); } @@ -1745,6 +1614,12 @@ var JSHINT = (function () { combine(predefined, vars.typed); } + if (state.option.browserify) { + combine(predefined, vars.browser); + combine(predefined, vars.typed); + combine(predefined, vars.browserify); + } + if (state.option.nonstandard) { combine(predefined, vars.nonstandard); } @@ -1949,6 +1824,9 @@ var JSHINT = (function () { // if the identifier is from a let, adds it only to the current blockscope if (islet) { funct["(blockscope)"].current.add(name, type, state.tokens.curr); + if (funct["(blockscope)"].atTop() && exported[name]) { + state.tokens.curr.exported = true; + } } else { funct["(blockscope)"].shadow(name); funct[name] = type; @@ -2179,10 +2057,10 @@ var JSHINT = (function () { var tn; if (val === "true" || val === "false") { if (nt.type === "jslint") { - tn = renamedOptions[key] || key; + tn = options.renamed[key] || key; state.option[tn] = (val === "true"); - if (invertedOptions[tn] !== undefined) { + if (options.inverted[tn] !== undefined) { state.option[tn] = !state.option[tn]; } } else { @@ -2221,9 +2099,19 @@ var JSHINT = (function () { return t; } + function peekIgnoreEOL() { + var i = 0; + var t; + do { + t = peek(i++); + } while (t.id === "(endline)"); + return t; + } + // Produce the next token. It looks for programming errors. function advance(id, t) { + switch (state.tokens.curr.id) { case "(number)": if (state.tokens.next.id === ".") { @@ -2242,10 +2130,6 @@ var JSHINT = (function () { break; } - if (state.tokens.curr.type === "(string)" || state.tokens.curr.identifier) { - anonname = state.tokens.curr.value; - } - if (id && state.tokens.next.id !== id) { if (t) { if (state.tokens.next.id === "(end)") { @@ -2254,7 +2138,14 @@ var JSHINT = (function () { error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value); } } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) { - warning("W116", state.tokens.next, id, state.tokens.next.value); + // parameter destructuring with rest operator + if (state.tokens.next.value === "...") { + if (!state.option.esnext) { + warning("W119", state.tokens.next, "spread/rest operator"); + } + } else { + warning("W116", state.tokens.next, id, state.tokens.next.value); + } } } @@ -2316,7 +2207,10 @@ var JSHINT = (function () { // They are elements of the parsing method called Top Down Operator Precedence. function expression(rbp, initial) { - var left, isArray = false, isObject = false, isLetExpr = false; + var left, isArray = false, isObject = false, isLetExpr = false, + isFatArrowBody = state.tokens.curr.value === "=>"; + + state.nameStack.push(); // if current expression is a let expression if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") { @@ -2335,6 +2229,10 @@ var JSHINT = (function () { if (state.tokens.next.id === "(end)") error("E006", state.tokens.curr); + if (state.tokens.next.type === "(template)") { + doTemplateLiteral(); + } + var isDangerous = state.option.asi && state.tokens.prev.line < state.tokens.curr.line && @@ -2347,7 +2245,6 @@ var JSHINT = (function () { advance(); if (initial) { - anonname = "anonymous"; funct["(verb)"] = state.tokens.curr.value; } @@ -2402,6 +2299,14 @@ var JSHINT = (function () { if (isLetExpr) { funct["(blockscope)"].unstack(); } + + if (state.option.singleGroups && left && left.paren && !left.exprs && + !isFatArrowBody && !left.triggerFnExpr) { + warning("W126"); + } + + state.nameStack.pop(); + return left; } @@ -2438,6 +2343,10 @@ var JSHINT = (function () { function comma(opts) { opts = opts || {}; + if (state.option.nocomma) { + warning("W127"); + } + if (!opts.peek) { nobreakcomma(state.tokens.curr, state.tokens.next); advance(","); @@ -2620,14 +2529,10 @@ var JSHINT = (function () { var x = symbol(s, 42); x.led = function (left) { - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "arrow function syntax (=>)"); - } - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); this.left = left; - this.right = doFunction(undefined, undefined, false, left); + this.right = doFunction(undefined, undefined, false, { loneArg: left }); return this; }; return x; @@ -2754,6 +2659,7 @@ var JSHINT = (function () { warning("E031", that); } + state.nameStack.set(state.tokens.prev); that.right = expression(10); return that; } else if (left.id === "[") { @@ -2768,12 +2674,16 @@ var JSHINT = (function () { } else if (left.left.value === "arguments" && !state.directive["use strict"]) { warning("E031", that); } + + state.nameStack.set(left.right); + that.right = expression(10); return that; } else if (left.identifier && !isReserved(left)) { if (funct[left.value] === "exception") { warning("W022", left); } + state.nameStack.set(left); that.right = expression(10); return that; } @@ -2848,17 +2758,24 @@ var JSHINT = (function () { // fnparam means that this identifier is being defined as a function // argument (see identifier()) // prop means that this identifier is that of an object property + // exported means that the identifier is part of a valid ES6 `export` declaration - function optionalidentifier(fnparam, prop) { + function optionalidentifier(fnparam, prop, preserve, exported) { if (!state.tokens.next.identifier) { return; } - advance(); + if (!preserve) { + advance(); + } var curr = state.tokens.curr; var val = state.tokens.curr.value; + if (exported) { + state.tokens.curr.exported = true; + } + if (!isReserved(curr)) { return val; } @@ -2880,22 +2797,35 @@ var JSHINT = (function () { // fnparam means that this identifier is being defined as a function // argument // prop means that this identifier is that of an object property - function identifier(fnparam, prop) { - var i = optionalidentifier(fnparam, prop); + // `exported` means that the identifier token should be exported. + function identifier(fnparam, prop, exported) { + var i = optionalidentifier(fnparam, prop, false, exported); if (i) { return i; } - if (state.tokens.curr.id === "function" && state.tokens.next.id === "(") { - warning("W025"); + + // parameter destructuring with rest operator + if (state.tokens.next.value === "...") { + if (!state.option.esnext) { + warning("W119", state.tokens.next, "spread/rest operator"); + } } else { error("E030", state.tokens.next, state.tokens.next.value); + + // The token should be consumed after a warning is issued so the parser + // can continue as though an identifier were found. The semicolon token + // should not be consumed in this way so that the parser interprets it as + // a statement delimeter; + if (state.tokens.next.id !== ";") { + advance(); + } } } - function reachable(s) { + function reachable(controlToken) { var i = 0, t; - if (state.tokens.next.id !== ";" || noreach) { + if (state.tokens.next.id !== ";" || controlToken.inBracelessBlock) { return; } for (;;) { @@ -2915,7 +2845,7 @@ var JSHINT = (function () { break; } - warning("W027", t, t.value, s); + warning("W027", t, t.value, controlToken.value); break; } } @@ -3052,7 +2982,7 @@ var JSHINT = (function () { } - function statements(startLine) { + function statements() { var a = [], p; while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { @@ -3065,7 +2995,7 @@ var JSHINT = (function () { advance(";"); } else { - a.push(statement(startLine === state.tokens.next.line)); + a.push(statement()); } } return a; @@ -3080,53 +3010,46 @@ var JSHINT = (function () { function directives() { var i, p, pn; - for (;;) { - if (state.tokens.next.id === "(string)") { - p = peek(0); - if (p.id === "(endline)") { - i = 1; - do { - pn = peek(i); - i = i + 1; - } while (pn.id === "(endline)"); - - if (pn.id !== ";") { - if (pn.id !== "(string)" && pn.id !== "(number)" && - pn.id !== "(regexp)" && pn.identifier !== true && - pn.id !== "}") { - break; - } - warning("W033", state.tokens.next); - } else { - p = pn; - } - } else if (p.id === "}") { - // Directive with no other statements, warn about missing semicolon - warning("W033", p); - } else if (p.id !== ";") { - break; + while (state.tokens.next.id === "(string)") { + p = peek(0); + if (p.id === "(endline)") { + i = 1; + do { + pn = peek(i++); + } while (pn.id === "(endline)"); + if (pn.id === ";") { + p = pn; + } else if (pn.value === "[" || pn.value === ".") { + // string -> [ | . is a valid production + return; + } else if (!state.option.asi || pn.value === "(") { + // string -> ( is not a valid production + warning("W033", state.tokens.next); } - - advance(); - if (state.directive[state.tokens.curr.value]) { - warning("W034", state.tokens.curr, state.tokens.curr.value); - } - - if (state.tokens.curr.value === "use strict") { - if (!state.option["(explicitNewcap)"]) - state.option.newcap = true; - state.option.undef = true; - } - - // there's no directive negation, so always set to true - state.directive[state.tokens.curr.value] = true; - - if (p.id === ";") { - advance(";"); - } - continue; + } else if (p.id === "." || p.id === "[") { + return; + } else if (p.id !== ";") { + warning("W033", p); + } + + advance(); + if (state.directive[state.tokens.curr.value]) { + warning("W034", state.tokens.curr, state.tokens.curr.value); + } + + if (state.tokens.curr.value === "use strict") { + if (!state.option["(explicitNewcap)"]) { + state.option.newcap = true; + } + state.option.undef = true; + } + + // there's no directive negation, so always set to true + state.directive[state.tokens.curr.value] = true; + + if (p.id === ";") { + advance(";"); } - break; } } @@ -3191,7 +3114,7 @@ var JSHINT = (function () { } } - a = statements(line); + a = statements(); metrics.statementCount += a.length; @@ -3240,12 +3163,11 @@ var JSHINT = (function () { warning("W116", state.tokens.next, "{", state.tokens.next.value); } - noreach = true; + state.tokens.next.inBracelessBlock = true; indent += state.option.indent; // test indentation only if statement is in new line a = [statement()]; indent -= state.option.indent; - noreach = false; delete funct["(nolet)"]; } @@ -3268,7 +3190,7 @@ var JSHINT = (function () { if (!ordinary || !state.option.funcscope) scope = s; inblock = b; if (ordinary && state.option.noempty && (!a || a.length === 0)) { - warning("W035"); + warning("W035", state.tokens.prev); } metrics.nestedBlockDepth -= 1; return a; @@ -3308,10 +3230,6 @@ var JSHINT = (function () { return this; }); - type("(template)", function () { - return this; - }); - state.syntax["(identifier)"] = { type: "(identifier)", lbp: 0, @@ -3323,6 +3241,18 @@ var JSHINT = (function () { var f; var block; + // If this identifier is the lone parameter to a shorthand "fat arrow" + // function definition, i.e. + // + // x => x; + // + // ...it should not be considered as a variable in the current scope. It + // will be added to the scope of the new function when the next token is + // parsed, so it can be safely ignored for now. + if (state.tokens.next.id === "=>") { + return this; + } + if (typeof s === "function") { // Protection against accidental inheritance. s = undefined; @@ -3360,33 +3290,6 @@ var JSHINT = (function () { warning("W037", state.tokens.curr, v); break; } - } else if (funct["(global)"]) { - // The name is not defined in the function. If we are in the global - // scope, then we have an undefined variable. - // - // Operators typeof and delete do not raise runtime errors even if - // the base object of a reference is null so no need to display warning - // if we're inside of typeof or delete. - - if (typeof predefined[v] !== "boolean") { - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === "typeof" || anonname === "delete") || - (state.tokens.next && (state.tokens.next.value === "." || - state.tokens.next.value === "["))) { - - // if we're in a list comprehension, variables are declared - // locally and used before being defined. So we check - // the presence of the given variable in the comp array - // before declaring it undefined. - - if (!funct["(comparray)"].check(v)) { - isundef(funct, "W117", state.tokens.curr, v); - } - } - } - - note_implied(state.tokens.curr); } else { // If the name is already defined in the current // function, but not as outer, then there is a scope error. @@ -3413,19 +3316,20 @@ var JSHINT = (function () { warning("W039", state.tokens.curr, v); note_implied(state.tokens.curr); } else if (typeof s !== "object") { - // Operators typeof and delete do not raise runtime errors even - // if the base object of a reference is null so no need to - // - // display warning if we're inside of typeof or delete. - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === "typeof" || anonname === "delete") || - (state.tokens.next && - (state.tokens.next.value === "." || state.tokens.next.value === "["))) { + // if we're in a list comprehension, variables are declared + // locally and used before being defined. So we check + // the presence of the given variable in the comp array + // before declaring it undefined. + if (!funct["(comparray)"].check(v)) { isundef(funct, "W117", state.tokens.curr, v); } - funct[v] = true; + + // Explicitly mark the variable as used within function scopes + if (!funct["(global)"]) { + funct[v] = true; + } + note_implied(state.tokens.curr); } else { switch (s[v]) { @@ -3460,6 +3364,21 @@ var JSHINT = (function () { } }; + state.syntax["(template)"] = { + type: "(template)", + lbp: 0, + identifier: false, + fud: doTemplateLiteral + }; + + type("(template middle)", function () { + return this; + }); + + type("(template tail)", function () { + return this; + }); + type("(regexp)", function () { return this; }); @@ -3494,7 +3413,8 @@ var JSHINT = (function () { reservevar("Infinity"); reservevar("null"); reservevar("this", function (x) { - if (state.directive["use strict"] && !state.option.validthis && ((funct["(statement)"] && + if (state.directive["use strict"] && !isMethod() && + !state.option.validthis && ((funct["(statement)"] && funct["(name)"].charAt(0) > "Z") || funct["(global)"])) { warning("W040", x); } @@ -3511,12 +3431,12 @@ var JSHINT = (function () { }; assignop("%=", "assignmod", 20); - bitwiseassignop("&=", "assignbitand", 20); - bitwiseassignop("|=", "assignbitor", 20); - bitwiseassignop("^=", "assignbitxor", 20); - bitwiseassignop("<<=", "assignshiftleft", 20); - bitwiseassignop(">>=", "assignshiftright", 20); - bitwiseassignop(">>>=", "assignshiftrightunsigned", 20); + bitwiseassignop("&="); + bitwiseassignop("|="); + bitwiseassignop("^="); + bitwiseassignop("<<="); + bitwiseassignop(">>="); + bitwiseassignop(">>>="); infix(",", function (left, that) { var expr; that.exprs = [left]; @@ -3667,11 +3587,11 @@ var JSHINT = (function () { infix("/", "div", 140); infix("%", "mod", 140); - suffix("++", "postinc"); + suffix("++"); prefix("++", "preinc"); state.syntax["++"].exps = true; - suffix("--", "postdec"); + suffix("--"); prefix("--", "predec"); state.syntax["--"].exps = true; prefix("delete", function () { @@ -3680,6 +3600,12 @@ var JSHINT = (function () { warning("W051"); } this.first = p; + + // The `delete` operator accepts unresolvable references when not in strict + // mode, so the operand may be undefined. + if (p.identifier && !state.directive["use strict"]) { + p.forgiveUndef = true; + } return this; }).exps = true; @@ -3692,8 +3618,8 @@ var JSHINT = (function () { }); prefix("...", function () { - if (!state.option.inESNext()) { - warning("W104", this, "spread/rest operator"); + if (!state.option.esnext) { + warning("W119", this, "spread/rest operator"); } if (!state.tokens.next.identifier) { error("E030", state.tokens.next, state.tokens.next.value); @@ -3716,7 +3642,17 @@ var JSHINT = (function () { return this; }); - prefix("typeof", "typeof"); + prefix("typeof", (function () { + var p = expression(150); + this.first = p; + + // The `typeof` operator accepts unresolvable references, so the operand + // may be undefined. + if (p.identifier) { + p.forgiveUndef = true; + } + return this; + })); prefix("new", function () { var c = expression(155), i; if (c && c.id !== "function") { @@ -3730,6 +3666,11 @@ var JSHINT = (function () { case "JSON": warning("W053", state.tokens.prev, c.value); break; + case "Symbol": + if (state.option.esnext) { + warning("W053", state.tokens.prev, c.value); + } + break; case "Function": if (!state.option.evil) { warning("W054"); @@ -3808,7 +3749,7 @@ var JSHINT = (function () { if (left) { if (left.type === "(identifier)") { if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { - if ("Number String Boolean Date Object Error".indexOf(left.value) === -1) { + if ("Number String Boolean Date Object Error Symbol".indexOf(left.value) === -1) { if (left.value === "Math") { warning("W063", left); } else if (state.option.newcap) { @@ -3862,8 +3803,8 @@ var JSHINT = (function () { } if (!left.identifier && left.id !== "." && left.id !== "[" && left.id !== "(" && left.id !== "&&" && left.id !== "||" && - left.id !== "?") { - warning("W067", left); + left.id !== "?" && !(state.option.esnext && left["(name)"])) { + warning("W067", that); } } @@ -3873,13 +3814,11 @@ var JSHINT = (function () { prefix("(", function () { var bracket, brackets = []; - var pn, pn1, i = 0; - var ret; + var pn = state.tokens.next, pn1, i = -1; + var ret, triggerFnExpr; var parens = 1; do { - pn = peek(i); - if (pn.value === "(") { parens += 1; } else if (pn.value === ")") { @@ -3887,19 +3826,27 @@ var JSHINT = (function () { } i += 1; - pn1 = peek(i); - } while (!(parens === 0 && pn.value === ")") && - pn1.value !== "=>" && pn1.value !== ";" && pn1.type !== "(end)"); + pn1 = pn; + pn = peek(i); + } while (!(parens === 0 && pn1.value === ")") && + pn.value !== ";" && pn.type !== "(end)"); if (state.tokens.next.id === "function") { - state.tokens.next.immed = true; + triggerFnExpr = state.tokens.next.immed = true; + } + + // If the balanced grouping operator is followed by a "fat arrow", the + // current token marks the beginning of a "fat arrow" function and parsing + // should proceed accordingly. + if (pn.value === "=>") { + return doFunction(null, null, null, { parsedParen: true }); } var exprs = []; if (state.tokens.next.id !== ")") { for (;;) { - if (pn1.value === "=>" && _.contains(["{", "["], state.tokens.next.value)) { + if (pn.value === "=>" && _.contains(["{", "["], state.tokens.next.value)) { bracket = state.tokens.next; bracket.left = destructuringExpression(); brackets.push(bracket); @@ -3919,7 +3866,7 @@ var JSHINT = (function () { advance(")", this); if (state.option.immed && exprs[0] && exprs[0].id === "function") { if (state.tokens.next.id !== "(" && - (state.tokens.next.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) { + state.tokens.next.id !== "." && state.tokens.next.id !== "[") { warning("W068", this); } } @@ -3938,6 +3885,7 @@ var JSHINT = (function () { } if (ret) { ret.paren = true; + ret.triggerFnExpr = triggerFnExpr; } return ret; }); @@ -4024,7 +3972,7 @@ var JSHINT = (function () { } prefix("[", function () { - var blocktype = lookupBlockType(true); + var blocktype = lookupBlockType(); if (blocktype.isCompArray) { if (!state.option.inESNext()) { warning("W119", state.tokens.curr, "array comprehension"); @@ -4043,8 +3991,19 @@ var JSHINT = (function () { } while (state.tokens.next.id !== "(end)") { while (state.tokens.next.id === ",") { - if (!state.option.inES5()) - warning("W070"); + if (!state.option.elision) { + if (!state.option.inES5()) { + // Maintain compat with old options --- ES5 mode without + // elision=true will warn once per comma + warning("W070"); + } else { + warning("W128"); + do { + advance(","); + } while(state.tokens.next.id === ","); + continue; + } + } advance(","); } @@ -4068,20 +4027,45 @@ var JSHINT = (function () { } advance("]", this); return this; - }, 160); + }); - function property_name() { - var id = optionalidentifier(false, true); + function isMethod() { + return funct["(statement)"] && funct["(statement)"].type === "class" || + funct["(context)"] && funct["(context)"]["(verb)"] === "class"; + } + + + function isPropertyName(token) { + return token.identifier || token.id === "(string)" || token.id === "(number)"; + } + + + function propertyName(preserveOrToken) { + var id; + var preserve = true; + if (typeof preserveOrToken === "object") { + id = preserveOrToken; + } else { + preserve = preserveOrToken; + id = optionalidentifier(false, true, preserve); + } if (!id) { if (state.tokens.next.id === "(string)") { id = state.tokens.next.value; - advance(); + if (!preserve) { + advance(); + } } else if (state.tokens.next.id === "(number)") { id = state.tokens.next.value.toString(); - advance(); + if (!preserve) { + advance(); + } } + } else if (typeof id === "object") { + if (id.id === "(string)" || id.id === "(identifier)") id = id.value; + else if (id.id === "(number)") id = id.value.toString(); } if (id === "hasOwnProperty") { @@ -4091,40 +4075,25 @@ var JSHINT = (function () { return id; } - function functionparams(parsed) { - var curr, next; + function functionparams(fatarrow) { + var next; var params = []; var ident; var tokens = []; var t; var pastDefault = false; + var loneArg = fatarrow && fatarrow.loneArg; - if (parsed) { - if (Array.isArray(parsed)) { - for (var i in parsed) { - curr = parsed[i]; - if (curr.value === "...") { - if (!state.option.inESNext()) { - warning("W104", curr, "spread/rest operator"); - } - continue; - } else if (curr.value !== ",") { - params.push(curr.value); - addlabel(curr.value, { type: "unused", token: curr }); - } - } - return params; - } else { - if (parsed.identifier === true) { - addlabel(parsed.value, { type: "unused", token: parsed }); - return [parsed]; - } - } + if (loneArg && loneArg.identifier === true) { + addlabel(loneArg.value, { type: "unused", token: loneArg }); + return [loneArg]; } next = state.tokens.next; - advance("("); + if (!fatarrow || !fatarrow.parsedParen) { + advance("("); + } if (state.tokens.next.id === ")") { advance(")"); @@ -4142,8 +4111,8 @@ var JSHINT = (function () { } } } else if (state.tokens.next.value === "...") { - if (!state.option.inESNext()) { - warning("W104", state.tokens.next, "spread/rest operator"); + if (!state.option.esnext) { + warning("W119", state.tokens.next, "spread/rest operator"); } advance("..."); ident = identifier(true); @@ -4234,7 +4203,34 @@ var JSHINT = (function () { return funct; } - function doFunction(name, statement, generator, fatarrowparams) { + function doTemplateLiteral() { + while (state.tokens.next.type !== "(template tail)" && state.tokens.next.id !== "(end)") { + advance(); + if (state.tokens.next.type === "(template tail)") { + break; + } else if (state.tokens.next.type !== "(template middle)" && + state.tokens.next.type !== "(end)") { + expression(10); // should probably have different rbp? + } + } + return { + id: "(template)", + type: "(template)" + }; + } + + /** + * @param {Object} [fatarrow] In the case that the function being parsed + * takes the "fat arrow" form, this object will + * contain details about the in-progress parsing + * operation. + * @param {Token} [fatarrow.loneArg] The argument to the function in cases + * where it was defined using the single- + * argument shorthand. + * @param {bool} [fatarrow.parsedParen] Whether the opening parenthesis has + * already been parsed. + */ + function doFunction(name, statement, generator, fatarrow) { var f; var oldOption = state.option; var oldIgnored = state.ignored; @@ -4244,7 +4240,7 @@ var JSHINT = (function () { state.ignored = Object.create(state.ignored); scope = Object.create(scope); - funct = functor(name || "\"" + anonname + "\"", state.tokens.next, scope, { + funct = functor(name || state.nameStack.infer(), state.tokens.next, scope, { "(statement)": statement, "(context)": funct, "(generator)": generator ? true : null @@ -4259,21 +4255,23 @@ var JSHINT = (function () { addlabel(name, { type: "function" }); } - funct["(params)"] = functionparams(fatarrowparams); + funct["(params)"] = functionparams(fatarrow); funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]); - // So we parse fat-arrow functions after we encounter =>. So basically - // doFunction is called with the left side of => as its last argument. - // This means that the parser, at that point, had already added its - // arguments to the undefs array and here we undo that. + if (fatarrow) { + if (!state.option.esnext) { + warning("W119", state.tokens.curr, "arrow function syntax (=>)"); + } - JSHINT.undefs = _.filter(JSHINT.undefs, function (item) { - return !_.contains(_.union(fatarrowparams), item[2]); - }); + if (!fatarrow.loneArg) { + advance("=>"); + } + } - block(false, true, true, fatarrowparams ? true : false); + block(false, true, true, !!fatarrow); - if (!state.option.noyield && generator && funct["(generator)"] !== "yielded") { + if (!state.option.noyield && generator && + funct["(generator)"] !== "yielded") { warning("W124", state.tokens.curr); } @@ -4369,46 +4367,25 @@ var JSHINT = (function () { } } + /** + * @param {object} props Collection of property descriptors for a given + * object. + */ + function checkProperties(props) { + // Check for lonely setters if in the ES5 mode. + if (state.option.inES5()) { + for (var name in props) { + if (_.has(props, name) && props[name].setterToken && !props[name].getterToken) { + warning("W078", props[name].setterToken); + } + } + } + } (function (x) { - x.nud = function (isclassdef) { - var b, f, i, p, t, g; + x.nud = function () { + var b, f, i, p, t, g, nextVal; var props = {}; // All properties, including accessors - var tag = ""; - - function saveProperty(name, tkn) { - if (props[name] && _.has(props, name)) - warning("W075", state.tokens.next, i); - else - props[name] = {}; - - props[name].basic = true; - props[name].basictkn = tkn; - } - - function saveSetter(name, tkn) { - if (props[name] && _.has(props, name)) { - if (props[name].basic || props[name].setter) - warning("W075", state.tokens.next, i); - } else { - props[name] = {}; - } - - props[name].setter = true; - props[name].setterToken = tkn; - } - - function saveGetter(name) { - if (props[name] && _.has(props, name)) { - if (props[name].basic || props[name].getter) - warning("W075", state.tokens.next, i); - } else { - props[name] = {}; - } - - props[name].getter = true; - props[name].getterToken = state.tokens.curr; - } b = state.tokens.curr.line !== state.tokens.next.line; if (b) { @@ -4423,19 +4400,15 @@ var JSHINT = (function () { break; } - if (isclassdef && state.tokens.next.value === "static") { - advance("static"); - tag = "static "; - } + nextVal = state.tokens.next.value; + if (peek().id !== ":" && (nextVal === "get" || nextVal === "set")) { + advance(nextVal); - if (state.tokens.next.value === "get" && peek().id !== ":") { - advance("get"); - - if (!state.option.inES5(!isclassdef)) { + if (!state.option.inES5()) { error("E034"); } - i = property_name(); + i = propertyName(); // ES6 allows for get() {...} and set() {...} method // definition shorthand syntax, so we don't produce an error @@ -4444,16 +4417,10 @@ var JSHINT = (function () { error("E035"); } - // It is a Syntax Error if PropName of MethodDefinition is - // "constructor" and SpecialMethod of MethodDefinition is true. - if (isclassdef && i === "constructor") { - error("E049", state.tokens.next, "class getter method", i); - } - // We don't want to save this getter unless it's an actual getter // and not an ES6 concise method if (i) { - saveGetter(tag + i); + saveAccessor(nextVal, props, i, state.tokens.curr); } t = state.tokens.next; @@ -4461,43 +4428,9 @@ var JSHINT = (function () { p = f["(params)"]; // Don't warn about getter/setter pairs if this is an ES6 concise method - if (i && p) { + if (nextVal === "get" && i && p) { warning("W076", t, p[0], i); - } - } else if (state.tokens.next.value === "set" && peek().id !== ":") { - advance("set"); - - if (!state.option.inES5(!isclassdef)) { - error("E034"); - } - - i = property_name(); - - // ES6 allows for get() {...} and set() {...} method - // definition shorthand syntax, so we don't produce an error - // if the esnext option is enabled. - if (!i && !state.option.inESNext()) { - error("E035"); - } - - // It is a Syntax Error if PropName of MethodDefinition is - // "constructor" and SpecialMethod of MethodDefinition is true. - if (isclassdef && i === "constructor") { - error("E049", state.tokens.next, "class setter method", i); - } - - // We don't want to save this getter unless it's an actual getter - // and not an ES6 concise method - if (i) { - saveSetter(tag + i, state.tokens.next); - } - - t = state.tokens.next; - f = doFunction(); - p = f["(params)"]; - - // Don't warn about getter/setter pairs if this is an ES6 concise method - if (i && (!p || p.length !== 1)) { + } else if (nextVal === "set" && i && (!p || p.length !== 1)) { warning("W077", t, i); } } else { @@ -4509,33 +4442,43 @@ var JSHINT = (function () { advance("*"); g = true; } - i = property_name(); - saveProperty(tag + i, state.tokens.next); - - if (typeof i !== "string") { - break; - } - - if (state.tokens.next.value === "(") { + if (state.tokens.next.identifier && + (peekIgnoreEOL().id === "," || peekIgnoreEOL().id === "}")) { if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "concise methods"); + warning("W104", state.tokens.next, "object short notation"); } - doFunction(i, undefined, g); - } else if (!isclassdef) { - advance(":"); + i = propertyName(true); + saveProperty(props, i, state.tokens.next); + expression(10); + } else { + if (state.tokens.next.id === "[") { + i = computedPropertyName(); + state.nameStack.set(i); + } else { + state.nameStack.set(state.tokens.next); + i = propertyName(); + saveProperty(props, i, state.tokens.next); + + if (typeof i !== "string") { + break; + } + } + + if (state.tokens.next.value === "(") { + if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "concise methods"); + } + doFunction(null, undefined, g); + } else { + advance(":"); + expression(10); + } } } - // It is a Syntax Error if PropName of MethodDefinition is "prototype". - if (isclassdef && i === "prototype") { - error("E049", state.tokens.next, "class method", i); - } countMember(i); - if (isclassdef) { - tag = ""; - continue; - } + if (state.tokens.next.id === ",") { comma({ allowTrailing: true, property: true }); if (state.tokens.next.id === ",") { @@ -4552,14 +4495,8 @@ var JSHINT = (function () { } advance("}", this); - // Check for lonely setters if in the ES5 mode. - if (state.option.inES5()) { - for (var name in props) { - if (_.has(props, name) && props[name].setter && !props[name].getter) { - warning("W078", props[name].setterToken); - } - } - } + checkProperties(props); + return this; }; x.fud = function () { @@ -4747,12 +4684,15 @@ var JSHINT = (function () { this.first = this.first.concat(names); if (state.tokens.next.id === "=") { + state.nameStack.set(state.tokens.curr); advance("="); if (state.tokens.next.id === "undefined") { warning("W080", state.tokens.prev, state.tokens.prev.value); } if (peek(0).id === "=" && state.tokens.next.identifier) { - warning("W120", state.tokens.next, state.tokens.next.value); + if (!funct["(params)"] || funct["(params)"].indexOf(state.tokens.next.value) === -1) { + warning("W120", state.tokens.next, state.tokens.next.value); + } } value = expression(10); if (lone) { @@ -4868,6 +4808,8 @@ var JSHINT = (function () { } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { // BindingIdentifier(opt) this.name = identifier(); + } else { + this.name = state.nameStack.infer(); } classtail(this); return this; @@ -4886,10 +4828,97 @@ var JSHINT = (function () { state.directive["use strict"] = true; advance("{"); // ClassBody(opt) - c.body = state.syntax["{"].nud(true); + c.body = classbody(c); + advance("}"); state.directive["use strict"] = strictness; } + function classbody(c) { + var name; + var isStatic; + var getset; + var props = {}; + var staticProps = {}; + var computed; + for (var i = 0; state.tokens.next.id !== "}"; ++i) { + name = state.tokens.next; + isStatic = false; + getset = null; + if (name.id === "[") { + name = computedPropertyName(); + } else if (isPropertyName(name)) { + // Non-Computed PropertyName + advance(); + computed = false; + if (name.identifier && name.value === "static") { + if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") { + computed = state.tokens.next.id === "["; + isStatic = true; + name = state.tokens.next; + if (state.tokens.next.id === "[") { + name = computedPropertyName(); + } else advance(); + } + } + + if (name.identifier && (name.value === "get" || name.value === "set")) { + if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") { + computed = state.tokens.next.id === "["; + getset = name; + name = state.tokens.next; + if (state.tokens.next.id === "[") { + name = computedPropertyName(); + } else advance(); + } + } + } else { + warning("W052", state.tokens.next, state.tokens.next.value || state.tokens.next.type); + advance(); + continue; + } + + if (!checkPunctuators(state.tokens.next, ["("])) { + // error --- class properties must be methods + error("E054", state.tokens.next, state.tokens.next.value); + while (state.tokens.next.id !== "}" && + !checkPunctuators(state.tokens.next, ["("])) { + advance(); + } + if (state.tokens.next.value !== "(") { + doFunction(undefined, c, false, null); + } + } + + if (!computed) { + // We don't know how to determine if we have duplicate computed property names :( + if (getset) { + saveAccessor( + getset.value, isStatic ? staticProps : props, name.value, name, true, isStatic); + } else { + if (name.value === "constructor") { + state.nameStack.set(c); + } else { + state.nameStack.set(name); + } + saveProperty(isStatic ? staticProps : props, name.value, name, true, isStatic); + } + } + + if (getset && name.value === "constructor") { + var propDesc = getset.value === "get" ? "class getter method" : "class setter method"; + error("E049", name, propDesc, "constructor"); + } else if (name.value === "prototype") { + error("E049", name, "class method", "prototype"); + } + + propertyName(name); + + doFunction(null, c, false, null); + } + + checkProperties(props); + } + blockstmt("function", function () { var generator = false; if (state.tokens.next.value === "*") { @@ -4904,7 +4933,12 @@ var JSHINT = (function () { warning("W082", state.tokens.curr); } - var i = identifier(); + var i = optionalidentifier(); + + if (i === undefined) { + warning("W025"); + } + if (funct[i] === "const") { warning("E011", null, i); } @@ -4919,6 +4953,7 @@ var JSHINT = (function () { prefix("function", function () { var generator = false; + if (state.tokens.next.value === "*") { if (!state.option.inESNext()) { warning("W119", state.tokens.curr, "function*"); @@ -4926,10 +4961,20 @@ var JSHINT = (function () { advance("*"); generator = true; } + var i = optionalidentifier(); - doFunction(i, undefined, generator); + var fn = doFunction(i, undefined, generator); + + function isVariable(name) { return name[0] !== "("; } + function isLocal(name) { return fn[name] === "var"; } + if (!state.option.loopfunc && funct["(loopage)"]) { - warning("W083"); + // If the function we just parsed accesses any non-local variables + // trigger a warning. Otherwise, the function is safe even within + // a loop. + if (_.some(fn, function (val, name) { return isVariable(name) && !isLocal(name); })) { + warning("W083"); + } } return this; }); @@ -4939,14 +4984,38 @@ var JSHINT = (function () { increaseComplexityCount(); state.condition = true; advance("("); - checkCondAssignment(expression(0)); + var expr = expression(0); + checkCondAssignment(expr); + + // When the if is within a for-in loop, check if the condition + // starts with a negation operator + var forinifcheck = null; + if (state.option.forin && state.forinifcheckneeded) { + state.forinifcheckneeded = false; // We only need to analyze the first if inside the loop + forinifcheck = state.forinifchecks[state.forinifchecks.length - 1]; + if (expr.type === "(punctuator)" && expr.value === "!") { + forinifcheck.type = "(negative)"; + } else { + forinifcheck.type = "(positive)"; + } + } + advance(")", t); state.condition = false; - block(true, true); + var s = block(true, true); + + // When the if is within a for-in loop and the condition has a negative form, + // check if the body contains nothing but a continue statement + if (forinifcheck && forinifcheck.type === "(negative)") { + if (s && s.length === 1 && s[0].type === "(identifier)" && s[0].value === "continue") { + forinifcheck.type = "(negative-with-continue)"; + } + } + if (state.tokens.next.id === "else") { advance("else"); if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { - statement(true); + statement(); } else { block(true, true); } @@ -5254,7 +5323,9 @@ var JSHINT = (function () { case "var": break; default: - if (!funct["(blockscope)"].getlabel(state.tokens.next.value)) + var ident = state.tokens.next.value; + if (!funct["(blockscope)"].getlabel(ident) && + !(scope[ident] || {})[ident]) warning("W088", state.tokens.next, state.tokens.next.value); } advance(); @@ -5262,11 +5333,41 @@ var JSHINT = (function () { advance(nextop.value); expression(20); advance(")", t); - s = block(true, true); - if (state.option.forin && s && (s.length > 1 || typeof s[0] !== "object" || - s[0].value !== "if")) { - warning("W089", this); + + if (nextop.value === "in" && state.option.forin) { + state.forinifcheckneeded = true; + + if (state.forinifchecks === undefined) { + state.forinifchecks = []; + } + + // Push a new for-in-if check onto the stack. The type will be modified + // when the loop's body is parsed and a suitable if statement exists. + state.forinifchecks.push({ + type: "(none)" + }); } + + s = block(true, true); + + if (nextop.value === "in" && state.option.forin) { + if (state.forinifchecks && state.forinifchecks.length > 0) { + var check = state.forinifchecks.pop(); + + if (// No if statement or not the first statement in loop body + s && s.length > 0 && (typeof s[0] !== "object" || s[0].value !== "if") || + // Positive if statement is not the only one in loop body + check.type === "(positive)" && s.length > 1 || + // Negative if statement but no continue + check.type === "(negative)") { + warning("W089", this); + } + } + + // Reset the flag in case no if statement was contained in the loop body + state.forinifcheckneeded = false; + } + funct["(breakage)"] -= 1; funct["(loopage)"] -= 1; } else { @@ -5346,7 +5447,9 @@ var JSHINT = (function () { advance(); } } - reachable("break"); + + reachable(this); + return this; }).exps = true; @@ -5373,7 +5476,9 @@ var JSHINT = (function () { } else if (!funct["(loopage)"]) { warning("W052", state.tokens.next, this.value); } - reachable("continue"); + + reachable(this); + return this; }).exps = true; @@ -5395,7 +5500,9 @@ var JSHINT = (function () { nolinebreak(this); // always warn (Line breaking error) } } - reachable("return"); + + reachable(this); + return this; }).exps = true; @@ -5413,8 +5520,17 @@ var JSHINT = (function () { warning("W104", state.tokens.curr, "yield"); } funct["(generator)"] = "yielded"; + var delegatingYield = false; + + if (state.tokens.next.value === "*") { + delegatingYield = true; + advance("*"); + } + if (this.line === state.tokens.next.line || !state.option.inMoz(true)) { - if (state.tokens.next.id !== ";" && !state.tokens.next.reach && state.tokens.next.nud) { + if (delegatingYield || + (state.tokens.next.id !== ";" && !state.tokens.next.reach && state.tokens.next.nud)) { + nobreaknonadjacent(state.tokens.curr, state.tokens.next); this.first = expression(10); @@ -5438,7 +5554,9 @@ var JSHINT = (function () { stmt("throw", function () { nolinebreak(this); this.first = expression(20); - reachable("throw"); + + reachable(this); + return this; }).exps = true; @@ -5448,12 +5566,23 @@ var JSHINT = (function () { } if (state.tokens.next.type === "(string)") { + // ModuleSpecifier :: StringLiteral advance("(string)"); return this; } + if (state.tokens.next.identifier) { + // ImportClause :: ImportedDefaultBinding this.name = identifier(); addlabel(this.name, { type: "unused", token: state.tokens.curr }); + } else if (state.tokens.next.id === "*") { + // ImportClause :: NameSpaceImport + advance("*"); + advance("as"); + if (state.tokens.next.identifier) { + this.name = identifier(); + addlabel(this.name, { type: "unused", token: state.tokens.curr }); + } } else { advance("{"); for (;;) { @@ -5486,17 +5615,33 @@ var JSHINT = (function () { } } + // FromClause advance("from"); advance("(string)"); return this; }).exps = true; stmt("export", function () { + var ok = true; if (!state.option.inESNext()) { warning("W119", state.tokens.curr, "export"); + ok = false; + } + + if (!funct["(global)"] || !funct["(blockscope)"].atTop()) { + error("E053", state.tokens.curr); + ok = false; + } + + if (state.tokens.next.value === "*") { + advance("*"); + advance("from"); + advance("(string)"); + return this; } if (state.tokens.next.type === "default") { + state.nameStack.set(state.tokens.next); advance("default"); if (state.tokens.next.id === "function" || state.tokens.next.id === "class") { this.block = true; @@ -5509,7 +5654,11 @@ var JSHINT = (function () { if (state.tokens.next.value === "{") { advance("{"); for (;;) { - exported[identifier()] = true; + var id; + exported[id = identifier(false, false, ok)] = ok; + if (ok) { + funct["(blockscope)"].setExported(id); + } if (state.tokens.next.value === ",") { advance(","); @@ -5526,25 +5675,30 @@ var JSHINT = (function () { if (state.tokens.next.id === "var") { advance("var"); - exported[state.tokens.next.value] = true; + exported[state.tokens.next.value] = ok; + state.tokens.next.exported = true; state.syntax["var"].fud.call(state.syntax["var"].fud); } else if (state.tokens.next.id === "let") { advance("let"); - exported[state.tokens.next.value] = true; + exported[state.tokens.next.value] = ok; + state.tokens.next.exported = true; state.syntax["let"].fud.call(state.syntax["let"].fud); } else if (state.tokens.next.id === "const") { advance("const"); - exported[state.tokens.next.value] = true; + exported[state.tokens.next.value] = ok; + state.tokens.next.exported = true; state.syntax["const"].fud.call(state.syntax["const"].fud); } else if (state.tokens.next.id === "function") { this.block = true; advance("function"); - exported[state.tokens.next.value] = true; + exported[state.tokens.next.value] = ok; + state.tokens.next.exported = true; state.syntax["function"].fud(); } else if (state.tokens.next.id === "class") { this.block = true; advance("class"); - exported[state.tokens.next.value] = true; + exported[state.tokens.next.value] = ok; + state.tokens.next.exported = true; state.syntax["class"].fud(); } else { error("E024", state.tokens.next, state.tokens.next.value); @@ -5584,7 +5738,7 @@ var JSHINT = (function () { FutureReservedWord("transient"); FutureReservedWord("volatile"); - // this function is used to determine wether a squarebracket or a curlybracket + // this function is used to determine whether a squarebracket or a curlybracket // expression is a comprehension array, destructuring assignment or a json value. var lookupBlockType = function () { @@ -5592,15 +5746,15 @@ var JSHINT = (function () { var i = -1; var bracketStack = 0; var ret = {}; - if (_.contains(["[", "{"], state.tokens.curr.value)) + if (checkPunctuators(state.tokens.curr, ["[", "{"])) bracketStack += 1; do { pn = (i === -1) ? state.tokens.next : peek(i); pn1 = peek(i + 1); i = i + 1; - if (_.contains(["[", "{"], pn.value)) { + if (checkPunctuators(pn, ["[", "{"])) { bracketStack += 1; - } else if (_.contains(["]", "}"], pn.value)) { + } else if (checkPunctuators(pn, ["]", "}"])) { bracketStack -= 1; } if (pn.identifier && pn.value === "for" && bracketStack === 1) { @@ -5608,10 +5762,15 @@ var JSHINT = (function () { ret.notJson = true; break; } - if (_.contains(["}", "]"], pn.value) && pn1.value === "=" && bracketStack === 0) { - ret.isDestAssign = true; - ret.notJson = true; - break; + if (checkPunctuators(pn, ["}", "]"]) && bracketStack === 0) { + if (pn1.value === "=") { + ret.isDestAssign = true; + ret.notJson = true; + break; + } else if (pn1.value === ".") { + ret.notJson = true; + break; + } } if (pn.value === ";") { ret.isBlock = true; @@ -5621,6 +5780,74 @@ var JSHINT = (function () { return ret; }; + function saveProperty(props, name, tkn, isClass, isStatic) { + var msg = ["key", "class method", "static class method"]; + msg = msg[(isClass || false) + (isStatic || false)]; + if (tkn.identifier) { + name = tkn.value; + } + + if (props[name] && _.has(props, name)) { + warning("W075", state.tokens.next, msg, name); + } else { + props[name] = {}; + } + + props[name].basic = true; + props[name].basictkn = tkn; + } + + /** + * @param {string} accessorType - Either "get" or "set" + * @param {object} props - a collection of all properties of the object to + * which the current accessor is being assigned + * @param {object} tkn - the identifier token representing the accessor name + * @param {boolean} isClass - whether the accessor is part of an ES6 Class + * definition + * @param {boolean} isStatic - whether the accessor is a static method + */ + function saveAccessor(accessorType, props, name, tkn, isClass, isStatic) { + var flagName = accessorType === "get" ? "getterToken" : "setterToken"; + var msg = ""; + + if (isClass) { + if (isStatic) { + msg += "static "; + } + msg += accessorType + "ter method"; + } else { + msg = "key"; + } + + state.tokens.curr.accessorType = accessorType; + state.nameStack.set(tkn); + + if (props[name] && _.has(props, name)) { + if (props[name].basic || props[name][flagName]) { + warning("W075", state.tokens.next, msg, name); + } + } else { + props[name] = {}; + } + + props[name][flagName] = tkn; + } + + function computedPropertyName() { + advance("["); + if (!state.option.esnext) { + warning("W119", state.tokens.curr, "computed property names"); + } + var value = expression(10); + advance("]"); + return value; + } + + // Test whether a given token is a punctuator matching one of the specified values + function checkPunctuators(token, values) { + return token.type === "(punctuator)" && _.contains(values, token.value); + } + // Check whether this function has been reached for a destructuring assign with undeclared values function destructuringAssignOrJsonValue() { // lookup for the assignment (esnext only) @@ -5686,7 +5913,7 @@ var JSHINT = (function () { unstack: function () { _current.variables.filter(function (v) { if (v.unused) - warning("W098", v.token, v.value); + warning("W098", v.token, v.raw_text || v.value); if (v.undef) isundef(v.funct, "W117", v.token, v.value); }); @@ -5839,6 +6066,10 @@ var JSHINT = (function () { if (_current[t]["(type)"] === "unused") { if (state.option.unused) { var tkn = _current[t]["(token)"]; + // Don't report exported labels as unused + if (tkn.exported) { + continue; + } var line = tkn.line; var chr = tkn.character; warningAt("W098", line, chr, t); @@ -5883,6 +6114,19 @@ var JSHINT = (function () { } }, + atTop: function () { + return _variables.length === 1; + }, + + setExported: function (id) { + if (funct["(blockscope)"].atTop()) { + var item = _current[id]; + if (item && item["(token)"]) { + item["(token)"].exported = true; + } + } + }, + current: { has: function (t) { return _.has(_current, t); @@ -5895,9 +6139,13 @@ var JSHINT = (function () { }; }; + var escapeRegex = function(str) { + return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); + }; + // The actual JSHINT function itself. var itself = function (s, o, g) { - var i, k, x; + var i, k, x, reIgnoreStr, reIgnore; var optionKeys; var newOptionObj = {}; var newIgnoredObj = {}; @@ -5941,6 +6189,8 @@ var JSHINT = (function () { if (item[0] === "-") { slice = item.slice(1); JSHINT.blacklist[slice] = slice; + // remove from predefined if there + delete predefined[slice]; } else { prop = Object.getOwnPropertyDescriptor(o.predef, item); predefined[item] = prop ? prop.value : false; @@ -6034,6 +6284,28 @@ var JSHINT = (function () { state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; + if (o && o.ignoreDelimiters) { + + if (!Array.isArray(o.ignoreDelimiters)) { + o.ignoreDelimiters = [o.ignoreDelimiters]; + } + + o.ignoreDelimiters.forEach(function (delimiterPair) { + if (!delimiterPair.start || !delimiterPair.end) + return; + + reIgnoreStr = escapeRegex(delimiterPair.start) + + "[\\s\\S]*?" + + escapeRegex(delimiterPair.end); + + reIgnore = new RegExp(reIgnoreStr, "ig"); + + s = s.replace(reIgnore, function(match) { + return match.replace(/./g, " "); + }); + }); + } + lex = new Lexer(s); lex.on("warning", function (ev) { @@ -6088,8 +6360,10 @@ var JSHINT = (function () { directives(); if (state.directive["use strict"]) { - if (!state.option.globalstrict && !(state.option.node || state.option.phantom)) { - warning("W097", state.tokens.prev); + if (!state.option.globalstrict) { + if (!(state.option.node || state.option.phantom || state.option.browserify)) { + warning("W097", state.tokens.prev); + } } } @@ -6139,7 +6413,8 @@ var JSHINT = (function () { var warnUnused = function (name, tkn, type, unused_opt) { var line = tkn.line; - var chr = tkn.character; + var chr = tkn.from; + var raw_name = tkn.raw_text || name; if (unused_opt === undefined) { unused_opt = state.option.unused; @@ -6157,7 +6432,9 @@ var JSHINT = (function () { if (unused_opt) { if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) { - warningAt("W098", line, chr, name); + if (!tkn.exported) { + warningAt("W098", line, chr, raw_name); + } } } @@ -6197,7 +6474,7 @@ var JSHINT = (function () { for (i = 0; i < JSHINT.undefs.length; i += 1) { k = JSHINT.undefs[i].slice(0); - if (markDefined(k[2].value, k[0])) { + if (markDefined(k[2].value, k[0]) || k[2].forgiveUndef) { clearImplied(k[2].value, k[2].line); } else if (state.option.undef) { warning.apply(warning, k.slice(1)); @@ -6384,7 +6661,7 @@ if (typeof exports === "object" && exports) { } }, -{"./lex.js":4,"./messages.js":5,"./reg.js":6,"./state.js":7,"./style.js":8,"./vars.js":9,"events":10,"underscore":2}], +{"./lex.js":4,"./messages.js":5,"./options.js":7,"./reg.js":8,"./state.js":9,"./style.js":10,"./vars.js":11,"events":12,"underscore":2}], 4:[function(_dereq_,module,exports){ /* * Lexical analysis and token construction. @@ -6415,7 +6692,9 @@ var Token = { NullLiteral: 7, BooleanLiteral: 8, RegExp: 9, - TemplateLiteral: 10 + TemplateHead: 10, + TemplateMiddle: 11, + TemplateTail: 12 }; // Object that handles postponed lexing verifications that checks the parsed @@ -6495,6 +6774,9 @@ function Lexer(source) { this.from = 1; this.input = ""; this.inComment = false; + this.inTemplate = false; + this.templateLine = null; + this.templateChar = null; for (var i = 0; i < state.option.indent; i += 1) { state.tab += " "; @@ -6704,13 +6986,10 @@ Lexer.prototype = { }; } - // Special case: /=. We need to make sure that this is an - // operator and not a regular expression. + // Special case: /=. if (ch1 === "/") { - if (ch2 === "=" && /\/=(?!(\S*\/[gim]?))/.test(this.input)) { - // /= is not a part of a regular expression, return it as a - // punctuator. + if (ch2 === "=") { return { type: Token.Punctuator, value: "/=" @@ -6758,6 +7037,8 @@ Lexer.prototype = { value += "*/"; } + body = body.replace(/\n/g, " "); + special.forEach(function (str) { if (isSpecial) { return; @@ -6769,13 +7050,14 @@ Lexer.prototype = { return; } - if (body.substr(0, str.length) === str) { + if (body.charAt(str.length) === " " && body.substr(0, str.length) === str) { isSpecial = true; label = label + str; body = body.substr(str.length); } - if (!isSpecial && body.charAt(0) === " " && body.substr(1, str.length) === str) { + if (!isSpecial && body.charAt(0) === " " && body.charAt(str.length + 1) === " " && + body.substr(1, str.length) === str) { isSpecial = true; label = label + " " + str; body = body.substr(str.length + 1); @@ -6919,7 +7201,7 @@ Lexer.prototype = { return (/^[0-9a-fA-F]$/).test(str); } - var readUnicodeEscapeSequence = function () { + var readUnicodeEscapeSequence = function() { /*jshint validthis:true */ index += 1; @@ -6999,6 +7281,12 @@ Lexer.prototype = { return null; }.bind(this); + function removeEscapeSequences(id) { + return id.replace(/\\u([0-9a-fA-F]{4})/g, function(m0, codepoint) { + return String.fromCharCode(parseInt(codepoint, 16)); + }); + } + char = getIdentifierStart(); if (char === null) { return null; @@ -7029,7 +7317,9 @@ Lexer.prototype = { return { type: type, - value: id + value: removeEscapeSequences(id), + text: id, + tokenLength: id.length }; }, @@ -7048,6 +7338,9 @@ Lexer.prototype = { var length = this.input.length; var char = this.peek(index); var bad; + var isAllowedDigit = isDecimalDigit; + var base = 10; + var isLegacy = false; function isDecimalDigit(str) { return (/^[0-9]$/).test(str); @@ -7057,6 +7350,10 @@ Lexer.prototype = { return (/^[0-7]$/).test(str); } + function isBinaryDigit(str) { + return (/^[01]$/).test(str); + } + function isHexDigit(str) { return (/^[0-9a-fA-F]$/).test(str); } @@ -7080,81 +7377,64 @@ Lexer.prototype = { if (value === "0") { // Base-16 numbers. if (char === "x" || char === "X") { + isAllowedDigit = isHexDigit; + base = 16; + index += 1; value += char; - - while (index < length) { - char = this.peek(index); - if (!isHexDigit(char)) { - break; - } - value += char; - index += 1; - } - - if (value.length <= 2) { // 0x - return { - type: Token.NumericLiteral, - value: value, - isMalformed: true - }; - } - - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } - } - - return { - type: Token.NumericLiteral, - value: value, - base: 16, - isMalformed: false - }; } // Base-8 numbers. - if (isOctalDigit(char)) { + if (char === "o" || char === "O") { + isAllowedDigit = isOctalDigit; + base = 8; + + if (!state.option.esnext) { + this.trigger("warning", { + code: "W119", + line: this.line, + character: this.char, + data: [ "Octal integer literal" ] + }); + } + index += 1; value += char; + } + + // Base-2 numbers. + if (char === "b" || char === "B") { + isAllowedDigit = isBinaryDigit; + base = 2; + + if (!state.option.esnext) { + this.trigger("warning", { + code: "W119", + line: this.line, + character: this.char, + data: [ "Binary integer literal" ] + }); + } + + index += 1; + value += char; + } + + // Legacy base-8 numbers. + if (isOctalDigit(char)) { + isAllowedDigit = isOctalDigit; + base = 8; + isLegacy = true; bad = false; - while (index < length) { - char = this.peek(index); - - // Numbers like '019' (note the 9) are not valid octals - // but we still parse them and mark as malformed. - - if (isDecimalDigit(char)) { - bad = true; - } else if (!isOctalDigit(char)) { - break; - } - value += char; - index += 1; - } - - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } - } - - return { - type: Token.NumericLiteral, - value: value, - base: 8, - isMalformed: false - }; + index += 1; + value += char; } // Decimal numbers that start with '0' such as '09' are illegal // but we still parse them and return as malformed. - if (isDecimalDigit(char)) { + if (!isOctalDigit(char) && isDecimalDigit(char)) { index += 1; value += char; } @@ -7162,12 +7442,42 @@ Lexer.prototype = { while (index < length) { char = this.peek(index); - if (!isDecimalDigit(char)) { + + if (isLegacy && isDecimalDigit(char)) { + // Numbers like '019' (note the 9) are not valid octals + // but we still parse them and mark as malformed. + bad = true; + } else if (!isAllowedDigit(char)) { break; } value += char; index += 1; } + + if (isAllowedDigit !== isDecimalDigit) { + if (!isLegacy && value.length <= 2) { // 0x + return { + type: Token.NumericLiteral, + value: value, + isMalformed: true + }; + } + + if (index < length) { + char = this.peek(index); + if (isIdentifierStart(char)) { + return null; + } + } + + return { + type: Token.NumericLiteral, + value: value, + base: base, + isLegacy: isLegacy, + isMalformed: false + }; + } } // Decimal digits. @@ -7226,64 +7536,178 @@ Lexer.prototype = { return { type: Token.NumericLiteral, value: value, - base: 10, + base: base, isMalformed: !isFinite(value) }; }, + + // Assumes previously parsed character was \ (=== '\\') and was not skipped. + scanEscapeSequence: function (checks) { + var allowNewLine = false; + var jump = 1; + this.skip(); + var char = this.peek(); + + switch (char) { + case "'": + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\'" ] + }, checks, function () {return state.jsonMode; }); + break; + case "b": + char = "\\b"; + break; + case "f": + char = "\\f"; + break; + case "n": + char = "\\n"; + break; + case "r": + char = "\\r"; + break; + case "t": + char = "\\t"; + break; + case "0": + char = "\\0"; + + // Octal literals fail in strict mode. + // Check if the number is between 00 and 07. + var n = parseInt(this.peek(1), 10); + this.triggerAsync("warning", { + code: "W115", + line: this.line, + character: this.char + }, checks, + function () { return n >= 0 && n <= 7 && state.directive["use strict"]; }); + break; + case "u": + char = String.fromCharCode(parseInt(this.input.substr(1, 4), 16)); + jump = 5; + break; + case "v": + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\v" ] + }, checks, function () { return state.jsonMode; }); + + char = "\v"; + break; + case "x": + var x = parseInt(this.input.substr(1, 2), 16); + + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\x-" ] + }, checks, function () { return state.jsonMode; }); + + char = String.fromCharCode(x); + jump = 3; + break; + case "\\": + char = "\\\\"; + break; + case "\"": + char = "\\\""; + break; + case "/": + break; + case "": + allowNewLine = true; + char = ""; + break; + } + + return {char: char, jump: jump, allowNewLine: allowNewLine}; + }, + /* * Extract a template literal out of the next sequence of characters * and/or lines or return 'null' if its not possible. Since template * literals can span across multiple lines, this method has to move * the char pointer. */ - scanTemplateLiteral: function () { + scanTemplateLiteral: function (checks) { + var tokenType; + var value = ''; + var ch; + // String must start with a backtick. - if (!state.option.esnext || this.peek() !== "`") { + if (!this.inTemplate) { + if (!state.option.esnext || this.peek() !== "`") { + return null; + } + this.templateLine = this.line; + this.templateChar = this.char; + this.skip(1); + } else if (this.peek() !== '}') { + // If we're in a template, and we don't have a '}', lex something else instead. return null; } - var startLine = this.line; - var startChar = this.char; - var jump = 1; - var value = ""; - - // For now, do not perform any linting of the content of the template - // string. Just skip until the next backtick is found. - this.skip(); - while (this.peek() !== "`") { - while (this.peek() === "") { - // End of line --- For template literals in ES6, no backslash is - // required to precede newlines. + while ((ch = this.peek()) === "") { if (!this.nextLine()) { + // Unclosed template literal --- point to the starting line, or the EOF? + tokenType = this.inTemplate ? Token.TemplateHead : Token.TemplateMiddle; + this.inTemplate = false; this.trigger("error", { code: "E052", - line: startLine, - character: startChar + line: this.templateLine, + character: this.templateChar }); - return { - type: Token.TemplateLiteral, + type: tokenType, value: value, isUnclosed: true }; } - value += "\n"; } - // TODO: do more interesting linting here, similar to string literal - // linting. - var char = this.peek(); - this.skip(jump); - value += char; + if (ch === '$' && this.peek(1) === '{') { + value += '${'; + tokenType = value.charAt(0) === '}' ? Token.TemplateMiddle : Token.TemplateHead; + // Either TokenHead or TokenMiddle --- depending on if the initial value + // is '}' or not. + this.skip(2); + this.inTemplate = true; + return { + type: tokenType, + value: value, + isUnclosed: false + }; + } else if (ch === '\\') { + var escape = this.scanEscapeSequence(checks); + value += escape.char; + this.skip(escape.jump); + } else if (ch === '`') { + break; + } else { + // Otherwise, append the value and continue. + value += ch; + this.skip(1); + } } - this.skip(); + // Final value is either TokenTail or NoSubstititionTemplate --- essentially a string + tokenType = this.inTemplate ? Token.TemplateTail : Token.StringLiteral; + this.inTemplate = false; + this.skip(1); + return { - type: Token.TemplateLiteral, + type: tokenType, value: value, - isUnclosed: false + isUnclosed: false, + quote: "`" }; }, @@ -7394,101 +7818,11 @@ Lexer.prototype = { } // Special treatment for some escaped characters. - if (char === "\\") { - this.skip(); - char = this.peek(); - - switch (char) { - case "'": - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\'" ] - }, checks, function () {return state.jsonMode; }); - break; - case "b": - char = "\\b"; - break; - case "f": - char = "\\f"; - break; - case "n": - char = "\\n"; - break; - case "r": - char = "\\r"; - break; - case "t": - char = "\\t"; - break; - case "0": - char = "\\0"; - - // Octal literals fail in strict mode. - // Check if the number is between 00 and 07. - var n = parseInt(this.peek(1), 10); - this.triggerAsync("warning", { - code: "W115", - line: this.line, - character: this.char - }, checks, - function () { return n >= 0 && n <= 7 && state.directive["use strict"]; }); - break; - case "u": - char = String.fromCharCode(parseInt(this.input.substr(1, 4), 16)); - jump = 5; - break; - case "v": - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\v" ] - }, checks, function () { return state.jsonMode; }); - - char = "\v"; - break; - case "x": - var x = parseInt(this.input.substr(1, 2), 16); - - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\x-" ] - }, checks, function () { return state.jsonMode; }); - - char = String.fromCharCode(x); - jump = 3; - break; - case "\\": - char = "\\\\"; - break; - case "\"": - char = "\\\""; - break; - case "/": - break; - case "": - allowNewLine = true; - char = ""; - break; - case "!": - if (value.slice(value.length - 2) === "<") { - break; - } - - /*falls through */ - default: - // Weird escaping. - this.trigger("warning", { - code: "W044", - line: this.line, - character: this.char - }); - } + var parsed = this.scanEscapeSequence(checks); + char = parsed.char; + jump = parsed.jump; + allowNewLine = parsed.allowNewLine; } value += char; @@ -7672,7 +8006,7 @@ Lexer.prototype = { }, /* - * Scan for any occurence of non-breaking spaces. Non-breaking spaces + * Scan for any occurrence of non-breaking spaces. Non-breaking spaces * can be mistakenly typed on OS X with option-space. Non UTF-8 web * pages with non-breaking pages produce syntax errors. */ @@ -7711,7 +8045,7 @@ Lexer.prototype = { var match = this.scanComments() || this.scanStringLiteral(checks) || - this.scanTemplateLiteral(); + this.scanTemplateLiteral(checks); if (match) { return match; @@ -7727,7 +8061,7 @@ Lexer.prototype = { this.scanNumericLiteral(); if (match) { - this.skip(match.value.length); + this.skip(match.tokenLength || match.value.length); return match; } @@ -7769,7 +8103,7 @@ Lexer.prototype = { // If we are ignoring linter errors, replace the input with empty string // if it doesn't already at least start or end a multi-line comment if (state.ignoreLinterErrors === true) { - if (!startsWith("/*", "//") && !endsWith("*/")) { + if (!startsWith("/*", "//") && !(this.inComment && endsWith("*/"))) { this.input = ""; } } @@ -7814,7 +8148,7 @@ Lexer.prototype = { /* * Produce the next token. This function is called by advance() to get - * the next token. It retuns a token in a JSLint-compatible format. + * the next token. It returns a token in a JSLint-compatible format. */ token: function () { /*jshint loopfunc:true */ @@ -7851,7 +8185,7 @@ Lexer.prototype = { } // Produce a token object. - var create = function (type, value, isProperty) { + var create = function (type, value, isProperty, token) { /*jshint validthis:true */ var obj; @@ -7866,6 +8200,8 @@ Lexer.prototype = { case "~": case "#": case "]": + case "++": + case "--": this.prereg = false; break; default: @@ -7900,6 +8236,7 @@ Lexer.prototype = { obj.line = this.line; obj.character = this.char; obj.from = this.from; + if (obj.identifier && token) obj.raw_text = token.text || token.value; if (isProperty && obj.identifier) { obj.isProperty = isProperty; @@ -7945,8 +8282,8 @@ Lexer.prototype = { return create("(string)", token.value); - case Token.TemplateLiteral: - this.trigger("Template", { + case Token.TemplateHead: + this.trigger("TemplateHead", { line: this.line, char: this.char, from: this.from, @@ -7954,12 +8291,31 @@ Lexer.prototype = { }); return create("(template)", token.value); + case Token.TemplateMiddle: + this.trigger("TemplateMiddle", { + line: this.line, + char: this.char, + from: this.from, + value: token.value + }); + return create("(template middle)", token.value); + + case Token.TemplateTail: + this.trigger("TemplateTail", { + line: this.line, + char: this.char, + from: this.from, + value: token.value + }); + return create("(template tail)", token.value); + case Token.Identifier: this.trigger("Identifier", { line: this.line, char: this.char, from: this.form, name: token.value, + raw_name: token.text, isProperty: state.tokens.curr.id === "." }); @@ -7967,7 +8323,7 @@ Lexer.prototype = { case Token.Keyword: case Token.NullLiteral: case Token.BooleanLiteral: - return create("(identifier)", token.value, state.tokens.curr.id === "."); + return create("(identifier)", token.value, state.tokens.curr.id === ".", token); case Token.NumericLiteral: if (token.isMalformed) { @@ -7991,7 +8347,7 @@ Lexer.prototype = { line: this.line, character: this.char }, checks, function () { - return state.directive["use strict"] && token.base === 8; + return state.directive["use strict"] && token.base === 8 && token.isLegacy; }); this.trigger("Number", { @@ -8039,7 +8395,7 @@ Lexer.prototype = { exports.Lexer = Lexer; }, -{"../data/ascii-identifier-data.js":1,"./reg.js":6,"./state.js":7,"events":10,"underscore":2}], +{"../data/ascii-identifier-data.js":1,"./reg.js":8,"./state.js":9,"events":12,"underscore":2}], 5:[function(_dereq_,module,exports){ "use strict"; @@ -8110,7 +8466,9 @@ var errors = { E049: "A {a} cannot be named '{b}'.", E050: "Mozilla requires the yield expression to be parenthesized here.", E051: "Regular parameters cannot come after default parameters.", - E052: "Unclosed template literal." + E052: "Unclosed template literal.", + E053: "Export declaration must be in global scope.", + E054: "Class properties must be methods. Expected '(' but instead saw '{a}'." }; var warnings = { @@ -8156,7 +8514,7 @@ var warnings = { W041: "Use '{a}' to compare with '{b}'.", W042: "Avoid EOL escaping.", W043: "Bad escaping of EOL. Use option multistr if needed.", - W044: "Bad or unnecessary escaping.", + W044: "Bad or unnecessary escaping.", /* TODO(caitp): remove W044 */ W045: "Bad number '{a}'.", W046: "Don't use extra leading zeros '{a}'.", W047: "A trailing decimal point can be confused with a dot: '{a}'.", @@ -8189,7 +8547,7 @@ var warnings = { W072: "This function has too many parameters. ({a})", W073: "Blocks are nested too deeply. ({a})", W074: "This function's cyclomatic complexity is too high. ({a})", - W075: "Duplicate key '{a}'.", + W075: "Duplicate {a} '{b}'.", W076: "Unexpected parameter '{a}' in get {b} function.", W077: "Expected a single parameter in set {a} function.", W078: "Setter is defined without getter.", @@ -8240,7 +8598,10 @@ var warnings = { W122: "Invalid typeof value '{a}'", W123: "'{a}' is already defined in outer scope.", W124: "A generator function shall contain a yield statement.", - W125: "This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp" + W125: "This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp", + W126: "Grouping operator is unnecessary for lone expressions.", + W127: "Unexpected use of a comma operator.", + W128: "Empty array elements require elision=true." }; var info = { @@ -8268,13 +8629,978 @@ _.each(info, function (desc, code) { }, {"underscore":2}], 6:[function(_dereq_,module,exports){ +"use strict"; + +function NameStack() { + this._stack = []; +} + +Object.defineProperty(NameStack.prototype, "length", { + get: function() { + return this._stack.length; + } +}); + +/** + * Create a new entry in the stack. Useful for tracking names across + * expressions. + */ +NameStack.prototype.push = function() { + this._stack.push(null); +}; + +/** + * Discard the most recently-created name on the stack. + */ +NameStack.prototype.pop = function() { + this._stack.pop(); +}; + +/** + * Update the most recent name on the top of the stack. + * + * @param {object} token The token to consider as the source for the most + * recent name. + */ +NameStack.prototype.set = function(token) { + this._stack[this.length - 1] = token; +}; + +/** + * Generate a string representation of the most recent name. + * + * @returns {string} + */ +NameStack.prototype.infer = function() { + var nameToken = this._stack[this.length - 1]; + var prefix = ""; + var type; + + // During expected operation, the topmost entry on the stack will only + // reflect the current function's name when the function is declared without + // the `function` keyword (i.e. for in-line accessor methods). In other + // cases, the `function` expression itself will introduce an empty entry on + // the top of the stack, and this should be ignored. + if (!nameToken || nameToken.type === "class") { + nameToken = this._stack[this.length - 2]; + } + + if (!nameToken) { + return "(empty)"; + } + + type = nameToken.type; + + if (type !== "(string)" && type !== "(number)" && type !== "(identifier)" && type !== "default") { + return "(expression)"; + } + + if (nameToken.accessorType) { + prefix = nameToken.accessorType + " "; + } + + return prefix + nameToken.value; +}; + +module.exports = NameStack; + +}, +{}], +7:[function(_dereq_,module,exports){ +"use strict"; + +// These are the JSHint boolean options. +exports.bool = { + enforcing: { + + /** + * This option prohibits the use of bitwise operators such as `^` (XOR), + * `|` (OR) and others. Bitwise operators are very rare in JavaScript + * programs and quite often `&` is simply a mistyped `&&`. + */ + bitwise : true, + + /** + * + * This options prohibits overwriting prototypes of native objects such as + * `Array`, `Date` and so on. + * + * // jshint freeze:true + * Array.prototype.count = function (value) { return 4; }; + * // -> Warning: Extending prototype of native object: 'Array'. + */ + freeze : true, + + /** + * This option allows you to force all variable names to use either + * camelCase style or UPPER_CASE with underscores. + */ + camelcase : true, + + /** + * This option requires you to always put curly braces around blocks in + * loops and conditionals. JavaScript allows you to omit curly braces when + * the block consists of only one statement, for example: + * + * while (day) + * shuffle(); + * + * However, in some circumstances, it can lead to bugs (you'd think that + * `sleep()` is a part of the loop while in reality it is not): + * + * while (day) + * shuffle(); + * sleep(); + */ + curly : true, + + /** + * This options prohibits the use of `==` and `!=` in favor of `===` and + * `!==`. The former try to coerce values before comparing them which can + * lead to some unexpected results. The latter don't do any coercion so + * they are generally safer. If you would like to learn more about type + * coercion in JavaScript, we recommend [Truth, Equality and + * JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/) + * by Angus Croll. + */ + eqeqeq : true, + + /** + * This option suppresses warnings about invalid `typeof` operator values. + * This operator has only [a limited set of possible return + * values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof). + * By default, JSHint warns when you compare its result with an invalid + * value which often can be a typo. + * + * // 'fuction' instead of 'function' + * if (typeof a == "fuction") { // Invalid typeof value 'fuction' + * // ... + * } + * + * Do not use this option unless you're absolutely sure you don't want + * these checks. + */ + notypeof : true, + + /** + * This option tells JSHint that your code needs to adhere to ECMAScript 3 + * specification. Use this option if you need your program to be executable + * in older browsers—such as Internet Explorer 6/7/8/9—and other legacy + * JavaScript environments. + */ + es3 : true, + + /** + * This option enables syntax first defined in [the ECMAScript 5.1 + * specification](http://es5.github.io/). This includes allowing reserved + * keywords as object properties. + */ + es5 : true, + + /** + * This option requires all `for in` loops to filter object's items. The + * for in statement allows for looping through the names of all of the + * properties of an object including those inherited through the prototype + * chain. This behavior can lead to unexpected items in your object so it + * is generally safer to always filter inherited properties out as shown in + * the example: + * + * for (key in obj) { + * if (obj.hasOwnProperty(key)) { + * // We are sure that obj[key] belongs to the object and was not inherited. + * } + * } + * + * For more in-depth understanding of `for in` loops in JavaScript, read + * [Exploring JavaScript for-in + * loops](http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/) + * by Angus Croll. + */ + forin : true, + + /** + * This option suppresses warnings about declaring variables inside of + * control + * structures while accessing them later from the outside. Even though + * JavaScript has only two real scopes—global and function—such practice + * leads to confusion among people new to the language and hard-to-debug + * bugs. This is why, by default, JSHint warns about variables that are + * used outside of their intended scope. + * + * function test() { + * if (true) { + * var x = 0; + * } + * + * x += 1; // Default: 'x' used out of scope. + * // No warning when funcscope:true + * } + */ + funcscope : true, + + /** + * This option suppresses warnings about the use of global strict mode. + * Global strict mode can break third-party widgets so it is not + * recommended. + * + * For more info about strict mode see the `strict` option. + */ + globalstrict: true, + + /** + * This option prohibits the use of immediate function invocations without + * wrapping them in parentheses. Wrapping parentheses assists readers of + * your code in understanding that the expression is the result of a + * function, and not the function itself. + */ + immed : true, + + /** + * This option suppresses warnings about the `__iterator__` property. This + * property is not supported by all browsers so use it carefully. + */ + iterator : true, + + /** + * This option requires you to capitalize names of constructor functions. + * Capitalizing functions that are intended to be used with `new` operator + * is just a convention that helps programmers to visually distinguish + * constructor functions from other types of functions to help spot + * mistakes when using `this`. + * + * Not doing so won't break your code in any browsers or environments but + * it will be a bit harder to figure out—by reading the code—if the + * function was supposed to be used with or without new. And this is + * important because when the function that was intended to be used with + * `new` is used without it, `this` will point to the global object instead + * of a new object. + */ + newcap : true, + + /** + * This option prohibits the use of `arguments.caller` and + * `arguments.callee`. Both `.caller` and `.callee` make quite a few + * optimizations impossible so they were deprecated in future versions of + * JavaScript. In fact, ECMAScript 5 forbids the use of `arguments.callee` + * in strict mode. + */ + noarg : true, + + /** + * This option prohibits the use of the comma operator. When misused, the + * comma operator can obscure the value of a statement and promote + * incorrect code. + */ + nocomma : true, + + /** + * This option warns when you have an empty block in your code. JSLint was + * originally warning for all empty blocks and we simply made it optional. + * There were no studies reporting that empty blocks in JavaScript break + * your code in any way. + */ + noempty : true, + + /** + * This option warns about "non-breaking whitespace" characters. These + * characters can be entered with option-space on Mac computers and have a + * potential of breaking non-UTF8 web pages. + */ + nonbsp : true, + + /** + * This option prohibits the use of constructor functions for side-effects. + * Some people like to call constructor functions without assigning its + * result to any variable: + * + * new MyConstructor(); + * + * There is no advantage in this approach over simply calling + * `MyConstructor` since the object that the operator `new` creates isn't + * used anywhere so you should generally avoid constructors like this one. + */ + nonew : true, + + /** + * This option prohibits the use of explicitly undeclared variables. This + * option is very useful for spotting leaking and mistyped variables. + * + * // jshint undef:true + * + * function test() { + * var myVar = 'Hello, World'; + * console.log(myvar); // Oops, typoed here. JSHint with undef will complain + * } + * + * If your variable is defined in another file, you can use the `global` + * directive to tell JSHint about it. + */ + undef : true, + + /** + * This option prohibits the use of the grouping operator for + * single-expression statements. This unecessary usage commonly reflects + * a misunderstanding of unary operators, for example: + * + * // jshint singleGroups: true + * + * delete(obj.attr); // Warning: Grouping operator is unnecessary for lone expressions. + */ + singleGroups: false, + + /** + * This option is a short hand for the most strict JSHint configuration. It + * enables all enforcing options and disables all relaxing options. + */ + enforceall : false + }, + relaxing: { + + /** + * This option suppresses warnings about missing semicolons. There is a lot + * of FUD about semicolon spread by quite a few people in the community. + * The common myths are that semicolons are required all the time (they are + * not) and that they are unreliable. JavaScript has rules about semicolons + * which are followed by *all* browsers so it is up to you to decide + * whether you should or should not use semicolons in your code. + * + * For more information about semicolons in JavaScript read [An Open Letter + * to JavaScript Leaders Regarding + * Semicolons](http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding) + * by Isaac Schlueter and [JavaScript Semicolon + * Insertion](http://inimino.org/~inimino/blog/javascript_semicolons). + */ + asi : true, + + /** + * This option suppresses warnings about multi-line strings. Multi-line + * strings can be dangerous in JavaScript because all hell breaks loose if + * you accidentally put a whitespace in between the escape character (`\`) + * and a new line. + * + * Note that even though this option allows correct multi-line strings, it + * still warns about multi-line strings without escape characters or with + * anything in between the escape character and a whitespace. + * + * // jshint multistr:true + * + * var text = "Hello\ + * World"; // All good. + * + * text = "Hello + * World"; // Warning, no escape character. + * + * text = "Hello\ + * World"; // Warning, there is a space after \ + */ + multistr : true, + + /** + * This option suppresses warnings about the `debugger` statements in your + * code. + */ + debug : true, + + /** + * This option suppresses warnings about the use of assignments in cases + * where comparisons are expected. More often than not, code like `if (a = + * 10) {}` is a typo. However, it can be useful in cases like this one: + * + * for (var i = 0, person; person = people[i]; i++) {} + * + * You can silence this error on a per-use basis by surrounding the assignment + * with parenthesis, such as: + * + * for (var i = 0, person; (person = people[i]); i++) {} + */ + boss : true, + + /** + * This option defines globals available when your core is running inside + * of the PhantomJS runtime environment. [PhantomJS](http://phantomjs.org/) + * is a headless WebKit scriptable with a JavaScript API. It has fast and + * native support for various web standards: DOM handling, CSS selector, + * JSON, Canvas, and SVG. + */ + phantom : true, + + /** + * This option suppresses warnings about the use of `eval`. The use of + * `eval` is discouraged because it can make your code vulnerable to + * various injection attacks and it makes it hard for JavaScript + * interpreter to do certain optimizations. + */ + evil : true, + + /** + * This option prohibits the use of unary increment and decrement + * operators. Some people think that `++` and `--` reduces the quality of + * their coding styles and there are programming languages—such as + * Python—that go completely without these operators. + */ + plusplus : true, + + /** + * This option suppresses warnings about the `__proto__` property. + */ + proto : true, + + /** + * This option suppresses warnings about the use of script-targeted + * URLs—such as `javascript:...`. + */ + scripturl : true, + + /** + * This option requires all functions to run in ECMAScript 5's strict mode. + * [Strict mode](https://developer.mozilla.org/en/JavaScript/Strict_mode) + * is a way to opt in to a restricted variant of JavaScript. Strict mode + * eliminates some JavaScript pitfalls that didn't cause errors by changing + * them to produce errors. It also fixes mistakes that made it difficult + * for the JavaScript engines to perform certain optimizations. + * + * *Note:* This option enables strict mode for function scope only. It + * *prohibits* the global scoped strict mode because it might break + * third-party widgets on your page. If you really want to use global + * strict mode, see the *globalstrict* option. + */ + strict : true, + + /** + * This option suppresses warnings about using `[]` notation when it can be + * expressed in dot notation: `person['name']` vs. `person.name`. + */ + sub : true, + + /** + * This option suppresses warnings about "weird" constructions like + * `new function () { ... }` and `new Object;`. Such constructions are + * sometimes used to produce singletons in JavaScript: + * + * var singleton = new function() { + * var privateVar; + * + * this.publicMethod = function () {} + * this.publicMethod2 = function () {} + * }; + */ + supernew : true, + + /** + * This option suppresses most of the warnings about possibly unsafe line + * breakings in your code. It doesn't suppress warnings about comma-first + * coding style. To suppress those you have to use `laxcomma` (see below). + */ + laxbreak : true, + + /** + * This option suppresses warnings about comma-first coding style: + * + * var obj = { + * name: 'Anton' + * , handle: 'valueof' + * , role: 'SW Engineer' + * }; + */ + laxcomma : true, + + /** + * This option suppresses warnings about possible strict violations when + * the code is running in strict mode and you use `this` in a + * non-constructor function. You should use this option—in a function scope + * only—when you are positive that your use of `this` is valid in the + * strict mode (for example, if you call your function using + * `Function.call`). + * + * **Note:** This option can be used only inside of a function scope. + * JSHint will fail with an error if you will try to set this option + * globally. + */ + validthis : true, + + /** + * This option suppresses warnings about the use of the `with` statement. + * The semantics of the `with` statement can cause confusion among + * developers and accidental definition of global variables. + * + * More info: + * + * * [with Statement Considered + * Harmful](http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/) + */ + withstmt : true, + + /** + * This options tells JSHint that your code uses Mozilla JavaScript + * extensions. Unless you develop specifically for the Firefox web browser + * you don't need this option. + * + * More info: + * + * * [New in JavaScript + * 1.7](https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7) + */ + moz : true, + + /** + * This option suppresses warnings about generator functions with no + * `yield` statement in them. + */ + noyield : true, + + /** + * This option suppresses warnings about `== null` comparisons. Such + * comparisons are often useful when you want to check if a variable is + * `null` or `undefined`. + */ + eqnull : true, + + /** + * This option suppresses warnings about missing semicolons, but only when + * the semicolon is omitted for the last statement in a one-line block: + * + * var name = (function() { return 'Anton' }()); + * + * This is a very niche use case that is useful only when you use automatic + * JavaScript code generators. + */ + lastsemic : true, + + /** + * This option suppresses warnings about functions inside of loops. + * Defining functions inside of loops can lead to bugs such as this one: + * + * var nums = []; + * + * for (var i = 0; i < 10; i++) { + * nums[i] = function (j) { + * return i + j; + * }; + * } + * + * nums[0](2); // Prints 12 instead of 2 + * + * To fix the code above you need to copy the value of `i`: + * + * var nums = []; + * + * for (var i = 0; i < 10; i++) { + * (function (i) { + * nums[i] = function (j) { + * return i + j; + * }; + * }(i)); + * } + */ + loopfunc : true, + + /** + * This option suppresses warnings about the use of expressions where + * normally you would expect to see assignments or function calls. Most of + * the time, such code is a typo. However, it is not forbidden by the spec + * and that's why this warning is optional. + */ + expr : true, + + /** + * This option tells JSHint that your code uses ECMAScript 6 specific + * syntax. Note that these features are not finalized yet and not all + * browsers implement them. + * + * More info: + * + * * [Draft Specification for ES.next (ECMA-262 Ed. + * 6)](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts) + */ + esnext : true, + + /** + * This option tells JSHint that your code uses ES3 array elision elements, + * or empty elements (for example, `[1, , , 4, , , 7]`). + */ + elision : true, + }, + + // Third party globals + environments: { + + /** + * This option defines globals exposed by the + * [MooTools](http://mootools.net/) JavaScript framework. + */ + mootools : true, + + /** + * This option defines globals exposed by + * [CouchDB](http://couchdb.apache.org/). CouchDB is a document-oriented + * database that can be queried and indexed in a MapReduce fashion using + * JavaScript. + */ + couch : true, + + /** + * This option defines globals exposed by [the Jasmine unit testing + * framework](https://jasmine.github.io/). + */ + jasmine : true, + + /** + * This option defines globals exposed by the [jQuery](http://jquery.com/) + * JavaScript library. + */ + jquery : true, + + /** + * This option defines globals available when your code is running inside + * of the Node runtime environment. [Node.js](http://nodejs.org/) is a + * server-side JavaScript environment that uses an asynchronous + * event-driven model. This option also skips some warnings that make sense + * in the browser environments but don't make sense in Node such as + * file-level `use strict` pragmas and `console.log` statements. + */ + node : true, + + /** + * This option defines globals exposed by [the QUnit unit testing + * framework](http://qunitjs.com/). + */ + qunit : true, + + /** + * This option defines globals available when your code is running inside + * of the Rhino runtime environment. [Rhino](http://www.mozilla.org/rhino/) + * is an open-source implementation of JavaScript written entirely in Java. + */ + rhino : true, + + /** + * This option defines globals exposed by [the ShellJS + * library](http://documentup.com/arturadib/shelljs). + */ + shelljs : true, + + /** + * This option defines globals exposed by the + * [Prototype](http://www.prototypejs.org/) JavaScript framework. + */ + prototypejs : true, + + /** + * This option defines globals exposed by the [YUI](http://yuilibrary.com/) + * JavaScript framework. + */ + yui : true, + + /** + * This option defines globals exposed by the "BDD" and "TDD" UIs of the + * [Mocha unit testing framework](http://mochajs.org/). + */ + mocha : true, + + /** + * This option defines globals available when your code is running as a + * script for the [Windows Script + * Host](http://en.wikipedia.org/wiki/Windows_Script_Host). + */ + wsh : true, + + /** + * This option defines globals available when your code is running inside + * of a Web Worker. [Web + * Workers](https://developer.mozilla.org/en/Using_web_workers) provide a + * simple means for web content to run scripts in background threads. + */ + worker : true, + + /** + * This option defines non-standard but widely adopted globals such as + * `escape` and `unescape`. + */ + nonstandard : true, + + /** + * This option defines globals exposed by modern browsers: all the way from + * good old `document` and `navigator` to the HTML5 `FileReader` and other + * new developments in the browser world. + * + * **Note:** This option doesn't expose variables like `alert` or + * `console`. See option `devel` for more information. + */ + browser : true, + + /** + * This option defines globals available when using [the Browserify + * tool](http://browserify.org/) to build a project. + */ + browserify : true, + + /** + * This option defines globals that are usually used for logging poor-man's + * debugging: `console`, `alert`, etc. It is usually a good idea to not + * ship them in production because, for example, `console.log` breaks in + * legacy versions of Internet Explorer. + */ + devel : true, + + /** + * This option defines globals exposed by the [Dojo + * Toolkit](http://dojotoolkit.org/). + */ + dojo : true, + + /** + * This option defines globals for typed array constructors. + * + * More info: + * + * * [JavaScript typed + * arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays) + */ + typed : true + }, + + // Obsolete options + obsolete: { + onecase : true, // if one case switch statements should be allowed + regexp : true, // if the . should not be allowed in regexp literals + regexdash : true // if unescaped first/last dash (-) inside brackets + // should be tolerated + } +}; + +// These are the JSHint options that can take any value +// (we use this object to detect invalid options) +exports.val = { + + /** + * This option lets you set the maximum length of a line. + */ + maxlen : false, + + /** + * This option sets a specific tab width for your code. + */ + indent : false, + + /** + * This options allows you to set the maximum amount of warnings JSHint will + * produce before giving up. Default is 50. + */ + maxerr : false, + + predef : false, // predef is deprecated and being replaced by globals + + /** + * This option can be used to specify a white list of global variables that + * are not formally defined in the source code. This is most useful when + * combined with the `undef` option in order to suppress warnings for + * project-specific global variables. + * + * Setting an entry to `true` enables reading and writing to that variable. + * Setting it to `false` will trigger JSHint to consider that variable + * read-only. + * + * See also the "environment" options: a set of options to be used as short + * hand for enabling global variables defined in common JavaScript + * environments. + */ + globals : false, + + /** + * This option enforces the consistency of quotation marks used throughout + * your code. It accepts three values: `true` if you don't want to enforce + * one particular style but want some consistency, `"single"` if you want to + * allow only single quotes and `"double"` if you want to allow only double + * quotes. + */ + quotmark : false, + + scope : false, + + /** + * This option lets you set the max number of statements allowed per function: + * + * // jshint maxstatements:4 + * + * function main() { + * var i = 0; + * var j = 0; + * + * // Function declarations count as one statement. Their bodies + * // don't get taken into account for the outer function. + * function inner() { + * var i2 = 1; + * var j2 = 1; + * + * return i2 + j2; + * } + * + * j = i + j; + * return j; // JSHint: Too many statements per function. (5) + * } + */ + maxstatements: false, + + /** + * This option lets you control how nested do you want your blocks to be: + * + * // jshint maxdepth:2 + * + * function main(meaning) { + * var day = true; + * + * if (meaning === 42) { + * while (day) { + * shuffle(); + * + * if (tired) { // JSHint: Blocks are nested too deeply (3). + * sleep(); + * } + * } + * } + * } + */ + maxdepth : false, + + /** + * This option lets you set the max number of formal parameters allowed per + * function: + * + * // jshint maxparams:3 + * + * function login(request, onSuccess) { + * // ... + * } + * + * // JSHint: Too many parameters per function (4). + * function logout(request, isManual, whereAmI, onSuccess) { + * // ... + * } + */ + maxparams : false, + + /** + * This option lets you control cyclomatic complexity throughout your code. + * Cyclomatic complexity measures the number of linearly independent paths + * through a program's source code. Read more about [cyclomatic complexity on + * Wikipedia](http://en.wikipedia.org/wiki/Cyclomatic_complexity). + */ + maxcomplexity: false, + + /** + * This option suppresses warnings about variable shadowing i.e. declaring a + * variable that had been already declared somewhere in the outer scope. + * + * - "inner" - check for variables defined in the same scope only + * - "outer" - check for variables defined in outer scopes as well + * - false - same as inner + * - true - allow variable shadowing + */ + shadow : false, + + /** + * This option warns when you define and never use your variables. It is very + * useful for general code cleanup, especially when used in addition to + * `undef`. + * + * // jshint unused:true + * + * function test(a, b) { + * var c, d = 2; + * + * return a + d; + * } + * + * test(1, 2); + * + * // Line 3: 'b' was defined but never used. + * // Line 4: 'c' was defined but never used. + * + * In addition to that, this option will warn you about unused global + * variables declared via the `global` directive. + * + * This can be set to `vars` to only check for variables, not function + * parameters, or `strict` to check all variables and parameters. The + * default (true) behavior is to allow unused parameters that are followed by + * a used parameter. + */ + unused : true, + + /** + * This option prohibits the use of a variable before it was defined. + * JavaScript has function scope only and, in addition to that, all variables + * are always moved—or hoisted— to the top of the function. This behavior can + * lead to some very nasty bugs and that's why it is safer to always use + * variable only after they have been explicitly defined. + * + * Setting this option to "nofunc" will allow function declarations to be + * ignored. + * + * For more in-depth understanding of scoping and hoisting in JavaScript, + * read [JavaScript Scoping and + * Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) + * by Ben Cherry. + */ + latedef : false, + + ignore : false, // start/end ignoring lines of code, bypassing the lexer + // start - start ignoring lines, including the current line + // end - stop ignoring lines, starting on the next line + // line - ignore warnings / errors for just a single line + // (this option does not bypass the lexer) + ignoreDelimiters: false // array of start/end delimiters used to ignore + // certain chunks from code +}; + +// These are JSHint boolean options which are shared with JSLint +// where the definition in JSHint is opposite JSLint +exports.inverted = { + bitwise : true, + forin : true, + newcap : true, + plusplus: true, + regexp : true, + undef : true, + + // Inverted and renamed, use JSHint name here + eqeqeq : true, + strict : true +}; + +exports.validNames = Object.keys(exports.val) + .concat(Object.keys(exports.bool.relaxing)) + .concat(Object.keys(exports.bool.enforcing)) + .concat(Object.keys(exports.bool.obsolete)) + .concat(Object.keys(exports.bool.environments)); + +// These are JSHint boolean options which are shared with JSLint +// where the name has been changed but the effect is unchanged +exports.renamed = { + eqeq : "eqeqeq", + windows: "wsh", + sloppy : "strict" +}; + +exports.removed = { + nomen: true, + onevar: true, + passfail: true, + white: true, + gcl: true, + smarttabs: true, + trailing: true +}; + +}, +{}], +8:[function(_dereq_,module,exports){ /* * Regular expressions. Some of these are stupidly long. */ /*jshint maxlen:1000 */ -"use string"; +"use strict"; // Unsafe comment or string (ax) exports.unsafeString = @@ -8309,8 +9635,9 @@ exports.maxlenException = /^(?:(?:\/\/|\/\*|\*) ?)?[^ ]+$/; }, {}], -7:[function(_dereq_,module,exports){ +9:[function(_dereq_,module,exports){ "use strict"; +var NameStack = _dereq_("./name-stack.js"); var state = { syntax: {}, @@ -8331,6 +9658,8 @@ var state = { this.tab = ""; this.cache = {}; // Node.JS doesn't have Map. Sniff. this.ignoredLines = {}; + this.forinifcheckneeded = false; + this.nameStack = new NameStack(); // Blank out non-multi-line-commented lines when ignoring linter errors this.ignoreLinterErrors = false; @@ -8340,8 +9669,8 @@ var state = { exports.state = state; }, -{}], -8:[function(_dereq_,module,exports){ +{"./name-stack.js":6}], +10:[function(_dereq_,module,exports){ "use strict"; exports.register = function (linter) { @@ -8400,12 +9729,18 @@ exports.register = function (linter) { linter.on("String", function style_scanQuotes(data) { var quotmark = linter.getOption("quotmark"); + var esnext = linter.getOption("esnext"); var code; if (!quotmark) { return; } + // If quotmark is enabled, return if this is a template literal. + if (esnext && data.quote === "`") { + return; + } + // If quotmark is set to 'single' warn about all double-quotes. if (quotmark === "single" && data.quote !== "'") { @@ -8488,7 +9823,7 @@ exports.register = function (linter) { }, {}], -9:[function(_dereq_,module,exports){ +11:[function(_dereq_,module,exports){ // jshint -W001 "use strict"; @@ -8516,18 +9851,24 @@ exports.ecmaIdentifiers = { isFinite : false, isNaN : false, JSON : false, + Map : false, Math : false, Number : false, Object : false, + Proxy : false, + Promise : false, parseInt : false, parseFloat : false, RangeError : false, ReferenceError : false, RegExp : false, + Set : false, String : false, SyntaxError : false, TypeError : false, URIError : false, + WeakMap : false, + WeakSet : false }; exports.newEcmaIdentifiers = { @@ -8536,7 +9877,10 @@ exports.newEcmaIdentifiers = { WeakMap : false, WeakSet : false, Proxy : false, - Promise : false + Promise : false, + Reflect : false, + Symbol : false, + System : false }; // Global variables commonly provided by a web browser environment. @@ -8549,9 +9893,11 @@ exports.browser = { atob : false, blur : false, btoa : false, + cancelAnimationFrame : false, CanvasGradient : false, CanvasPattern : false, CanvasRenderingContext2D: false, + CSS : false, clearInterval : false, clearTimeout : false, close : false, @@ -8559,9 +9905,11 @@ exports.browser = { CustomEvent : false, DOMParser : false, defaultStatus : false, + Document : false, document : false, Element : false, ElementTimeControl : false, + Event : false, event : false, FileReader : false, FormData : false, @@ -8624,6 +9972,7 @@ exports.browser = { HTMLVideoElement : false, history : false, Image : false, + Intl : false, length : false, localStorage : false, location : false, @@ -8653,6 +10002,7 @@ exports.browser = { Option : false, parent : false, print : false, + requestAnimationFrame : false, removeEventListener : false, resizeBy : false, resizeTo : false, @@ -8820,12 +10170,26 @@ exports.browser = { SVGViewElement : false, SVGViewSpec : false, SVGZoomAndPan : false, + TextDecoder : false, + TextEncoder : false, TimeEvent : false, top : false, URL : false, + WebGLActiveInfo : false, + WebGLBuffer : false, + WebGLContextEvent : false, + WebGLFramebuffer : false, + WebGLProgram : false, + WebGLRenderbuffer : false, + WebGLRenderingContext: false, + WebGLShader : false, + WebGLShaderPrecisionFormat: false, + WebGLTexture : false, + WebGLUniformLocation : false, WebSocket : false, window : false, Worker : false, + XDomainRequest : false, XMLHttpRequest : false, XMLSerializer : false, XPathEvaluator : false, @@ -8846,9 +10210,10 @@ exports.devel = { }; exports.worker = { - importScripts: true, - postMessage : true, - self : true + importScripts : true, + postMessage : true, + self : true, + FileReaderSync : true }; // Widely adopted global names that are not part of ECMAScript standard @@ -8896,6 +10261,17 @@ exports.node = { clearImmediate: true // v0.9.1+ }; +exports.browserify = { + __filename : false, + __dirname : false, + global : false, + module : false, + require : false, + Buffer : true, + exports : true, + process : true +}; + exports.phantom = { phantom : true, require : true, @@ -9125,10 +10501,12 @@ exports.mocha = { beforeEach : false, afterEach : false, // TDD - suite : false, - test : false, - setup : false, - teardown : false + suite : false, + test : false, + setup : false, + teardown : false, + suiteSetup : false, + suiteTeardown : false }; exports.jasmine = { @@ -9145,12 +10523,18 @@ exports.jasmine = { // Jasmine 1.3 runs : false, waitsFor : false, - waits : false + waits : false, + // Jasmine 2.1 + beforeAll : false, + afterAll : false, + fail : false, + fdescribe : false, + fit : false }; }, {}], -10:[function(_dereq_,module,exports){ +12:[function(_dereq_,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -9298,7 +10682,10 @@ EventEmitter.prototype.addListener = function(type, listener) { 'leak detected. %d listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.', this._events[type].length); - console.trace(); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } } } From 55bf8e56d3df192127119621742f7a9e193fa692 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 7 Jan 2015 01:15:36 +0400 Subject: [PATCH 18/26] fix highlighting of ?" in ruby mode --- demo/kitchen-sink/docs/ruby.rb | 2 +- lib/ace/mode/_test/text_ruby.txt | 2 +- lib/ace/mode/_test/tokens_ruby.json | 12 ++++++++++-- lib/ace/mode/ruby_highlight_rules.js | 3 +++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/demo/kitchen-sink/docs/ruby.rb b/demo/kitchen-sink/docs/ruby.rb index c4d73d19..386fbb86 100644 --- a/demo/kitchen-sink/docs/ruby.rb +++ b/demo/kitchen-sink/docs/ruby.rb @@ -20,7 +20,7 @@ class Range end end -{:id => 34, :key => "value"} +{:id => ?", :key => "value"} herDocs = [<<'FOO', < 34, :key => "value"} +{:id => ?", :key => "value", anotherKey: [x, y?]} =begin =end diff --git a/lib/ace/mode/_test/tokens_ruby.json b/lib/ace/mode/_test/tokens_ruby.json index 1809f5ee..f9991e9c 100644 --- a/lib/ace/mode/_test/tokens_ruby.json +++ b/lib/ace/mode/_test/tokens_ruby.json @@ -139,7 +139,7 @@ ["text"," "], ["punctuation.separator.key-value","=>"], ["text"," "], - ["constant.numeric","34"], + ["string.character","?\""], ["text",", "], ["constant.other.symbol.ruby",":key"], ["text"," "], @@ -148,7 +148,15 @@ ["string.start","\""], ["string","value"], ["string.end","\""], - ["paren.rparen","}"] + ["text",", "], + ["identifier","anotherKey"], + ["text",": "], + ["paren.lparen","["], + ["identifier","x"], + ["text",", "], + ["identifier","y"], + ["text","?"], + ["paren.rparen","]}"] ],[ "start" ],[ diff --git a/lib/ace/mode/ruby_highlight_rules.js b/lib/ace/mode/ruby_highlight_rules.js index a1cb12f9..b78597db 100644 --- a/lib/ace/mode/ruby_highlight_rules.js +++ b/lib/ace/mode/ruby_highlight_rules.js @@ -288,6 +288,9 @@ var RubyHighlightRules = function() { return stack[0]; return currentState; } + }, { + token : "string.character", + regex : "\\B\\?." }, { token : "keyword.operator", regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)" From 5e4facea446e8743c106f924ad1968b2f946f087 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 11 Jan 2015 22:23:25 +0400 Subject: [PATCH 19/26] fix livescript highlighting --- lib/ace/mode/livescript.js | 13 +++++-------- tool/update_deps.js | 4 ++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/ace/mode/livescript.js b/lib/ace/mode/livescript.js index d692a6d3..d8330791 100644 --- a/lib/ace/mode/livescript.js +++ b/lib/ace/mode/livescript.js @@ -52,8 +52,7 @@ define(function(require, exports, module){ }(require('../mode/text').Mode)); keywordend = '(?![$\\w]|-[A-Za-z]|\\s*:(?![:=]))'; stringfill = { - token: 'string', - regex: '.+' + defaultToken: 'string' }; LiveScriptMode.Rules = { start: [ @@ -146,7 +145,7 @@ define(function(require, exports, module){ next: 'key' }, { token: 'keyword.operator', - regex: '\\S+' + regex: '[\\^!|&%+\\-]+' }, { token: 'text', regex: '\\s+' @@ -164,8 +163,7 @@ define(function(require, exports, module){ token: 'comment.regex', regex: '\\s+(?:#.*)?' }, { - token: 'string.regex', - regex: '\\S+' + defaultToken: 'string.regex' } ], key: [ @@ -178,7 +176,7 @@ define(function(require, exports, module){ next: 'start' }, { token: 'text', - regex: '.', + regex: '', next: 'start' } ], @@ -188,8 +186,7 @@ define(function(require, exports, module){ regex: '.*?\\*/', next: 'start' }, { - token: 'comment.doc', - regex: '.+' + defaultToken: 'comment.doc' } ], qdoc: [ diff --git a/tool/update_deps.js b/tool/update_deps.js index 09ea8766..d02581ae 100644 --- a/tool/update_deps.js +++ b/tool/update_deps.js @@ -135,6 +135,10 @@ var deps = { }); } }, + liveScript: { + path: "mode/livescript.js", + url: "https://raw.githubusercontent.com/gkz/LiveScript/master/lib/mode-ls.js" + }, coffee: { fetch: function(){ var rootHref = "https://raw.github.com/jashkenas/coffee-script/master/"; From e1a5492a7fc8cf27b9b7d6d9ba06700030a2e449 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 11 Jan 2015 22:27:12 +0400 Subject: [PATCH 20/26] do not throw error when trying to match tag at the end of the document --- lib/ace/editor.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 3bb2c0e4..5f9d10be 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -545,9 +545,12 @@ var Editor = function(renderer, session) { return; } - if (token.type.indexOf("tag-open") != -1) + if (token.type.indexOf("tag-open") != -1) { token = iterator.stepForward(); - + if (!token) + return; + } + var tag = token.value; var depth = 0; var prevToken = iterator.stepBackward(); From 264923e4dfe0c0c82035be462af2a1c31e8c6b78 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 11 Jan 2015 22:48:39 +0400 Subject: [PATCH 21/26] make worker events more consistent --- lib/ace/mode/coffee.js | 6 +++--- lib/ace/mode/coffee_worker.js | 7 +++---- lib/ace/mode/css.js | 2 +- lib/ace/mode/css_worker.js | 4 ++-- lib/ace/mode/javascript.js | 2 +- lib/ace/mode/javascript_worker.js | 10 ++++------ lib/ace/mode/json.js | 6 +++--- lib/ace/mode/json_worker.js | 7 +++---- lib/ace/mode/lua.js | 6 +++--- lib/ace/mode/lua_worker.js | 23 +++++++++++------------ lib/ace/mode/php.js | 4 ++-- lib/ace/mode/php_worker.js | 6 +----- 12 files changed, 37 insertions(+), 46 deletions(-) diff --git a/lib/ace/mode/coffee.js b/lib/ace/mode/coffee.js index 34c1a55a..e866f2b0 100644 --- a/lib/ace/mode/coffee.js +++ b/lib/ace/mode/coffee.js @@ -116,11 +116,11 @@ oop.inherits(Mode, TextMode); var worker = new WorkerClient(["ace"], "ace/mode/coffee_worker", "Worker"); worker.attachToDocument(session.getDocument()); - worker.on("error", function(e) { - session.setAnnotations([e.data]); + worker.on("annotate", function(e) { + session.setAnnotations(e.data); }); - worker.on("ok", function(e) { + worker.on("terminate", function() { session.clearAnnotations(); }); diff --git a/lib/ace/mode/coffee_worker.js b/lib/ace/mode/coffee_worker.js index a5f700f8..d68f1296 100644 --- a/lib/ace/mode/coffee_worker.js +++ b/lib/ace/mode/coffee_worker.js @@ -49,13 +49,13 @@ oop.inherits(Worker, Mirror); this.onUpdate = function() { var value = this.doc.getValue(); - + var errors = []; try { coffee.parse(value).compile(); } catch(e) { var loc = e.location; if (loc) { - this.sender.emit("error", { + errors.push({ row: loc.first_line, column: loc.first_column, endRow: loc.last_line, @@ -64,9 +64,8 @@ oop.inherits(Worker, Mirror); type: "error" }); } - return; } - this.sender.emit("ok"); + this.sender.emit("annotate", errors); }; }).call(Worker.prototype); diff --git a/lib/ace/mode/css.js b/lib/ace/mode/css.js index c74bd654..6fef5ccd 100644 --- a/lib/ace/mode/css.js +++ b/lib/ace/mode/css.js @@ -81,7 +81,7 @@ oop.inherits(Mode, TextMode); var worker = new WorkerClient(["ace"], "ace/mode/css_worker", "Worker"); worker.attachToDocument(session.getDocument()); - worker.on("csslint", function(e) { + worker.on("annotate", function(e) { session.setAnnotations(e.data); }); diff --git a/lib/ace/mode/css_worker.js b/lib/ace/mode/css_worker.js index 585faf63..ef327e79 100644 --- a/lib/ace/mode/css_worker.js +++ b/lib/ace/mode/css_worker.js @@ -80,11 +80,11 @@ oop.inherits(Worker, Mirror); this.onUpdate = function() { var value = this.doc.getValue(); if (!value) - return this.sender.emit("csslint", []); + return this.sender.emit("annotate", []); var infoRules = this.infoRules; var result = CSSLint.verify(value, this.ruleset); - this.sender.emit("csslint", result.messages.map(function(msg) { + this.sender.emit("annotate", result.messages.map(function(msg) { return { row: msg.line - 1, column: msg.col - 1, diff --git a/lib/ace/mode/javascript.js b/lib/ace/mode/javascript.js index af62ae76..b6ebe5a0 100644 --- a/lib/ace/mode/javascript.js +++ b/lib/ace/mode/javascript.js @@ -98,7 +98,7 @@ oop.inherits(Mode, TextMode); var worker = new WorkerClient(["ace"], "ace/mode/javascript_worker", "JavaScriptWorker"); worker.attachToDocument(session.getDocument()); - worker.on("jslint", function(results) { + worker.on("annotate", function(results) { session.setAnnotations(results.data); }); diff --git a/lib/ace/mode/javascript_worker.js b/lib/ace/mode/javascript_worker.js index e6503efc..fd5788e7 100644 --- a/lib/ace/mode/javascript_worker.js +++ b/lib/ace/mode/javascript_worker.js @@ -116,12 +116,10 @@ oop.inherits(JavaScriptWorker, Mirror); this.onUpdate = function() { var value = this.doc.getValue(); value = value.replace(/^#!.*\n/, "\n"); - if (!value) { - this.sender.emit("jslint", []); - return; - } - var errors = []; + if (!value) + return this.sender.emit("annotate", []); + var errors = []; // jshint reports many false errors // report them as error only if code is actually invalid var maxErrorLevel = this.isValidJS(value) ? "warning" : "error"; @@ -179,7 +177,7 @@ oop.inherits(JavaScriptWorker, Mirror); } // console.log("lint time: " + (new Date() - start)); - this.sender.emit("jslint", errors); + this.sender.emit("annotate", errors); }; }).call(JavaScriptWorker.prototype); diff --git a/lib/ace/mode/json.js b/lib/ace/mode/json.js index 24a43d0f..cfb00dab 100644 --- a/lib/ace/mode/json.js +++ b/lib/ace/mode/json.js @@ -74,11 +74,11 @@ oop.inherits(Mode, TextMode); var worker = new WorkerClient(["ace"], "ace/mode/json_worker", "JsonWorker"); worker.attachToDocument(session.getDocument()); - worker.on("error", function(e) { - session.setAnnotations([e.data]); + worker.on("annotate", function(e) { + session.setAnnotations(e.data); }); - worker.on("ok", function() { + worker.on("terminate", function() { session.clearAnnotations(); }); diff --git a/lib/ace/mode/json_worker.js b/lib/ace/mode/json_worker.js index 57fa1c10..168278ba 100644 --- a/lib/ace/mode/json_worker.js +++ b/lib/ace/mode/json_worker.js @@ -46,21 +46,20 @@ oop.inherits(JsonWorker, Mirror); this.onUpdate = function() { var value = this.doc.getValue(); - + var errors = []; try { if (value) parse(value); } catch (e) { var pos = this.doc.indexToPosition(e.at-1); - this.sender.emit("error", { + errors.push({ row: pos.row, column: pos.column, text: e.message, type: "error" }); - return; } - this.sender.emit("ok"); + this.sender.emit("annotate", errors); }; }).call(JsonWorker.prototype); diff --git a/lib/ace/mode/lua.js b/lib/ace/mode/lua.js index a8d1f08b..75e91982 100644 --- a/lib/ace/mode/lua.js +++ b/lib/ace/mode/lua.js @@ -148,11 +148,11 @@ oop.inherits(Mode, TextMode); var worker = new WorkerClient(["ace"], "ace/mode/lua_worker", "Worker"); worker.attachToDocument(session.getDocument()); - worker.on("error", function(e) { - session.setAnnotations([e.data]); + worker.on("annotate", function(e) { + session.setAnnotations(e.data); }); - worker.on("ok", function(e) { + worker.on("terminate", function() { session.clearAnnotations(); }); diff --git a/lib/ace/mode/lua_worker.js b/lib/ace/mode/lua_worker.js index 9c08f614..dcff9514 100644 --- a/lib/ace/mode/lua_worker.js +++ b/lib/ace/mode/lua_worker.js @@ -46,24 +46,23 @@ oop.inherits(Worker, Mirror); this.onUpdate = function() { var value = this.doc.getValue(); - - // var t=Date.now() + var errors = []; + + // var t=Date.now() try { luaparse.parse(value); } catch(e) { if (e instanceof SyntaxError) { - this.sender.emit("error", { - row: e.line - 1, - column: e.column, - text: e.message, - type: "error" - }); + errors.push({ + row: e.line - 1, + column: e.column, + text: e.message, + type: "error" + }); } - // console.log( t-Date.now()) - return; } - // console.log( t-Date.now()) - this.sender.emit("ok"); + // console.log( t-Date.now()) + this.sender.emit("annotate", errors); }; }).call(Worker.prototype); diff --git a/lib/ace/mode/php.js b/lib/ace/mode/php.js index c7688d43..39119e22 100644 --- a/lib/ace/mode/php.js +++ b/lib/ace/mode/php.js @@ -143,11 +143,11 @@ oop.inherits(Mode, HtmlMode); if (this.inlinePhp) worker.call("setOptions", [{inline: true}]); - worker.on("error", function(e) { + worker.on("annotate", function(e) { session.setAnnotations(e.data); }); - worker.on("ok", function() { + worker.on("terminate", function() { session.clearAnnotations(); }); diff --git a/lib/ace/mode/php_worker.js b/lib/ace/mode/php_worker.js index 878d88d6..c0bb1304 100644 --- a/lib/ace/mode/php_worker.js +++ b/lib/ace/mode/php_worker.js @@ -69,11 +69,7 @@ oop.inherits(PhpWorker, Mirror); // console.log("lint time: " + (new Date() - start)); - if (errors.length) { - this.sender.emit("error", errors); - } else { - this.sender.emit("ok"); - } + this.sender.emit("annotate", errors); }; }).call(PhpWorker.prototype); From b57f2e2ae31ab042fe58a0fbff9e7e003e103d88 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 11 Jan 2015 23:23:53 +0400 Subject: [PATCH 22/26] fix inline editor demo --- demo/kitchen-sink/inline_editor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo/kitchen-sink/inline_editor.js b/demo/kitchen-sink/inline_editor.js index 3f814c21..6b56887d 100644 --- a/demo/kitchen-sink/inline_editor.js +++ b/demo/kitchen-sink/inline_editor.js @@ -53,16 +53,16 @@ require("ace/commands/default_commands").commands.push({ return; } - var rowCount = 10; + var rowCount = 10; var w = { row: row, // rowCount: rowCount, fixedWidth: true, el: dom.createElement("div"), - editor: editor + editor: inlineEditor }; var el = w.el; - el.appendChild(inlineEditor.container); + el.appendChild(inlineEditor.container); if (!editor.session.widgetManager) { editor.session.widgetManager = new LineWidgets(editor.session); From 100022564c95ba25370cec02c2bf11bdecc79941 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 12 Jan 2015 01:13:27 +0400 Subject: [PATCH 23/26] cancel gatherCompletions if cursor position changes --- lib/ace/autocomplete.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index dd04426e..630130ba 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -43,6 +43,7 @@ var Autocomplete = function() { this.autoInsert = true; this.autoSelect = true; this.exactMatch = false; + this.gatherCompletionsId = 0; this.keyboardHandler = new HashHandler(); this.keyboardHandler.bindKeys(this.commands); @@ -59,7 +60,6 @@ var Autocomplete = function() { }; (function() { - this.gatherCompletionsId = 0; this.$init = function() { this.popup = new AcePopup(document.body || document.documentElement); @@ -84,6 +84,8 @@ var Autocomplete = function() { this.popup.setData(this.completions.filtered); + editor.keyBinding.addKeyboardHandler(this.keyboardHandler); + var renderer = editor.renderer; this.popup.setRow(this.autoSelect ? 0 : -1); if (!keepPopupPosition) { @@ -115,10 +117,9 @@ var Autocomplete = function() { this.changeTimer.cancel(); this.hideDocTooltip(); - if (this.popup && this.popup.isOpen) { - this.gatherCompletionsId += 1; + this.gatherCompletionsId += 1; + if (this.popup && this.popup.isOpen) this.popup.hide(); - } if (this.base) this.base.detach(); @@ -261,7 +262,6 @@ var Autocomplete = function() { editor.completer = this; } - editor.keyBinding.addKeyboardHandler(this.keyboardHandler); editor.on("changeSelection", this.changeListener); editor.on("blur", this.blurListener); editor.on("mousedown", this.mousedownListener); From 57f6fbd7689eeba0addbf828ec44272c0b695211 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 12 Jan 2015 02:12:00 +0400 Subject: [PATCH 24/26] tweak completer --- lib/ace/autocomplete.js | 6 +++--- lib/ace/ext/language_tools.js | 7 ++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 630130ba..460a62e6 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -40,7 +40,7 @@ var dom = require("./lib/dom"); var snippetManager = require("./snippets").snippetManager; var Autocomplete = function() { - this.autoInsert = true; + this.autoInsert = false; this.autoSelect = true; this.exactMatch = false; this.gatherCompletionsId = 0; @@ -408,10 +408,10 @@ Autocomplete.startCommand = { exec: function(editor) { if (!editor.completer) editor.completer = new Autocomplete(); - editor.completer.autoInsert = + editor.completer.autoInsert = false; editor.completer.autoSelect = true; editor.completer.showPopup(editor); - // needed for firefox on mac + // prevent ctrl-space opening context menu on firefox on mac editor.completer.cancelContextMenu(); }, bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js index 12fcf5b2..f02390ee 100644 --- a/lib/ace/ext/language_tools.js +++ b/lib/ace/ext/language_tools.js @@ -140,7 +140,7 @@ var loadSnippetFile = function(id) { function getCompletionPrefix(editor) { var pos = editor.getCursorPosition(); var line = editor.session.getLine(pos.row); - var prefix = util.retrievePrecedingIdentifier(line, pos.column); + var prefix; // Try to find custom prefixes on the completers editor.completers.forEach(function(completer) { if (completer.identifierRegexps) { @@ -150,7 +150,7 @@ function getCompletionPrefix(editor) { }); } }); - return prefix; + return prefix || util.retrievePrecedingIdentifier(line, pos.column); } var doLiveAutocomplete = function(e) { @@ -158,8 +158,6 @@ var doLiveAutocomplete = function(e) { var text = e.args || ""; var hasCompleter = editor.completer && editor.completer.activated; - - // We don't want to autocomplete with no prefix if (e.command.name === "backspace") { if (hasCompleter && !getCompletionPrefix(editor)) @@ -174,7 +172,6 @@ var doLiveAutocomplete = function(e) { editor.completer = new Autocomplete(); } // Disable autoInsert - editor.completer.autoSelect = false; editor.completer.autoInsert = false; editor.completer.showPopup(editor); } From eddc5563d8525ff33eb4edf2bb45af673276a019 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 12 Jan 2015 02:23:50 +0400 Subject: [PATCH 25/26] update json worker tests --- lib/ace/mode/json_worker_test.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/ace/mode/json_worker_test.js b/lib/ace/mode/json_worker_test.js index b4a8610d..7113342d 100644 --- a/lib/ace/mode/json_worker_test.js +++ b/lib/ace/mode/json_worker_test.js @@ -58,7 +58,7 @@ module.exports = { worker.setValue("{}"); worker.deferredUpdate.call(); - assert.equal(this.sender.events[0][0], "ok"); + assert.equal(this.sender.events[0][1].length, 0); }, "test check for syntax error": function() { @@ -71,11 +71,12 @@ module.exports = { worker.deferredUpdate.call(); var event = this.sender.events[0]; - assert.equal(event[0], "error"); - assert.equal(event[1].type, "error"); - assert.equal(event[1].text, "Bad string"); - assert.equal(event[1].row, 1); - assert.equal(event[1].column, 0); + assert.equal(event[0], "annotate"); + assert.equal(event[1].length, 1); + assert.equal(event[1][0].type, "error"); + assert.equal(event[1][0].text, "Bad string"); + assert.equal(event[1][0].row, 1); + assert.equal(event[1][0].column, 0); }, @@ -85,11 +86,11 @@ module.exports = { worker.deferredUpdate.call(); var event = this.sender.events[0]; - assert.equal(event[0], "error"); - assert.equal(event[1].type, "error"); - assert.equal(event[1].text, "Unexpected 'x'"); - assert.equal(event[1].row, 0); - assert.equal(event[1].column, 0); + assert.equal(event[0], "annotate"); + assert.equal(event[1][0].type, "error"); + assert.equal(event[1][0].text, "Unexpected 'x'"); + assert.equal(event[1][0].row, 0); + assert.equal(event[1][0].column, 0); } }; From 68abe8507a2f2ee6b2980cf76ff17f76a3bc7ca1 Mon Sep 17 00:00:00 2001 From: Yihang Ho Date: Tue, 13 Jan 2015 20:45:01 +0800 Subject: [PATCH 26/26] Fix spacing in index.html --- index.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.html b/index.html index a377c612..9e05ed68 100644 --- a/index.html +++ b/index.html @@ -196,8 +196,7 @@ console.log(addResult);

> See all themes

Setting the Programming Language Mode

By default, the editor supports plain text mode. All other language modes are available as separate modules, loaded on demand like this:

-
editor.getSession().setMode("ace/mode/javascript");
-                            
+
editor.getSession().setMode("ace/mode/javascript");