2 # vim: set noexpandtab:
4 # * Figure out clean set of options. Hmm, isn't it pretty ok now?
5 # * add support for .lilyrc
6 # * EndLilyPondOutput is def'd as vfil. Causes large white gaps.
7 # * texinfo: add support for @pagesize
9 # todo: dimension handling (all the x2y) is clumsy. (tca: Thats
10 # because the values are taken directly from texinfo.tex,
11 # geometry.sty and article.cls. Give me a hint, and I'll
14 # This is was the idea for handling of comments:
15 # Multiline comments, @ignore .. @end ignore is scanned for
16 # in read_doc_file, and the chunks are marked as 'ignore', so
17 # lilypond-book will not touch them any more. The content of the
18 # chunks are written to the output file. Also 'include' and 'input'
19 # regex has to check if they are commented out.
21 # Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'.
22 # These three regex's has to check if they are on a commented line,
23 # % for latex, @c for texinfo.
25 # Then lines that are commented out with % (latex) and @c (Texinfo)
26 # are put into chunks marked 'ignore'. This cannot be done before
27 # searching for the lilypond-blocks because % is also the comment character
30 # The the rest of the rexeces are searched for. They don't have to test
31 # if they are on a commented out line.
43 program_version
= '@TOPLEVEL_VERSION@'
44 if program_version
== '@' + 'TOPLEVEL_VERSION' + '@':
45 program_version
= '1.3.113'
47 include_path
= [os
.getcwd()]
50 # g_ is for global (?)
52 g_here_dir
= os
.getcwd ()
55 g_force_lilypond_fontsize
= 0
63 default_music_fontsize
= 16
64 default_text_fontsize
= 12
67 # this code is ugly. It should be cleaned
71 # the dimensions are from geometry.sty
72 'a0paper': (mm2pt(841), mm2pt(1189)),
73 'a1paper': (mm2pt(595), mm2pt(841)),
74 'a2paper': (mm2pt(420), mm2pt(595)),
75 'a3paper': (mm2pt(297), mm2pt(420)),
76 'a4paper': (mm2pt(210), mm2pt(297)),
77 'a5paper': (mm2pt(149), mm2pt(210)),
78 'b0paper': (mm2pt(1000), mm2pt(1414)),
79 'b1paper': (mm2pt(707), mm2pt(1000)),
80 'b2paper': (mm2pt(500), mm2pt(707)),
81 'b3paper': (mm2pt(353), mm2pt(500)),
82 'b4paper': (mm2pt(250), mm2pt(353)),
83 'b5paper': (mm2pt(176), mm2pt(250)),
84 'letterpaper': (in2pt(8.5), in2pt(11)),
85 'legalpaper': (in2pt(8.5), in2pt(14)),
86 'executivepaper': (in2pt(7.25), in2pt(10.5))}
87 self
.m_use_geometry
= None
88 self
.m_papersize
= 'letterpaper'
92 self
.m_geo_landscape
= 0
93 self
.m_geo_width
= None
94 self
.m_geo_textwidth
= None
95 self
.m_geo_lmargin
= None
96 self
.m_geo_rmargin
= None
97 self
.m_geo_includemp
= None
98 self
.m_geo_marginparwidth
= {10: 57, 11: 50, 12: 35}
99 self
.m_geo_marginparsep
= {10: 11, 11: 10, 12: 10}
100 self
.m_geo_x_marginparwidth
= None
101 self
.m_geo_x_marginparsep
= None
103 def set_geo_option(self
, name
, value
):
104 if name
== 'body' or name
== 'text':
105 if type(value
) == type(""):
106 self
.m_geo_textwidth
= value
108 self
.m_geo_textwidth
= value
[0]
110 elif name
== 'portrait':
111 self
.m_geo_landscape
= 0
112 elif name
== 'reversemp' or name
== 'reversemarginpar':
113 if self
.m_geo_includemp
== None:
114 self
.m_geo_includemp
= 1
115 elif name
== 'marginparwidth' or name
== 'marginpar':
116 self
.m_geo_x_marginparwidth
= value
117 self
.m_geo_includemp
= 1
118 elif name
== 'marginparsep':
119 self
.m_geo_x_marginparsep
= value
120 self
.m_geo_includemp
= 1
121 elif name
== 'scale':
122 if type(value
) == type(""):
123 self
.m_geo_width
= self
.get_paperwidth() * float(value
)
125 self
.m_geo_width
= self
.get_paperwidth() * float(value
[0])
126 elif name
== 'hscale':
127 self
.m_geo_width
= self
.get_paperwidth() * float(value
)
128 elif name
== 'left' or name
== 'lmargin':
129 self
.m_geo_lmargin
= value
130 elif name
== 'right' or name
== 'rmargin':
131 self
.m_geo_rmargin
= value
132 elif name
== 'hdivide' or name
== 'divide':
133 if value
[0] not in ('*', ''):
134 self
.m_geo_lmargin
= value
[0]
135 if value
[1] not in ('*', ''):
136 self
.m_geo_width
= value
[1]
137 if value
[2] not in ('*', ''):
138 self
.m_geo_rmargin
= value
[2]
139 elif name
== 'hmargin':
140 if type(value
) == type(""):
141 self
.m_geo_lmargin
= value
142 self
.m_geo_rmargin
= value
144 self
.m_geo_lmargin
= value
[0]
145 self
.m_geo_rmargin
= value
[1]
146 elif name
== 'margin':#ugh there is a bug about this option in
147 # the geometry documentation
148 if type(value
) == type(""):
149 self
.m_geo_lmargin
= value
150 self
.m_geo_rmargin
= value
152 self
.m_geo_lmargin
= value
[0]
153 self
.m_geo_rmargin
= value
[0]
154 elif name
== 'total':
155 if type(value
) == type(""):
156 self
.m_geo_width
= value
158 self
.m_geo_width
= value
[0]
159 elif name
== 'width' or name
== 'totalwidth':
160 self
.m_geo_width
= value
161 elif name
== 'paper' or name
== 'papername':
162 self
.m_papersize
= value
163 elif name
[-5:] == 'paper':
164 self
.m_papersize
= name
166 self
._set
_dimen
('m_geo_'+name
, value
)
167 def __setattr__(self
, name
, value
):
168 if type(value
) == type("") and \
169 dimension_conversion_dict
.has_key (value
[-2:]):
170 f
= dimension_conversion_dict
[dim
]
171 self
.__dict
__[name
] = f(float(value
[:-2]))
173 self
.__dict
__[name
] = value
176 s
= "LatexPaper:\n-----------"
177 for v
in self
.__dict
__.keys():
179 s
= s
+ str (v
) + ' ' + str (self
.__dict
__[v
])
180 s
= s
+ "-----------"
183 def get_linewidth(self
):
184 w
= self
._calc
_linewidth
()
185 if self
.m_num_cols
== 2:
189 def get_paperwidth(self
):
190 #if self.m_use_geometry:
191 return self
.m_paperdef
[self
.m_papersize
][self
.m_landscape
or self
.m_geo_landscape
]
192 #return self.m_paperdef[self.m_papersize][self.m_landscape]
194 def _calc_linewidth(self
):
195 # since geometry sometimes ignores 'includemp', this is
196 # more complicated than it should be
198 if self
.m_geo_includemp
:
199 if self
.m_geo_x_marginparsep
is not None:
200 mp
= mp
+ self
.m_geo_x_marginparsep
202 mp
= mp
+ self
.m_geo_marginparsep
[self
.m_fontsize
]
203 if self
.m_geo_x_marginparwidth
is not None:
204 mp
= mp
+ self
.m_geo_x_marginparwidth
206 mp
= mp
+ self
.m_geo_marginparwidth
[self
.m_fontsize
]
208 #ugh test if this is necessary
212 if not self
.m_use_geometry
:
213 return latex_linewidths
[self
.m_papersize
][self
.m_fontsize
]
215 geo_opts
= (self
.m_geo_lmargin
== None,
216 self
.m_geo_width
== None,
217 self
.m_geo_rmargin
== None)
219 if geo_opts
== (1, 1, 1):
220 if self
.m_geo_textwidth
:
221 return self
.m_geo_textwidth
222 w
= self
.get_paperwidth() * 0.8
224 elif geo_opts
== (0, 1, 1):
225 if self
.m_geo_textwidth
:
226 return self
.m_geo_textwidth
227 return self
.f1(self
.m_geo_lmargin
, mp
)
228 elif geo_opts
== (1, 1, 0):
229 if self
.m_geo_textwidth
:
230 return self
.m_geo_textwidth
231 return self
.f1(self
.m_geo_rmargin
, mp
)
233 in ((0, 0, 1), (1, 0, 0), (1, 0, 1)):
234 if self
.m_geo_textwidth
:
235 return self
.m_geo_textwidth
236 return self
.m_geo_width
- mp
237 elif geo_opts
in ((0, 1, 0), (0, 0, 0)):
238 w
= self
.get_paperwidth() \
239 - self
.m_geo_lmargin
- self
.m_geo_rmargin
- mp
243 raise "Never do this!"
245 tmp
= self
.get_paperwidth() - m
* 2 - mp
250 tmp
= self
.get_paperwidth() - self
.m_geo_lmargin \
258 self
.m_papersize
= 'letterpaper'
260 def get_linewidth(self
):
261 return texi_linewidths
[self
.m_papersize
][self
.m_fontsize
]
267 def em2pt(x
, fontsize
= 10):
268 return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize
] * x
269 def ex2pt(x
, fontsize
= 10):
270 return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize
] * x
275 dimension_conversion_dict
={
285 # indices are no. of columns, papersize, fontsize
286 # Why can't this be calculated?
288 'a4paper':{10: 345, 11: 360, 12: 390},
289 'a4paper-landscape': {10: 598, 11: 596, 12:592},
290 'a5paper':{10: 276, 11: 276, 12: 276},
291 'b5paper':{10: 345, 11: 356, 12: 356},
292 'letterpaper':{10: 345, 11: 360, 12: 390},
293 'letterpaper-landscape':{10: 598, 11: 596, 12:596},
294 'legalpaper': {10: 345, 11: 360, 12: 390},
295 'executivepaper':{10: 345, 11: 360, 12: 379}}
298 'afourpaper': {12: mm2pt(160)},
299 'afourwide': {12: in2pt(6.5)},
300 'afourlatex': {12: mm2pt(150)},
301 'smallbook': {12: in2pt(5)},
302 'letterpaper': {12: in2pt(6)}}
304 option_definitions
= [
305 ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
306 ('DIM', '', 'default-music-fontsize', 'default fontsize for music. DIM is assumed to be in points'),
307 ('DIM', '', 'default-lilypond-fontsize', 'deprecated, use --default-music-fontsize'),
308 ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline lilypond. DIM is assumed be to in points'),
309 ('DIM', '', 'force-lilypond-fontsize', 'deprecated, use --force-music-fontsize'),
310 ('DIR', 'I', 'include', 'include path'),
311 ('', 'M', 'dependencies', 'write dependencies'),
312 ('PREF', '', 'dep-prefix', 'prepend PREF before each -M dependency'),
313 ('', 'n', 'no-lily', 'don\'t run lilypond'),
314 ('', '', 'no-pictures', "don\'t generate pictures"),
315 ('', '', 'read-lys', "don't write ly files."),
316 ('FILE', 'o', 'outname', 'filename main output file'),
317 ('FILE', '', 'outdir', "where to place generated files"),
318 ('', 'v', 'version', 'print version information' ),
319 ('', 'h', 'help', 'print help'),
322 # format specific strings, ie. regex-es for input, and % strings for output
325 'output-lilypond-fragment' : r
"""\begin[eps,singleline,%s]{lilypond}
332 'output-filename' : r
'''
335 'output-lilypond': r
"""\begin[%s]{lilypond}
338 'output-verbatim': "\\begin{verbatim}%s\\end{verbatim}",
339 'output-default-post': "\\def\postLilypondExample{}\n",
340 'output-default-pre': "\\def\preLilypondExample{}\n",
341 'usepackage-graphics': '\\usepackage{graphics}\n',
342 'output-eps': '\\noindent\\parbox{\\lilypondepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s.eps}}',
343 'output-tex': '\\preLilypondExample \\input %(fn)s.tex \\postLilypondExample\n',
344 'pagebreak': r
'\pagebreak',
346 'texi' : {'output-lilypond': """@lilypond[%s]
350 'output-filename' : r
'''
353 'output-lilypond-fragment': """@lilypond[%s]
354 \context Staff\context Voice{ %s }
357 'output-verbatim': r
"""@example
362 # do some tweaking: @ is needed in some ps stuff.
363 # override EndLilyPondOutput, since @tex is done
364 # in a sandbox, you can't do \input lilyponddefs at the
365 # top of the document.
367 # should also support fragment in
373 \def\EndLilyPondOutput{}
385 def output_verbatim (body
):
386 if __main__
.format
== 'texi':
387 body
= re
.sub ('([@{}])', '@\\1', body
)
388 return get_output ('output-verbatim') % body
392 'latex': {'input': r
'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
393 'include': r
'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
394 'option-sep' : ', *',
395 'header': r
"\\documentclass\s*(\[.*?\])?",
396 'geometry': r
"^(?m)[^%\n]*?\\usepackage\s*(\[(?P<options>.*)\])?\s*{geometry}",
397 'preamble-end': r
'(?P<code>\\begin{document})',
398 'verbatim': r
"(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})",
399 'verb': r
"(?P<code>\\verb(?P<del>.).*?(?P=del))",
400 'lilypond-file': r
'(?m)^[^%\n]*?(?P<match>\\lilypondfile(\[(?P<options>.*?)\])?\{(?P<filename>.+)})',
401 'lilypond' : r
'(?m)^[^%\n]*?(?P<match>\\lilypond(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
402 'lilypond-block': r
"(?sm)^[^%\n]*?(?P<match>\\begin(\[(?P<options>.*?)\])?{lilypond}(?P<code>.*?)\\end{lilypond})",
403 'def-post-re': r
"\\def\\postLilypondExample",
404 'def-pre-re': r
"\\def\\preLilypondExample",
405 'usepackage-graphics': r
"\usepackage{graphics}",
406 'intertext': r
',?\s*intertext=\".*?\"',
407 'multiline-comment': no_match
,
408 'singleline-comment': r
"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
409 'numcols': r
"(?P<code>\\(?P<num>one|two)column)",
413 # why do we have distinction between @mbinclude and @include?
415 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
418 'preamble-end': no_match
,
419 'landscape': no_match
,
420 'verbatim': r
"""(?s)(?P<code>@example\s.*?@end example\s)""",
421 'verb': r
"""(?P<code>@code{.*?})""",
422 'lilypond-file': '(?m)^(?!@c)(?P<match>@lilypondfile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
423 'lilypond' : '(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
424 'lilypond-block': r
"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s))""",
425 'option-sep' : ', *',
426 'intertext': r
',?\s*intertext=\".*?\"',
427 'multiline-comment': r
"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
428 'singleline-comment': r
"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
434 for r
in re_dict
.keys ():
437 for k
in olddict
.keys ():
438 newdict
[k
] = re
.compile (olddict
[k
])
452 def get_output (name
):
453 return output_dict
[format
][name
]
456 return re_dict
[format
][name
]
458 def bounding_box_dimensions(fname
):
460 fname
= os
.path
.join(g_outdir
, fname
)
464 error ("Error opening `%s'" % fname
)
466 s
= re
.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
468 return (int(s
.group(3))-int(s
.group(1)),
469 int(s
.group(4))-int(s
.group(2)))
475 sys
.stderr
.write (str + "\n Exiting ... \n\n")
479 def compose_full_body (body
, opts
):
480 """Construct the lilypond code to send to Lilypond.
481 Add stuff to BODY using OPTS as options."""
482 music_size
= default_music_fontsize
483 latex_size
= default_text_fontsize
485 if g_force_lilypond_fontsize
:
486 music_size
= g_force_lilypond_fontsize
488 m
= re
.match ('([0-9]+)pt', o
)
490 music_size
= string
.atoi(m
.group (1))
492 m
= re
.match ('latexfontsize=([0-9]+)pt', o
)
494 latex_size
= string
.atoi (m
.group (1))
496 if re
.search ('\\\\score', body
):
500 if 'fragment' in opts
:
502 if 'nonfragment' in opts
:
505 if is_fragment
and not 'multiline' in opts
:
506 opts
.append('singleline')
507 if 'singleline' in opts
:
510 l
= __main__
.paperguru
.get_linewidth()
512 if 'relative' in opts
:#ugh only when is_fragment
513 body
= '\\relative c { %s }' % body
522 optstring
= string
.join (opts
, ' ')
523 optstring
= re
.sub ('\n', ' ', optstring
)
525 %% Generated automatically by: lilypond-book.py
526 %% options are %s %%ughUGH not original options
527 \include "paper%d.ly"
528 \paper { linewidth = %f \pt; }
529 """ % (optstring
, music_size
, l
) + body
532 def parse_options_string(s
):
534 r1
= re
.compile("((\w+)={(.*?)})((,\s*)|$)")
535 r2
= re
.compile("((\w+)=(.*?))((,\s*)|$)")
536 r3
= re
.compile("(\w+?)((,\s*)|$)")
541 d
[m
.group(2)] = re
.split(",\s*", m
.group(3))
546 d
[m
.group(2)] = m
.group(3)
554 error ("format of option string invalid (was `%')" % s
)
557 def scan_latex_preamble(chunks
):
558 # first we want to scan the \documentclass line
559 # it should be the first non-comment line
562 if chunks
[idx
][0] == 'ignore':
565 m
= get_re ('header').match(chunks
[idx
][1])
566 options
= re
.split (',[\n \t]*', m
.group(1)[1:-1])
569 paperguru
.m_landscape
= 1
570 m
= re
.match("(.*?)paper", o
)
572 paperguru
.m_papersize
= m
.group()
574 m
= re
.match("(\d\d)pt", o
)
576 paperguru
.m_fontsize
= int(m
.group(1))
579 while chunks
[idx
][0] != 'preamble-end':
580 if chunks
[idx
] == 'ignore':
583 m
= get_re ('geometry').search(chunks
[idx
][1])
585 paperguru
.m_use_geometry
= 1
586 o
= parse_options_string(m
.group('options'))
588 paperguru
.set_geo_option(k
, o
[k
])
591 def scan_texi_preamble (chunks
):
592 # this is not bulletproof..., it checks the first 10 chunks
593 for c
in chunks
[:10]:
595 for s
in ('afourpaper', 'afourwide', 'letterpaper',
596 'afourlatex', 'smallbook'):
597 if string
.find(c
[1], "@%s" % s
) != -1:
598 paperguru
.m_papersize
= s
600 def scan_preamble (chunks
):
601 if __main__
.format
== 'texi':
602 scan_texi_preamble(chunks
)
604 assert __main__
.format
== 'latex'
605 scan_latex_preamble(chunks
)
608 def completize_preamble (chunks
):
609 if __main__
.format
== 'texi':
611 pre_b
= post_b
= graphics_b
= None
613 if chunk
[0] == 'preamble-end':
615 if chunk
[0] == 'input':
616 m
= get_re('def-pre-re').search(chunk
[1])
619 if chunk
[0] == 'input':
620 m
= get_re('def-post-re').search(chunk
[1])
623 if chunk
[0] == 'input':
624 m
= get_re('usepackage-graphics').search(chunk
[1])
628 while chunks
[x
][0] != 'preamble-end':
631 chunks
.insert(x
, ('input', get_output ('output-default-pre')))
633 chunks
.insert(x
, ('input', get_output ('output-default-post')))
635 chunks
.insert(x
, ('input', get_output ('usepackage-graphics')))
640 def find_file (name
):
642 Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
647 for a
in include_path
:
649 nm
= os
.path
.join (a
, name
)
651 __main__
.read_files
.append (nm
)
656 sys
.stderr
.write ("Reading `%s'\n" % nm
)
657 return (f
.read (), nm
)
659 error ("File not found `%s'\n" % name
)
662 def do_ignore(match_object
):
663 return [('ignore', match_object
.group('code'))]
664 def do_preamble_end(match_object
):
665 return [('preamble-end', match_object
.group('code'))]
667 def make_verbatim(match_object
):
668 return [('verbatim', match_object
.group('code'))]
670 def make_verb(match_object
):
671 return [('verb', match_object
.group('code'))]
673 def do_include_file(m
):
675 return [('input', get_output ('pagebreak'))] \
676 + read_doc_file(m
.group('filename')) \
677 + [('input', get_output ('pagebreak'))]
679 def do_input_file(m
):
680 return read_doc_file(m
.group('filename'))
682 def make_lilypond(m
):
683 if m
.group('options'):
684 options
= m
.group('options')
687 return [('input', get_output('output-lilypond-fragment') %
688 (options
, m
.group('code')))]
690 def make_lilypond_file(m
):
693 Find @lilypondfile{bla.ly} occurences and substitute bla.ly
694 into a @lilypond .. @end lilypond block.
698 if m
.group('options'):
699 options
= m
.group('options')
702 (content
, nm
) = find_file(m
.group('filename'))
703 options
= "filename=%s," % nm
+ options
705 return [('input', get_output('output-lilypond') %
708 def make_lilypond_block(m
):
709 if m
.group('options'):
710 options
= get_re('option-sep').split (m
.group('options'))
713 options
= filter(lambda s
: s
!= '', options
)
714 return [('lilypond', m
.group('code'), options
)]
717 if __main__
.format
!= 'latex':
719 if m
.group('num') == 'one':
720 return [('numcols', m
.group('code'), 1)]
721 if m
.group('num') == 'two':
722 return [('numcols', m
.group('code'), 2)]
724 def chop_chunks(chunks
, re_name
, func
, use_match
=0):
730 m
= get_re (re_name
).search (str)
732 newchunks
.append (('input', str))
736 newchunks
.append (('input', str[:m
.start ('match')]))
738 newchunks
.append (('input', str[:m
.start (0)]))
739 #newchunks.extend(func(m))
740 # python 1.5 compatible:
741 newchunks
= newchunks
+ func(m
)
742 str = str [m
.end(0):]
747 def determine_format (str):
748 if __main__
.format
== '':
750 latex
= re
.search ('\\\\document', str[:200])
751 texinfo
= re
.search ('@node|@setfilename', str[:200])
756 if texinfo
and latex
== None:
758 elif latex
and texinfo
== None:
761 error("error: can't determine format, please specify")
764 if __main__
.paperguru
== None:
765 if __main__
.format
== 'texi':
770 __main__
.paperguru
= g
773 def read_doc_file (filename
):
774 """Read the input file, find verbatim chunks and do \input and \include
776 (str, path
) = find_file(filename
)
777 determine_format (str)
779 chunks
= [('input', str)]
781 # we have to check for verbatim before doing include,
782 # because we don't want to include files that are mentioned
783 # inside a verbatim environment
784 chunks
= chop_chunks(chunks
, 'verbatim', make_verbatim
)
785 chunks
= chop_chunks(chunks
, 'verb', make_verb
)
786 chunks
= chop_chunks(chunks
, 'multiline-comment', do_ignore
)
788 chunks
= chop_chunks(chunks
, 'include', do_include_file
, 1)
789 chunks
= chop_chunks(chunks
, 'input', do_input_file
, 1)
793 taken_file_names
= {}
794 def schedule_lilypond_block (chunk
):
795 """Take the body and options from CHUNK, figure out how the
796 real .ly should look, and what should be left MAIN_STR (meant
797 for the main file). The .ly is written, and scheduled in
800 Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
802 TODO has format [basename, extension, extension, ... ]
805 (type, body
, opts
) = chunk
806 assert type == 'lilypond'
807 file_body
= compose_full_body (body
, opts
)
808 basename
= 'lily-' + `
abs(hash (file_body
))`
810 m
= re
.search ('filename="(.*?)"', o
)
812 basename
= m
.group (1)
813 if not taken_file_names
.has_key(basename
):
814 taken_file_names
[basename
] = 0
816 taken_file_names
[basename
] = taken_file_names
[basename
] + 1
817 basename
= basename
+ "-%i" % taken_file_names
[basename
]
819 update_file(file_body
, os
.path
.join(g_outdir
, basename
) + '.ly')
820 needed_filetypes
= ['tex']
823 needed_filetypes
.append('eps')
824 needed_filetypes
.append('png')
825 if 'eps' in opts
and not ('eps' in needed_filetypes
):
826 needed_filetypes
.append('eps')
827 pathbase
= os
.path
.join (g_outdir
, basename
)
828 def f(base
, ext1
, ext2
):
829 a
= os
.path
.isfile(base
+ ext2
)
830 if (os
.path
.isfile(base
+ ext1
) and
831 os
.path
.isfile(base
+ ext2
) and
832 os
.stat(base
+ext1
)[stat
.ST_MTIME
] >
833 os
.stat(base
+ext2
)[stat
.ST_MTIME
]) or \
834 not os
.path
.isfile(base
+ ext2
):
837 if 'tex' in needed_filetypes
and f(pathbase
, '.ly', '.tex'):
839 if 'eps' in needed_filetypes
and f(pathbase
, '.tex', '.eps'):
841 if 'png' in needed_filetypes
and f(pathbase
, '.eps', '.png'):
845 if 'printfilename' in opts
:
847 m
= re
.match ("filename=(.*)", o
)
849 newbody
= newbody
+ get_output ("output-filename") % m
.group(1)
853 if 'verbatim' in opts
:
854 newbody
= output_verbatim (body
)
857 m
= re
.search ('intertext="(.*?)"', o
)
859 newbody
= newbody
+ m
.group (1) + "\n\n"
860 if format
== 'latex':
865 else: # format == 'texi'
867 newbody
= newbody
+ get_output (s
) % {'fn': basename
}
868 return ('lilypond', newbody
, opts
, todo
, basename
)
870 def process_lilypond_blocks(outname
, chunks
):#ugh rename
872 # Count sections/chapters.
874 if c
[0] == 'lilypond':
875 c
= schedule_lilypond_block (c
)
876 elif c
[0] == 'numcols':
877 paperguru
.m_num_cols
= c
[2]
882 def find_eps_dims (match
):
883 "Fill in dimensions of EPS files."
886 dims
= bounding_box_dimensions (fn
)
888 fn
= os
.path
.join(g_outdir
, fn
)
890 return '%ipt' % dims
[0]
894 sys
.stderr
.write ("invoking `%s'\n" % cmd
)
897 error ('Error command exited with value %d\n' % st
)
900 def compile_all_files (chunks
):
907 if c
[0] <> 'lilypond':
916 if base
+ '.ly' not in tex
:
917 tex
.append (base
+ '.ly')
918 elif e
== 'png' and g_do_pictures
:
924 # fixme: be sys-independent.
926 if g_outdir
and x
[0] <> '/' :
927 x
= os
.path
.join (g_here_dir
, x
)
930 incs
= map (incl_opt
, include_path
)
931 lilyopts
= string
.join (incs
, ' ' )
933 lilyopts
= lilyopts
+ ' --dependencies '
935 lilyopts
= lilyopts
+ '--dep-prefix=' + g_outdir
+ '/'
936 texfiles
= string
.join (tex
, ' ')
937 system ('lilypond --header=texidoc %s %s' % (lilyopts
, texfiles
))
940 # Ugh, fixing up dependencies for .tex generation
943 depfiles
=map (lambda x
: re
.sub ('(.*)\.ly', '\\1.dep', x
), tex
)
945 text
=open (i
).read ()
946 text
=re
.sub ('\n([^:\n]*):', '\n' + foutn
+ ':', text
)
947 open (i
, 'w').write (text
)
950 system(r
"tex '\nonstopmode \input %s'" % e
)
951 system(r
"dvips -E -o %s %s" % (e
+ '.eps', e
))
953 cmd
= r
"""gs -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r90 -dNOPAUSE %s -c quit | pnmcrop | pnmtopng > %s"""
954 cmd
= cmd
% (g
+ '.eps', g
+ '.png')
959 def update_file (body
, name
):
961 write the body if it has changed
972 f
= open (name
, 'w')
979 def getopt_args (opts
):
980 "Construct arguments (LONG, SHORT) for getopt from list of options."
995 def option_help_str (o
):
996 "Transform one option description (4-tuple ) into neatly formatted string"
1014 return ' ' + sh
+ sep
+ long + arg
1017 def options_help_str (opts
):
1018 "Convert a list of options into a neatly formatted string"
1024 s
= option_help_str (o
)
1025 strs
.append ((s
, o
[3]))
1031 str = str + '%s%s%s\n' % (s
[0], ' ' * (w
- len(s
[0]) + 3), s
[1])
1035 sys
.stdout
.write("""Usage: lilypond-book [options] FILE\n
1036 Generate hybrid LaTeX input from Latex + lilypond
1039 sys
.stdout
.write (options_help_str (option_definitions
))
1040 sys
.stdout
.write (r
"""Warning all output is written in the CURRENT directory
1044 Report bugs to bug-gnu-music@gnu.org.
1046 Written by Tom Cato Amundsen <tca@gnu.org> and
1047 Han-Wen Nienhuys <hanwen@cs.uu.nl>
1053 def write_deps (fn
, target
, chunks
):
1055 sys
.stdout
.write('Writing `%s\'\n' % os
.path
.join(g_outdir
, fn
))
1056 f
= open (os
.path
.join(g_outdir
, fn
), 'w')
1057 f
.write ('%s%s: ' % (g_dep_prefix
, target
))
1058 for d
in read_files
:
1062 if c
[0] == 'lilypond':
1063 (type, body
, opts
, todo
, basename
) = c
;
1064 basenames
.append (basename
)
1067 d
=g_outdir
+ '/' + d
1069 #if not os.isfile (d): # thinko?
1070 if not re
.search ('/', d
):
1071 d
= g_dep_prefix
+ d
1072 f
.write ('%s.tex ' % d
)
1074 #if len (basenames):
1075 # for d in basenames:
1076 # f.write ('%s.ly ' % d)
1077 # f.write (' : %s' % target)
1083 sys
.stdout
.write ('lilypond-book (GNU LilyPond) %s\n' % program_version
)
1085 def print_version ():
1087 sys
.stdout
.write (r
"""Copyright 1998--1999
1088 Distributed under terms of the GNU General Public License. It comes with
1093 def check_texidoc (chunks
):
1096 if c
[0] == 'lilypond':
1097 (type, body
, opts
, todo
, basename
) = c
;
1098 pathbase
= os
.path
.join (g_outdir
, basename
)
1099 if os
.path
.isfile (pathbase
+ '.texidoc'):
1100 body
= '\n@include %s.texidoc\n' % basename
+ body
1101 c
= (type, body
, opts
, todo
, basename
)
1105 def fix_epswidth (chunks
):
1108 if c
[0] == 'lilypond' and 'eps' in c
[2]:
1109 body
= re
.sub (r
"""\\lilypondepswidth{(.*?)}""", find_eps_dims
, c
[1])
1110 newchunks
.append(('lilypond', body
, c
[2], c
[3], c
[4]))
1112 newchunks
.append (c
)
1117 def do_file(input_filename
):
1121 my_outname
= outname
1123 my_outname
= os
.path
.basename(os
.path
.splitext(input_filename
)[0])
1124 my_depname
= my_outname
+ '.dep'
1126 chunks
= read_doc_file(input_filename
)
1127 chunks
= chop_chunks(chunks
, 'lilypond', make_lilypond
, 1)
1128 chunks
= chop_chunks(chunks
, 'lilypond-file', make_lilypond_file
, 1)
1129 chunks
= chop_chunks(chunks
, 'lilypond-block', make_lilypond_block
, 1)
1130 chunks
= chop_chunks(chunks
, 'singleline-comment', do_ignore
, 1)
1131 chunks
= chop_chunks(chunks
, 'preamble-end', do_preamble_end
)
1132 chunks
= chop_chunks(chunks
, 'numcols', do_columns
)
1134 #for c in chunks: print "c:", c;
1136 scan_preamble(chunks
)
1137 chunks
= process_lilypond_blocks(my_outname
, chunks
)
1139 foutn
= os
.path
.join (g_outdir
, my_outname
+ '.' + format
)
1142 if __main__
.g_run_lilypond
:
1143 compile_all_files (chunks
)
1144 chunks
= fix_epswidth (chunks
)
1146 if __main__
.format
== 'texi':
1147 chunks
= check_texidoc (chunks
)
1150 chunks
= completize_preamble (chunks
)
1151 sys
.stderr
.write ("Writing `%s'\n" % foutn
)
1152 fout
= open (foutn
, 'w')
1159 write_deps (my_depname
, foutn
, chunks
)
1164 (sh
, long) = getopt_args (__main__
.option_definitions
)
1165 (options
, files
) = getopt
.getopt(sys
.argv
[1:], sh
, long)
1166 except getopt
.error
, msg
:
1167 sys
.stderr
.write("error: %s" % msg
)
1175 if o
== '--include' or o
== '-I':
1176 include_path
.append (a
)
1177 elif o
== '--version' or o
== '-v':
1180 elif o
== '--format' or o
== '-f':
1182 elif o
== '--outname' or o
== '-o':
1185 sys
.stderr
.write("Lilypond-book is confused by --outname on multiple files")
1188 elif o
== '--help' or o
== '-h':
1190 elif o
== '--no-lily' or o
== '-n':
1191 __main__
.g_run_lilypond
= 0
1192 elif o
== '--dependencies' or o
== '-M':
1194 elif o
== '--default-music-fontsize':
1195 default_music_fontsize
= string
.atoi (a
)
1196 elif o
== '--default-lilypond-fontsize':
1197 print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
1198 default_music_fontsize
= string
.atoi (a
)
1199 elif o
== '--force-music-fontsize':
1200 g_force_lilypond_fontsize
= string
.atoi(a
)
1201 elif o
== '--force-lilypond-fontsize':
1202 print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize"
1203 g_force_lilypond_fontsize
= string
.atoi(a
)
1204 elif o
== '--dep-prefix':
1206 elif o
== '--no-pictures':
1208 elif o
== '--read-lys':
1210 elif o
== '--outdir':
1215 if os
.path
.isfile(g_outdir
):
1216 error ("outdir is a file: %s" % g_outdir
)
1217 if not os
.path
.exists(g_outdir
):
1219 for input_filename
in files
:
1220 do_file(input_filename
)
1223 # Petr, ik zou willen dat ik iets zinvoller deed,
1224 # maar wat ik kan ik doen, het verandert toch niets?