]> git.donarmstrong.com Git - lilypond.git/blob - python/convertrules.py
Web-ja: update introduction
[lilypond.git] / python / convertrules.py
1 # -*- coding: utf-8 -*-
2 # (setq py-indent-offset 4)
3
4
5 import string
6 import re
7 import sys
8 import lilylib
9
10 _ = lilylib._
11
12
13 NOT_SMART = "\n" + _ ("Not smart enough to convert %s.") + "\n"
14 UPDATE_MANUALLY = _ ("Please refer to the manual for details, and update manually.") + "\n"
15 FROM_TO = _ ("%s has been replaced by %s") + "\n"
16
17
18 class FatalConversionError:
19     pass
20
21 conversions = []
22 stderr_write = lilylib.stderr_write
23
24 def warning (str):
25     stderr_write (_ ("warning: %s") % str)
26
27 # Decorator to make rule syntax simpler
28 def rule (version, message):
29     """
30     version: a LilyPond version tuple like (2, 11, 50)
31     message: the message that describes the conversion.
32
33     This decorator adds its function together with the version and the
34     message to the global conversions list.  (It doesn't need to return
35     the function as it isn't used directly anyway.)
36
37     A conversion rule using this decorator looks like this:
38
39     @rule ((1, 2, 3), "convert foo to bar")
40     def conv(str):
41         str = str.replace('foo', 'bar')
42         return str
43
44     """
45     def dec(f):
46         conversions.append ((version, f, message))
47     return dec
48
49
50 @rule ((0, 1, 9), _ ('\\header { key = concat + with + operator }'))
51 def conv(str):
52     if re.search ('\\\\multi', str):
53         stderr_write (NOT_SMART % "\\multi")
54     return str
55
56
57 @rule ((0, 1, 19), _ ('deprecated %s') % '\\octave')
58 def conv (str):
59     if re.search ('\\\\octave', str):
60         stderr_write (NOT_SMART % "\\octave")
61         stderr_write (UPDATE_MANUALLY)
62     #   raise FatalConversionError ()
63     return str
64
65
66 @rule ((0, 1, 20), _ ('deprecated \\textstyle, new \\key syntax'))
67 def conv (str):
68     str = re.sub ('\\\\textstyle([^;]+);',
69                              '\\\\property Lyrics . textstyle = \\1', str)
70     # harmful to current .lys
71     # str = re.sub ('\\\\key([^;]+);', '\\\\accidentals \\1;', str)
72     return str
73
74
75 @rule ((0, 1, 21), '\\musical_pitch -> \\musicalpitch, \\meter -> \\time')
76 def conv (str):
77     str = re.sub ('\\\\musical_pitch', '\\\\musicalpitch',str)
78     str = re.sub ('\\\\meter', '\\\\time',str)
79     return str
80
81
82 @rule ((1, 0, 0), _ ("bump version for release"))
83 def conv (str):
84     return str
85
86
87 @rule ((1, 0, 1), '\\accidentals -> \\keysignature, specialaccidentals -> keyoctaviation')
88 def conv (str):
89     str = re.sub ('\\\\accidentals', '\\\\keysignature',str)
90     str = re.sub ('specialaccidentals *= *1', 'keyoctaviation = 0',str)
91     str = re.sub ('specialaccidentals *= *0', 'keyoctaviation = 1',str)
92     return str
93
94
95 @rule ((1, 0, 2), _ ('\\header { key = concat + with + operator }'))
96 def conv(str):
97     if re.search ('\\\\header', str):
98         stderr_write (NOT_SMART % _ ("new \\header format"))
99     return str
100
101
102 @rule ((1, 0, 3), '\\melodic -> \\notes')
103 def conv(str):
104     str =  re.sub ('\\\\melodic([^a-zA-Z])', '\\\\notes\\1',str)
105     return str
106
107
108 @rule ((1, 0, 4), 'default_{paper,midi}')
109 def conv(str):
110     str =  re.sub ('default_paper *=', '',str)
111     str =  re.sub ('default_midi *=', '',str)
112     return str
113
114
115 @rule ((1, 0, 5), 'ChoireStaff -> ChoirStaff')
116 def conv(str):
117     str =  re.sub ('ChoireStaff', 'ChoirStaff',str)
118     str =  re.sub ('\\\\output', 'output = ',str)
119     return str
120
121
122 @rule ((1, 0, 6), 'foo = \\translator {\\type .. } ->\\translator {\\type ..; foo; }')
123 def conv(str):
124     if re.search ('[a-zA-Z]+ = *\\translator',str):
125         stderr_write (NOT_SMART % _ ("\\translator syntax"))
126     #   raise FatalConversionError ()
127     return str
128
129
130 @rule ((1, 0, 7), '\\lyric -> \\lyrics')
131 def conv(str):
132     str =  re.sub ('\\\\lyrics*', '\\\\lyrics',str)
133     return str
134
135
136 @rule ((1, 0, 10), '[2/3 ]1/1 -> \\times 2/3 ')
137 def conv(str):
138     str =  re.sub ('\\\\\\[/3+', '\\\\times 2/3 { ',str)
139     str =  re.sub ('\\[/3+', '\\\\times 2/3 { [',str)
140     str =  re.sub ('\\\\\\[([0-9/]+)', '\\\\times \\1 {',str)
141     str =  re.sub ('\\[([0-9/]+)', '\\\\times \\1 { [',str)
142     str =  re.sub ('\\\\\\]([0-9/]+)', '}', str)
143     str =  re.sub ('\\\\\\]', '}',str)
144     str =  re.sub ('\\]([0-9/]+)', '] }', str)
145     return str
146
147
148 @rule ((1, 0, 12), 'Chord syntax stuff')
149 def conv(str):
150     return str
151
152
153 @rule ((1, 0, 13), '<a ~ b> c -> <a b> ~ c')
154 def conv(str):
155     str =  re.sub ('<([^>~]+)~([^>]*)>','<\\1 \\2> ~', str)
156     return str
157
158
159 @rule ((1, 0, 14), '<[a b> <a b]>c -> [<a b> <a b>]')
160 def conv(str):
161     str =  re.sub ('<\\[','[<', str)
162     str =  re.sub ('\\]>','>]', str)
163     return str
164
165
166 @rule ((1, 0, 16), '\\type -> \\context, textstyle -> textStyle')
167 def conv(str):
168     str =  re.sub ('\\\\type([^\n]*engraver)','\\\\TYPE\\1', str)
169     str =  re.sub ('\\\\type([^\n]*performer)','\\\\TYPE\\1', str)
170     str =  re.sub ('\\\\type','\\\\context', str)
171     str =  re.sub ('\\\\TYPE','\\\\type', str)
172     str =  re.sub ('textstyle','textStyle', str)
173     return str
174
175
176 @rule ((1, 0, 18), _ ('\\repeat NUM Music Alternative -> \\repeat FOLDSTR Music Alternative'))
177 def conv(str):
178     if re.search ('\\\\repeat',str):
179         stderr_write (NOT_SMART % "\\repeat")
180     #   raise FatalConversionError ()
181     return str
182
183
184 @rule ((1, 0, 19), 'fontsize -> fontSize, midi_instrument -> midiInstrument, SkipBars -> skipBars')
185 def conv(str):
186     str =  re.sub ('SkipBars','skipBars', str)
187     str =  re.sub ('fontsize','fontSize', str)
188     str =  re.sub ('midi_instrument','midiInstrument', str)
189     return str
190
191
192 @rule ((1, 0, 20), '{,tie,slur}ydirection -> {v,tieV,slurV}erticalDirection')
193 def conv(str):
194     str =  re.sub ('tieydirection','tieVerticalDirection', str)
195     str =  re.sub ('slurydirection','slurVerticalDirection', str)
196     str =  re.sub ('ydirection','verticalDirection', str)
197     return str
198
199
200 @rule ((1, 0, 21), 'hshift -> horizontalNoteShift')
201 def conv(str):
202     str =  re.sub ('hshift','horizontalNoteShift', str)
203     return str
204
205
206 @rule ((1, 1, 52), _ ('deprecate %s') % '\\grouping')
207 def conv(str):
208     str =  re.sub ('\\\\grouping[^;]*;','', str)
209     return str
210
211
212 @rule ((1, 1, 55), '\\wheel -> \\coda')
213 def conv(str):
214     str =  re.sub ('\\\\wheel','\\\\coda', str)
215     return str
216
217
218 @rule ((1, 1, 65), 'slurdash -> slurDash, keyoctaviation -> keyOctaviation')
219 def conv(str):
220     str =  re.sub ('keyoctaviation','keyOctaviation', str)
221     str =  re.sub ('slurdash','slurDash', str)
222     return str
223
224
225 @rule ((1, 1, 66), 'semi -> volta')
226 def conv(str):
227     str =  re.sub ('\\\\repeat *\"?semi\"?','\\\\repeat "volta"', str)
228     return str
229
230
231 @rule ((1, 1, 67), 'beamAuto -> noAutoBeaming')
232 def conv(str):
233     str =  re.sub ('\"?beamAuto\"? *= *\"?0?\"?','noAutoBeaming = "1"', str)
234     return str
235
236
237 @rule ((1, 2, 0), 'automaticMelismas -> automaticMelismata')
238 def conv(str):
239     str =  re.sub ('automaticMelismas', 'automaticMelismata', str)
240     return str
241
242
243 @rule ((1, 2, 1), 'dynamicDir -> dynamicDirection')
244 def conv(str):
245     str =  re.sub ('dynamicDir\\b', 'dynamicDirection', str)
246     return str
247
248
249 @rule ((1, 3, 4), '\\cadenza -> \\cadenza{On|Off}')
250 def conv(str):
251     str =  re.sub ('\\\\cadenza *0 *;', '\\\\cadenzaOff', str)
252     str =  re.sub ('\\\\cadenza *1 *;', '\\\\cadenzaOn', str)
253     return str
254
255
256 @rule ((1, 3, 5), 'beamAuto moment properties')
257 def conv (str):
258     str = re.sub ('"?beamAuto([^"=]+)"? *= *"([0-9]+)/([0-9]+)" *;*',
259                   'beamAuto\\1 = #(make-moment \\2 \\3)',
260                   str)
261     return str
262
263
264 @rule ((1, 3, 17), 'stemStyle -> flagStyle')
265 def conv (str):
266     str = re.sub ('stemStyle',
267                   'flagStyle',
268                   str)
269     return str
270
271
272 @rule ((1, 3, 18), 'staffLineLeading -> staffSpace')
273 def conv (str):
274     str = re.sub ('staffLineLeading',
275                   'staffSpace',
276                   str)
277     return str
278
279
280 @rule ((1, 3, 23), _ ('deprecate %s ') % '\\repetitions')
281 def conv(str):
282     if re.search ('\\\\repetitions',str):
283         stderr_write (NOT_SMART % "\\repetitions")
284     #   raise FatalConversionError ()
285     return str
286
287
288 @rule ((1, 3, 35), 'textEmptyDimension -> textNonEmpty')
289 def conv (str):
290     str = re.sub ('textEmptyDimension *= *##t',
291                   'textNonEmpty = ##f',
292                   str)
293     str = re.sub ('textEmptyDimension *= *##f',
294                   'textNonEmpty = ##t',
295                   str)
296     return str
297
298
299 @rule ((1, 3, 38), '\musicalpitch { a b c } -> #\'(a b c)')
300 def conv (str):
301     str = re.sub ("([a-z]+)[ \t]*=[ \t]*\\\\musicalpitch *{([- 0-9]+)} *\n",
302                   "(\\1 . (\\2))\n", str)
303     str = re.sub ("\\\\musicalpitch *{([0-9 -]+)}",
304                   "\\\\musicalpitch #'(\\1)", str)
305     if re.search ('\\\\notenames',str):
306         stderr_write (NOT_SMART % _ ("new \\notenames format"))
307     return str
308
309
310 @rule ((1, 3, 39), '\\key A ;  ->\\key a;')
311 def conv (str):
312     def replace (match):
313         return '\\key %s;' % match.group (1).lower ()
314
315     str = re.sub ("\\\\key ([^;]+);",  replace, str)
316     return str
317
318
319 @rule ((1, 3, 41), '[:16 c4 d4 ] -> \\repeat "tremolo" 2 { c16 d16 }')
320 def conv (str):
321     if re.search ('\\[:',str):
322         stderr_write (NOT_SMART % _ ("new tremolo format"))
323     return str
324
325
326 @rule ((1, 3, 42), _ ('Staff_margin_engraver deprecated, use Instrument_name_engraver'))
327 def conv (str):
328     str = re.sub ('Staff_margin_engraver' , 'Instrument_name_engraver', str)
329     return str
330
331
332 @rule ((1, 3, 49), 'noteHeadStyle value: string -> symbol')
333 def conv (str):
334     str = re.sub ('note[hH]eadStyle\\s*=\\s*"?(\\w+)"?' , "noteHeadStyle = #'\\1", str)
335     return str
336
337
338 @rule ((1, 3, 58), 'noteHeadStyle value: string -> symbol')
339 def conv (str):
340     if re.search ('\\\\keysignature', str):
341         stderr_write (NOT_SMART % '\\keysignature')
342     return str
343
344
345 @rule ((1, 3, 59), '\key X ; -> \key X major; ')
346 def conv (str):
347     str = re.sub (r"""\\key *([a-z]+) *;""", r"""\\key \1 \major;""",str);
348     return str
349
350
351 @rule ((1, 3, 68), 'latexheaders = "\\input global" -> latexheaders = "global"')
352 def conv (str):
353     str = re.sub (r'latexheaders *= *"\\\\input ',
354                   'latexheaders = "',
355                   str)
356     return str
357
358
359 # TODO: lots of other syntax changes should be done here as well
360 @rule ((1, 3, 92), 'basicXXXProperties -> XXX, Repeat_engraver -> Volta_engraver')
361 def conv (str):
362     str = re.sub ('basicCollisionProperties', 'NoteCollision', str)
363     str = re.sub ('basicVoltaSpannerProperties' , "VoltaBracket", str)
364     str = re.sub ('basicKeyProperties' , "KeySignature", str)
365
366     str = re.sub ('basicClefItemProperties' ,"Clef", str)
367
368
369     str = re.sub ('basicLocalKeyProperties' ,"Accidentals", str)
370     str = re.sub ('basicMarkProperties' ,"Accidentals", str)
371     str = re.sub ('basic([A-Za-z_]+)Properties', '\\1', str)
372
373     str = re.sub ('Repeat_engraver' ,'Volta_engraver', str)
374     return str
375
376
377 @rule ((1, 3, 93), _ ('change property definition case (eg. onevoice -> oneVoice)'))
378 def conv (str):
379     # Ugh, but meaning of \stemup changed too
380     # maybe we should do \stemup -> \stemUp\slurUp\tieUp ?
381     str = re.sub ('\\\\stemup', '\\\\stemUp', str)
382     str = re.sub ('\\\\stemdown', '\\\\stemDown', str)
383     str = re.sub ('\\\\stemboth', '\\\\stemBoth', str)
384
385     str = re.sub ('\\\\slurup', '\\\\slurUp', str)
386     str = re.sub ('\\\\slurboth', '\\\\slurBoth', str)
387     str = re.sub ('\\\\slurdown', '\\\\slurDown', str)
388     str = re.sub ('\\\\slurdotted', '\\\\slurDotted', str)
389     str = re.sub ('\\\\slurnormal', '\\\\slurNoDots', str)
390
391     str = re.sub ('\\\\shiftoff', '\\\\shiftOff', str)
392     str = re.sub ('\\\\shifton', '\\\\shiftOn', str)
393     str = re.sub ('\\\\shiftonn', '\\\\shiftOnn', str)
394     str = re.sub ('\\\\shiftonnn', '\\\\shiftOnnn', str)
395
396     str = re.sub ('\\\\onevoice', '\\\\oneVoice', str)
397     str = re.sub ('\\\\voiceone', '\\\\voiceOne', str)
398     str = re.sub ('\\\\voicetwo', '\\\\voiceTwo', str)
399     str = re.sub ('\\\\voicethree', '\\\\voiceThree', str)
400     str = re.sub ('\\\\voicefour', '\\\\voiceFour', str)
401
402     # I don't know exactly when these happened...
403     # ugh, we lose context setting here...
404     str = re.sub ('\\\\property *[^ ]*verticalDirection[^=]*= *#?"?(1|(\\\\up))"?', '\\\\stemUp\\\\slurUp\\\\tieUp', str)
405     str = re.sub ('\\\\property *[^ ]*verticalDirection[^=]*= *#?"?((-1)|(\\\\down))"?', '\\\\stemDown\\\\slurDown\\\\tieDown', str)
406     str = re.sub ('\\\\property *[^ ]*verticalDirection[^=]*= *#?"?(0|(\\\\center))"?', '\\\\stemBoth\\\\slurBoth\\\\tieBoth', str)
407
408     str = re.sub ('verticalDirection[^=]*= *#?"?(1|(\\\\up))"?', 'Stem \\\\override #\'direction = #0\nSlur \\\\override #\'direction = #0\n Tie \\\\override #\'direction = #1', str)
409     str = re.sub ('verticalDirection[^=]*= *#?"?((-1)|(\\\\down))"?', 'Stem \\\\override #\'direction = #0\nSlur \\\\override #\'direction = #0\n Tie \\\\override #\'direction = #-1', str)
410     str = re.sub ('verticalDirection[^=]*= *#?"?(0|(\\\\center))"?', 'Stem \\\\override #\'direction = #0\nSlur \\\\override #\'direction = #0\n Tie \\\\override #\'direction = #0', str)
411
412     str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)VerticalDirection[^=]*= *#?"?(1|(\\\\up))"?', '\\\\\\1Up', str)
413     str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)VerticalDirection[^=]*= *#?"?((-1)|(\\\\down))"?', '\\\\\\1Down', str)
414     str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)VerticalDirection[^=]*= *#?"?(0|(\\\\center))"?', '\\\\\\1Both', str)
415
416     # (lacks capitalization slur -> Slur)
417     str = re.sub ('([a-z]+)VerticalDirection[^=]*= *#?"?(1|(\\\\up))"?', '\\1 \\\\override #\'direction = #1', str)
418     str = re.sub ('([a-z]+)VerticalDirection[^=]*= *#?"?((-1)|(\\\\down))"?', '\\1 \\override #\'direction = #-1', str)
419     str = re.sub ('([a-z]+)VerticalDirection[^=]*= *#?"?(0|(\\\\center))"?', '\\1 \\\\override #\'direction = #0', str)
420
421     ## dynamic..
422     str = re.sub ('\\\\property *[^ .]*[.]?dynamicDirection[^=]*= *#?"?(1|(\\\\up))"?', '\\\\dynamicUp', str)
423     str = re.sub ('\\\\property *[^ .]*[.]?dyn[^=]*= *#?"?((-1)|(\\\\down))"?', '\\\\dynamicDown', str)
424     str = re.sub ('\\\\property *[^ .]*[.]?dyn[^=]*= *#?"?(0|(\\\\center))"?', '\\\\dynamicBoth', str)
425
426     str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)Dash[^=]*= *#?"?(0|(""))"?', '\\\\\\1NoDots', str)
427     str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)Dash[^=]*= *#?"?([1-9]+)"?', '\\\\\\1Dotted', str)
428
429     str = re.sub ('\\\\property *[^ .]*[.]?noAutoBeaming[^=]*= *#?"?(0|(""))"?', '\\\\autoBeamOn', str)
430     str = re.sub ('\\\\property *[^ .]*[.]?noAutoBeaming[^=]*= *#?"?([1-9]+)"?', '\\\\autoBeamOff', str)
431     return str
432
433
434 @rule ((1, 3, 97), 'ChordName -> ChordNames')
435 def conv (str):
436     str = re.sub ('ChordNames*', 'ChordNames', str)
437     if re.search ('\\\\textscript "[^"]* *"[^"]*"', str):
438         stderr_write (NOT_SMART % _ ("new \\textscript markup text"))
439
440     str = re.sub ('\\textscript +("[^"]*")', '\\textscript #\\1', str)
441     return str
442
443 # TODO: add lots of these
444
445 @rule ((1, 3, 98), 'CONTEXT.textStyle -> GROB.#font-style ')
446 def conv (str):
447     str = re.sub ('\\\\property *"?Voice"? *[.] *"?textStyle"? *= *"([^"]*)"', '\\\\property Voice.TextScript \\\\set #\'font-style = #\'\\1', str)
448     str = re.sub ('\\\\property *"?Lyrics"? *[.] *"?textStyle"? *= *"([^"]*)"', '\\\\property Lyrics.LyricText \\\\set #\'font-style = #\'\\1', str)
449
450     str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?timeSignatureStyle"? *= *"([^"]*)"', '\\\\property \\1.TimeSignature \\\\override #\'style = #\'\\2', str)
451
452     str = re.sub ('"?timeSignatureStyle"? *= *#?""', 'TimeSignature \\\\override #\'style = ##f', str)
453
454     str = re.sub ('"?timeSignatureStyle"? *= *#?"([^"]*)"', 'TimeSignature \\\\override #\'style = #\'\\1', str)
455
456     str = re.sub ('#\'style *= #*"([^"])"', '#\'style = #\'\\1', str)
457
458     str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?horizontalNoteShift"? *= *"?#?([-0-9]+)"?', '\\\\property \\1.NoteColumn \\\\override #\'horizontal-shift = #\\2', str)
459
460     # ugh
461     str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?flagStyle"? *= *""', '\\\\property \\1.Stem \\\\override #\'flag-style = ##f', str)
462
463     str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?flagStyle"? *= *"([^"]*)"', '\\\\property \\1.Stem \\\\override #\'flag-style = #\'\\2', str)
464     return str
465
466
467 @rule ((1, 3, 102), 'beamAutoEnd -> autoBeamSettings \\push (end * * * *)')
468 def conv (str):
469     str = re.sub ('"?beamAutoEnd_([0-9]*)"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(end 1 \\1 * *) = \\2', str)
470     str = re.sub ('"?beamAutoBegin_([0-9]*)"? *= *(#\\([^)]*\))', 'autoBeamSettings \\push #\'(begin 1 \\1 * *) = \\2', str)
471     str = re.sub ('"?beamAutoEnd"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(end * * * *) = \\1', str)
472     str = re.sub ('"?beamAutoBegin"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(begin * * * *) = \\1', str)
473     return str
474
475
476 @rule ((1, 3, 111), '\\push -> \\override, \\pop -> \\revert')
477 def conv (str):
478     str = re.sub ('\\\\push', '\\\\override', str)
479     str = re.sub ('\\\\pop', '\\\\revert', str)
480     return str
481
482
483 @rule ((1, 3, 113), 'LyricVoice -> LyricsVoice')
484 def conv (str):
485     str = re.sub ('LyricVoice', 'LyricsVoice', str)
486     # old fix
487     str = re.sub ('Chord[Nn]ames*.Chord[Nn]ames*', 'ChordNames.ChordName', str)
488     str = re.sub ('Chord[Nn]ames([ \t\n]+\\\\override)', 'ChordName\\1', str)
489     return str
490
491
492 def regularize_id (str):
493     s = ''
494     lastx = ''
495     for x in str:
496         if x == '_':
497             lastx = x
498             continue
499         elif x in string.digits:
500             x = chr(ord (x) - ord ('0')  +ord ('A'))
501         elif x not in string.letters:
502             x = 'x'
503         elif x in string.lowercase and lastx == '_':
504             x = x.upper ()
505         s = s + x
506         lastx = x
507     return s
508
509
510 @rule ((1, 3, 117), _ ('identifier names: %s') % '$!foo_bar_123 -> xfooBarABC')
511 def conv (str):
512     def regularize_dollar_reference (match):
513         return regularize_id (match.group (1))
514     def regularize_assignment (match):
515         return '\n' + regularize_id (match.group (1)) + ' = '
516     str = re.sub ('\$([^\t\n ]+)', regularize_dollar_reference, str)
517     str = re.sub ('\n([^ \t\n]+)[ \t]*= *', regularize_assignment, str)
518     return str
519
520
521 @rule ((1, 3, 120), 'paper_xxx -> paperXxxx, pedalup -> pedalUp.')
522 def conv (str):
523     def regularize_paper (match):
524         return regularize_id (match.group (1))
525     str = re.sub ('(paper_[a-z]+)', regularize_paper, str)
526     str = re.sub ('sustainup', 'sustainUp', str)
527     str = re.sub ('nobreak', 'noBreak', str)
528     str = re.sub ('sustaindown', 'sustainDown', str)
529     str = re.sub ('sostenutoup', 'sostenutoUp', str)
530     str = re.sub ('sostenutodown', 'sostenutoDown', str)
531     str = re.sub ('unachorda', 'unaChorda', str)
532     str = re.sub ('trechorde', 'treChorde', str)
533     return str
534
535
536 @rule ((1, 3, 122), 'drarnChords -> chordChanges, \\musicalpitch -> \\pitch')
537 def conv (str):
538     str = re.sub ('drarnChords', 'chordChanges', str)
539     str = re.sub ('\\musicalpitch', '\\pitch', str)
540     return str
541
542
543 @rule ((1, 3, 136), 'ly-X-elt-property -> ly-X-grob-property')
544 def conv (str):
545     str = re.sub ('ly-([sg])et-elt-property', 'ly-\\1et-grob-property', str)
546     return str
547
548
549 @rule ((1, 3, 138), _ ('point-and-click argument changed to procedure.'))
550 def conv (str):
551     str = re.sub ('point-and-click +#t', 'point-and-click line-column-location', str)
552     return str
553
554
555 @rule ((1, 3, 138), 'followThread -> followVoice.')
556 def conv (str):
557     str = re.sub ('followThread', 'followVoice', str)
558     str = re.sub ('Thread.FollowThread', 'Voice.VoiceFollower', str)
559     str = re.sub ('FollowThread', 'VoiceFollower', str)
560     return str
561
562
563 @rule ((1, 3, 139), 'font-point-size -> font-design-size.')
564 def conv (str):
565     str = re.sub ('font-point-size', 'font-design-size', str)
566     return str
567
568
569 @rule ((1, 3, 141), 'xNoDots -> xSolid')
570 def conv (str):
571     str = re.sub ('([a-zA-Z]*)NoDots', '\\1Solid', str)
572     return str
573
574
575 @rule ((1, 3, 144), 'Chorda -> Corda')
576 def conv (str):
577     str = re.sub ('([Cc])hord([ea])', '\\1ord\\2', str)
578     return str
579
580
581 @rule ((1, 3, 145), 'ContextNameXxxxVerticalExtent -> XxxxVerticalExtent')
582 def conv (str):
583     str = re.sub ('([A-Za-z]+)MinimumVerticalExtent', 'MinimumV@rticalExtent', str)
584     str = re.sub ('([A-Za-z]+)ExtraVerticalExtent', 'ExtraV@rticalExtent', str)
585     str = re.sub ('([A-Za-z]+)VerticalExtent', 'VerticalExtent', str)
586     str = re.sub ('ExtraV@rticalExtent', 'ExtraVerticalExtent', str)
587     str = re.sub ('MinimumV@rticalExtent', 'MinimumVerticalExtent', str)
588     return str
589
590
591 @rule ((1, 3, 146), _('semicolons removed'))
592 def conv (str):
593     str = re.sub ('\\\\key[ \t]*;', '\\key \\default;', str)
594     str = re.sub ('\\\\mark[ \t]*;', '\\mark \\default;', str)
595
596     # Make sure groups of more than one ; have space before
597     # them, so that non of them gets removed by next rule
598     str = re.sub ("([^ \n\t;]);(;+)", "\\1 ;\\2", str)
599
600     # Only remove ; that are not after spaces, # or ;
601     # Otherwise  we interfere with Scheme comments,
602     # which is badbadbad.
603     str = re.sub ("([^ \t;#]);", "\\1", str)
604     return str
605
606
607 @rule ((1, 3, 147), 'default-neutral-direction -> neutral-direction')
608 def conv (str):
609     str = re.sub ('default-neutral-direction', 'neutral-direction',str)
610     return str
611
612
613 @rule ((1, 3, 148), '"(align" -> "(axis", "(rows" -> "(columns"')
614 def conv (str):
615     str = re.sub ('\(align', '(axis', str)
616     str = re.sub ('\(rows', '(columns', str)
617     return str
618
619
620 @rule ((1, 5, 33), 'SystemStartDelimiter -> systemStartDelimiter')
621 def conv (str):
622     str = re.sub ('SystemStartDelimiter', 'systemStartDelimiter', str)
623     return str
624
625
626 @rule ((1, 5, 38), 'arithmetic... -> spacing...')
627 def conv (str):
628     str = re.sub ('arithmetic-multiplier', 'spacing-increment', str)
629     str = re.sub ('arithmetic-basicspace', 'shortest-duration-space', str)
630     return str
631
632
633 # 40 ?
634 @rule ((1, 5, 40), _ ('%s property names') % 'breakAlignOrder')
635 def conv (str):
636
637     def func(match):
638         break_dict = {
639         "Instrument_name": "instrument-name",
640         "Left_edge_item": "left-edge",
641         "Span_bar": "span-bar",
642         "Breathing_sign": "breathing-sign",
643         "Staff_bar": "staff-bar",
644         "Clef_item": "clef",
645         "Key_item": "key-signature",
646         "Time_signature": "time-signature",
647         "Custos": "custos"
648         }
649         props =  match.group (1)
650         for (k,v) in break_dict.items():
651             props = re.sub (k, v, props)
652         return  "breakAlignOrder = #'(%s)" % props
653
654     str = re.sub ("breakAlignOrder *= *#'\\(([a-z_\n\tA-Z ]+)\\)",
655                   func, str)
656     return str
657
658
659 @rule ((1, 5, 49), 'noAutoBeaming -> autoBeaming')
660 def conv (str):
661     str = re.sub ('noAutoBeaming *= *##f', 'autoBeaming = ##t', str)
662     str = re.sub ('noAutoBeaming *= *##t', 'autoBeaming = ##f', str)
663     return str
664
665
666 @rule ((1, 5, 52), 'tuplet-X-visibility -> X-visibility')
667 def conv (str):
668     str = re.sub ('tuplet-bracket-visibility', 'bracket-visibility', str)
669     str = re.sub ('tuplet-number-visibility', 'number-visibility', str)
670     return str
671
672
673 @rule ((1, 5, 56), 'Pitch::transpose -> ly-transpose-pitch')
674 def conv (str):
675     str = re.sub ('Pitch::transpose', 'ly-transpose-pitch', str)
676     return str
677
678
679 @rule ((1, 5, 58), _ ('deprecate %s') % 'textNonEmpty')
680 def conv (str):
681     str = re.sub ('textNonEmpty *= *##t', "TextScript \\set #'no-spacing-rods = ##f", str)
682     str = re.sub ('textNonEmpty *= *##f', "TextScript \\set #'no-spacing-rods = ##t", str)
683     return str
684
685
686 @rule ((1, 5, 59), 'XxxxVerticalExtent -> xxxVerticalExtent')
687 def conv (str):
688     str = re.sub ('MinimumVerticalExtent', 'minimumV@rticalExtent', str)
689     str = re.sub ('minimumVerticalExtent', 'minimumV@rticalExtent', str)
690     str = re.sub ('ExtraVerticalExtent', 'extraV@rticalExtent', str)
691     str = re.sub ('extraVerticalExtent', 'extraV@rticalExtent', str)
692     str = re.sub ('VerticalExtent', 'verticalExtent', str)
693     str = re.sub ('extraV@rticalExtent', 'extraVerticalExtent', str)
694     str = re.sub ('minimumV@rticalExtent', 'minimumVerticalExtent', str)
695     return str
696
697
698 @rule ((1, 5, 62), 'visibility-lambda -> break-visibility')
699 def conv (str):
700     str = re.sub ('visibility-lambda', 'break-visibility', str)
701     return str
702
703
704 @rule ((1, 5, 67), _ ('automaticMelismata turned on by default'))
705 def conv (str):
706     if re.search (r'\addlyrics',str) \
707            and re.search ('automaticMelismata', str)  == None:
708         stderr_write (NOT_SMART % "automaticMelismata")
709         stderr_write (_ ("automaticMelismata is turned on by default since 1.5.67."))
710         stderr_write ('\n')
711         raise FatalConversionError ()
712     return str
713
714
715 @rule ((1, 5, 68), 'ly-set-X-property -> ly-set-X-property!')
716 def conv (str):
717     str = re.sub ('ly-set-grob-property([^!])', 'ly-set-grob-property!\1', str)
718     str = re.sub ('ly-set-mus-property([^!])', 'ly-set-mus-property!\1', str)
719     return str
720
721
722 @rule ((1, 5, 71), 'extent-[XY] -> [XY]-extent')
723 def conv (str):
724     str = re.sub ('extent-X', 'X-extent', str)
725     str = re.sub ('extent-Y', 'Y-extent', str)
726     return str
727
728
729 @rule ((1, 5, 72), 'set! point-and-click -> set-point-and-click!')
730 def conv (str):
731     str = re.sub ("""#\(set! +point-and-click +line-column-location\)""",
732                   """#(set-point-and-click! \'line-column)""", str)
733     str = re.sub ("""#\(set![ \t]+point-and-click +line-location\)""",
734                   '#(set-point-and-click! \'line)', str)
735     str = re.sub ('#\(set! +point-and-click +#f\)',
736                   '#(set-point-and-click! \'none)', str)
737     return str
738
739
740 @rule ((1, 6, 5), 'Stems: flag-style -> stroke-style; style -> flag-style')
741 def conv (str):
742     str = re.sub ('flag-style', 'stroke-style', str)
743     str = re.sub (r"""Stem([ ]+)\\override #'style""", r"""Stem \\override #'flag-style""", str);
744     str = re.sub (r"""Stem([ ]+)\\set([ ]+)#'style""", r"""Stem \\set #'flag-style""", str);
745     return str
746
747
748 def subst_req_name (match):
749     return "(make-music-by-name \'%sEvent)" % regularize_id (match.group(1))
750
751
752 @rule ((1, 7, 1), 'ly-make-music foo_bar_req -> make-music-by-name FooBarEvent')
753 def conv (str):
754     str = re.sub ('\\(ly-make-music *\"([A-Z][a-z_]+)_req\"\\)', subst_req_name, str)
755     str = re.sub ('Request_chord', 'EventChord', str)
756     return str
757
758
759 spanner_subst ={
760         "text" : 'TextSpanEvent',
761         "decrescendo" : 'DecrescendoEvent',
762         "crescendo" : 'CrescendoEvent',
763         "Sustain" : 'SustainPedalEvent',
764         "slur" : 'SlurEvent',
765         "UnaCorda" : 'UnaCordaEvent',
766         "Sostenuto" : 'SostenutoEvent',
767         }
768
769 def subst_ev_name (match):
770     stype = 'STOP'
771     if re.search ('start', match.group(1)):
772         stype= 'START'
773     mtype = spanner_subst[match.group(2)]
774     return "(make-span-event '%s %s)" % (mtype , stype)
775
776 def subst_definition_ev_name(match):
777     return ' = #%s' % subst_ev_name (match)
778
779 def subst_inline_ev_name (match):
780     s = subst_ev_name (match)
781     return '#(ly-export %s)' % s
782
783 def subst_csp_definition (match):
784     return ' = #(make-event-chord (list %s))' % subst_ev_name (match)
785
786 def subst_csp_inline (match):
787     return '#(ly-export (make-event-chord (list %s)))' % subst_ev_name (match)
788
789
790 @rule ((1, 7, 2), '\\spanrequest -> #(make-span-event .. ), \script -> #(make-articulation .. )')
791 def conv (str):
792     str = re.sub (r' *= *\\spanrequest *([^ ]+) *"([^"]+)"', subst_definition_ev_name, str)
793     str = re.sub (r'\\spanrequest *([^ ]+) *"([^"]+)"', subst_inline_ev_name, str)
794     str = re.sub (r' *= *\\commandspanrequest *([^ ]+) *"([^"]+)"', subst_csp_definition, str)
795     str = re.sub (r'\\commandspanrequest *([^ ]+) *"([^"]+)"', subst_csp_inline, str)
796     str = re.sub (r'ly-id ', 'ly-import ', str)
797
798     str = re.sub (r' *= *\\script "([^"]+)"', ' = #(make-articulation "\\1")', str)
799     str = re.sub (r'\\script "([^"]+)"', '#(ly-export (make-articulation "\\1"))', str)
800     return str
801
802
803 @rule ((1, 7, 3), 'ly- -> ly:')
804 def conv(str):
805     str = re.sub (r'\(ly-', '(ly:', str)
806
807     changed = [
808             r'duration\?',
809             r'font-metric\?',
810             r'molecule\?',
811             r'moment\?',
812             r'music\?',
813             r'pitch\?',
814             'make-duration',
815             'music-duration-length',
816             'duration-log',
817             'duration-dotcount',
818             'intlog2',
819             'duration-factor',
820             'transpose-key-alist',
821             'get-system',
822             'get-broken-into',
823             'get-original',
824             'set-point-and-click!',
825             'make-moment',
826             'make-pitch',
827             'pitch-octave',
828             'pitch-alteration',
829             'pitch-notename',
830             'pitch-semitones',
831             r'pitch<\?',
832             r'dir\?',
833             'music-duration-compress',
834             'set-point-and-click!'
835             ]
836
837     origre = r'\b(%s)' % '|'.join (changed)
838
839     str = re.sub (origre, r'ly:\1',str)
840     str = re.sub ('set-point-and-click!', 'set-point-and-click', str)
841     return str
842
843
844 @rule ((1, 7, 4), '<< >> -> < <  > >')
845 def conv(str):
846     if re.search ('new-chords-done',str):
847         return str
848
849     str = re.sub (r'<<', '< <', str)
850     str = re.sub (r'>>', '> >', str)
851     return str
852
853
854 @rule ((1, 7, 5), '\\transpose TO -> \\transpose FROM  TO')
855 def conv(str):
856     str = re.sub (r"\\transpose", r"\\transpose c'", str)
857     str = re.sub (r"\\transpose c' *([a-z]+)'", r"\\transpose c \1", str)
858     return str
859
860
861 @rule ((1, 7, 6), 'note\\script -> note-\script')
862 def conv(str):
863     kws =   ['arpeggio',
864              'sustainDown',
865              'sustainUp',
866              'f',
867              'p',
868              'pp',
869              'ppp',
870              'fp',
871              'ff',
872              'mf',
873              'mp',
874              'sfz',
875              ]
876
877     origstr = '|'.join (kws)
878     str = re.sub (r'([^_^-])\\(%s)\b' % origstr, r'\1-\\\2', str)
879     return str
880
881
882 @rule ((1, 7, 10), "\property ChordName #'style -> #(set-chord-name-style 'style)")
883 def conv(str):
884     str = re.sub (r"\\property *ChordNames *\. *ChordName *\\(set|override) *#'style *= *#('[a-z]+)",
885                   r"#(set-chord-name-style \2)", str)
886     str = re.sub (r"\\property *ChordNames *\. *ChordName *\\revert *#'style",
887                   r"", str)
888     return str
889
890
891 @rule ((1, 7, 11), "transpose-pitch -> pitch-transpose")
892 def conv(str):
893     str = re.sub (r"ly:transpose-pitch", "ly:pitch-transpose", str)
894     return str
895
896
897 @rule ((1, 7, 13), "ly:XX-molecule-YY -> ly:molecule-XX-YY")
898 def conv(str):
899     str = re.sub (r"ly:get-molecule-extent", "ly:molecule-get-extent", str)
900     str = re.sub (r"ly:set-molecule-extent!", "ly:molecule-set-extent!", str)
901     str = re.sub (r"ly:add-molecule", "ly:molecule-add", str)
902     str = re.sub (r"ly:combine-molecule-at-edge", "ly:molecule-combine-at-edge", str)
903     str = re.sub (r"ly:align-to!", "ly:molecule-align-to!", str)
904     return str
905
906
907 @rule ((1, 7, 15), "linewidth = -1 -> raggedright = ##t")
908 def conv(str):
909     str = re.sub (r"linewidth *= *-[0-9.]+ *(\\mm|\\cm|\\in|\\pt)?", 'raggedright = ##t', str )
910     return str
911
912
913 @rule ((1, 7, 16), "divisiomaior -> divisioMaior")
914 def conv(str):
915     str = re.sub ("divisiomaior",
916                   "divisioMaior", str)
917     str = re.sub ("divisiominima",
918                   "divisioMinima", str)
919     str = re.sub ("divisiomaxima",
920                   "divisioMaxima", str)
921     return str
922
923
924 @rule ((1, 7, 17), "Skip_req  -> Skip_event")
925 def conv(str):
926     str = re.sub ("Skip_req_swallow_translator",
927                   "Skip_event_swallow_translator", str)
928     return str
929
930
931 @rule ((1, 7, 18), "groupOpen/Close  -> start/stopGroup, #'outer  -> #'enclose-bounds")
932 def conv(str):
933     str = re.sub ("groupOpen",
934                   "startGroup", str)
935     str = re.sub ("groupClose",
936                   "stopGroup", str)
937     str = re.sub ("#'outer",
938                   "#'enclose-bounds", str)
939
940     return str
941
942
943 @rule ((1, 7, 19), _ ("remove %s") % "GraceContext")
944 def conv(str):
945     if re.search( r'\\GraceContext', str):
946         stderr_write (NOT_SMART % "GraceContext")
947         stderr_write (FROM_TO \
948                           % ("GraceContext", "#(add-to-grace-init .. )"))
949         stderr_write (UPDATE_MANUALLY)
950         raise FatalConversionError ()
951
952     str = re.sub ('HaraKiriStaffContext', 'RemoveEmptyStaffContext', str)
953     return str
954
955
956 @rule ((1, 7, 22), "#'type -> #'style")
957 def conv(str):
958     str = re.sub (
959             r"(set|override|revert) *#'type",
960             r"\1 #'style",
961             str)
962     return str
963
964
965 @rule ((1, 7, 23), "barNonAuto -> automaticBars")
966 def conv(str):
967     str = re.sub (
968             "barNonAuto *= *##t",
969             "automaticBars = ##f",
970             str)
971     str = re.sub (
972             "barNonAuto *= *##f",
973             "automaticBars = ##t",
974             str)
975     return str
976
977
978 @rule ((1, 7, 24), _ ("cluster syntax"))
979 def conv(str):
980     if re.search( r'-(start|stop)Cluster', str):
981         stderr_write (NOT_SMART % _ ("cluster syntax"))
982         stderr_write (UPDATE_MANUALLY)
983
984         raise FatalConversionError ()
985     return str
986
987
988 @rule ((1, 7, 28), _ ("new Pedal style syntax"))
989 def conv(str):
990     str = re.sub (r"\\property *Staff\.(Sustain|Sostenuto|UnaCorda)Pedal *\\(override|set) *#'pedal-type *",
991                     r"\property Staff.pedal\1Style ", str)
992     str = re.sub (r"\\property *Staff\.(Sustain|Sostenuto|UnaCorda)Pedal *\\revert *#'pedal-type", '', str)
993     return str
994
995
996 def sub_chord (m):
997     str = m.group(1)
998
999     origstr =  '<%s>' % str
1000     if re.search (r'\\\\', str):
1001         return origstr
1002
1003     if re.search (r'\\property', str):
1004         return origstr
1005
1006     if re.match (r'^\s*\)?\s*\\[a-zA-Z]+', str):
1007         return origstr
1008
1009     durs = []
1010     def sub_durs (m, durs = durs):
1011         durs.append(m.group(2))
1012         return m.group (1)
1013
1014     str = re.sub (r"([a-z]+[,'!? ]*)([0-9]+\.*)", sub_durs, str)
1015     dur_str = ''
1016
1017     for d in durs:
1018         if dur_str == '':
1019             dur_str = d
1020         if dur_str <> d:
1021             return '<%s>' % m.group (1)
1022
1023     pslur_strs = ['']
1024     dyns = ['']
1025     slur_strs = ['']
1026
1027     last_str = ''
1028     while last_str <> str:
1029         last_str = str
1030
1031         def sub_tremolos (m, slur_strs = slur_strs):
1032             tr = m.group (2)
1033             if tr not in slur_strs:
1034                 slur_strs.append (tr)
1035             return  m.group (1)
1036
1037         str = re.sub (r"([a-z]+[',!? ]*)(:[0-9]+)",
1038                       sub_tremolos, str)
1039
1040         def sub_dyn_end (m, dyns = dyns):
1041             dyns.append (' \!')
1042             return ' ' + m.group(2)
1043
1044         str = re.sub (r'(\\!)\s*([a-z]+)', sub_dyn_end, str)
1045         def sub_slurs(m, slur_strs = slur_strs):
1046             if '-)' not in slur_strs:
1047                 slur_strs.append (')')
1048             return m.group(1)
1049
1050         def sub_p_slurs(m, slur_strs = slur_strs):
1051             if '-\)' not in slur_strs:
1052                 slur_strs.append ('\)')
1053             return m.group(1)
1054
1055         str = re.sub (r"\)[ ]*([a-z]+)", sub_slurs, str)
1056         str = re.sub (r"\\\)[ ]*([a-z]+)", sub_p_slurs, str)
1057         def sub_begin_slurs(m, slur_strs = slur_strs):
1058             if '-(' not in slur_strs:
1059                 slur_strs.append ('(')
1060             return m.group(1)
1061
1062         str = re.sub (r"([a-z]+[,'!?0-9 ]*)\(",
1063                       sub_begin_slurs, str)
1064         def sub_begin_p_slurs(m, slur_strs = slur_strs):
1065             if '-\(' not in slur_strs:
1066                 slur_strs.append ('\(')
1067             return m.group(1)
1068
1069         str = re.sub (r"([a-z]+[,'!?0-9 ]*)\\\(",
1070                 sub_begin_p_slurs, str)
1071
1072         def sub_dyns (m, slur_strs = slur_strs):
1073             s = m.group(0)
1074             if s == '@STARTCRESC@':
1075                 slur_strs.append ("\\<")
1076             elif s == '@STARTDECRESC@':
1077                 slur_strs.append ("\\>")
1078             elif s == r'-?\\!':
1079                 slur_strs.append ('\\!')
1080             return ''
1081
1082         str = re.sub (r'@STARTCRESC@', sub_dyns, str)
1083         str = re.sub (r'-?\\!', sub_dyns, str)
1084
1085         def sub_articulations (m, slur_strs = slur_strs):
1086             a = m.group(1)
1087             if a not in slur_strs:
1088                 slur_strs.append (a)
1089             return ''
1090
1091         str = re.sub (r"([_^-]\@ACCENT\@)", sub_articulations,
1092                       str)
1093         str = re.sub (r"([_^-]\\[a-z]+)", sub_articulations,
1094                       str)
1095         str = re.sub (r"([_^-][>_.+|^-])", sub_articulations,
1096                       str)
1097         str = re.sub (r'([_^-]"[^"]+")', sub_articulations,
1098                       str)
1099
1100         def sub_pslurs(m, slur_strs = slur_strs):
1101             slur_strs.append (' \\)')
1102             return m.group(1)
1103         str = re.sub (r"\\\)[ ]*([a-z]+)", sub_pslurs, str)
1104
1105     ## end of while <>
1106
1107     suffix = ''.join (slur_strs) + ''.join (pslur_strs) \
1108              + ''.join (dyns)
1109
1110     return '@STARTCHORD@%s@ENDCHORD@%s%s' % (str , dur_str, suffix)
1111
1112
1113
1114 def sub_chords (str):
1115     simend = '>'
1116     simstart = '<'
1117     chordstart = '<<'
1118     chordend = '>>'
1119     marker_str = '%% new-chords-done %%'
1120
1121     if re.search (marker_str,str):
1122         return str
1123     str = re.sub ('<<', '@STARTCHORD@', str)
1124     str = re.sub ('>>', '@ENDCHORD@', str)
1125
1126     str = re.sub (r'\\<', '@STARTCRESC@', str)
1127     str = re.sub (r'\\>', '@STARTDECRESC@', str)
1128     str = re.sub (r'([_^-])>', r'\1@ACCENT@', str)
1129     str = re.sub (r'<([^<>{}]+)>', sub_chord, str)
1130
1131     # add dash: -[, so that [<<a b>> c d] becomes
1132     #                      <<a b>>-[ c d]
1133     # and gets skipped by articulation_substitute
1134     str = re.sub (r'\[ *(@STARTCHORD@[^@]+@ENDCHORD@[0-9.]*)',
1135                   r'\1-[', str)
1136     str = re.sub (r'\\! *(@STARTCHORD@[^@]+@ENDCHORD@[0-9.]*)',
1137                   r'\1-\\!', str)
1138
1139     str = re.sub (r'<([^?])', r'%s\1' % simstart, str)
1140     str = re.sub (r'>([^?])', r'%s\1' % simend,  str)
1141     str = re.sub ('@STARTCRESC@', r'\\<', str)
1142     str = re.sub ('@STARTDECRESC@', r'\\>' ,str)
1143     str = re.sub (r'\\context *Voice *@STARTCHORD@',
1144                   '@STARTCHORD@', str)
1145     str = re.sub ('@STARTCHORD@', chordstart, str)
1146     str = re.sub ('@ENDCHORD@', chordend, str)
1147     str = re.sub (r'@ACCENT@', '>', str)
1148     return str
1149
1150 markup_start = re.compile(r"([-^_]|\\mark)\s*(#\s*'\s*)\(")
1151 musicglyph = re.compile(r"\(\s*music\b")
1152 columns = re.compile(r"\(\s*columns\b")
1153 submarkup_start = re.compile(r"\(\s*([a-zA-Z]+)")
1154 leftpar = re.compile(r"\(")
1155 rightpar = re.compile(r"\)")
1156
1157 def text_markup (str):
1158     result = ''
1159     # Find the beginning of each markup:
1160     match = markup_start.search (str)
1161     while match:
1162         result = result + str[:match.end (1)] + " \markup"
1163         str = str[match.end( 2):]
1164         # Count matching parentheses to find the end of the
1165         # current markup:
1166         nesting_level = 0
1167         pars = re.finditer(r"[()]",str)
1168         for par in pars:
1169             if par.group () == '(':
1170                 nesting_level = nesting_level + 1
1171             else:
1172                 nesting_level = nesting_level - 1
1173             if nesting_level == 0:
1174                 markup_end = par.end ()
1175                 break
1176         # The full markup in old syntax:
1177         markup = str[:markup_end]
1178         # Modify to new syntax:
1179         markup = musicglyph.sub (r"{\\musicglyph", markup)
1180         markup = columns.sub (r"{", markup)
1181         markup = submarkup_start.sub (r"{\\\1", markup)
1182         markup = leftpar.sub ("{", markup)
1183         markup = rightpar.sub ("}", markup)
1184
1185         result = result + markup
1186         # Find next markup
1187         str = str[markup_end:]
1188         match = markup_start.search(str)
1189     result = result + str
1190     return result
1191
1192 def articulation_substitute (str):
1193     str = re.sub (r"""([^-])\[ *(\\?\)?[a-z]+[,']*[!?]?[0-9:]*\.*)""",
1194                   r"\1 \2[", str)
1195     str = re.sub (r"""([^-])\\\) *([a-z]+[,']*[!?]?[0-9:]*\.*)""",
1196                   r"\1 \2\\)", str)
1197     str = re.sub (r"""([^-\\])\) *([a-z]+[,']*[!?]?[0-9:]*\.*)""",
1198                   r"\1 \2)", str)
1199     str = re.sub (r"""([^-])\\! *([a-z]+[,']*[!?]?[0-9:]*\.*)""",
1200                   r"\1 \2\\!", str)
1201     return str
1202
1203 string_or_scheme = re.compile ('("(?:[^"\\\\]|\\\\.)*")|(#\\s*\'?\\s*\\()')
1204
1205 # Only apply articulation_substitute () outside strings and
1206 # Scheme expressions:
1207 def smarter_articulation_subst (str):
1208     result = ''
1209     # Find the beginning of next string or Scheme expr.:
1210     match = string_or_scheme.search (str)
1211     while match:
1212         # Convert the preceding LilyPond code:
1213         previous_chunk = str[:match.start()]
1214         result = result + articulation_substitute (previous_chunk)
1215         if match.group (1): # Found a string
1216             # Copy the string to output:
1217             result = result + match.group (1)
1218             str = str[match.end(1):]
1219         else: # Found a Scheme expression. Count
1220             # matching parentheses to find its end
1221             str = str[match.start ():]
1222             nesting_level = 0
1223             pars = re.finditer(r"[()]",str)
1224             for par in pars:
1225                 if par.group () == '(':
1226                     nesting_level = nesting_level + 1
1227                 else:
1228                     nesting_level = nesting_level - 1
1229                 if nesting_level == 0:
1230                     scheme_end = par.end ()
1231                     break
1232             # Copy the Scheme expression to output:
1233             result = result + str[:scheme_end]
1234             str = str[scheme_end:]
1235         # Find next string or Scheme expression:
1236         match = string_or_scheme.search (str)
1237     # Convert the remainder of the file
1238     result = result + articulation_substitute (str)
1239     return result
1240
1241 def conv_relative(str):
1242     if re.search (r"\\relative", str):
1243         str= "#(ly:set-option 'old-relative)\n" + str
1244
1245     return str
1246
1247 @rule ((1, 9, 0), _ ("""New relative mode,
1248 Postfix articulations, new text markup syntax, new chord syntax."""))
1249 def conv (str):
1250     str = re.sub (r"#'\(\)", "@SCM_EOL@", str)
1251     str =  conv_relative (str)
1252     str = sub_chords (str)
1253
1254     str = text_markup (str)
1255     str = smarter_articulation_subst (str)
1256     str = re.sub ("@SCM_EOL@", "#'()", str)
1257     return str
1258
1259
1260 @rule ((1, 9, 1), _ ("Remove - before articulation"))
1261 def conv (str):
1262     if re.search ("font-style",str):
1263         stderr_write (NOT_SMART % "font-style")
1264         stderr_write (UPDATE_MANUALLY)
1265
1266         raise FatalConversionError ()
1267
1268     str = re.sub (r'-\\markup', r'@\\markup', str)
1269     str = re.sub (r'-\\', r'\\', str)
1270     str = re.sub (r'-\)', ')', str)
1271     str = re.sub (r'-\(', '(', str)
1272     str = re.sub ('-\[', '[', str)
1273     str = re.sub ('-\]', ']', str)
1274     str = re.sub ('-~', '~', str)
1275     str = re.sub (r'@\\markup', r'-\\markup', str)
1276     return str
1277
1278
1279 @rule ((1, 9, 2), "\\newcontext -> \\new")
1280 def conv (str):
1281     str = re.sub ('ly:set-context-property',
1282                   'ly:set-context-property!', str)
1283     str = re.sub ('\\\\newcontext', '\\\\new', str)
1284     str = re.sub ('\\\\grace[\t\n ]*([^{ ]+)',
1285                   r'\\grace { \1 }', str)
1286     str = re.sub ("\\\\grace[\t\n ]*{([^}]+)}",
1287                   r"""\\grace {
1288 \\property Voice.Stem \\override #'stroke-style = #"grace"
1289   \1
1290   \\property Voice.Stem \\revert #'stroke-style }
1291 """, str)
1292     return str
1293
1294
1295 @rule ((1, 9, 3), (_ ("%s misspelling") % "\\acciaccatura") +
1296                          ", fingerHorizontalDirection -> fingeringOrientations")
1297 def conv (str):
1298     str = re.sub ('accacciatura',
1299                   'acciaccatura', str)
1300
1301     if re.search ("context-spec-music", str):
1302         stderr_write (NOT_SMART % "context-spec-music")
1303         stderr_write (UPDATE_MANUALLY)
1304
1305         raise FatalConversionError ()
1306
1307     str = re.sub ('fingerHorizontalDirection *= *#(LEFT|-1)',
1308                   "fingeringOrientations = #'(up down left)", str)
1309     str = re.sub ('fingerHorizontalDirection *= *#(RIGHT|1)',
1310                   "fingeringOrientations = #'(up down right)", str)
1311     return str
1312
1313
1314 @rule ((1, 9, 4), _ ('Swap < > and << >>'))
1315 def conv (str):
1316     if re.search ('\\figures', str):
1317         warning (_ ("attempting automatic \\figures conversion.  Check results!"));
1318
1319     def figures_replace (m):
1320         s = m.group (1)
1321         s = re.sub ('<', '@FIGOPEN@',s)
1322         s = re.sub ('>', '@FIGCLOSE@',s)
1323         return '\\figures { %s }' % s
1324
1325     str = re.sub (r'\\figures[ \t\n]*{([^}]+)}', figures_replace, str)
1326     str = re.sub (r'\\<', '@STARTCRESC@', str)
1327     str = re.sub (r'\\>', '@STARTDECRESC@', str)
1328     str = re.sub (r'([-^_])>', r'\1@ACCENT@', str)
1329     str = re.sub (r'<<', '@STARTCHORD@', str)
1330     str = re.sub (r'>>', '@ENDCHORD@', str)
1331     str = re.sub (r'>', '@ENDSIMUL@', str)
1332     str = re.sub (r'<', '@STARTSIMUL@', str)
1333     str = re.sub ('@STARTDECRESC@', '\\>', str)
1334     str = re.sub ('@STARTCRESC@', '\\<', str)
1335     str = re.sub ('@ACCENT@', '>', str)
1336     str = re.sub ('@ENDCHORD@', '>', str)
1337     str = re.sub ('@STARTCHORD@', '<', str)
1338     str = re.sub ('@STARTSIMUL@', '<<', str)
1339     str = re.sub ('@ENDSIMUL@', '>>', str)
1340     str = re.sub ('@FIGOPEN@', '<', str)
1341     str = re.sub ('@FIGCLOSE@', '>', str)
1342     return str
1343
1344
1345 @rule ((1, 9, 5), 'HaraKiriVerticalGroup -> RemoveEmptyVerticalGroup')
1346 def conv (str):
1347     str = re.sub ('HaraKiriVerticalGroup', 'RemoveEmptyVerticalGroup', str)
1348     return str
1349
1350
1351 @rule ((1, 9, 6), _ ('deprecate %s') % 'ly:get-font')
1352 def conv (str):
1353     if re.search ("ly:get-font", str) :
1354         stderr_write (NOT_SMART % "ly:get-font")
1355         stderr_write (FROM_TO \
1356                           % ("(ly:paper-get-font (ly:grob-get-paper foo) .. )",
1357                              "(ly:paper-get-font (ly:grob-get-paper foo) .. )"))
1358         stderr_write (UPDATE_MANUALLY)
1359         raise FatalConversionError ()
1360
1361     if re.search ("\\pitch *#", str) :
1362         stderr_write (NOT_SMART % "\\pitch")
1363         stderr_write (_ ("Use Scheme code to construct arbitrary note events."))
1364         stderr_write ('\n')
1365
1366         raise FatalConversionError ()
1367     return str
1368
1369
1370 @rule ((1, 9, 7), _ ('''use symbolic constants for alterations,
1371 remove \\outputproperty, move ly:verbose into ly:get-option'''))
1372 def conv (str):
1373     def sub_alteration (m):
1374         alt = m.group (3)
1375         alt = {
1376                 '-1': 'FLAT',
1377                 '-2': 'DOUBLE-FLAT',
1378                 '0': 'NATURAL',
1379                 '1': 'SHARP',
1380                 '2': 'DOUBLE-SHARP',
1381                 }[alt]
1382
1383         return '(ly:make-pitch %s %s %s)' % (m.group(1), m.group (2),
1384                                              alt)
1385
1386     str =re.sub ("\\(ly:make-pitch *([0-9-]+) *([0-9-]+) *([0-9-]+) *\\)",
1387                  sub_alteration, str)
1388
1389
1390     str = re.sub ("ly:verbose", "ly:get-option 'verbose", str)
1391
1392     m= re.search ("\\\\outputproperty #([^#]+)[\t\n ]*#'([^ ]+)", str)
1393     if m:
1394         stderr_write (_ (\
1395                 r"""\outputproperty found,
1396 Please hand-edit, using
1397
1398   \applyoutput #(outputproperty-compatibility %s '%s <GROB PROPERTY VALUE>)
1399
1400 as a substitution text.""") % (m.group (1), m.group (2)) )
1401         raise FatalConversionError ()
1402
1403     if re.search ("ly:(make-pitch|pitch-alteration)", str) \
1404            or re.search ("keySignature", str):
1405         stderr_write (NOT_SMART % "pitches")
1406         stderr_write (
1407             _ ("""The alteration field of Scheme pitches was multiplied by 2
1408 to support quarter tone accidentals.  You must update the following constructs manually:
1409
1410 * calls of ly:make-pitch and ly:pitch-alteration
1411 * keySignature settings made with \property
1412 """))
1413         raise FatalConversionError ()
1414     return str
1415
1416
1417 @rule ((1, 9, 8), "dash-length -> dash-fraction")
1418 def conv (str):
1419     if re.search ("dash-length",str):
1420         stderr_write (NOT_SMART % "dash-length")
1421         stderr_write (FROM_TO % ("dash-length", "dash-fraction"))
1422         stderr_write (UPDATE_MANUALLY)
1423         raise FatalConversionError ()
1424     return str
1425
1426
1427 @rule ((2, 1, 1), "font-relative-size -> font-size")
1428 def conv (str):
1429     def func(match):
1430         return "#'font-size = #%d" % (2*int (match.group (1)))
1431
1432     str =re.sub (r"#'font-relative-size\s*=\s*#\+?([0-9-]+)", func, str)
1433     str =re.sub (r"#'font-family\s*=\s*#'ancient",
1434                  r"#'font-family = #'music", str)
1435     return str
1436
1437
1438 @rule ((2, 1, 2), "ly:get-music-length -> ly:music-length")
1439 def conv (str):
1440     str =re.sub (r"ly:get-music-length", "ly:music-length", str)
1441     return str
1442
1443
1444 @rule ((2, 1, 3), "stanza -> instrument")
1445 def conv (str):
1446     str =re.sub (r"\.\s+stz=", ". instr ", str)
1447     return str
1448
1449
1450 @rule ((2, 1, 4), _ ("removal of automaticMelismata; use melismaBusyProperties instead."))
1451 def conv (str):
1452     def func (match):
1453         c = match.group (1)
1454         b = match.group (2)
1455
1456         if b == 't':
1457             if c == 'Score':
1458                 return ''
1459             else:
1460                 return r" \property %s.melismaBusyProperties \unset"  % c
1461         elif b == 'f':
1462             return r"\property %s.melismaBusyProperties = #'(melismaBusy)"  % c
1463
1464     str = re.sub (r"\\property ([a-zA-Z]+)\s*\.\s*automaticMelismata\s*=\s*##([ft])", func, str)
1465     return str
1466
1467
1468 @rule ((2, 1, 7), "\\translator Staff -> \\change Staff")
1469 def conv (str):
1470     str =re.sub (r"\\translator\s+([a-zA-Z]+)", r"\\change \1", str)
1471     return str
1472
1473
1474 @rule ((2, 1, 10), "\\newaddlyrics -> \\lyricsto")
1475 def conv (str):
1476     str =re.sub (r"\\newaddlyrics", r"\\lyricsto", str)
1477     return str
1478
1479
1480 @rule ((2, 1, 11), """\\include "paper16.ly" -> #(set-staff-size 16)
1481 \\note #3 #1 #1 -> \\note #"8." #1
1482 """)
1483 def conv (str):
1484     str = re.sub (r'\\include\s*"paper([0-9]+)(-init)?.ly"',
1485                   r"#(set-staff-size \1)", str)
1486
1487     def sub_note (match):
1488         dur = ''
1489         log = int (match.group (1))
1490         dots = int (match.group (2))
1491
1492         if log >= 0:
1493             dur = '%d' % (1 << log)
1494         else:
1495             dur = { -1 : 'breve',
1496                     -2 : 'longa',
1497                     -3 : 'maxima'}[log]
1498
1499         dur += ('.' * dots)
1500
1501         return r'\note #"%s" #%s' % (dur, match.group (3))
1502
1503     str = re.sub (r'\\note\s+#([0-9-]+)\s+#([0-9]+)\s+#([0-9.-]+)',
1504                   sub_note, str)
1505     return str
1506
1507
1508 @rule ((2, 1, 12), "OttavaSpanner -> OttavaBracket")
1509 def conv (str):
1510     str = re.sub (r"OttavaSpanner", r"OttavaBracket", str)
1511     return str
1512
1513
1514 @rule ((2, 1, 13), "set-staff-size -> set-global-staff-size")
1515 def conv (str):
1516     str = re.sub (r"\(set-staff-size ", r"(set-global-staff-size ", str)
1517     return str
1518
1519
1520 @rule ((2, 1, 14), "style = dotted -> dash-fraction = 0")
1521 def conv (str):
1522     str = re.sub (r"#'style\s*=\s*#'dotted-line",
1523                  r"#'dash-fraction = #0.0 ", str)
1524     return str
1525
1526
1527 @rule ((2, 1, 15), "LyricsVoice . instr(ument) -> vocalName")
1528 def conv (str):
1529     str = re.sub (r'LyricsVoice\s*\.\s*instrument\s*=\s*("[^"]*")',
1530                  r'LyricsVoice . vocalName = \1', str)
1531
1532     str = re.sub (r'LyricsVoice\s*\.\s*instr\s*=\s*("[^"]*")',
1533                  r'LyricsVoice . vocNam = \1', str)
1534     return str
1535
1536
1537 @rule ((2, 1, 16), '\\musicglyph #"accidentals-NUM" -> \\sharp/flat/etc.')
1538 def conv (str):
1539     def sub_acc (m):
1540         d = {
1541         '4': 'doublesharp',
1542         '3': 'threeqsharp',
1543         '2': 'sharp',
1544         '1': 'semisharp',
1545         '0': 'natural',
1546         '-1': 'semiflat',
1547         '-2': 'flat',
1548         '-3': 'threeqflat',
1549         '-4': 'doubleflat'}
1550         return '\\%s' %  d[m.group (1)]
1551
1552     str = re.sub (r'\\musicglyph\s*#"accidentals-([0-9-]+)"',
1553                   sub_acc, str)
1554     return str
1555
1556
1557 @rule ((2, 1, 17), _ ("\\partcombine syntax change to \\newpartcombine"))
1558 def conv (str):
1559
1560     if re.search (r'\\partcombine', str):
1561         stderr_write (NOT_SMART % "\\partcombine")
1562         stderr_write (UPDATE_MANUALLY)
1563         raise FatalConversionError ()
1564
1565     # this rule doesn't really work,
1566     # too lazy to figure out why.
1567     str = re.sub (r'\\context\s+Voice\s*=\s*one\s*\\partcombine\s+Voice\s*\\context\s+Thread\s*=\s*one(.*)\s*'
1568                   + r'\\context\s+Thread\s*=\s*two',
1569                   '\\\\newpartcombine\n\\1\n', str)
1570     return str
1571
1572
1573 @rule ((2, 1, 18), """\\newpartcombine -> \\partcombine,
1574 \\autochange Staff -> \\autochange
1575 """)
1576 def conv (str):
1577     str = re.sub (r'\\newpartcombine', r'\\partcombine', str)
1578     str = re.sub (r'\\autochange\s+Staff', r'\\autochange ', str)
1579     return str
1580
1581
1582 @rule ((2, 1, 19), _ ("""Drum notation changes, Removing \\chordmodifiers, \\notenames.
1583 Harmonic notes. Thread context removed. Lyrics context removed."""))
1584 def conv (str):
1585     if re.search ('include "drumpitch', str):
1586         stderr_write (_ ("Drums found. Enclose drum notes in \\drummode"))
1587
1588     str = re.sub (r'\\include "drumpitch-init.ly"','', str)
1589
1590     str = re.sub (r'\\pitchnames ','pitchnames = ', str)
1591     str = re.sub (r'\\chordmodifiers ','chordmodifiers = ', str)
1592     str = re.sub (r'\bdrums\b\s*=','drumContents = ', str)
1593     str = re.sub (r'\\drums\b','\\drumContents ', str)
1594
1595
1596     if re.search ('drums->paper', str):
1597         stderr_write (_ ("\n%s found. Check file manually!\n") % _("Drum notation"))
1598
1599     str = re.sub (r"""\\apply\s+#\(drums->paper\s+'([a-z]+)\)""",
1600                   r"""\property DrumStaff.drumStyleTable = #\1-style""",
1601                   str)
1602
1603     if re.search ('Thread', str):
1604         stderr_write (_ ("\n%s found. Check file manually!\n") % "Thread");
1605
1606     str = re.sub (r"""(\\once\s*)?\\property\s+Thread\s*\.\s*NoteHead\s*"""
1607                   + r"""\\(set|override)\s*#'style\s*=\s*#'harmonic"""
1608                   + r"""\s+([a-z]+[,'=]*)([0-9]*\.*)"""
1609                   ,r"""<\3\\harmonic>\4""", str)
1610
1611     str = re.sub (r"""\\new Thread""", """\context Voice""", str)
1612     str = re.sub (r"""Thread""", """Voice""", str)
1613
1614     if re.search ('\bLyrics\b', str):
1615         stderr_write (_ ("\n%s found. Check file manually!\n") % "Lyrics");
1616
1617     str = re.sub (r"""LyricsVoice""", r"""L@ricsVoice""", str)
1618     str = re.sub (r"""\bLyrics\b""", r"""LyricsVoice""", str)
1619     str = re.sub (r"""LyricsContext""", r"""LyricsVoiceContext""", str)
1620     str = re.sub (r"""L@ricsVoice""", r"""LyricsVoice""",str)
1621     return str
1622
1623
1624 @rule ((2, 1, 20), "nonevent-skip -> skip-music")
1625 def conv (str):
1626     str = re.sub (r'nonevent-skip', 'skip-music', str)
1627     return str
1628
1629
1630 @rule ((2, 1, 21), """molecule-callback -> print-function,
1631 brew_molecule -> print
1632 brew-new-markup-molecule -> Text_item::print
1633 LyricsVoice -> Lyrics
1634 tupletInvisible -> TupletBracket \set #'transparent
1635 %s.
1636 """ % (_ ("remove %s") % "Grob::preset_extent"))
1637 def conv (str):
1638     str = re.sub (r'molecule-callback', 'print-function', str)
1639     str = re.sub (r'brew_molecule', 'print', str)
1640     str = re.sub (r'brew-new-markup-molecule', 'Text_item::print', str)
1641     str = re.sub (r'LyricsVoice', 'Lyrics', str)
1642     str = re.sub (r'tupletInvisible',
1643                   r"TupletBracket \\set #'transparent", str)
1644 #       str = re.sub (r'molecule', 'collage', str)
1645 #molecule -> collage
1646     str = re.sub (r"\\property\s+[a-zA-Z]+\s*\.\s*[a-zA-Z]+\s*"
1647                   + r"\\set\s*#'X-extent-callback\s*=\s*#Grob::preset_extent",
1648                   "", str)
1649     return str
1650
1651
1652 @rule ((2, 1, 22), """%s
1653         \\set A.B = #C , \\unset A.B
1654         \\override A.B #C = #D, \\revert A.B #C
1655
1656 """ % _ ("new syntax for property settings:"))
1657 def conv (str):
1658     str = re.sub (r'(\\property[^=]+)=\s*([-0-9]+)',
1659                   r'\1= #\2', str)
1660     str = re.sub (r'\\property\s+([^. ]+)\s*\.\s*([^\\=]+)\s*\\(set|override)',
1661                   r"\\overrid@ \1.\2 ", str)
1662     str = re.sub (r'\\property\s+([^. ]+)\s*\.\s*([^\\= ]+)\s*=\s*',
1663                   r'\\s@t \1.\2 = ', str)
1664     str = re.sub (r'\\property\s+([^. ]+)\s*\.\s*([^\\= ]+)\s*\\unset',
1665                   r'\\uns@t \1.\2 ', str)
1666     str = re.sub (r'\\property\s+([^. ]+)\s*\.\s*([^\\= ]+)\s*\\revert'
1667                   + r"\s*#'([-a-z0-9_]+)",
1668                   r"\\rev@rt \1.\2 #'\3", str)
1669     str = re.sub (r'Voice\.', '', str)
1670     str = re.sub (r'Lyrics\.', '', str)
1671     str = re.sub (r'ChordNames\.', '', str)
1672
1673     str = re.sub ('rev@rt', 'revert',str)
1674     str = re.sub ('s@t', 'set',str)
1675     str = re.sub ('overrid@', 'override',str)
1676
1677     str = re.sub ('molecule', 'stencil', str)
1678     str = re.sub ('Molecule', 'Stencil', str)
1679     return str
1680
1681
1682 @rule ((2, 1, 23), _ ("Property setting syntax in \\translator{ }"))
1683 def conv (str):
1684     def subst_in_trans (match):
1685         s = match.group (0)
1686         s = re.sub (r'\s([a-zA-Z]+)\s*\\override',
1687                       r' \\override \1', s)
1688         s = re.sub (r'\s([a-zA-Z]+)\s*\\set',
1689                       r' \\override \1', s)
1690         s = re.sub (r'\s([a-zA-Z]+)\s*\\revert',
1691                       r' \\revert \1', s)
1692         return s
1693     str = re.sub (r'\\(translator|with)\s*{[^}]+}',  subst_in_trans, str)
1694
1695     def sub_abs (m):
1696
1697         context = m.group ('context')
1698         d = m.groupdict ()
1699         if context:
1700             context = " '%s" % context[:-1] # -1: remove .
1701         else:
1702             context = ''
1703
1704         d['context'] = context
1705
1706         return r"""#(override-auto-beam-setting %(prop)s %(num)s %(den)s%(context)s)""" % d
1707
1708     str = re.sub (r"""\\override\s*(?P<context>[a-zA-Z]+\s*\.\s*)?autoBeamSettings"""
1709                   +r"""\s*#(?P<prop>[^=]+)\s*=\s*#\(ly:make-moment\s+(?P<num>\d+)\s+(?P<den>\d)\s*\)""",
1710                   sub_abs, str)
1711     return str
1712
1713
1714 @rule ((2, 1, 24), "music-list? -> ly:music-list?")
1715 def conv (str):
1716     str = re.sub (r'music-list\?', 'ly:music-list?', str)
1717     str = re.sub (r'\|\s*~', '~ |', str)
1718     return str
1719
1720
1721 @rule ((2, 1, 25), _ ("Scheme grob function renaming"))
1722 def conv (str):
1723     str = re.sub (r'ly:get-spanner-bound', 'ly:spanner-get-bound', str)
1724     str = re.sub (r'ly:get-extent', 'ly:grob-extent', str)
1725     str = re.sub (r'ly:get-system', 'ly:grob-system', str)
1726     str = re.sub (r'ly:get-original', 'ly:grob-original', str)
1727     str = re.sub (r'ly:get-parent', 'ly:grob-parent', str)
1728     str = re.sub (r'ly:get-broken-into', 'ly:spanner-broken-into', str)
1729     str = re.sub (r'Melisma_engraver', 'Melisma_translator', str)
1730     if re.search ("ly:get-paper-variable", str):
1731         stderr_write (NOT_SMART % "ly:paper-get-variable")
1732         stderr_write (_ ('Use %s\n') % '(ly:paper-lookup (ly:grob-paper ))')
1733         raise FatalConversionError ()
1734
1735     str = re.sub (r'\\defaultAccidentals', "#(set-accidental-style 'default)", str)
1736     str = re.sub (r'\\voiceAccidentals', "#(set-accidental-style 'voice)", str)
1737     str = re.sub (r'\\modernAccidentals', "#(set-accidental-style 'modern)", str)
1738     str = re.sub (r'\\modernCautionaries', "#(set-accidental-style 'modern-cautionary)", str)
1739     str = re.sub (r'\\modernVoiceAccidental', "#(set-accidental-style 'modern-voice)", str)
1740     str = re.sub (r'\\modernVoiceCautionaries', "#(set-accidental-style 'modern-voice-cautionary)", str)
1741     str = re.sub (r'\\pianoAccidentals', "#(set-accidental-style 'piano)", str)
1742     str = re.sub (r'\\pianoCautionaries', "#(set-accidental-style 'piano-cautionary)", str)
1743     str = re.sub (r'\\forgetAccidentals', "#(set-accidental-style 'forget)", str)
1744     str = re.sub (r'\\noResetKey', "#(set-accidental-style 'no-reset)", str)
1745     return str
1746
1747
1748 @rule ((2, 1, 26), _ ("More Scheme function renaming"))
1749 def conv (str):
1750     str = re.sub ('ly:set-grob-property!', 'ly:grob-set-property!',str)
1751     str = re.sub ('ly:set-mus-property!', 'ly:music-set-property!',str)
1752     str = re.sub ('ly:set-context-property!', 'ly:context-set-property!', str)
1753     str = re.sub ('ly:get-grob-property', 'ly:grob-property',str)
1754     str = re.sub ('ly:get-mus-property', 'ly:music-property',str)
1755     str = re.sub ('ly:get-context-property', 'ly:context-property',str)
1756     return str
1757
1758
1759 @rule ((2, 1, 27), "property transposing -> tuning")
1760 def conv (str):
1761     def subst (m):
1762         g = int (m.group (2))
1763         o = g / 12
1764         g -= o * 12
1765         if g <  0:
1766             g += 12
1767             o -= 1
1768
1769
1770         lower_pitches = filter (lambda x : x <= g, [0, 2, 4, 5, 7, 9, 11, 12])
1771         s = len (lower_pitches) -1
1772         a = g - lower_pitches [-1]
1773
1774
1775         str = 'cdefgab' [s]
1776         str += ['eses', 'es', '', 'is', 'isis'][a + 2]
1777         if o < 0:
1778             str += ',' * (-o - 1)
1779         elif o >= 0:
1780             str += "'" * (o + 1)
1781
1782         return '\\transposition %s ' % str
1783
1784
1785     str = re.sub (r"\\set ([A-Za-z]+\s*\.\s*)?transposing\s*=\s*#([-0-9]+)",
1786                   subst, str)
1787     return str
1788
1789
1790 @rule ((2, 1, 28), """make-music-by-name -> make-music,
1791 new syntax for setting \\arpeggioBracket""")
1792 def conv (str):
1793     str = re.sub (r'make-music-by-name', 'make-music', str)
1794     str = re.sub (r"\\override\s+.*Arpeggio\s+#.print-function\s+=\s+\\arpeggioBracket", r"\\arpeggioBracket", str)
1795     return str
1796
1797
1798 @rule ((2, 1, 29), '\\center -> \\center-align, \\translator -> \\context')
1799 def conv (str):
1800     str = re.sub (r'\\center([^-])', '\\center-align\\1', str)
1801     str = re.sub (r'\\translator', '\\context', str)
1802     return str
1803
1804
1805 @rule ((2, 1, 30), '''\\threeq{flat,sharp} -> \\sesqui{flat,sharp}
1806 ly:get-mutable-properties -> ly:mutable-music-properties
1807 centralCPosition -> middleCPosition
1808 ly:unset-context-property -> ly:context-unset-property
1809 ly:translator-find -> ly:context-find
1810 ly:get-stencil-extent -> ly:stencil-extent
1811 ''')
1812 def conv (str):
1813     str = re.sub (r'\\threeq(flat|sharp)', r'\\sesqui\1', str)
1814     str = re.sub (r'ly:stencil-get-extent',
1815                   'ly:stencil-extent', str)
1816     str = re.sub (r'ly:translator-find',
1817                   'ly:context-find', str)
1818     str = re.sub ('ly:unset-context-property','ly:context-unset-property',
1819                   str)
1820
1821     str = re.sub (r'ly:get-mutable-properties',
1822                   'ly:mutable-music-properties',str)
1823     str = re.sub (r'centralCPosition',
1824                   'middleCPosition',str)
1825     return str
1826
1827
1828 @rule ((2, 1, 31), 'remove \\alias Timing')
1829 def conv (str):
1830     str = re.sub (r'\\alias\s*"?Timing"?', '', str)
1831     return str
1832
1833
1834 @rule ((2, 1, 33), 'breakAlignOrder -> break-align-orders.')
1835 def conv (str):
1836     str = re.sub (r"(\\set\s+)?(?P<context>(Score\.)?)breakAlignOrder\s*=\s*#'(?P<list>[^\)]+)",
1837                   r"\n\\override \g<context>BreakAlignment #'break-align-orders = "
1838                   + "#(make-vector 3 '\g<list>)", str)
1839     return str
1840
1841
1842 @rule ((2, 1, 34), 'set-paper-size -> set-default-paper-size.')
1843 def conv (str):
1844     str = re.sub (r"\(set-paper-size",
1845                   "(set-default-paper-size",str)
1846     return str
1847
1848
1849 @rule ((2, 1, 36), 'ly:mutable-music-properties -> ly:music-mutable-properties')
1850 def conv (str):
1851     str = re.sub (r"ly:mutable-music-properties",
1852                   "ly:music-mutable-properties", str)
1853     return str
1854
1855
1856 @rule ((2, 2, 0), _ ("bump version for release"))
1857 def conv (str):
1858     return str
1859
1860
1861 @rule ((2, 3, 1), '\\apply -> \\applymusic')
1862 def conv (str):
1863     return re.sub (r'\\apply\b', r'\\applymusic', str)
1864
1865
1866 @rule ((2, 3, 2), '\\FooContext -> \\Foo')
1867 def conv (str):
1868     if re.search ('textheight', str):
1869         stderr_write (NOT_SMART % "textheight")
1870         stderr_write (UPDATE_MANUALLY)
1871         stderr_write (
1872 _ ("""Page layout has been changed, using paper size and margins.
1873 textheight is no longer used.
1874 """))
1875     str = re.sub (r'\\OrchestralScoreContext', '\\Score', str)
1876     def func(m):
1877         if m.group(1) not in ['RemoveEmptyStaff',
1878                               'AncientRemoveEmptyStaffContext',
1879                               'EasyNotation']:
1880             return '\\' + m.group (1)
1881         else:
1882             return m.group (0)
1883
1884
1885     str = re.sub (r'\\([a-zA-Z]+)Context\b', func, str)
1886     str = re.sub ('ly:paper-lookup', 'ly:output-def-lookup', str)
1887     return str
1888
1889
1890 @rule ((2, 3, 4), _ ('remove %s') % '\\notes')
1891 def conv (str):
1892     str = re.sub (r'\\notes\b', '', str)
1893     return str
1894
1895
1896 @rule ((2, 3, 6), 'lastpagefill -> raggedlastbottom')
1897 def conv (str):
1898     str = re.sub (r'lastpagefill\s*=\s*"?1"', 'raggedlastbottom = ##t', str)
1899     return str
1900
1901
1902 @rule ((2, 3, 8), 'remove \\consistsend, strip \\lyrics from \\lyricsto.')
1903 def conv (str):
1904     str = re.sub (r'\\consistsend', '\\consists', str)
1905     str = re.sub (r'\\lyricsto\s+("?[a-zA-Z]+"?)(\s*\\new Lyrics\s*)?\\lyrics',
1906                   r'\\lyricsto \1 \2', str)
1907     return str
1908
1909
1910 @rule ((2, 3, 9), 'neo_mensural -> neomensural, if-text-padding -> bound-padding')
1911 def conv (str):
1912     str = re.sub (r'neo_mensural', 'neomensural', str)
1913     str = re.sub (r'if-text-padding', 'bound-padding', str)
1914     return str
1915
1916
1917 @rule ((2, 3, 10), '\\addlyrics -> \\oldaddlyrics, \\newlyrics -> \\addlyrics')
1918 def conv (str):
1919     str = re.sub (r'\\addlyrics', r'\\oldaddlyrics', str)
1920     str = re.sub (r'\\newlyrics', r'\\addlyrics', str)
1921     if re.search (r"\\override\s*TextSpanner", str):
1922         stderr_write ("\nWarning: TextSpanner has been split into DynamicTextSpanner and TextSpanner\n")
1923     return str
1924
1925
1926 @rule ((2, 3, 11), '\\setMmRestFermata -> ^\\fermataMarkup')
1927 def conv (str):
1928     str = re.sub (r'\\setMmRestFermata\s+(R[0-9.*/]*)',
1929                   r'\1^\\fermataMarkup', str)
1930     return str
1931
1932
1933 @rule ((2, 3, 12), '''\\newpage -> \\pageBreak, junk \\script{up,down,both},
1934 soloADue -> printPartCombineTexts, #notes-to-clusters -> \\makeClusters
1935 ''')
1936 def conv (str):
1937     str = re.sub (r'\\newpage', r'\\pageBreak', str)
1938     str = re.sub (r'\\scriptUp', r"""{
1939 \\override TextScript  #'direction = #1
1940 \\override Script  #'direction = #1
1941 }""", str)
1942     str = re.sub (r'\\scriptDown', r"""{
1943   \\override TextScript  #'direction = #-1
1944   \\override Script  #'direction = #-1
1945 }""", str)
1946     str = re.sub (r'\\scriptBoth', r"""{
1947   \\revert TextScript  #'direction
1948   \\revert Script  #'direction
1949 }""", str)
1950     str = re.sub ('soloADue', 'printPartCombineTexts', str)
1951     str = re.sub (r'\\applymusic\s*#notes-to-clusters',
1952                       '\\makeClusters', str)
1953
1954     str = re.sub (r'pagenumber\s*=', 'firstpagenumber = ', str)
1955     return str
1956
1957
1958 @rule ((2, 3, 16), _ ('''\\foo -> \\foomode (for chords, notes, etc.)
1959 fold \\new FooContext \\foomode into \\foo.'''))
1960 def conv (str):
1961     str = re.sub (r'\\chords\b', r'\\chordmode', str)
1962     str = re.sub (r'\\lyrics\b', r'\\lyricmode', str)
1963     str = re.sub (r'\\figures\b', r'\\figuremode', str)
1964     str = re.sub (r'\\notes\b', r'\\notemode', str)
1965     str = re.sub (r'\\drums\b', r'\\drummode', str)
1966     str = re.sub (r'\\chordmode\s*\\new ChordNames', r'\\chords', str)
1967     str = re.sub (r'\\new ChordNames\s*\\chordmode', r'\\chords', str)
1968     str = re.sub (r'\\new FiguredBass\s*\\figuremode', r'\\figures', str)
1969     str = re.sub (r'\\figuremode\s*\new FiguredBass', r'\\figures', str)
1970     str = re.sub (r'\\new DrumStaff\s*\\drummode', r'\\drums', str)
1971     str = re.sub (r'\\drummode\s*\\new DrumStaff', r'\\drums', str)
1972
1973     return str
1974
1975
1976 @rule ((2, 3, 17), '''slurBoth -> slurNeutral, stemBoth -> stemNeutral, etc.
1977 \\applymusic #(remove-tag 'foo) -> \\removeWithTag 'foo''')
1978 def conv (str):
1979     str = re.sub (r'(slur|stem|phrasingSlur|tie|dynamic|dots|tuplet|arpeggio|)Both', r'\1Neutral', str)
1980     str = re.sub (r"\\applymusic\s*#\(remove-tag\s*'([a-z-0-9]+)\)",
1981                   r"\\removeWithTag #'\1", str)
1982     return str
1983
1984
1985 @rule ((2, 3, 18), 'Text_item -> Text_interface')
1986 def conv (str):
1987     str = re.sub (r'Text_item', 'Text_interface', str)
1988     return str
1989
1990
1991 @rule ((2, 3, 22), 'paper -> layout, bookpaper -> paper')
1992 def conv (str):
1993     str = re.sub (r'\\paper', r'\\layout', str)
1994     str = re.sub (r'\\bookpaper', r'\\paper', str)
1995     if re.search ('paper-set-staff-size', str):
1996         warning (_ ('''staff size should be changed at top-level
1997 with
1998
1999   #(set-global-staff-size <STAFF-HEIGHT-IN-POINT>)
2000
2001 '''))
2002
2003
2004     str = re.sub (r'#\(paper-set-staff-size', '%Use set-global-staff-size at toplevel\n% #(layout-set-staff-size', str)
2005     return str
2006
2007
2008 @rule ((2, 3, 23), r'\context Foo = NOTENAME -> \context Foo = "NOTENAME"')
2009 def conv (str):
2010     str = re.sub (r'\\context\s+([a-zA-Z]+)\s*=\s*([a-z]+)\s',
2011                   r'\\context \1 = "\2" ',
2012                   str )
2013     return str
2014
2015
2016 @rule ((2, 3, 24), _ ('''regularize other identifiers'''))
2017 def conv (str):
2018     def sub(m):
2019         return regularize_id (m.group (1))
2020     str = re.sub (r'(maintainer_email|maintainer_web|midi_stuff|gourlay_maxmeasures)',
2021                   sub, str)
2022     return str
2023
2024
2025 @rule ((2, 3, 25), 'petrucci_c1 -> petrucci-c1, 1style -> single-digit')
2026 def conv (str):
2027     str = re.sub ('petrucci_c1', 'petrucci-c1', str)
2028     str = re.sub ('1style', 'single-digit', str)
2029     return str
2030
2031
2032 @rule ((2, 4, 0), _ ("bump version for release"))
2033 def conv (str):
2034     return str
2035
2036
2037 @rule ((2, 5, 0), '\\quote -> \\quoteDuring')
2038 def conv (str):
2039     str = re.sub (r'\\quote\s+"?([a-zA-Z0-9]+)"?\s+([0-9.*/]+)',
2040                   r'\\quoteDuring #"\1" { \skip \2 }',
2041                   str)
2042     return str
2043
2044
2045 @rule ((2, 5, 1), 'ly:import-module -> ly:module-copy')
2046 def conv (str):
2047     str = re.sub (r'ly:import-module',
2048                   r'ly:module-copy', str)
2049     return str
2050
2051
2052 @rule ((2, 5, 2), '\markup .. < .. > .. -> \markup .. { .. } ..')
2053 def conv (str):
2054     str = re.sub (r'\\(column|fill-line|dir-column|center-align|right-align|left-align|bracketed-y-column)\s*<(([^>]|<[^>]*>)*)>',
2055                   r'\\\1 {\2}', str)
2056     str = re.sub (r'\\(column|fill-line|dir-column|center-align|right-align|left-align|bracketed-y-column)\s*<(([^>]|<[^>]*>)*)>',
2057                   r'\\\1 {\2}', str)
2058     str = re.sub (r'\\(column|fill-line|dir-column|center-align|right-align|left-align|bracketed-y-column)\s*<(([^>]|<[^>]*>)*)>',
2059                   r'\\\1 {\2}', str)
2060     def get_markup (m):
2061         s = m.group (0)
2062         s = re.sub (r'''((\\"|})\s*){''', '\2 \\line {', s)
2063         return s
2064     str = re.sub (r'\\markup\s*{([^}]|{[^}]*})*}', get_markup, str)
2065     return str
2066
2067
2068 @rule ((2, 5, 3), 'ly:find-glyph-by-name -> ly:font-get-glyph, remove - from glyphnames.')
2069 def conv (str):
2070     str = re.sub ('ly:find-glyph-by-name', 'ly:font-get-glyph', str)
2071     str = re.sub ('"(scripts|clefs|accidentals)-', r'"\1.', str)
2072     str = re.sub ("'hufnagel-do-fa", "'hufnagel.do.fa", str)
2073     str = re.sub ("'(vaticana|hufnagel|medicaea|petrucci|neomensural|mensural)-", r"'\1.", str)
2074     return str
2075
2076
2077 @rule ((2, 5, 12), '\set Slur #\'dashed = #X -> \slurDashed')
2078 def conv (str):
2079     str = re.sub (r"\\override\s+(Voice\.)?Slur #'dashed\s*=\s*#\d*(\.\d+)?",
2080                   r"\\slurDashed", str)
2081     return str
2082
2083
2084 @rule ((2, 5, 13), _ ('\\encoding: smart recode latin1..utf-8. Remove ly:point-and-click'))
2085 def conv (str):
2086     input_encoding = 'latin1'
2087     def func (match):
2088         encoding = match.group (1)
2089
2090         # FIXME: automatic recoding of other than latin1?
2091         if encoding == 'latin1':
2092             return match.group (2)
2093
2094         stderr_write (NOT_SMART % ("\\encoding: %s" % encoding))
2095         stderr_write (_ ("LilyPond source must be UTF-8"))
2096         stderr_write ('\n')
2097         if encoding == 'TeX':
2098             stderr_write (_ ("Try the texstrings backend"))
2099             stderr_write ('\n')
2100         else:
2101             stderr_write ( _("Do something like: %s") % \
2102                                ("recode %s..utf-8 FILE" % encoding))
2103             stderr_write ('\n')
2104         stderr_write (_ ("Or save as UTF-8 in your editor"))
2105         stderr_write ('\n')
2106         raise FatalConversionError ()
2107
2108         return match.group (0)
2109
2110     str = re.sub (r'\\encoding\s+"?([a-zA-Z0-9]+)"?(\s+)', func, str)
2111
2112     import codecs
2113     de_ascii = codecs.getdecoder ('ascii')
2114     de_utf_8 = codecs.getdecoder ('utf_8')
2115     de_input = codecs.getdecoder (input_encoding)
2116     en_utf_8 = codecs.getencoder ('utf_8')
2117     try:
2118         de_ascii (str)
2119     # only in python >= 2.3
2120     # except UnicodeDecodeError:
2121     except UnicodeError:
2122         # do not re-recode UTF-8 input
2123         try:
2124             de_utf_8 (str)
2125         #except UnicodeDecodeError:
2126         except UnicodeError:
2127             str = en_utf_8 (de_input (str)[0])[0]
2128
2129
2130
2131     str = re.sub (r"#\(ly:set-point-and-click '[a-z-]+\)", '', str)
2132     return str
2133
2134
2135 @rule ((2, 5, 17), _ ('remove %s') % 'ly:stencil-set-extent!')
2136 def conv (str):
2137     if re.search ("ly:stencil-set-extent!", str):
2138         stderr_write (NOT_SMART % "ly:stencil-set-extent!")
2139         stderr_write (_ ('Use %s\n') % '(set! VAR (ly:make-stencil (ly:stencil-expr VAR) X-EXT Y-EXT))')
2140         raise FatalConversionError ()
2141     if re.search ("ly:stencil-align-to!", str):
2142         stderr_write (NOT_SMART % "ly:stencil-align-to!")
2143         stderr_write (_ ('Use %s\n') % '(set! VAR (ly:stencil-aligned-to VAR AXIS DIR))')
2144         raise FatalConversionError ()
2145     return str
2146
2147
2148 @rule ((2, 5, 18), 'ly:warn -> ly:warning')
2149 def conv (str):
2150     str = re.sub (r"ly:warn\b", 'ly:warning', str)
2151     return str
2152
2153
2154 @rule ((2, 5, 21), _ ('warn about auto beam settings'))
2155 def conv (str):
2156     if re.search ("(override-|revert-)auto-beam-setting", str)\
2157        or re.search ("autoBeamSettings", str):
2158         stderr_write (NOT_SMART % _ ("auto beam settings"))
2159         stderr_write (_ ('''
2160 Auto beam settings must now specify each interesting moment in a measure
2161 explicitly; 1/4 is no longer multiplied to cover moments 1/2 and 3/4 too.
2162 '''))
2163         stderr_write (UPDATE_MANUALLY)
2164         raise FatalConversionError ()
2165     return str
2166
2167
2168 @rule ((2, 5, 25), 'unfoldrepeats -> unfoldRepeats, compressmusic -> compressMusic')
2169 def conv (str):
2170     str = re.sub (r"unfoldrepeats", 'unfoldRepeats', str)
2171     str = re.sub (r"compressmusic", 'compressMusic', str)
2172     return str
2173
2174
2175 @rule ((2, 6, 0), _ ("bump version for release"))
2176 def conv (str):
2177     return str
2178
2179
2180 @rule ((2, 7, 0), 'ly:get-default-font -> ly:grob-default-font')
2181 def conv (str):
2182     return re.sub('ly:get-default-font', 'ly:grob-default-font', str)
2183
2184
2185 @rule ((2, 7, 1), '''ly:parser-define -> ly:parser-define!
2186 excentricity -> eccentricity
2187 Timing_engraver -> Timing_translator + Default_bar_line_engraver
2188 ''')
2189 def conv (str):
2190     str = re.sub('ly:parser-define', 'ly:parser-define!', str)
2191     str = re.sub('excentricity', 'eccentricity', str)
2192     str = re.sub(r'\\(consists|remove) *"?Timing_engraver"?',
2193                  r'\\\1 "Timing_translator" \\\1 "Default_bar_line_engraver"',
2194                  str)
2195     return str
2196
2197
2198 @rule ((2, 7, 2), 'ly:X-moment -> ly:moment-X')
2199 def conv (str):
2200     str = re.sub('ly:(add|mul|mod|div)-moment', r'ly:moment-\1', str)
2201     return str
2202
2203
2204 @rule ((2, 7, 4), 'keyAccidentalOrder -> keyAlterationOrder')
2205 def conv (str):
2206     str = re.sub('keyAccidentalOrder', 'keyAlterationOrder', str)
2207     return str
2208
2209
2210 @rule ((2, 7, 6), '''Performer_group_performer -> Performer_group, Engraver_group_engraver -> Engraver_group,
2211 inside-slur -> avoid-slur''')
2212 def conv (str):
2213     str = re.sub('Performer_group_performer', 'Performer_group', str)
2214     str = re.sub('Engraver_group_engraver', 'Engraver_group', str)
2215     str = re.sub (r"#'inside-slur\s*=\s*##t *",
2216                   r"#'avoid-slur = #'inside ", str)
2217     str = re.sub (r"#'inside-slur\s*=\s*##f *",
2218                   r"#'avoid-slur = #'around ", str)
2219     str = re.sub (r"#'inside-slur",
2220                   r"#'avoid-slur", str)
2221     return str
2222
2223
2224 @rule ((2, 7, 10), '\\applyxxx -> \\applyXxx')
2225 def conv (str):
2226     str = re.sub(r'\\applyoutput', r'\\applyOutput', str)
2227     str = re.sub(r'\\applycontext', r'\\applyContext', str)
2228     str = re.sub(r'\\applymusic',  r'\\applyMusic', str)
2229     str = re.sub(r'ly:grob-suicide', 'ly:grob-suicide!', str)
2230     return str
2231
2232
2233 @rule ((2, 7, 11), '"tabloid" -> "11x17"')
2234 def conv (str):
2235     str = re.sub(r'\"tabloid\"', '"11x17"', str)
2236     return str
2237
2238
2239 @rule ((2, 7, 12), 'outputProperty -> overrideProperty')
2240 def conv (str):
2241     str = re.sub(r'outputProperty' , 'overrideProperty', str)
2242     return str
2243
2244
2245 @rule ((2, 7, 13), 'layout engine refactoring [FIXME]')
2246 def conv (str):
2247     def subber (match):
2248         newkey = {'spacing-procedure': 'springs-and-rods',
2249                   'after-line-breaking-callback' : 'after-line-breaking',
2250                   'before-line-breaking-callback' : 'before-line-breaking',
2251                   'print-function' : 'stencil'} [match.group(3)]
2252         what = match.group (1)
2253         grob = match.group (2)
2254
2255         if what == 'revert':
2256             return "revert %s #'callbacks %% %s\n" % (grob, newkey)
2257         elif what == 'override':
2258             return "override %s #'callbacks #'%s" % (grob, newkey)
2259         else:
2260             raise 'urg'
2261             return ''
2262
2263     str = re.sub(r"(override|revert)\s*([a-zA-Z.]+)\s*#'(spacing-procedure|after-line-breaking-callback"
2264                 + r"|before-line-breaking-callback|print-function)",
2265                 subber, str)
2266
2267     if re.search ('bar-size-procedure', str):
2268         stderr_write (NOT_SMART % "bar-size-procedure")
2269     if re.search ('space-function', str):
2270         stderr_write (NOT_SMART % "space-function")
2271     if re.search ('verticalAlignmentChildCallback', str):
2272         stderr_write (_ ('verticalAlignmentChildCallback has been deprecated'))
2273         stderr_write ('\n')
2274     return str
2275
2276
2277 @rule ((2, 7, 14), _ ('Remove callbacks property, deprecate XY-extent-callback.'))
2278 def conv (str):
2279     str = re.sub (r"\\override +([A-Z.a-z]+) #'callbacks",
2280                   r"\\override \1", str)
2281     str = re.sub (r"\\revert ([A-Z.a-z]+) #'callbacks % ([a-zA-Z]+)",
2282                   r"\\revert \1 #'\2", str)
2283     str = re.sub (r"([XY]-extent)-callback", r'\1', str)
2284     str = re.sub (r"RemoveEmptyVerticalGroup", "VerticalAxisGroup", str)
2285     str = re.sub (r"\\set ([a-zA-Z]*\.?)minimumVerticalExtent",
2286                   r"\\override \1VerticalAxisGroup #'minimum-Y-extent",
2287                   str)
2288     str = re.sub (r"minimumVerticalExtent",
2289                   r"\\override VerticalAxisGroup #'minimum-Y-extent",
2290                   str)
2291     str = re.sub (r"\\set ([a-zA-Z]*\.?)extraVerticalExtent",
2292                   r"\\override \1VerticalAxisGroup #'extra-Y-extent", str)
2293     str = re.sub (r"\\set ([a-zA-Z]*\.?)verticalExtent",
2294                   r"\\override \1VerticalAxisGroup #'Y-extent", str)
2295     return str
2296
2297
2298 @rule ((2, 7, 15), _ ('Use grob closures iso. XY-offset-callbacks.'))
2299 def conv (str):
2300     if re.search ('[XY]-offset-callbacks', str):
2301         stderr_write (NOT_SMART % "[XY]-offset-callbacks")
2302     if re.search ('position-callbacks', str):
2303         stderr_write (NOT_SMART % "position-callbacks")
2304     return str
2305
2306
2307 @rule ((2, 7, 22), r"\tag #'(a b) -> \tag #'a \tag #'b")
2308 def conv (str):
2309     def sub_syms (m):
2310         syms =  m.group (1).split ()
2311         tags = ["\\tag #'%s" % s for s in syms]
2312         return ' '.join (tags)
2313
2314     str = re.sub (r"\\tag #'\(([^)]+)\)",  sub_syms, str)
2315     return str
2316
2317
2318 @rule ((2, 7, 24), _ ('deprecate %s') % 'number-visibility')
2319 def conv (str):
2320     str = re.sub (r"#'number-visibility",
2321                   "#'number-visibility % number-visibility is deprecated. Tune the TupletNumber instead\n",
2322                   str)
2323     return str
2324
2325
2326 @rule ((2, 7, 28), "ly:spanner-get-bound -> ly:spanner-bound")
2327 def conv (str):
2328     str = re.sub (r"ly:spanner-get-bound", "ly:spanner-bound", str)
2329     return str
2330
2331
2332 @rule ((2, 7, 29), "override Stem #'beamed-* -> #'details #'beamed-*")
2333 def conv (str):
2334     for a in ['beamed-lengths', 'beamed-minimum-free-lengths',
2335               'lengths',
2336               'beamed-extreme-minimum-free-lengths']:
2337         str = re.sub (r"\\override\s+Stem\s+#'%s" % a,
2338                       r"\\override Stem #'details #'%s" % a,
2339                       str)
2340     return str
2341
2342
2343 @rule ((2, 7, 30), "\\epsfile")
2344 def conv (str):
2345     str = re.sub (r'\\epsfile *#"', r'\\epsfile #X #10 #"', str)
2346     return str
2347
2348
2349 @rule ((2, 7, 31), "Foo_bar::bla_bla -> ly:foo-bar::bla-bla")
2350 def conv (str):
2351     def sub_cxx_id (m):
2352         str = m.group(1)
2353         return 'ly:' + str.lower ().replace ('_','-')
2354
2355     str = re.sub (r'([A-Z][a-z_0-9]+::[a-z_0-9]+)',
2356                   sub_cxx_id, str)
2357     return str
2358
2359
2360 @rule ((2, 7, 32), _ ("foobar -> foo-bar for \paper, \layout"))
2361 def conv (str):
2362     identifier_subs = [
2363             ('inputencoding', 'input-encoding'),
2364             ('printpagenumber', 'print-page-number'),
2365             ('outputscale', 'output-scale'),
2366             ('betweensystemspace', 'between-system-space'),
2367             ('betweensystempadding', 'between-system-padding'),
2368             ('pagetopspace', 'page-top-space'),
2369             ('raggedlastbottom', 'ragged-last-bottom'),
2370             ('raggedright', 'ragged-right'),
2371             ('raggedlast', 'ragged-last'),
2372             ('raggedbottom', 'ragged-bottom'),
2373             ('aftertitlespace', 'after-title-space'),
2374             ('beforetitlespace', 'before-title-space'),
2375             ('betweentitlespace', 'between-title-space'),
2376             ('topmargin', 'top-margin'),
2377             ('bottommargin', 'bottom-margin'),
2378             ('headsep', 'head-separation'),
2379             ('footsep', 'foot-separation'),
2380             ('rightmargin', 'right-margin'),
2381             ('leftmargin', 'left-margin'),
2382             ('printfirstpagenumber', 'print-first-page-number'),
2383             ('firstpagenumber', 'first-page-number'),
2384             ('hsize', 'paper-width'),
2385             ('vsize', 'paper-height'),
2386             ('horizontalshift', 'horizontal-shift'),
2387             ('staffspace', 'staff-space'),
2388             ('linethickness', 'line-thickness'),
2389             ('ledgerlinethickness', 'ledger-line-thickness'),
2390             ('blotdiameter', 'blot-diameter'),
2391             ('staffheight', 'staff-height'),
2392             ('linewidth', 'line-width'),
2393             ('annotatespacing', 'annotate-spacing')
2394             ]
2395
2396     for (a,b)  in identifier_subs:
2397         ### for C++:
2398         ## str = re.sub ('"%s"' % a, '"%s"' b, str)
2399
2400         str = re.sub (a, b, str)
2401     return str
2402
2403
2404 @rule ((2, 7, 32), "debug-beam-quanting -> debug-beam-scoring")
2405 def conv (str):
2406     str = re.sub ('debug-beam-quanting', 'debug-beam-scoring', str)
2407     return str
2408
2409
2410 @rule ((2, 7, 36), "def-(music-function|markup-command) -> define-(music-function|markup-command)")
2411 def conv (str):
2412     str = re.sub ('def-music-function', 'define-music-function', str)
2413     str = re.sub ('def-markup-command', 'define-markup-command', str)
2414     return str
2415
2416
2417 @rule ((2, 7, 40), "rehearsalMarkAlignSymbol/barNumberAlignSymbol -> break-align-symbol")
2418 def conv (str):
2419     str = re.sub (r'\\set\s+Score\s*\.\s*barNumberAlignSymbol\s*=',
2420                   r"\\override Score.BarNumber #'break-align-symbol = ", str)
2421     str = re.sub (r'\\set\s*Score\s*\.\s*rehearsalMarkAlignSymbol\s*=',
2422                   r"\\override Score.RehearsalMark #'break-align-symbol = ", str)
2423     return str
2424
2425
2426 @rule ((2, 9, 4), "(page-)penalty -> (page-)break-penalty")
2427 def conv (str):
2428     str = re.sub ('page-penalty', 'page-break-penalty', str)
2429     str = re.sub ('([^-])penalty', '\1break-penalty', str)
2430     return str
2431
2432
2433 @rule ((2, 9, 6), "\\context Foo \\applyOutput #bla -> \\applyOutput #'Foo #bla ")
2434 def conv (str):
2435     str = re.sub (r'\\context\s+\"?([a-zA-Z]+)\"?\s*\\applyOutput', r"\\applyOutput #'\1", str)
2436     return str
2437
2438
2439 @rule ((2, 9, 9), "annotatefoo -> annotate-foo")
2440 def conv (str):
2441     str = re.sub ('annotatepage', 'annotate-page', str)
2442     str = re.sub ('annotateheaders', 'annotate-headers', str)
2443     str = re.sub ('annotatesystems', 'annotate-systems', str)
2444     return str
2445
2446
2447 @rule ((2, 9, 11), "\\set tupletNumberFormatFunction -> \\override #'text = ")
2448 def conv (str):
2449     str = re.sub (r"""(\\set\s)?(?P<context>[a-zA-Z]*.?)tupletNumberFormatFunction\s*=\s*#denominator-tuplet-formatter""",
2450                   r"""\\override \g<context>TupletNumber #'text = #tuplet-number::calc-denominator-text""", str)
2451
2452     str = re.sub (r"""(\\set\s+)?(?P<context>[a-zA-Z]*.?)tupletNumberFormatFunction\s*=\s*#fraction-tuplet-formatter""",
2453                   r"""\\override \g<context>TupletNumber #'text = #tuplet-number::calc-fraction-text""", str)
2454
2455     if re.search ('tupletNumberFormatFunction', str):
2456         stderr_write ("\n")
2457         stderr_write ("tupletNumberFormatFunction has been removed. Use #'text property on TupletNumber")
2458         stderr_write ("\n")
2459     return str
2460
2461
2462 @rule ((2, 9, 13), "instrument -> instrumentName, instr -> shortInstrumentName, vocNam -> shortVocalName")
2463 def conv (str):
2464     str = re.sub ('vocNam', 'shortVocalName', str)
2465     str = re.sub (r'\.instr\s*=', r'.shortInstrumentName =', str)
2466     str = re.sub (r'\.instrument\s*=', r'.instrumentName =', str)
2467     return str
2468
2469
2470 @rule ((2, 9, 16), _ ("deprecate \\tempo in \\midi"))
2471 def conv (str):
2472
2473     def sub_tempo (m):
2474         dur = int (m.group (1))
2475         dots = len (m.group (2))
2476         count = int (m.group (3))
2477
2478         log2 = 0
2479         while dur > 1 :
2480             dur /= 2
2481             log2 += 1
2482
2483         den = (1 << dots) * (1 << log2)
2484         num = ((1 << (dots+1))  - 1)
2485
2486         return  """
2487   \midi {
2488     \context {
2489       \Score
2490       tempoWholesPerMinute = #(ly:make-moment %d %d)
2491       }
2492     }
2493
2494 """ % (num*count, den)
2495
2496     str = re.sub (r'\\midi\s*{\s*\\tempo ([0-9]+)\s*([.]*)\s*=\s*([0-9]+)\s*}', sub_tempo, str)
2497     return str
2498
2499
2500 @rule ((2, 9, 19), "printfirst-page-number -> print-first-page-number")
2501 def conv (str):
2502     str = re.sub ('printfirst-page-number', 'print-first-page-number', str)
2503     return str
2504
2505
2506 @rule ((2, 10, 0), _ ("bump version for release"))
2507 def conv (str):
2508     return str
2509
2510
2511 @rule ((2, 11, 2), "ly:clone-parser -> ly:parser-clone")
2512 def conv (str):
2513     return re.sub ('ly:clone-parser',
2514                    'ly:parser-clone', str)
2515
2516 @rule ((2, 11, 3), "no-spacing-rods -> extra-spacing-width")
2517 def conv (str):
2518     str = re.sub (r"no-spacing-rods\s+=\s+##t", r"extra-spacing-width = #'(+inf.0 . -inf.0)", str)
2519     str = re.sub (r"no-spacing-rods\s+=\s+##f", r"extra-spacing-width = #'(0 . 0)", str)
2520     return str
2521
2522
2523 @rule ((2, 11, 5), _ ("deprecate cautionary-style. Use AccidentalCautionary properties"))
2524 def conv (str):
2525     str = re.sub ("Accidental\s*#'cautionary-style\s*=\s*#'smaller",
2526                    "AccidentalCautionary #'font-size = #-2", str)
2527     str = re.sub ("Accidental\s*#'cautionary-style\s*=\s*#'parentheses",
2528                    "AccidentalCautionary #'parenthesized = ##t", str)
2529     str = re.sub ("([A-Za-z]+)\s*#'cautionary-style\s*=\s*#'parentheses",
2530                    r"\1 #'parenthesized = ##t", str)
2531     str = re.sub ("([A-Za-z]+)\s*#'cautionary-style\s*=\s*#'smaller",
2532                    r"\1 #'font-size = #-2", str)
2533     return str
2534
2535
2536 @rule ((2, 11, 6), _ ("Rename accidental glyphs, use glyph-name-alist."))
2537 def conv (str):
2538
2539     def sub_acc_name (m):
2540         idx = int (m.group (1).replace ('M','-'))
2541
2542         return ["accidentals.doublesharp",
2543                 "accidentals.sharp.slashslash.stemstemstem",
2544                 "accidentals.sharp",
2545                 "accidentals.sharp.slashslash.stem",
2546                 "accidentals.natural",
2547                 "accidentals.mirroredflat",
2548                 "accidentals.flat",
2549                 "accidentals.mirroredflat.flat",
2550                 "accidentals.flatflat"][4-idx]
2551
2552     str = re.sub (r"accidentals[.](M?[-0-9]+)",
2553                   sub_acc_name, str)
2554     str = re.sub (r"(KeySignature|Accidental[A-Za-z]*)\s*#'style\s*=\s*#'([a-z]+)",
2555                   r"\1 #'glyph-name-alist = #alteration-\2-glyph-name-alist", str)
2556     ## FIXME: standard vs default, alteration-FOO vs FOO-alteration
2557     str = str.replace ('alteration-default-glyph-name-alist',
2558                        'standard-alteration-glyph-name-alist')
2559     return str
2560
2561
2562 @rule ((2, 11, 10), """allowBeamBreak -> Beam #'breakable = ##t
2563 addquote -> addQuote
2564 """)
2565 def conv (str):
2566     str = re.sub (r'(\\set\s+)?([A-Z][a-zA-Z]+\s*\.\s*)allowBeamBreak',
2567                   r"\override \2Beam #'breakable", str)
2568     str = re.sub (r'(\\set\s+)?allowBeamBreak',
2569                   r"\override Beam #'breakable", str)
2570     str = re.sub (r'addquote', 'addQuote', str)
2571     if re.search ("Span_dynamic_performer", str):
2572         stderr_write ("Span_dynamic_performer has been merged into Dynamic_performer")
2573
2574     return str
2575
2576
2577 @rule ((2, 11, 11), "layout-set-staff-size -> layout-set-absolute-staff-size")
2578 def conv (str):
2579     str = re.sub (r'\(layout-set-staff-size \(\*\s*([0-9.]+)\s*(pt|mm|cm)\)\)',
2580                   r'(layout-set-absolute-staff-size (* \1 \2))', str)
2581     return str
2582
2583
2584 @rule ((2, 11, 13), "#'arrow = ##t -> #'bound-details #'right #'arrow = ##t")
2585 def conv (str):
2586     str = re.sub (r"\\override\s*([a-zA-Z.]+)\s*#'arrow\s*=\s*##t",
2587                   r"\\override \1 #'bound-details #'right #'arrow = ##t",
2588                   str)
2589
2590     if re.search ('edge-text', str):
2591         stderr_write (NOT_SMART % _ ("edge-text settings for TextSpanner"))
2592         stderr_write (_ ("Use\n\n%s") %
2593                           "\t\\override TextSpanner #'bound-details #'right #'text = <right-text>\n"
2594                           "\t\\override TextSpanner #'bound-details #'left #'text = <left-text>\n")
2595     return str
2596
2597
2598 @rule ((2, 11, 15), "TextSpanner #'edge-height -> #'bound-details #'right/left #'text = ...\n\
2599 Remove 'forced-distance for fixed spacing between staves in a PianoStaff.")
2600 def conv (str):
2601     def sub_edge_height (m):
2602         s = ''
2603         for (var, h) in [('left', m.group (3)),
2604                          ('right', m.group (4))]:
2605
2606             if h and float (h):
2607                 once = m.group (1)
2608                 if not once:
2609                     once = ''
2610                 context = m.group (2)
2611                 if not context:
2612                     context = ''
2613
2614                 s += (r"%s \override %sTextSpanner #'bound-details #'%s #'text = \markup { \draw-line #'(0 . %s) }"
2615                       % (once, context, var, h))
2616
2617                 s += '\n'
2618
2619         return s
2620
2621
2622     str = re.sub (r"(\\once)?\s*\\override\s*([a-zA-Z]+\s*[.]\s*)?TextSpanner\s*#'edge-height\s*=\s*#'\(\s*([0-9.-]+)\s+[.]\s+([0-9.-]+)\s*\)", sub_edge_height, str)
2623     if re.search (r"#'forced-distance", str):
2624         stderr_write (NOT_SMART % "VerticalAlignment #'forced-distance")
2625         stderr_write (_ ("Use the `alignment-offsets' sub-property of\n"))
2626         stderr_write (_ ("NonMusicalPaperColumn #'line-break-system-details\n"))
2627         stderr_write (_ ("to set fixed distances between staves.\n"))
2628     return str
2629
2630
2631 @rule ((2, 11, 23), "#'break-align-symbol -> #'break-align-symbols")
2632 def conv (str):
2633     str = re.sub (r"\\override\s*([a-zA-Z.]+)\s*#'break-align-symbol\s*=\s*#'([a-z-]+)",
2634                   r"\\override \1 #'break-align-symbols = #'(\2)", str)
2635     return str
2636
2637
2638 @rule ((2, 11, 35), """scripts.caesura -> scripts.caesura.curved.
2639 """ + _ ("Use #'style not #'dash-fraction to select solid/dashed lines."))
2640 def conv (str):
2641     str = re.sub (r"scripts\.caesura",
2642                   r"scripts.caesura.curved", str)
2643
2644     if re.search ('dash-fraction', str):
2645         stderr_write (NOT_SMART % _ ("all settings related to dashed lines"))
2646         stderr_write (_ ("Use \\override ... #'style = #'line for solid lines and\n"))
2647         stderr_write (_ ("\t\\override ... #'style = #'dashed-line for dashed lines."))
2648     return str
2649
2650
2651 @rule ((2, 11, 38), """\\setEasyHeads -> \\easyHeadsOn, \\fatText -> \\textLengthOn,
2652 \\emptyText -> \\textLengthOff""")
2653 def conv (str):
2654     str = re.sub (r"setEasyHeads", r"easyHeadsOn", str)
2655     str = re.sub (r"fatText", r"textLengthOn", str)
2656     str = re.sub (r"emptyText", r"textLengthOff", str)
2657     return str
2658
2659
2660 @rule ((2, 11, 46), "\\set hairpinToBarline -> \\override Hairpin #'to-barline")
2661 def conv (str):
2662     str = re.sub (r"\\set\s+([a-zA-Z]+)\s*.\s*hairpinToBarline\s*=\s*##([tf]+)",
2663                   r"\\override \1.Hairpin #'to-barline = ##\2", str)
2664     str = re.sub (r"\\set\s+hairpinToBarline\s*=\s*##([tf]+)",
2665                   r"\\override Hairpin #'to-barline = ##\1", str)
2666     str = re.sub (r"\\unset\s+([a-zA-Z]+)\s*.\s*hairpinToBarline",
2667                   r"\\revert \1.Hairpin #'to-barline", str)
2668     str = re.sub (r"\\unset\s+hairpinToBarline",
2669                   r"\\revert Hairpin #'to-barline", str)
2670     str = re.sub (r"hairpinToBarline\s*=\s*##([tf]+)",
2671                   r"\\override Hairpin #'to-barline = ##\1", str)
2672     str = re.sub (r"\\set (de|)crescendoSpanner = #'dashed-line",
2673                   r"\\set \1crescendoSpanner = #'text", str)
2674     return str
2675
2676
2677 @rule ((2, 11, 48), "\\compressMusic -> \\scaleDurations")
2678 def conv (str):
2679     str = re.sub (r"compressMusic", r"scaleDurations", str)
2680     return str
2681
2682
2683 @rule ((2, 11, 50), _ ("metronomeMarkFormatter uses text markup as second argument,\n\
2684 fret diagram properties moved to fret-diagram-details."))
2685 def conv (str):
2686     ## warning 1/2: metronomeMarkFormatter uses text markup as second argument
2687     if re.search ('metronomeMarkFormatter', str):
2688         stderr_write (NOT_SMART % "metronomeMarkFormatter")
2689         stderr_write (_ ("metronomeMarkFormatter got an additional text argument.\n"))
2690         stderr_write (_ ("The function assigned to Score.metronomeMarkFunction now uses the signature\n%s") %
2691                           "\t(format-metronome-markup text dur count context)\n")
2692
2693     ## warning 2/2: fret diagram properties moved to fret-diagram-details
2694     fret_props = ['barre-type',
2695                 'dot-color',
2696                 'dot-radius',
2697                 'finger-code',
2698                 'fret-count',
2699                 'label-dir',
2700                 'number-type',
2701                 'string-count',
2702                 'xo-font-magnification',
2703                 'mute-string',
2704                 'open-string',
2705                 'orientation']
2706     for prop in fret_props:
2707       if re.search (prop, str):
2708           stderr_write (NOT_SMART % (_ ("%s in fret-diagram properties") % prop))
2709           stderr_write (_ ('Use %s\n') % "fret-diagram-details")
2710     return str
2711
2712 @rule ((2, 11, 51), "\\octave -> \\octaveCheck, \\arpeggioUp -> \\arpeggioArrowUp,\n\
2713 \\arpeggioDown -> \\arpeggioArrowDown, \\arpeggioNeutral -> \\arpeggioNormal,\n\
2714 \\setTextCresc -> \\crescTextCresc, \\setTextDecresc -> \\dimTextDecresc,\n\
2715 \\setTextDecr -> \\dimTextDecr, \\setTextDim -> \\dimTextDim,\n\
2716 \\setHairpinCresc -> \\crescHairpin, \\setHairpinDecresc -> \\dimHairpin,\n\
2717 \\sustainUp -> \\sustainOff, \\sustainDown -> \\sustainOn\n\
2718 \\sostenutoDown -> \\sostenutoOn, \\sostenutoUp -> \\sostenutoOff")
2719 def conv (str):
2720     str = re.sub (r"\\octave(?![a-zA-Z])", r"\\octaveCheck", str)
2721     str = re.sub (r"arpeggioUp", r"arpeggioArrowUp", str)
2722     str = re.sub (r"arpeggioDown", r"arpeggioArrowDown", str)
2723     str = re.sub (r"arpeggioNeutral", r"arpeggioNormal", str)
2724     str = re.sub (r"setTextCresc", r"crescTextCresc", str)
2725     str = re.sub (r"setTextDecresc", r"dimTextDecresc", str)
2726     str = re.sub (r"setTextDecr", r"dimTextDecr", str)
2727     str = re.sub (r"setTextDim", r"dimTextDim", str)
2728     str = re.sub (r"setHairpinCresc", r"crescHairpin", str)
2729     str = re.sub (r"setHairpinDecresc", r"dimHairpin", str)
2730     str = re.sub (r"sustainUp", r"sustainOff", str)
2731     str = re.sub (r"sustainDown", r"sustainOn", str)
2732     str = re.sub (r"sostenutoDown", r"sostenutoOn", str)
2733     str = re.sub (r"sostenutoUp", r"sostenutoOff", str)
2734     return str
2735
2736 @rule ((2, 11, 52), "\\setHairpinDim -> \\dimHairpin")
2737 def conv (str):
2738     str = str.replace ("setHairpinDim", "dimHairpin")
2739     return str
2740
2741 @rule ((2, 11, 53), "infinite-spacing-height -> extra-spacing-height")
2742 def conv (str):
2743     str = re.sub (r"infinite-spacing-height\s+=\s+##t", r"extra-spacing-height = #'(-inf.0 . +inf.0)", str)
2744     str = re.sub (r"infinite-spacing-height\s+=\s+##f", r"extra-spacing-height = #'(0 . 0)", str)
2745     return str
2746
2747 @rule ((2, 11, 55), "#(set-octavation oct) -> \\ottava #oct,\n\
2748 \\put-adjacent markup axis dir markup -> \\put-adjacent axis dir markup markup")
2749 def conv (str):
2750     str = re.sub (r"#\(set-octavation (-*[0-9]+)\)", r"\\ottava #\1", str)
2751     if re.search ('put-adjacent', str):
2752         stderr_write (NOT_SMART % _ ("\\put-adjacent argument order"))
2753         stderr_write (_ ("Axis and direction now come before markups:\n"))
2754         stderr_write (_ ("\\put-adjacent axis dir markup markup."))
2755         stderr_write ("\n")
2756     return str
2757
2758 @rule ((2, 11, 57), "\\center-align -> \\center-column, \\hcenter -> \\center-align")
2759 def conv (str):
2760     str = re.sub (r"([\\:]+)center-align", r"\1center-column", str)
2761     str = re.sub (r"hcenter(\s+)", r"center-align\1", str)
2762     return str
2763
2764 @rule ((2, 11, 60), "printallheaders -> print-all-headers")
2765 def conv (str):
2766     str = re.sub (r"printallheaders", r"print-all-headers", str)
2767     return str
2768
2769 @rule ((2, 11, 61), "gregorian-init.ly -> gregorian.ly")
2770 def conv (str):
2771     str = re.sub (r'\\include(\s+)"gregorian-init.ly"', r'\\include\1"gregorian.ly"', str)
2772     return str
2773
2774 @rule ((2, 11, 62), "makam-init.ly -> makam.ly, \\bigger -> \\larger")
2775 def conv (str):
2776     str = re.sub (r'\\include(\s+)"makam-init.ly"', r'\\include\1"makam.ly"', str)
2777     str = re.sub (r"([\\:])bigger", r"\1larger", str)
2778     return str
2779
2780 @rule ((2, 11, 64), "systemSeparatorMarkup -> system-separator-markup,\n\
2781 InnerStaffGroup -> StaffGroup, InnerChoirStaff -> ChoirStaff")
2782 def conv (str):
2783     str = re.sub (r'systemSeparatorMarkup', r'system-separator-markup', str)
2784     if re.search (r'\\InnerStaffGroup', str):
2785         stderr_write (NOT_SMART % _("re-definition of InnerStaffGroup"))
2786         stderr_write (FROM_TO % ("InnerStaffGroup", "StaffGroup"))
2787         stderr_write (UPDATE_MANUALLY)
2788         raise FatalConversionError ()
2789     if re.search (r'\\InnerChoirStaff', str):
2790         stderr_write (NOT_SMART % _("re-definition of InnerChoirStaff"))
2791         stderr_write (FROM_TO % ("InnerChoirStaff", "ChoirStaff"))
2792         stderr_write (UPDATE_MANUALLY)
2793         raise FatalConversionError ()
2794     else:
2795         str = re.sub ('InnerStaffGroup', 'StaffGroup', str)
2796         str = re.sub ('InnerChoirStaff', 'ChoirStaff', str)
2797     return str
2798
2799 @rule ((2, 12, 0),
2800        _ ("Syntax changes for \\addChordShape and \\chord-shape") + "\n" + \
2801        _ ("bump version for release"))
2802 def conv(str):
2803     if re.search(r'\\addChordShape', str):
2804         stderr_write (NOT_SMART % "addChordShape")
2805         stderr_write (_ ("stringTuning must be added to addChordShape call.\n"))
2806         stderr_write (UPDATE_MANUALLY)
2807         raise FatalConversionError ()
2808     if re.search (r'\\chord-shape', str):
2809         stderr_write (NOT_SMART % "chord-shape")
2810         stderr_write (_ ("stringTuning must be added to chord-shape call.\n"))
2811         stderr_write (UPDATE_MANUALLY)
2812         raise FatalConversionError ()
2813     return str
2814
2815 @rule ((2,12,3),
2816     _ ("Remove oldaddlyrics"))
2817 def conv(str):
2818     if re.search(r'\\oldaddlyrics', str):
2819         stderr_write (NOT_SMART % "oldaddlyrics")
2820         stderr_write (_ ("oldaddlyrics is no longer supported. \n \
2821         Use addlyrics or lyricsto instead.\n"))
2822         stderr_write (UPDATE_MANUALLY)
2823         raise FatalConversionError ()
2824     return str
2825
2826 @rule ((2, 13, 0), _ ("keySignature property not reversed any more\n\
2827 MIDI 47: orchestral strings -> orchestral harp"))
2828 def conv(str):
2829     if re.search(r'\set Staff.keySignature', str):
2830         stderr_write (NOT_SMART % "Staff.keySignature")
2831         stderr_write (_ ("The alist for Staff.keySignature is no \
2832 longer in reversed order.\n"))
2833     str = str.replace('"orchestral strings"', '"orchestral harp"')
2834     return str
2835
2836 @rule ((2, 13, 1),
2837        _ ("\\bar \".\" now produces a thick barline\n\
2838 ly:hairpin::after-line-breaking -> ly:spanner::kill-zero-spanned-time\n\
2839 Dash parameters for slurs and ties are now in dash-definition"))
2840 def conv(str):
2841     if re.search(r'\\bar\s*"\."', str):
2842         stderr_write (NOT_SMART % "\\bar \".\"")
2843         stderr_write (_ ("\\bar \".\" now produces a thick barline.\n"))
2844         stderr_write (UPDATE_MANUALLY)
2845     str = re.sub (r'ly:hairpin::after-line-breaking', r'ly:spanner::kill-zero-spanned-time', str)
2846     if re.search("(Slur|Tie)\w+#\'dash-fraction", str) \
2847         or re.search("(Slur|Tie)\w+#\'dash-period", str):
2848         stderr_write (NOT_SMART % "dash-fraction, dash-period")
2849         stderr_write (_ ("Dash parameters for slurs and ties are now in \'dash-definition.\n"))
2850         stderr_write (UPDATE_MANUALLY)
2851     return str
2852
2853 @rule ((2, 13, 4),
2854        _ ("Autobeaming rules have changed.  override-auto-beam-setting and\n\
2855 revert-auto-beam-setting have been eliminated.\n\
2856 \\overrideBeamSettings has been added.\n\
2857 beatGrouping has been eliminated.\n\
2858 Different settings for vertical layout.\n\
2859 ly:system-start-text::print -> system-start-text::print\n\
2860 Beam #'thickness -> Beam #'beam-thickness\n\
2861 ly:note-head::brew-ez-stencil -> note-head::brew-ez-stencil\n\
2862 ly:ambitus::print -> ambitus::print\n\
2863 Explicit dynamics context definition from `Piano centered dynamics'\n\
2864 template replaced by new `Dynamics' context."))
2865 def conv(str):
2866     if re.search("override-auto-beam-setting", str):
2867         stderr_write (NOT_SMART % "override-auto-beam-setting")
2868         stderr_write (_ (" \
2869    Autobeam settings are now overriden with \\overrideBeamSettings.\n"))
2870         stderr_write (UPDATE_MANUALLY)
2871     if re.search("revert-auto-beam-setting", str):
2872         stderr_write (NOT_SMART % "override-auto-beam-setting")
2873         stderr_write (_ (" \
2874    Autobeam settings are now reverted with \\revertBeamSettings.\n"))
2875         stderr_write (UPDATE_MANUALLY)
2876     str = re.sub(r"\\set\s+beatGrouping", r"\\setBeatGrouping", str)
2877     if re.search(r"\w+\s*.\s*beatGrouping", str):
2878         stderr_write (NOT_SMART % "beatGrouping")
2879         stderr_write (_ (" \
2880    beatGrouping with a specified context must now be accomplished with\n\
2881    \\overrideBeamSettings.\n"))
2882         stderr_write (UPDATE_MANUALLY)
2883     if re.search(r'alignment-offsets', str):
2884         stderr_write (NOT_SMART % "alignment-offsets")
2885         stderr_write (_ ("alignment-offsets has been changed to alignment-distances: \
2886 you must now specify the distances between staves rather than the offset of staves.\n"))
2887         stderr_write (UPDATE_MANUALLY)
2888     str = re.sub ('ly:(system-start-text::print|note-head::brew-ez-stencil|ambitus::print)',
2889                   '\\1', str)
2890     str = re.sub ('(\\bBeam\\s+#\')(?=thickness\\b)', '\\1beam-', str)
2891     str = re.sub (r'(\\context\s*\{{1}[^\}]+\\type\s+\"?Engraver_group\"?\s+\\name\s+"*Dynamics"*[^\}]*\}{1})',
2892                   '% [Convert-ly] The Dynamics context is now included by default.', str)
2893     return str
2894
2895 @rule ((2, 13, 10),
2896        _ ("Remove obsolete engravers/translators: Note_swallow_translator,\n\
2897 Rest_swallow_translator, Skip_event_swallow_translator, Swallow_engraver,\n\
2898 Swallow_performer and String_number_engraver.\n\
2899 New vertical spacing variables."))
2900 def conv(str):
2901     str = re.sub (r'\\(consists|remove)\s+"*(Swallow_(engraver|performer)|'
2902                   '(Note|Rest|Skip_event)_swallow_translator|String_number_engraver)"*',
2903                   '', str)
2904
2905     # match through the end of assignments in the form "x = 30", "x = 1 \in", or "x = #3"
2906     str = re.sub (r"(page-top-space)\s*=\s*(([+-]?[.\d]*\s*\\[-\w]+)|(#?\s*[-+]?[.\d]+))",
2907                   r"obsolete-\g<0>"
2908                   r"  top-system-spacing #'space = #(/ obsolete-\1 staff-space)",
2909                   str)
2910     str = re.sub (r"(between-system-space)\s*=\s*(([+-]?[.\d]*\s*\\[-\w]+)|(#?\s*[-+]?[.\d]+))",
2911                   r"obsolete-\g<0>"
2912                   r"  between-system-spacing #'space = #(/ obsolete-\1 staff-space)"
2913                   r"  between-scores-system-spacing #'space = #(/ obsolete-\1 staff-space)",
2914                   str)
2915     str = re.sub (r"(between-system-padding)\s*=\s*(([+-]?[.\d]*\s*\\[-\w]+)|(#?\s*[-+]?[.\d]+))",
2916                   r"obsolete-\g<0>"
2917                   r"  between-system-spacing #'padding = #(/ obsolete-\1 staff-space)"
2918                   r"  between-scores-system-spacing #'padding = #(/ obsolete-\1 staff-space)",
2919                   str)
2920     str = re.sub (r"((before|between|after)-title-space)\s*=\s*(([+-]?[.\d]*\s*\\[-\w]+)|(#?\s*[-+]?[.\d]+))",
2921                   r"obsolete-\g<0>"
2922                   r"  \2-title-spacing #'space = #(/ obsolete-\1 staff-space)",
2923                   str)
2924
2925     if re.search(r"VerticalAxisGroup\s*#\s*'minimum-Y-extent", str):
2926         stderr_write (NOT_SMART % "minimum-Y-extent")
2927         stderr_write (_ ("Vertical spacing no longer depends on the Y-extent of a VerticalAxisGroup.\n"))
2928         stderr_write (UPDATE_MANUALLY)
2929
2930     return str
2931
2932 @rule ((2, 13, 16),
2933        _ ("Unify fetaNumber and fetaDynamic encodings"))
2934 def conv(str):
2935     return re.sub(r'\bfeta(Number|Dynamic)', 'fetaText', str)
2936
2937 @rule ((2, 13, 18),
2938        _ ("\\RemoveEmpty*StaffContext -> \\*Staff \\RemoveEmptyStaves"))
2939 def conv(str):
2940     str = re.sub (r"\\RemoveEmpty(|Drum|Rhythmic|Tab)StaffContext",
2941                   r"\\\1Staff \\RemoveEmptyStaves",
2942                   str);
2943     str = re.sub (r"\\AncientRemoveEmptyStaffContext",
2944                   r"\\VaticanaStaff \\RemoveEmptyStaves",
2945                   str);
2946     return str
2947
2948 @rule ((2, 13, 20),
2949        _ ("\\cresc etc. are now postfix operators"))
2950 def conv (str):
2951     str = re.sub (r'\\(cresc|dim|endcresc|enddim)\b', r'\\deprecated\1', str)
2952     return str
2953
2954 @rule ((2, 13, 27),
2955        ("interval-translate -> coord-translate"))
2956 def conv (str):
2957     str = re.sub ('interval-translate', 'coord-translate', str)
2958     return str
2959
2960 @rule ((2, 13, 29),
2961        _ ("Eliminate beamSettings, beatLength, \\setBeatGrouping, \\overrideBeamSettings and \\revertBeamSettings.\n\
2962 \"accordion.accEtcbase\" -> \"accordion.etcbass\""))
2963 def conv(str):
2964     def sub_acc (m):
2965         d = {
2966             'Dot': 'dot',
2967             'Discant': 'discant',
2968             'Bayanbase': 'bayanbass',
2969             'Stdbase': 'stdbass',
2970             'Freebase': 'freebass',
2971             'OldEE': 'oldEE'
2972             }
2973         return '"accordion.%s"' %  d[m.group (1)]
2974
2975     str = re.sub (r'"accordion\.acc([a-zA-Z]+)"',
2976                   sub_acc, str)
2977     if re.search(r'overrideBeamSettings', str):
2978         stderr_write (NOT_SMART % "\\overrideBeamSettings")
2979         stderr_write (_ ("Use \\set beamExceptions or \\overrideTimeSignatureSettings.\n"))
2980         stderr_write (UPDATE_MANUALLY)
2981     if re.search(r'revertBeamSettings', str):
2982         stderr_write (NOT_SMART % "\\revertBeamSettings")
2983         stderr_write (_ ("Use \\set beamExceptions or \\revertTimeSignatureSettings.\n"))
2984         stderr_write (UPDATE_MANUALLY)
2985     if re.search(r'beamSettings', str):
2986         stderr_write (NOT_SMART % "beamSettings")
2987         stderr_write (_ ("Use baseMoment, beatStructure, and beamExceptions.\n"))
2988         stderr_write (UPDATE_MANUALLY)
2989     if re.search(r'beatLength', str):
2990         stderr_write (NOT_SMART % "beatLength")
2991         stderr_write (_ ("Use baseMoment and beatStructure.\n"))
2992         stderr_write (UPDATE_MANUALLY)
2993     if re.search(r'setBeatGrouping', str):
2994         stderr_write (NOT_SMART % "setbeatGrouping")
2995         stderr_write (_ ("Use baseMoment and beatStructure.\n"))
2996         stderr_write (UPDATE_MANUALLY)
2997     return str
2998
2999 @rule ((2, 13, 31),
3000     _ ("Woodwind diagrams: Move size, thickness, and graphic from argument list to properties.\n\
3001 Deprecate negative dash-period for hidden lines: use #'style = #'none instead."))
3002 def conv(str):
3003     if re.search(r'woodwind-diagram', str):
3004         stderr_write (NOT_SMART % "woodwind-diagrams")
3005         stderr_write (_ ("Move size, thickness, and graphic to properties.  Argument should be just the key list.\n"))
3006         stderr_write (UPDATE_MANUALLY)
3007     str = re.sub (r"dash-period\s+=\s*#\s*-[0-9.]+",
3008                   r"style = #'none",
3009                   str);
3010     return str
3011
3012 @rule ((2, 13, 36),
3013     _ ("Rename vertical spacing variables.\n\
3014 Add fretboard-table argument to savePredefinedFretboard."))
3015 def conv(str):
3016     str = re.sub ('after-title-spacing',           'markup-system-spacing', str)
3017     str = re.sub ('before-title-spacing',          'score-markup-spacing',  str)
3018     str = re.sub ('between-scores-system-spacing', 'score-system-spacing',  str)
3019     # this rule also converts page-breaking-between-system-spacing:
3020     str = re.sub ('between-system-spacing',        'system-system-spacing', str)
3021     str = re.sub ('between-title-spacing',         'markup-markup-spacing', str)
3022     str = re.sub ('bottom-system-spacing',         'last-bottom-spacing',   str)
3023     str = re.sub ('top-title-spacing',             'top-markup-spacing',    str)
3024
3025     str = re.sub (r"storePredefinedDiagram",
3026                   r"storePredefinedDiagram #default-fret-table",
3027                   str);
3028     return str
3029
3030 @rule ((2, 13, 39),
3031     _ ("Rename vertical spacing grob properties."))
3032 def conv(str):
3033     # this rule also converts default-next-staff-spacing:
3034     str = re.sub ('next-staff-spacing',       'staff-staff-spacing',             str)
3035     # this is not a mistake:
3036     #   Both 'next- and 'between- become 'staff-staff-spacing.
3037     #   There is no conflict since they are in different grobs.
3038     str = re.sub ('between-staff-spacing',    'staff-staff-spacing',             str)
3039     str = re.sub ('after-last-staff-spacing', 'staffgroup-staff-spacing',        str)
3040     str = re.sub ('inter-staff-spacing',      'nonstaff-relatedstaff-spacing',   str)
3041     str = re.sub ('non-affinity-spacing',     'nonstaff-unrelatedstaff-spacing', str)
3042     str = re.sub ('inter-loose-line-spacing', 'nonstaff-nonstaff-spacing',       str);
3043
3044     return str
3045
3046 @rule ((2, 13, 40),
3047     _ ("Remove \\paper variables head-separation and foot-separation."))
3048 def conv(str):
3049     if re.search (r'head-separation', str):
3050         stderr_write (NOT_SMART % "head-separation")
3051         stderr_write (_ ("Adjust settings for top-system-spacing instead.\n"))
3052         stderr_write (UPDATE_MANUALLY)
3053     if re.search (r'foot-separation', str):
3054         stderr_write (NOT_SMART % "foot-separation")
3055         stderr_write (_ ("Adjust settings for last-bottom-spacing instead.\n"))
3056         stderr_write (UPDATE_MANUALLY);
3057
3058     return str
3059
3060 @rule ((2, 13, 42),
3061     _ ("Rename space to basic-distance in various spacing alists.\n\
3062 Remove HarmonicParenthesesItem grob."))
3063 def conv(str):
3064     str = re.sub (r'\(space\s+\.\s+([0-9]*\.?[0-9]*)\)', r'(basic-distance . \1)', str)
3065     str = re.sub (r"#'space\s+=\s+#?([0-9]*\.?[0-9]*)", r"#'basic-distance = #\1", str)
3066     if re.search (r'HarmonicParenthesesItem', str):
3067         stderr_write (NOT_SMART % "HarmonicParenthesesItem")
3068         stderr_write (_ ("HarmonicParenthesesItem has been eliminated.\n"))
3069         stderr_write (_ ("Harmonic parentheses are part of the TabNoteHead grob.\n"))
3070         stderr_write (UPDATE_MANUALLY);
3071     return str
3072
3073 @rule ((2, 13, 44),
3074     _ ("Remove context from overrideTimeSignatureSettings and revertTimeSignatureSettings.\n"))
3075
3076 def conv(str):
3077     str = re.sub (r"\\(override|revert)TimeSignatureSettings(\s+[^#]*)(#[^#]*)#", r"\\\1TimeSignatureSettings\2#", str)
3078     return str
3079
3080 @rule ((2, 13, 46),
3081     _ ("Change stringTunings from a list of semitones to a list of pitches.\n"\
3082        "Change tenor and baritone ukulele names in string tunings.\n"\
3083        "Generate messages for manual conversion of vertical spacing if required."))
3084
3085 def conv(str):
3086     def semitones2pitch(semitones):
3087         steps = [0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6]
3088         alterations = ["NATURAL", "SHARP", "NATURAL", "SHARP", "NATURAL", "NATURAL", "SHARP", "NATURAL", "SHARP", "NATURAL", "SHARP", "NATURAL"]
3089         octave = 0
3090         while semitones > 11:
3091             octave += 1
3092             semitones -=12
3093         while semitones < 0:
3094             octave -= 1
3095             semitones += 12
3096         pitchArgs = "%d %d %s" % (octave, steps[semitones], alterations[semitones])
3097         return pitchArgs
3098
3099     def convert_tones (semitone_list):
3100         tones = semitone_list.split ()
3101         res = ""
3102         for tone in tones:
3103             args = semitones2pitch(int(tone))
3104             res += ",(ly:make-pitch " + args + ") "
3105         return res
3106
3107     def new_tunings (matchobj):
3108         return "stringTunings = #`(" + convert_tones(matchobj.group(1)) + ")"
3109     str = re.sub (r"stringTunings\s*=\s*#'\(([\d\s-]*)\)", \
3110           new_tunings , str)
3111
3112     str = re.sub (r"ukulele-(tenor|baritone)-tuning", r"\1-ukulele-tuning", str)
3113
3114     if re.search (r"[^-]page-top-space", str):
3115         stderr_write (NOT_SMART % "page-top-space")
3116         stderr_write (UPDATE_MANUALLY)
3117     if re.search (r"[^-]between-system-(space|padding)", str):
3118         stderr_write (NOT_SMART % "between-system-space, -padding")
3119         stderr_write (UPDATE_MANUALLY)
3120     if re.search (r"[^-](before|between|after)-title-space", str):
3121         stderr_write (NOT_SMART % "before-, between-, after-title-space")
3122         stderr_write (UPDATE_MANUALLY)
3123     if re.search (r"\\name\s", str):
3124         stderr_write ("\n" + _("Vertical spacing changes might affect user-defined contexts.") + "\n")
3125         stderr_write (UPDATE_MANUALLY)
3126
3127     return str
3128
3129 @rule ((2, 13, 48),
3130        _ ("Replace bar-size with bar-extent."))
3131
3132 def conv(str):
3133     def size_as_extent (matchobj):
3134         half = "%g" % (float (matchobj.group (1)) / 2)
3135         return "bar-extent = #'(-" + half + " . " + half + ")"
3136
3137     str = re.sub (r"bar-size\s*=\s*#([0-9\.]+)", size_as_extent, str)
3138
3139     return str
3140
3141 @rule ((2, 13, 51),
3142     _ ("Woodwind diagrams: Changes to the clarinet diagram."))
3143 def conv(str):
3144     if re.search (r'\\woodwind-diagram\s*#[^#]*clarinet\s', str):
3145         stderr_write (NOT_SMART % "woodwind-diagrams")
3146         stderr_write (_ ("Clarinet fingering changed to reflect actual anatomy of instrument.\n"))
3147         stderr_write (UPDATE_MANUALLY)
3148     return str
3149
3150 @rule ((2, 14, 0),
3151        _ ("bump version for release"))
3152 def conv (str):
3153     return str
3154
3155 @rule ((2, 15, 7),
3156     _ ("Handling of non-automatic footnotes."))
3157 def conv(str):
3158     if re.search (r'\\footnote', str):
3159         stderr_write (NOT_SMART % "\\footnote")
3160         stderr_write (_ ("If you are using non-automatic footnotes, make sure to set footnote-auto-numbering = ##f in the paper block.\n"))
3161         stderr_write (UPDATE_MANUALLY)
3162     return str
3163
3164 @rule ((2, 15, 9),
3165        _ ("Change in internal property for MultiMeasureRest"))
3166 def conv (str):
3167     if re.search (r'use-breve-rest',str):
3168         stderr_write (NOT_SMART % "use-breve-rest")
3169         stderr_write (_ ("This internal property has been replaced by round-up-to-longer-rest, round-up-exceptions and usable-duration-logs.\n"))
3170         stderr_write (UPDATE_MANUALLY)
3171     return str
3172
3173 @rule ((2, 15, 10),
3174        _ ("Creation of a Flag grob and moving of certain Stem properties to this grob"))
3175 def conv (str):
3176     str = re.sub (r"Stem\s+#'flag-style", r"Flag #'style", str)
3177     str = re.sub (r"Stem\s+#'stroke-style", r"Flag #'stroke-style", str)
3178     str = re.sub (r"Stem\s+#'flag", r"Flag #'stencil", str)
3179     str = re.sub (r"(\s+(?:\\once\s*)?)\\override\s+Stem\s+#'transparent\s*=\s*##t", r"\g<1>\\override Stem #'transparent = ##t\g<1>\\override Flag #'transparent = ##t", str)
3180     str = re.sub (r"(\s+(?:\\once\s*)?)\\revert\s*Stem\s+#'transparent", r"\g<1>\\revert Stem #'transparent\g<1>\\revert Flag #'transparent", str)
3181     str = re.sub (r"(\s+(?:\\once\s*)?)\\override\s+Stem\s+#'stencil\s*=\s*##f", r"\g<1>\\override Stem #'stencil = ##f\g<1>\\override Flag #'stencil = ##f", str)
3182     str = re.sub (r"(\s+(?:\\once\s*)?)\\revert\s*Stem\s+#'stencil", r"\g<1>\\revert Stem #'stencil\g<1>\\revert Flag #'stencil", str)
3183     return str
3184
3185 @rule ((2, 15, 16), r"\makeStringTuning, \contextStringTuning -> \stringTuning")
3186 def conv (str):
3187     str = re.sub (r"(\s+)\\contextStringTuning(\s+)#'([-a-zA-Z]+)(\s+<[^<>]+>)",
3188                   r"""\g<1>#(define \g<3> #{ \\stringTuning\g<4> #})\g<1>\\set stringTunings = #\g<3>""",
3189                   str)
3190     str = re.sub (r"""
3191 \\makeStringTuning(\s+)#'([-a-zA-Z]+)""",
3192                   r"""
3193 "\g<2>" = \\stringTuning""", str)
3194     str = re.sub (r"\\makeStringTuning(\s+)#'([-a-zA-Z]+)(\s+<[^<>]+>)",
3195                   r"#(define \g<2> #{ \\stringTuning\g<3> #})", str)
3196     return str
3197
3198 @rule ((2, 15, 17), "\\markuplines -> \\markuplist\n\
3199 Change Beam broken slope syntax.")
3200 def conv (str):
3201     str = re.sub (r"""
3202 \\markuplines( +)([^ ].*)
3203             \1([^ ])""", r"""
3204 \\markuplist\g<1>\g<2>
3205            \g<1>\g<3>""", str)
3206     str = re.sub (r"\\markuplines", r"\\markuplist", str)
3207     str = re.sub (r"@funindex markuplines", r"@funindex markuplist", str)
3208     if re.search (r'consistent-broken-slope', str):
3209         stderr_write (NOT_SMART % "consistent-broken-slope")
3210         stderr_write (_ ("consistent-broken-slope is now handled through the positions callback.\n"))
3211         stderr_write (_ ("input/regression/beam-broken-classic.ly shows how broken beams are now handled.\n"))
3212         stderr_write (UPDATE_MANUALLY)
3213     return str
3214
3215 def paren_matcher (n):
3216     # poor man's matched paren scanning, gives up
3217     # after n+1 levels.  Matches any string with balanced
3218     # parens inside; add the outer parens yourself if needed.
3219     # Nongreedy.
3220     return r"[^()]*?(?:\("*n+r"[^()]*?"+r"\)[^()]*?)*?"*n
3221     return
3222
3223 def undollar_scm (m):
3224     return re.sub (r"\$(.?)", r"\1", m.group (0))
3225
3226 def undollar_embedded (m):
3227     str = re.sub (r"#\$", "#", m.group (1))
3228     # poor man's matched paren scanning after #, gives up
3229     # after 25 levels.
3230     str = re.sub ("#`?\("+paren_matcher (25)+"\)", undollar_scm, str)
3231     return m.string[m.start (0):m.start (1)] + str + m.string[m.end (1):m.end (0)]
3232
3233 def strip_export (str):
3234     return re.sub (r"\(ly:export\s+(" + paren_matcher (25) + r")\)",
3235                    r"\1", str)
3236
3237 def export_puller (m):
3238     if not re.search (r"ly:export\s+", m.group (0)):
3239         return m.group (0)
3240     return "$" + strip_export (m.string[m.start (0)+1:m.end (0)])
3241
3242 def ugly_function_rewriter (m):
3243     return m.string[m.start(0):m.start(1)] + strip_export (m.group (1)) + m.string[m.end(1):m.end(0)]
3244
3245 should_really_be_music_function = "(?:\
3246 set-time-signature|empty-music|add-grace-property|\
3247 remove-grace-property|set-accidental-style)"
3248
3249 def record_ugly (m):
3250     global should_really_be_music_function
3251     if not re.match (should_really_be_music_function, m.group (1)) \
3252             and re.search (r"ly:export\s+", m.group (2)):
3253         should_really_be_music_function = \
3254             should_really_be_music_function[:-1] + "|" + m.group (1) + ")"
3255     return m.group (0)
3256
3257 @rule ((2, 15, 18), "#$ -> #, ly:export -> $")
3258 def conv (str):
3259     str = re.sub (r"(?s)#@?\{(.*?)#@?\}", undollar_embedded, str)
3260     str = re.sub (r"#\(define(?:-public)?\s+\(([-a-zA-Z]+)"
3261                   + r"\b[^()]*?\)(" + paren_matcher (25)
3262                   + r")\)", record_ugly, str)
3263     str = re.sub (r"\(define(?:-public)?\s+\(" + should_really_be_music_function
3264                   + r"\b[^()]*\)(" + paren_matcher (25)
3265                   + r")\)", ugly_function_rewriter, str)
3266     str = re.sub (r"#(?=\(" + should_really_be_music_function + ")", "$", str)
3267     str = re.sub (r"#\(markup\*(?=\s)", r"$(markup", str)
3268     str = re.sub ("#\("+paren_matcher (25)+"\)", export_puller, str)
3269     if re.search (r"\(ly:export\s+", str):
3270         stderr_write (NOT_SMART % "ly:export")
3271     return str
3272
3273 @rule ((2, 15, 19), r"$(set-time-signature ...) -> \time")
3274 def conv (str):
3275     str = re.sub (r"\$\(set-time-signature\s+([0-9]+)\s+([0-9]+)\s*\)",
3276                   r"\\time \1/\2", str)
3277     str = re.sub (r"\$\(set-time-signature\s+([0-9]+)\s+([0-9]+)\s+(" +
3278                   paren_matcher (5) + r")\)", r"\\time #\3 \1/\2", str)
3279     if re.search (r"\(set-time-signature\s+", str):
3280         stderr_write (NOT_SMART % "set-time-signature")
3281     return str
3282
3283 @rule ((2, 15, 20), r"$(set-accidental-style ...) -> \accidentalStyle")
3284 def conv (str):
3285     str = re.sub (r"\$\(set-accidental-style\s+'([-a-z]+)\)",
3286                   r'\\accidentalStyle "\1"', str)
3287     str = re.sub (r"\$\(set-accidental-style\s+'([-a-z]+)\s+'([-A-Za-z]+)\s*\)",
3288                   r'''\\accidentalStyle #'\2 "\1"''', str)
3289     str = re.sub (r"(@funindex\s+)set-accidental-style",
3290                   r"\1\\accidentalStyle", str)
3291     return str
3292
3293 def brace_matcher (n):
3294     # poor man's matched brace scanning, gives up
3295     # after n+1 levels.  Matches any string with balanced
3296     # braces inside; add the outer braces yourself if needed.
3297     # Nongreedy.
3298     return r"[^{}]*?(?:{"*n+r"[^{}]*?"+r"}[^{}]*?)*?"*n
3299
3300 matchstring = r'"(?:[^"\\]|\\.)*"'
3301 matcharg = (r"\s+(?:[$#]['`]?\s*(?:[a-zA-Z][^ \t\n()\\]*|" + matchstring
3302             + r"|#?\(" + paren_matcher(20) + r"\)|"
3303             + r"-?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)|"
3304             + r"#(?:[tf]|\\.|@?\{" + brace_matcher (10) + r"#@?\}))|"
3305             + matchstring + r"|\\[a-z_A-Z]+|[0-9]+(?:/[0-9]+)?|-[0-9]+)")
3306 matchmarkup = (r'(?:\\markup\s*(?:@?\{' + brace_matcher (20) +r'\}|' +
3307                matchstring + r'|(?:\\[a-z_A-Z][a-z_A-Z-]*(?:' + matcharg +
3308                r')*?\s*)*(?:' + matchstring + r"|@?\{" + brace_matcher (20) +
3309                r"\}))|" + matchstring + ")")
3310
3311 @rule((2, 15, 25), r"\(auto)?Footnote(Grob)? -> \footnote")
3312 def conv (str):
3313     # The following replacement includes the final markup argument in
3314     # the match in order to better avoid touching the equally named
3315     # markup function.  The other functions have unique names, so
3316     # there is no point in including their last, possibly complex
3317     # argument in the match.
3318     str = re.sub (r"\\footnote(" + matcharg + (r")(\s*" + matchmarkup)*2 + ")",
3319                   r"\\footnote\2\1\3", str)
3320     str = re.sub (r"\\footnoteGrob"+("(" + matcharg + ")")*2 + r"(\s*" + matchmarkup + ")",
3321                   r"\\footnote\3\2\1", str)
3322     str = re.sub (r"\\autoFootnoteGrob" + ("(" + matcharg + ")")*2,
3323                   r"\\footnote\2\1", str)
3324     str = re.sub (r"\\autoFootnote",
3325                   r"\\footnote", str)
3326     return str
3327
3328 @rule((2, 15, 32), r"tempoWholesPerMinute -> \tempo")
3329 def conv (str):
3330     def sub_tempo (m):
3331         num = int (m.group (1))
3332         den = int (m.group (2))
3333
3334         if (den & (den - 1)) != 0 :
3335             return m.group (0)
3336
3337         # Don't try dotted forms if they result in less than 30 bpm.
3338         # It is not actually relevant to get this right since this
3339         # only occurs in non-printing situations
3340         if den >= 16 and (num % 7) == 0 and num >= 210 :
3341             return r"\tempo %d.. = %d" % (den/4, num/7)
3342
3343         if den >= 8 and (num % 3) == 0 and num >= 90 :
3344             return r"\tempo %d. = %d" % (den/2, num/3)
3345
3346         return r"\tempo %d = %d" % (den, num)
3347
3348     str = re.sub (r"\\context\s*@?\{\s*\\Score\s+tempoWholesPerMinute\s*=\s*" +
3349                   r"#\(ly:make-moment\s+([0-9]+)\s+([0-9]+)\)\s*@?\}",
3350                   sub_tempo, str)
3351     return str
3352
3353 @rule((2, 15, 39), r"\footnote ... -> \footnote ... \default")
3354 def conv (str):
3355     def not_first (s):
3356         def match_fun (m):
3357             if m.group (1):
3358                 return m.group (0)
3359             return m.expand (s)
3360         return match_fun
3361     str = re.sub ("(" + matchmarkup + ")|"
3362                   + r"(\\footnote(?:\s*"
3363                   + matchmarkup + ")?" + matcharg + "(?:" + matcharg
3364                   + ")?\s+" + matchmarkup + ")",
3365                   not_first (r"\2 \\default"), str)
3366     return str
3367
3368 @rule ((2, 15, 40), r"Remove beamWholeMeasure")
3369 def conv (str):
3370     if re.search (r"\bbeamWholeMeasure\b", str):
3371         stderr_write (NOT_SMART % "beamWholeMeasure")
3372         stderr_write (_ ("beamExceptions controls whole-measure beaming.") + "\n")
3373     return str
3374
3375 @rule ((2, 15, 42), r"\set stringTuning -> \set Staff.stringTuning")
3376 def conv (str):
3377     str = re.sub (r"(\\set\s+)stringTuning", r"\1Staff.stringTuning", str)
3378     return str
3379
3380 wordsyntax = r"[a-zA-Z\200-\377](?:[-_]?[a-zA-Z\200-\377])*"
3381
3382 @rule ((2, 15, 43), r'"custom-tuning" = -> custom-tuning =')
3383 def conv (str):
3384     str = re.sub ('\n"(' + wordsyntax + r')"(\s*=\s*\\stringTuning)', "\n\\1\\2", str)
3385     return str
3386
3387 @rule ((2, 16, 0),
3388        _ ("bump version for release"))
3389 def conv (str):
3390     return str
3391
3392 @rule ((2, 17, 0), r"blank-*-force -> blank-*-penalty")
3393 def conv (str):
3394     str = re.sub ('blank-page-force', 'blank-page-penalty', str)
3395     str = re.sub ('blank-last-page-force', 'blank-last-page-penalty', str)
3396     str = re.sub ('blank-after-score-page-force', 'blank-after-score-page-penalty', str)
3397     return str
3398
3399
3400 @rule ((2, 17, 4), r"\shape Grob #offsets -> \shape #offsets Grob")
3401 def conv (str):
3402     str = re.sub (r"\\shape(\s+(?:[a-zA-Z]+|" + matchstring + "))(" +
3403                   matcharg + ")", r"\\shape\2\1", str)
3404     return str
3405
3406 barstring=r"(\\bar|whichBar|defaultBarType|segnoType|doubleRepeatType|startRepeatType|endRepeatType|doubleRepeatSegnoType|startRepeatSegnoType|endRepeatSegnoType)(\s*[=]?\s*[#]?)"
3407
3408 @rule ((2, 17, 5), r"New bar line interface")
3409 def conv(str):
3410     str = re.sub (barstring + r'"\|:"', '\\1\\2".|:"', str)
3411     str = re.sub (barstring + r'":\|"', '\\1\\2":|."', str)
3412     str = re.sub (barstring + r'"\|\|:"', '\\1\\2".|:-||"', str)
3413     str = re.sub (barstring + r'":\|:"', '\\1\\2":..:"', str)
3414     str = re.sub (barstring + r'"\.\|\."', '\\1\\2".."', str)
3415     str = re.sub (barstring + r'"\|S"', '\\1\\2"S-|"', str)
3416     str = re.sub (barstring + r'"S\|"', '\\1\\2"S-S"', str)
3417     str = re.sub (barstring + r'":\|S"', '\\1\\2":|.S"', str)
3418     str = re.sub (barstring + r'":\|S\."', '\\1\\2":|.S-S"', str)
3419     str = re.sub (barstring + r'"S\|:"', '\\1\\2"S.|:-S"', str)
3420     str = re.sub (barstring + r'"\.S\|:"', '\\1\\2"S.|:"', str)
3421     str = re.sub (barstring + r'":\|S\|:"', '\\1\\2":|.S.|:"', str)
3422     str = re.sub (barstring + r'":\|S\.\|:"', '\\1\\2":|.S.|:-S"', str)
3423     str = re.sub (barstring + r'":"', '\\1\\2";"', str)
3424     str = re.sub (barstring + r'"\|s"', '\\1\\2"|-s"', str)
3425     str = re.sub (barstring + r'"dashed"', '\\1\\2"!"', str)
3426     str = re.sub (barstring + r'"kievan"', '\\1\\2"k"', str)
3427     str = re.sub (barstring + r'"empty"', '\\1\\2"-"', str)
3428     return str
3429
3430 symbol_list = (r"#'(?:" + wordsyntax + r"|\(\s*(?:" + wordsyntax + r"\s+)*"
3431                + wordsyntax + r"\s*\))")
3432
3433 grob_path = r"(?:" + symbol_list + r"\s+)*" + symbol_list
3434
3435 grob_spec = wordsyntax + r"(?:\s*\.\s*" + wordsyntax + r")?"
3436
3437 def path_replace (m):
3438     return m.group (1) + string.join (re.findall (wordsyntax, m.group (2)), ".")
3439
3440 @rule ((2, 17, 6), r"""\accidentalStyle #'Context "style" -> \accidentalStyle Context.style
3441 \alterBroken "Context.grob" -> \alterBroken Context.grob
3442 \overrideProperty "Context.grob" -> \overrideProperty Context.grob
3443 \tweak Grob #'symbol -> \tweak Grob.symbol""")
3444 def conv (str):
3445     def patrep (m):
3446         def fn_path_replace (m):
3447             x = string.join (re.findall (wordsyntax, m.group (2)), ".")
3448             if x in ["TimeSignature", "KeySignature", "BarLine",
3449                      "Clef", "StaffSymbol", "OttavaBracket",
3450                      "LedgerLineSpanner"]:
3451                 x = "Staff." + x
3452             return m.group (1) + x
3453         if m.group (1):
3454             return m.group (0)
3455         x = m.group (2) + m.group (4)
3456
3457         if m.group (3):
3458             x = x + re.sub (r"(\s*)(" + symbol_list + ")", fn_path_replace,
3459                             m.group (3))
3460
3461             if not m.group (5):
3462                 x = r"\single" + x
3463         return x
3464
3465     str = re.sub (r'''(\\accidentalStyle\s+)#?"([-A-Za-z]+)"''',
3466                   r"\1\2", str)
3467     str = re.sub (r'''(\\accidentalStyle\s+)#'([A-Za-z]+)\s+#?"?([-A-Za-z]+)"?''',
3468                   r"\1\2.\3", str)
3469     str = re.sub (r'''(\\(?:alterBroken|overrideProperty)\s+)#?"([A-Za-z]+)\s*\.\s*([A-Za-z]+)"''',
3470                   r"\1\2.\3", str)
3471     str = re.sub (r'''(\\tweak\s+)#?"?([A-W][A-Za-z]*)"?\s+?#'([a-zX-Z][-A-Za-z]*)''',
3472                   r"\1\2.\3", str)
3473     str = re.sub (r'''(\\tweak\s+)#'([a-zX-Z][-A-Za-z]*)''',
3474                   r"\1\2", str)
3475     str = re.sub ("(" + matchmarkup + ")|"
3476                   + r"(\\footnote(?:\s*"
3477                   + matchmarkup + ")?" + matcharg + ")(" + matcharg
3478                   + r")?(\s+" + matchmarkup + r")(\s+\\default)?",
3479                   patrep, str)
3480     str = re.sub (r'''(\\alterBroken)(\s+[A-Za-z.]+)(''' + matcharg
3481                   + matcharg + ")", r"\1\3\2", str)
3482     str = re.sub (r"(\\overrideProperty\s+)(" + grob_spec + r"\s+" + grob_path + ")",
3483                   path_replace, str)
3484     str = re.sub (r"(\\(?:override|revert)\s+)(" + grob_spec + r"\s+" + grob_path + ")",
3485                   path_replace, str)
3486     return str
3487
3488 @rule ((2, 17, 11), r"""\times -> \tuplet, \set tupletSpannerDuration -> \tupletSpan
3489 (ly:make-moment 1 4) -> (ly:make-moment 1/4)
3490 (ly:make-duration 0 0 1 2) -> (ly:make-duration 0 0 1/2)""")
3491 def conv(str):
3492     def sub_dur (m):
3493         num = int (m.group (1))
3494         den = int (m.group (2))
3495
3496 # if den is no power of 2, don't even try to use an unscaled duration
3497         if (den & (den - 1)) != 0 :
3498             return (r"\tupletSpan 1*%d/%d" % (num, den))
3499
3500         if den >= 4 and num == 7 :
3501             return (r"\tupletSpan %d.." % (den/4))
3502
3503         if den >= 2 and num == 3 :
3504             return (r"\tupletSpan %d." % (den/2))
3505
3506         if num == 1 :
3507             return (r"\tupletSpan %d" % den)
3508
3509         return (r"\tupletSpan 1*%d/%d" % (num, den))
3510
3511     str = re.sub (r"\\set\s+tupletSpannerDuration\s*=\s*" +
3512                   r"#\(ly:make-moment\s+([0-9]+)\s+([0-9]+)\s*\)",
3513                   sub_dur, str)
3514     str = re.sub (r"\\unset tupletSpannerDuration",
3515                   r"\\tupletSpan \\default", str)
3516     str = re.sub (r"\\times(\s*)([0-9]+)/([0-9]+)",
3517                   r"\\tuplet\1\3/\2", str)
3518
3519     str = re.sub (r"(\(ly:make-moment\s+-?[0-9]+)\s+([1-9][0-9]*\))",
3520                   r"\1/\2", str)
3521     str = re.sub (r"(\(ly:make-moment\s+-?[0-9]+)\s+([0-9]+\s+-?[0-9]+)\s([0-9]+\))",
3522                   r"\1/\2/\3", str)
3523     str = re.sub (r"(\(ly:make-duration\s+-?[0-9]+\s+[0-9]+\s+[0-9]+)\s+([0-9]+\))",
3524                   r"\1/\2", str)
3525     return str
3526
3527 @rule((2, 17, 14), r"\accepts ... -> \accepts ... \defaultchild ...")
3528 def conv(str):
3529     def matchaccepts(m):
3530         # First weed out definitions starting from an existing
3531         # definition: we assume that the inherited \defaultchild is
3532         # good enough for our purposes.  Heuristic: starts with a
3533         # backslash and an uppercase letter.
3534         if re.match (r"\s*\\[A-Z]", m.group (1)):
3535             return m.group (0)
3536         # existing defaultchild obviously trumps all
3537         if re.search (r"\\defaultchild[^-_a-zA-Z]", m.group (1)):
3538             return m.group (0)
3539         # take the first \\accepts if any and replicate it
3540         return re.sub ("(\r?\n[ \t]*|[ \t]+)"
3541                        + r"""\\accepts(\s+(?:#?".*?"|[-_a-zA-Z]+))""",
3542                        r"\g<0>\1\\defaultchild\2",
3543                        m.group (0), 1)
3544
3545     str = re.sub (r"\\context\s*@?\{(" + brace_matcher (20) + ")\}",
3546                   matchaccepts, str)
3547     return str
3548
3549 @rule((2, 17, 15), r"""#(ly:set-option 'old-relative)
3550 \relative -> \relative c'""")
3551 def conv(str):
3552     if re.search (r"[#$]\(ly:set-option\s+'old-relative", str):
3553         stderr_write (NOT_SMART % "#(ly:set-option 'old-relative)")
3554         stderr_write (UPDATE_MANUALLY)
3555         raise FatalConversionError ();
3556     # If the file contains a language switch to a language where the
3557     # name of c is not "c", we can't reliably know which parts of the
3558     # file will need "c" and which need "do".
3559     m = re.search (r'\\language\s(?!\s*#?"(?:nederlands|deutsch|english|norsk|suomi|svenska))"', str)
3560     if m:
3561         # Heuristic: if there is a non-commented { before the language
3562         # selection, we can't be sure.
3563         # Also if there is any selection of a non-do language.
3564         if (re.search ("^[^%\n]*\\{", m.string[:m.start()], re.M)
3565             or re.search ('\\language\s(?!\s*#?"(?:catalan|espanol|español|italiano|français|portugues|vlaams))"', str)):
3566             do = "$(ly:make-pitch 0 0)"
3567         else:
3568             do = "do'"
3569     else:
3570         do = "c'"
3571     str = re.sub (r"(\\relative)(\s+(\{|[\\<]))",
3572                   r"\1 " + do + r"\2", str)
3573     return str
3574
3575 @rule ((2, 17, 18),
3576     "Rename OctavateEight to ClefModifier, rename related properties.")
3577 def conv(str):
3578     str = re.sub ('OctavateEight',               'ClefModifier',                   str)
3579     str = re.sub ('octavate-eight-interface',    'clef-modifier-interface',        str)
3580     str = re.sub ('clefOctavation',              'clefTransposition',              str)
3581     str = re.sub ('clefOctavationFormatter',     'clefTranspositionFormatter',     str)
3582     str = re.sub ('clefOctavationStyle',         'clefTranspositionStyle',         str)
3583     str = re.sub ('cueClefOctavation',           'cueClefTransposition',           str)
3584     str = re.sub ('cueClefOctavationFormatter',  'cueClefTranspositionFormatter',  str)
3585     str = re.sub ('cueClefOctavationStyle',      'cueClefTranspositionStyle',      str)
3586     return str
3587
3588 @rule((2, 17, 19), r"\column { \vspace #2 } -> \column { \combine \null \vspace #2 }")
3589 def conv(str):
3590     def vspace_replace(m):
3591
3592 # vspace now always adds space and does not, for example, change the
3593 # impact of either baselineskip or descenders on the line above.
3594 #
3595 # We can't simulate the old behavior in a simpler manner.  A command
3596 # of its own is not really warranted since this behavior combines
3597 # badly enough with other spacing considerations (like baselineskip
3598 # and descenders) as to make it not all that useful.  So this
3599 # conversion rule is here more for compatibility's sake rather than
3600 # preserving desirable behavior.
3601
3602         str = re.sub (r"(\\\\?)vspace(\s)", r"\1combine \1null \1vspace\2", m.group(0))
3603         return str
3604
3605     str = re.sub (r"\\(?:left-|right-|center-|)column\s*\{" + brace_matcher (20) + r"\}",
3606                   vspace_replace, str)
3607     return str
3608
3609 @rule((2, 17, 20), _(r"Flag.transparent and Flag.color inherit from Stem"))
3610 def conv(str):
3611     str = re.sub (r"(((?:\\once\s*)?)\\override\s+((?:\w+\.)?)Stem\.(transparent|color)\s*=\s*(#\S+))\s+\2\\override\s+\3Flag\.\4\s*=\s*\5",
3612                   r"\1", str)
3613     str = re.sub (r"(((?:\\once\s*)?)\\revert\s+((?:\w+\.)?)Stem\.(transparent|color))\s+\2\\revert\s+\3Flag\.\4",
3614                   r"\1", str)
3615     str = re.sub (r"(\\tweak\s+((?:\w+\.)?)Stem\.(transparent|color)\s+(#\S+))\s+\\tweak\s+\2Flag\.\3\s+\4",
3616                   r"\1", str)
3617     return str
3618
3619 @rule((2, 17, 25), r'''\tempo 4. = 50~60 -> \tempo 4. = 50-60
3620 -| -> -!
3621 pipeSymbol, escapedParenthesisOpenSymbol ... -> "|", "\\(" ...''')
3622 def conv(str):
3623 #  This goes for \tempo commands ending with a range, like
3624 #  = 50 ~ 60
3625 #  and uses - instead.  We don't explicitly look for \tempo since the
3626 #  complete syntax has a large number of variants, and this is quite
3627 #  unlikely to occur in other contexts
3628     str = re.sub (r"(=\s*[0-9]+\s*)~(\s*[0-9]+\s)", r"\1-\2", str)
3629 # Match strings, and articulation shorthands that end in -^_
3630 # so that we leave alone -| in quoted strings and c4--|
3631     def subnonstring(m):
3632         if m.group (1):
3633             return m.group (1)+"!"
3634         return m.group (0)
3635     str = re.sub (r"([-^_])\||" + matchstring + r"|[-^_][-^_]", subnonstring, str)
3636     str = re.sub (r"\bdashBar\b", "dashBang", str)
3637     orig = [ "pipeSymbol",
3638              "bracketOpenSymbol",
3639              "bracketCloseSymbol",
3640              "tildeSymbol",
3641              "parenthesisOpenSymbol",
3642              "parenthesisCloseSymbol",
3643              "escapedExclamationSymbol",
3644              "escapedParenthesisOpenSymbol",
3645              "escapedParenthesisCloseSymbol",
3646              "escapedBiggerSymbol",
3647              "escapedSmallerSymbol" ]
3648     repl = [ r'"|"',
3649              r'"["',
3650              r'"]"',
3651              r'"~"',
3652              r'"("',
3653              r'")"',
3654              r'"\\!"',
3655              r'"\\("',
3656              r'"\\)"',
3657              r'"\\>"',
3658              r'"\\<"']
3659     words = r"\b(?:(" + ")|(".join (orig) + r"))\b"
3660     def wordreplace(m):
3661         def instring(m):
3662             return re.sub (r'["\\]',r'\\\g<0>',repl[m.lastindex-1])
3663         if m.lastindex:
3664             return repl[m.lastindex-1]
3665         return '"' + re.sub (words, instring, m.group(0)[1:-1]) + '"'
3666     str = re.sub (words + "|" + matchstring, wordreplace, str)
3667     return str
3668
3669 @rule((2, 17, 27), r'''\stringTuning \notemode -> \stringTuning''')
3670 def conv(str):
3671     str = re.sub (r"\\stringTuning\s*\\notemode(\s*)@?\{\s*(.*?)\s*@?\}",
3672                   r"\\stringTuning\1\2", str)
3673     if re.search (r'[^-\w]staff-padding[^-\w]', str):
3674         stderr_write (NOT_SMART % "staff-padding")
3675         stderr_write (_ ("Staff-padding now controls the distance to the baseline, not the nearest point."))
3676     return str
3677
3678 @rule((2, 17, 29), r'''Dynamic_engraver -> New_dynamic_engraver+Dynamic_align_engraver
3679 New_dynamic_engraver -> Dynamic_engraver''')
3680 def conv(str):
3681     str = re.sub ("(\r?\n?[ \t]*\\\\(?:consists|remove)\\s*)(\"?)Dynamic_engraver\\2",
3682                   r"\1\2New_dynamic_engraver\2\1\2Dynamic_align_engraver\2",
3683                   str)
3684 # Should we warn about any remaining Dynamic_engraver?  Possibly it
3685 # will do the job just fine.
3686     str = re.sub ("New_dynamic_engraver", "Dynamic_engraver", str)
3687     return str
3688
3689 @rule ((2, 17, 97), r'''(make-relative (a b) b ...) -> make-relative (a b) #{ a b #}...''')
3690 def conv (str):
3691     str = re.sub (r"(\(make-relative\s+\(\s*(([A-Za-z][-_A-Za-z0-9]*)" +
3692                   r"(?:\s+[A-Za-z][-_A-Za-z0-9]*)*)\s*\)\s*)\3(?=\s)",
3693                   r"\1(make-event-chord (list \2))", str)
3694     str = re.sub (r"(\(make-relative\s+\(\s*([A-Za-z][-_A-Za-z0-9]*" +
3695                   r"(?:\s+([A-Za-z][-_A-Za-z0-9]*))+)\s*\)\s*)\3(?=\s)",
3696                   r"\1(make-sequential-music (list \2))", str)
3697     return str
3698
3699 @rule ((2, 18, 0),
3700        _ ("bump version for release"))
3701 def conv (str):
3702     return str
3703
3704 @rule ((2, 19, 2), r"\lyricsto \new/\context/... -> \new/\context/... \lyricsto")
3705 def conv (str):
3706     word=r'(?:#?"[^"]*"|\b' + wordsyntax + r'\b)'
3707     str = re.sub (r"(\\lyricsto\s*" + word + r"\s*)(\\(?:new|context)\s*" + word
3708                   + r"(?:\s*=\s*" + word + r")?\s*)",
3709                   r"\2\1", str)
3710     str = re.sub (r"(\\lyricsto\s*" + word + r"\s*)\\lyricmode\b\s*",
3711                   r"\1", str)
3712     str = re.sub (r"(\\lyricsto\s*" + word + r"\s*)\\lyrics\b\s*",
3713                   r"\\new Lyrics \1", str)
3714     str = re.sub (r'\\lyricmode\s*(\\lyricsto\b)', r"\1", str)
3715     return str
3716
3717 @rule ((2, 19, 7), "keySignature -> keyAlterations")
3718 def conv(str):
3719     str = re.sub (r'\bkeySignature\b', 'keyAlterations', str)
3720     str = re.sub (r'\blastKeySignature\b', 'lastKeyAlterations', str)
3721     str = re.sub (r'\blocalKeySignature\b', 'localAlterations', str)
3722     return str
3723
3724 @rule ((2, 19, 11), "thin-kern -> segno-kern")
3725 def conv(str):
3726     str = re.sub (r'\bthin-kern\b', 'segno-kern', str)
3727     return str
3728
3729 # before_id is written in a manner where it will only substantially
3730 # (rather than as a lookbefore assertion) match material that could
3731 # not be part of a previous id.  In that manner, one replacement does
3732 # not inhibit an immediately adjacent replacement.
3733
3734 before_id = r'(?:^|(?<!\\)(?:\\\\)+|(?<=[^-_\\a-zA-Z])|(?<=[^a-zA-Z][-_]))'
3735
3736 # after_id is a pure lookbehind assertion so its match string is
3737 # always empty
3738
3739 after_id = r'(?![a-zA-Z]|[-_][a-zA-Z])'
3740
3741 @rule ((2, 19, 16), """implicitTimeSignatureVisibility -> initialTimeSignatureVisibility
3742 csharp -> c-sharp""")
3743 def conv(str):
3744     str = re.sub (r'\bimplicitTimeSignatureVisibility\b', 'initialTimeSignatureVisibility', str)
3745     str = re.sub ('(' + before_id + r'[a-g])((?:sharp){1,2}|(?:flat){1,2})'
3746                   + after_id, r'\1-\2', str)
3747     return str
3748
3749 @rule ((2, 19, 22), """whiteout -> whiteout-box
3750 (define-xxx-function (parser location ...) -> (define-xxx-function (...)
3751 (xxx ... parser ...) -> (xxx ... ...)""")
3752 def conv(str):
3753     # whiteout -> whiteout-box
3754     str = re.sub (r"\\whiteout(?![a-z_-])", r"\\whiteout-box", str)
3755     str = re.sub (r"\b\.whiteout(?![a-z_-])\b", r".whiteout-box", str)
3756     str = re.sub (r"#'whiteout(?![a-z_-])\b", r"#'whiteout-box", str)
3757     str = re.sub (r"\bstencil-whiteout\b", r"stencil-whiteout-box", str)
3758     
3759     # (define-xxx-function (parser location ...) -> (define-xxx-function (...)
3760     def subst(m):
3761         def subsub(m):
3762             str = (m.group (1)
3763                    + re.sub ('(?<=\s|["\\()])' + m.group (2) + r'(?=\s|["\\()])',
3764                              r'(*location*)',
3765                              re.sub (r'(?<=\s|["\\()])parser(?=\s|["\\()])',
3766                                      r'(*parser*)', m.group (3))))
3767             return str
3768         return re.sub (r'(\([-a-z]+\s*\(+)parser\s+([-a-z]+)\s*((?:.|\n)*)$',
3769                        subsub, m.group (0))
3770     str = re.sub (r'\(define-(?:music|event|scheme|void)-function(?=\s|["(])'
3771                   + paren_matcher (20) + r'\)', subst, str)
3772
3773     # (xxx ... parser ...) -> (xxx ... ...)
3774     def repl (m):
3775         return m.group (1) + inner (m.group (2))
3776     def inner (str):
3777         str = re.sub (r"(\((?:" +
3778                       r"ly:parser-lexer|" +
3779                       r"ly:parser-clone|" +
3780                       r"ly:parser-output-name|" +
3781                       r"ly:parser-error|" +
3782                       r"ly:parser-define!|" +
3783                       r"ly:parser-lookup|" +
3784                       r"ly:parser-has-error\?|" +
3785                       r"ly:parser-clear-error|" +
3786                       r"ly:parser-set-note-names|" +
3787                       r"ly:parser-include-string|" +
3788                       r"note-names-language|" +
3789                       r"display-lily-music|" +
3790                       r"music->lily-string|" +
3791                       r"note-name->lily-string|" +
3792                       r"value->lily-string|"
3793                       r"check-grob-path|" +
3794                       r"event-chord-wrap!|" +
3795                       r"collect-bookpart-for-book|" +
3796                       r"collect-scores-for-book|" +
3797                       r"collect-music-aux|" +
3798                       r"collect-book-music-for-book|" +
3799                       r"scorify-music|" +
3800                       r"collect-music-for-book|" +
3801                       r"collect-book-music-for-book|" +
3802                       r"toplevel-book-handler|" +
3803                       r"default-toplevel-book-handler|" +
3804                       r"print-book-with-defaults|" +
3805                       r"toplevel-music-handler|" +
3806                       r"toplevel-score-handler|" +
3807                       r"toplevel-text-handler|" +
3808                       r"toplevel-bookpart-handler|" +
3809                       r"book-music-handler|" +
3810                       r"context-mod-music-handler|" +
3811                       r"bookpart-music-handler|" +
3812                       r"output-def-music-handler|" +
3813                       r"print-book-with-defaults-as-systems|" +
3814                       r"add-score|" +
3815                       r"add-text|" +
3816                       r"add-music|" +
3817                       r"make-part-combine-music|" +
3818                       r"make-directed-part-combine-music|" +
3819                       r"add-quotable|" +
3820                       r"paper-variable|" +
3821                       r"make-autochange-music|" +
3822                       r"context-mod-from-music|" +
3823                       r"context-defs-from-music)" +
3824                       r'(?=\s|[()]))(' + paren_matcher (20) + ")"
3825                       r"(?:\s+parser(?=\s|[()])|\s*\(\*parser\*\))", repl, str)
3826         return str
3827     str = inner (str)
3828     # This is the simplest case, resulting from one music function
3829     # trying to call another one via Scheme.  The caller is supposed
3830     # to have its uses of parser/location converted to
3831     # (*parser*)/(*location*) already.  Other uses of
3832     # ly:music-function-extract are harder to convert but unlikely.
3833     str = re.sub (r'(\(\s*\(ly:music-function-extract\s+' + wordsyntax +
3834                   r'\s*\)\s+)\(\*parser\*\)\s*\(\*location\*\)', r'\1',
3835                   str)
3836     return str
3837
3838 @rule ((2, 19, 24), r"""music-has-type -> music-is-of-type?
3839 \applyOutput #'Context -> \applyOutput Context""")
3840 def conv (str):
3841     str = re.sub (r'(?<=\s|["\\()])' + "music-has-type" + r'(?=\s|["\\()])',
3842                   "music-is-of-type?", str)
3843     str = re.sub (r"(\\applyOutput\s+)#'([a-zA-Z])", r"\1\2", str)
3844     return str
3845
3846 @rule ((2, 19, 28), r"c:5.x, c:5^x, c:sus -> c:3.5.x, c:3.5^x, c:5")
3847 def conv (str):
3848     str = re.sub (r":5([.^][1-9])", r":3.5\1", str)
3849     # row back for self-defeating forms
3850     str = re.sub (r":3\.5((?:\.[0-9]+)*\^(?:[0-9]+\.)*)3\.", r":5\1", str)
3851     str = re.sub (r":3\.5((?:\.[0-9]+)*\^?:[0-9]+(?:\.[0-9]+)*)\.3(?![.0-9])", r":5\1", str)
3852     str = re.sub (r":3\.5((?:\.[0-9]+)*)\^3(?=\s|\})", r":5\1", str)
3853     str = re.sub (r":sus(?=\s|\})", ":5", str)
3854     str = re.sub (r":1\.5(?=\s|[.^}])", r":5", str)
3855     return str
3856
3857 @rule ((2, 19, 29), r"partcombine*Once -> \once \partcombine*")
3858 def conv(str):
3859     str = re.sub (r"(\\partcombine(?:Apart|Chords|Unisono|SoloII?|Automatic))Once\b",
3860                   r"\\once \1", str)
3861     str = re.sub (r"(\\partcombineForce" + matcharg + r")\s*##f(\s)",
3862                   r"\1\2", str)
3863     str = re.sub (r"(\\partcombineForce" + matcharg + r")\s*##t(\s)",
3864                   r"\\once \1\2", str)
3865     return str
3866
3867 @rule ((2, 19, 32), r"whiteout-box -> whiteout")
3868 def conv(str):
3869     str = re.sub (r"\\whiteout-box(?![a-z_-])", r"\\whiteout", str)
3870     str = re.sub (r"\b\.whiteout-box(?![a-z_-])\b", r".whiteout", str)
3871     str = re.sub (r"#'whiteout-box(?![a-z_-])\b", r"#'whiteout", str)
3872     return str
3873
3874 @rule ((2, 19, 40), r"\time #'(2 3) ... -> \time 2,3 ...")
3875 def conv (str):
3876     def repl (m):
3877         return m.group(1) + re.sub (r"\s+", ",", m.group (2))
3878
3879     str = re.sub (r"(beatStructure\s*=\s*)#'\(([0-9]+(?:\s+[0-9]+)+)\)",
3880                   repl, str)
3881
3882     str = re.sub (r"(\\time\s*)#'\(([0-9]+(?:\s+[0-9]+)+)\)", repl, str)
3883     def repl (m):
3884         subst = re.sub (r"\s+", ",", m.group (1))
3885         return subst + (4 + len (m.group (1)) - len (subst)) * " " + m.group (2)
3886
3887     str = re.sub (r"#'\(([0-9]+(?:\s+[0-9]+)+)\)(\s+%\s*beatStructure)",
3888                   repl, str)
3889     return str
3890
3891 @rule ((2, 19, 46), r"""\context ... \modification -> \context ... \with \modification
3892 \consists "Output_property_engraver" ->""")
3893 def conv (str):
3894     word=r'(?:#?"[^"]*"|\b' + wordsyntax + r'\b)'
3895     mods = string.join (re.findall ("\n(" + wordsyntax + r")\s*=\s*\\with(?:\s|\\|\{)", str)
3896                         + ['RemoveEmptyStaves','RemoveAllEmptyStaves'], "|")
3897     str = re.sub (r"(\\(?:drums|figures|chords|lyrics|addlyrics|"
3898                   + r"(?:new|context)\s*" + word
3899                   + r"(?:\s*=\s*" + word + r")?)\s*)(\\(?:" + mods + "))",
3900                   r"\1\\with \2", str)
3901
3902     str = re.sub (r'\\(consists|remove)\s+"?Output_property_engraver"?\s*',
3903                   '', str)
3904     return str
3905
3906 @rule ((2, 19, 49), r"""id -> output-attributes.id or output-attributes
3907 for \tweak, \override, \overrideProperty, and \revert""")
3908 def conv (str):
3909     # path cannot start with '-' or '_' and matches zero or more path
3910     # units that each end in a dot
3911     path = r"(?:[a-zA-Z\200-\377](?:[-_]?[a-zA-Z\200-\377])*(?:\s*\.\s*))*"
3912
3913     # Manual editing is needed when id is set to #(...) or \xxx
3914     manual_edits = r"(\\(?:tweak|override|overrideProperty)\s+" + path + r")id(\s*=?\s*(?:\\|#\s*\())"
3915     automatic = r"(\\(?:tweak|override|overrideProperty|revert)\s+" + path + r")id"
3916     if re.search (manual_edits, str):
3917         stderr_write (NOT_SMART % "\"output-attributes\"")
3918         stderr_write (_ ("Previously the \"id\" grob property (string) was used for SVG output.") + "\n")
3919         stderr_write (_ ("Now \"output-attributes\" (association list) is used instead.") + "\n")
3920         stderr_write (UPDATE_MANUALLY)
3921
3922     # First, for manual editing cases we convert 'id' to 'output-attributes'
3923     # because Grob.output-attributes.id = #(lambda ... ) will not work.
3924     # Then for the rest we convert 'id' to 'output-attributes.id'
3925     str = re.sub (manual_edits, r"\1output-attributes\2", str)
3926     str = re.sub (automatic, r"\1output-attributes.id", str)
3927     return str
3928
3929 # Guidelines to write rules (please keep this at the end of this file)
3930 #
3931 # - keep at most one rule per version; if several conversions should be done,
3932 # concatenate them into a single "conv" function;
3933 #
3934 # - enclose strings to be localized with `_(' and  `)';
3935 #
3936 # - write rule for bumping major stable version with
3937 #
3938 #     _ ("bump version for release")
3939 #
3940 # as exact description.