#!@PYTHON@
# vim: set noexpandtab:
-# TODO:
-# * junk --outdir for --output
-# * Figure out clean set of options.
-# *
-# * EndLilyPondOutput is def'd as vfil. Causes large white gaps.
-# * texinfo: add support for @pagesize
-
-# todo: dimension handling (all the x2y) is clumsy. (tca: Thats
-# because the values are taken directly from texinfo.tex,
-# geometry.sty and article.cls. Give me a hint, and I'll
-# fix it.)
-#
-# TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips.
-#
+"""
+
+ TODO:
+ * junk --outdir for--output
+ * Figure out clean set of options.
+ *
+ * texinfo: add support for @pagesize
+
+ todo: dimension handling (all the x2y) is clumsy. (tca: Thats
+ because the values are taken directly from texinfo.tex,
+ geometry.sty and article.cls. Give me a hint, and I'll
+ fix it.)
+
+
+ TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips.
+
+
+
+ This is a slightly hairy program. The general approach is as follows
+ The input string is chopped up in chunks, i.e. , a list of tuples
+
+ with the format (TAG_STR, MAIN_STR, OPTIONS, TODO, BASE)
+
+ This list is built step by step: first ignore and verbatim commands
+ are handled, delivering a list of chunks.
+
+ then all chunks containing lilypond commands are chopped up
-# This is was the idea for handling of comments:
+ when all chunks have their final form, all bodies from lilypond blocks are
+ extracted, and if applicable, written do disk and run through lilypond.
+
+
+tags supported
+
+ ignore
+ lilypond
+ input
+ verb
+ verbatim
+ multicols
+ numcols
+
+
+
+
+"""
+
+# This is was the idea for handling of comments:
# Multiline comments, @ignore .. @end ignore is scanned for
# in read_doc_file, and the chunks are marked as 'ignore', so
# lilypond-book will not touch them any more. The content of the
# chunks are written to the output file. Also 'include' and 'input'
# regex has to check if they are commented out.
#
+
# Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'.
# These three regex's has to check if they are on a commented line,
# % for latex, @c for texinfo.
# The the rest of the rexeces are searched for. They don't have to test
# if they are on a commented out line.
-
-
-import os
+import glob
import stat
import string
-import re
-import getopt
-import sys
-import __main__
-import operator
-program_version = '@TOPLEVEL_VERSION@'
-if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
- program_version = '1.5.18'
+################################################################
+# Users of python modules should include this snippet
+# and customize variables below.
-# if set, LILYPONDPREFIX must take prevalence
-# if datadir is not set, we're doing a build and LILYPONDPREFIX
-datadir = '@datadir@'
+# We'll suffer this path init stuff as long as we don't install our
+# python packages in <prefix>/lib/pythonx.y (and don't kludge around
+# it as we do with teTeX on Red Hat Linux: set some environment var
+# (PYTHONPATH) in profile)
+# If set, LILYPONDPREFIX must take prevalence
+# if datadir is not set, we're doing a build and LILYPONDPREFIX
+import getopt, os, sys
+datadir = '@local_lilypond_datadir@'
+if not os.path.isdir (datadir):
+ datadir = '@lilypond_datadir@'
if os.environ.has_key ('LILYPONDPREFIX') :
datadir = os.environ['LILYPONDPREFIX']
-else:
- datadir = '@datadir@'
-
-while datadir[-1] == os.sep:
- datadir= datadir[:-1]
-
-# Try to cater for bad installations of LilyPond, that have
-# broken TeX setup. Just hope this doesn't hurt good TeX
-# setups. Maybe we should check if kpsewhich can find
-# feta16.{afm,mf,tex,tfm}, and only set env upon failure.
-environment = {
- 'MFINPUTS' : datadir + '/mf:',
- 'TEXINPUTS': datadir + '/tex:' + datadir + '/ps:.:',
- 'TFMFONTS' : datadir + '/tfm:',
- 'GS_FONTPATH' : datadir + '/afm:' + datadir + '/pfa',
- 'GS_LIB' : datadir + '/ps',
-}
+ while datadir[-1] == os.sep:
+ datadir= datadir[:-1]
+
+sys.path.insert (0, os.path.join (datadir, 'python'))
+
+# Customize these
+#if __name__ == '__main__':
+
+import lilylib as ly
+global _;_=ly._
+global re;re = ly.re
+
+# lilylib globals
+program_name = 'lilypond-book'
+verbose_p = 0
+pseudo_filter_p = 0
+original_dir = os.getcwd ()
+#temp_dir = os.path.join (original_dir, '%s.dir' % program_name)
+#urg
+temp_dir = '/tmp'
+keep_temp_dir_p = 0
+preview_resolution = 90
+
+## FIXME
+## ly2dvi: silly name?
+## do -P or -p by default?
+##help_summary = _ ("Run LilyPond using LaTeX for titling")
+help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document")
+copyright = ('Tom Cato Amundsen <tca@gnu.org>',
+ 'Han-Wen Nienhuys <hanwen@cs.uu.nl>')
+
+option_definitions = [
+ (_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")),
+ (_ ("DIM"), '', 'default-music-fontsize', _ ("default fontsize for music. DIM is assumed to be in points")),
+ (_ ("DIM"), '', 'default-lilypond-fontsize', _ ("deprecated, use --default-music-fontsize")),
+ (_ ("OPT"), '', 'extra-options', _ ("pass OPT quoted to the lilypond command line")),
+ (_ ("DIM"), '', 'force-music-fontsize', _ ("force fontsize for all inline lilypond. DIM is assumed be to in points")),
+ (_ ("DIM"), '', 'force-lilypond-fontsize', _ ("deprecated, use --force-music-fontsize")),
+ ('', 'h', 'help', _ ("this help")),
+ (_ ("DIR"), 'I', 'include', _ ("include path")),
+ ('', 'M', 'dependencies', _ ("write dependencies")),
+ (_ ("PREF"), '', 'dep-prefix', _ ("prepend PREF before each -M dependency")),
+ ('', 'n', 'no-lily', _ ("don't run lilypond")),
+ ('', '', 'no-pictures', _ ("don't generate pictures")),
+ ('', '', 'no-music', _ ("strip all lilypond blocks from output")),
+ (_ ("FILE"), 'o', 'outname', _ ("filename main output file")),
+ (_ ("FILE"), '', 'outdir', _ ("where to place generated files")),
+ (_ ('RES'), '', 'preview-resolution',
+ _ ("set the resolution of the preview to RES")),
+ ('', 'V', 'verbose', _ ("verbose")),
+ ('', 'v', 'version', _ ("print version information")),
+ ('', 'w', 'warranty', _ ("show warranty and copyright")),
+ ]
+
+# format specific strings, ie. regex-es for input, and % strings for output
+
+# global variables
+
+include_path = [os.getcwd ()]
-# tex needs lots of memory, more than it gets by default on Debian
-non_path_environment = {
- 'extra_mem_top' : '1000000',
- 'extra_mem_bottom' : '1000000',
- 'pool_size' : '250000',
-}
-def setup_environment ():
- for key in environment.keys ():
- val = environment[key]
- if os.environ.has_key (key):
- val = val + os.pathsep + os.environ[key]
- os.environ[key] = val
+#lilypond_binary = 'valgrind --suppressions=/home/hanwen/usr/src/guile-1.6.supp --num-callers=10 /home/hanwen/usr/src/lilypond/lily/out/lilypond'
- for key in non_path_environment.keys ():
- val = non_path_environment[key]
- print '%s=%s' % (key,val)
- os.environ[key] = val
+lilypond_binary = os.path.join ('@bindir@', 'lilypond')
-include_path = [os.getcwd()]
+# only use installed binary when we're installed too.
+if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
+ lilypond_binary = 'lilypond'
-# g_ is for global (?)
+ly2dvi_binary = os.path.join ('@bindir@', 'ly2dvi')
+
+# only use installed binary when we're installed too.
+if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
+ ly2dvi_binary = 'ly2dvi'
+
+
+
+g_extra_opts = ''
g_here_dir = os.getcwd ()
g_dep_prefix = ''
g_outdir = ''
-g_force_lilypond_fontsize = 0
-g_read_lys = 0
+g_force_music_fontsize = 0
g_do_pictures = 1
-g_num_cols = 1
+g_do_music = 1
+g_make_html = 0
+
format = ''
g_run_lilypond = 1
no_match = 'a\ba'
default_text_fontsize = 12
paperguru = None
-# this code is ugly. It should be cleaned
+################################################################
+# Dimension handling for LaTeX.
+#
class LatexPaper:
- def __init__(self):
- self.m_paperdef = {
- # the dimensions are from geometry.sty
- 'a0paper': (mm2pt(841), mm2pt(1189)),
- 'a1paper': (mm2pt(595), mm2pt(841)),
- 'a2paper': (mm2pt(420), mm2pt(595)),
- 'a3paper': (mm2pt(297), mm2pt(420)),
- 'a4paper': (mm2pt(210), mm2pt(297)),
- 'a5paper': (mm2pt(149), mm2pt(210)),
- 'b0paper': (mm2pt(1000), mm2pt(1414)),
- 'b1paper': (mm2pt(707), mm2pt(1000)),
- 'b2paper': (mm2pt(500), mm2pt(707)),
- 'b3paper': (mm2pt(353), mm2pt(500)),
- 'b4paper': (mm2pt(250), mm2pt(353)),
- 'b5paper': (mm2pt(176), mm2pt(250)),
- 'letterpaper': (in2pt(8.5), in2pt(11)),
- 'legalpaper': (in2pt(8.5), in2pt(14)),
- 'executivepaper': (in2pt(7.25), in2pt(10.5))}
- self.m_use_geometry = None
- self.m_papersize = 'letterpaper'
- self.m_fontsize = 10
+ def __init__ (self):
+ self.m_document_preamble = []
self.m_num_cols = 1
- self.m_landscape = 0
- self.m_geo_landscape = 0
- self.m_geo_width = None
- self.m_geo_textwidth = None
- self.m_geo_lmargin = None
- self.m_geo_rmargin = None
- self.m_geo_includemp = None
- self.m_geo_marginparwidth = {10: 57, 11: 50, 12: 35}
- self.m_geo_marginparsep = {10: 11, 11: 10, 12: 10}
- self.m_geo_x_marginparwidth = None
- self.m_geo_x_marginparsep = None
- self.__body = None
- def set_geo_option(self, name, value):
-
- if type(value) == type(""):
- m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value)
- if m:
- unit = m.group (2)
- num = string.atof(m.group (1))
- conv = dimension_conversion_dict[m.group(2)]
+ self.m_multicols = 1
- value = conv(num)
-
- if name == 'body' or name == 'text':
- if type(value) == type(""):
- self.m_geo_textwidth = value
- else:
- self.m_geo_textwidth = value[0]
- self.__body = 1
- elif name == 'portrait':
- self.m_geo_landscape = 0
- elif name == 'reversemp' or name == 'reversemarginpar':
- if self.m_geo_includemp == None:
- self.m_geo_includemp = 1
- elif name == 'marginparwidth' or name == 'marginpar':
- self.m_geo_x_marginparwidth = value
- self.m_geo_includemp = 1
- elif name == 'marginparsep':
- self.m_geo_x_marginparsep = value
- self.m_geo_includemp = 1
- elif name == 'scale':
- if type(value) == type(""):
- self.m_geo_width = self.get_paperwidth() * float(value)
- else:
- self.m_geo_width = self.get_paperwidth() * float(value[0])
- elif name == 'hscale':
- self.m_geo_width = self.get_paperwidth() * float(value)
- elif name == 'left' or name == 'lmargin':
- self.m_geo_lmargin = value
- elif name == 'right' or name == 'rmargin':
- self.m_geo_rmargin = value
- elif name == 'hdivide' or name == 'divide':
- if value[0] not in ('*', ''):
- self.m_geo_lmargin = value[0]
- if value[1] not in ('*', ''):
- self.m_geo_width = value[1]
- if value[2] not in ('*', ''):
- self.m_geo_rmargin = value[2]
- elif name == 'hmargin':
- if type(value) == type(""):
- self.m_geo_lmargin = value
- self.m_geo_rmargin = value
- else:
- self.m_geo_lmargin = value[0]
- self.m_geo_rmargin = value[1]
- elif name == 'margin':#ugh there is a bug about this option in
- # the geometry documentation
- if type(value) == type(""):
- self.m_geo_lmargin = value
- self.m_geo_rmargin = value
- else:
- self.m_geo_lmargin = value[0]
- self.m_geo_rmargin = value[0]
- elif name == 'total':
- if type(value) == type(""):
- self.m_geo_width = value
- else:
- self.m_geo_width = value[0]
- elif name == 'width' or name == 'totalwidth':
- self.m_geo_width = value
- elif name == 'paper' or name == 'papername':
- self.m_papersize = value
- elif name[-5:] == 'paper':
- self.m_papersize = name
- else:
- pass
- # what is _set_dimen ?? /MB
- #self._set_dimen('m_geo_'+name, value)
- def __setattr__(self, name, value):
- if type(value) == type("") and \
- dimension_conversion_dict.has_key (value[-2:]):
- f = dimension_conversion_dict[value[-2:]]
- self.__dict__[name] = f(float(value[:-2]))
+ def find_latex_dims (self):
+ if g_outdir:
+ fname = os.path.join (g_outdir, "lily-tmp.tex")
else:
- self.__dict__[name] = value
+ fname = "lily-tmp.tex"
+ try:
+ f = open (fname, "w")
+ except IOError:
+ error ("Error creating temporary file '%s'" % fname)
+
+ for s in self.m_document_preamble:
+ f.write (s)
+ f.write (r"""
+\begin{document}
+\typeout{---}
+\typeout{\columnsep \the\columnsep}
+\typeout{\textwidth \the\textwidth}
+\typeout{---}
+\end{document}
+ """)
+ f.close ()
+ re_dim = re.compile (r"\\(\w+)\s+(\d+\.\d+)")
+
+ cmd = "latex '\\nonstopmode \input %s'" % fname
+ # Ugh. (La)TeX writes progress and error messages on stdout
+ # Redirect to stderr
+ cmd += ' 1>/dev/stderr'
+ status = ly.system (cmd, ignore_error = 1)
+ signal = 0xf & status
+ exit_status = status >> 8
+
+ if status:
+ ly.error (_ ("LaTeX failed."))
+ ly.error (_ ("The error log is as follows:"))
- def __str__(self):
- s = "LatexPaper:\n-----------"
- for v in self.__dict__.keys():
- if v[:2] == 'm_':
- s = s + str (v) + ' ' + str (self.__dict__[v])
- s = s + "-----------"
- return s
-
- def get_linewidth(self):
- w = self._calc_linewidth()
- if self.m_num_cols == 2:
- return (w - 10) / 2
- else:
- return w
- def get_paperwidth(self):
- #if self.m_use_geometry:
- return self.m_paperdef[self.m_papersize][self.m_landscape or self.m_geo_landscape]
- #return self.m_paperdef[self.m_papersize][self.m_landscape]
-
- def _calc_linewidth(self):
- # since geometry sometimes ignores 'includemp', this is
- # more complicated than it should be
- mp = 0
- if self.m_geo_includemp:
- if self.m_geo_x_marginparsep is not None:
- mp = mp + self.m_geo_x_marginparsep
- else:
- mp = mp + self.m_geo_marginparsep[self.m_fontsize]
- if self.m_geo_x_marginparwidth is not None:
- mp = mp + self.m_geo_x_marginparwidth
- else:
- mp = mp + self.m_geo_marginparwidth[self.m_fontsize]
+ #URG see ly2dvi
+ try:
+ lns = open ('lily-tmp.log').readlines ()
+ except:
+ lns = ''
+ countdown = -3
+ for ln in lns:
+ sys.stderr.write (ln)
+ if re.match ('^!', ln):
+ countdown = 3
+
+ if countdown == 0:
+ break
+
+ if countdown > 0:
+ countdown = countdown -1
+
+ sys.stderr.write (" ... (further messages elided)...\n")
+ sys.exit (1)
+
+ lns = open ('lily-tmp.log').readlines ()
+ for ln in lns:
+ ln = string.strip (ln)
+ m = re_dim.match (ln)
+ if m:
+ if m.groups ()[0] in ('textwidth', 'columnsep'):
+ self.__dict__['m_%s' % m.groups ()[0]] = float (m.groups ()[1])
- #ugh test if this is necessary
- if self.__body:
- mp = 0
+ try:
+ os.remove (fname)
+ os.remove (os.path.splitext (fname)[0]+".aux")
+ os.remove (os.path.splitext (fname)[0]+".log")
+ except:
+ pass
+
+ if not self.__dict__.has_key ('m_textwidth'):
+ raise 'foo!'
- if not self.m_use_geometry:
- return latex_linewidths[self.m_papersize][self.m_fontsize]
+ def get_linewidth (self):
+ if self.m_num_cols == 1:
+ w = self.m_textwidth
else:
- geo_opts = (self.m_geo_lmargin == None,
- self.m_geo_width == None,
- self.m_geo_rmargin == None)
-
- if geo_opts == (1, 1, 1):
- if self.m_geo_textwidth:
- return self.m_geo_textwidth
- w = self.get_paperwidth() * 0.8
- return w - mp
- elif geo_opts == (0, 1, 1):
- if self.m_geo_textwidth:
- return self.m_geo_textwidth
- return self.f1(self.m_geo_lmargin, mp)
- elif geo_opts == (1, 1, 0):
- if self.m_geo_textwidth:
- return self.m_geo_textwidth
- return self.f1(self.m_geo_rmargin, mp)
- elif geo_opts \
- in ((0, 0, 1), (1, 0, 0), (1, 0, 1)):
- if self.m_geo_textwidth:
- return self.m_geo_textwidth
- return self.m_geo_width - mp
- elif geo_opts in ((0, 1, 0), (0, 0, 0)):
- w = self.get_paperwidth() \
- - self.m_geo_lmargin - self.m_geo_rmargin - mp
- if w < 0:
- w = 0
- return w
- raise "Never do this!"
- def f1(self, m, mp):
- tmp = self.get_paperwidth() - m * 2 - mp
- if tmp < 0:
- tmp = 0
- return tmp
- def f2(self):
- tmp = self.get_paperwidth() - self.m_geo_lmargin \
- - self.m_geo_rmargin
- if tmp < 0:
- return 0
- return tmp
+ w = (self.m_textwidth - self.m_columnsep)/2
+ if self.m_multicols > 1:
+ return (w - self.m_columnsep* (self.m_multicols-1)) \
+ / self.m_multicols
+ return w
+
+
+class HtmlPaper:
+ def __init__ (self):
+ self.m_papersize = 'letterpaper'
+ self.m_fontsize = 12
+ def get_linewidth (self):
+ return html_linewidths[self.m_papersize][self.m_fontsize]
class TexiPaper:
- def __init__(self):
+ def __init__ (self):
self.m_papersize = 'letterpaper'
self.m_fontsize = 12
- def get_linewidth(self):
+ def get_linewidth (self):
return texi_linewidths[self.m_papersize][self.m_fontsize]
-def mm2pt(x):
+def mm2pt (x):
return x * 2.8452756
-def in2pt(x):
+def in2pt (x):
return x * 72.26999
-def em2pt(x, fontsize = 10):
+def em2pt (x, fontsize = 10):
return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
-def ex2pt(x, fontsize = 10):
+def ex2pt (x, fontsize = 10):
return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
-def pt2pt(x):
+def pt2pt (x):
return x
dimension_conversion_dict ={
'mm': mm2pt,
- 'cm': lambda x: mm2pt(10*x),
+ 'cm': lambda x: mm2pt (10*x),
'in': in2pt,
'em': em2pt,
'ex': ex2pt,
'pt': pt2pt
}
-
-# latex linewidths:
-# indices are no. of columns, papersize, fontsize
-# Why can't this be calculated?
-latex_linewidths = {
- 'a4paper':{10: 345, 11: 360, 12: 390},
- 'a4paper-landscape': {10: 598, 11: 596, 12:592},
- 'a5paper':{10: 276, 11: 276, 12: 276},
- 'b5paper':{10: 345, 11: 356, 12: 356},
- 'letterpaper':{10: 345, 11: 360, 12: 390},
- 'letterpaper-landscape':{10: 598, 11: 596, 12:596},
- 'legalpaper': {10: 345, 11: 360, 12: 390},
- 'executivepaper':{10: 345, 11: 360, 12: 379}}
+# Convert numeric values, with or without specific dimension, to floats.
+# Keep other strings
+def conv_dimen_to_float (value):
+ if type (value) == type (""):
+ m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value)
+ if m:
+ unit = m.group (2)
+ num = string.atof (m.group (1))
+ conv = dimension_conversion_dict[m.group (2)]
-texi_linewidths = {
- 'afourpaper': {12: mm2pt(160)},
- 'afourwide': {12: in2pt(6.5)},
- 'afourlatex': {12: mm2pt(150)},
- 'smallbook': {12: in2pt(5)},
- 'letterpaper': {12: in2pt(6)}}
+ value = conv (num)
-option_definitions = [
- ('EXT', 'f', 'format', 'set format. EXT is one of texi and latex.'),
- ('DIM', '', 'default-music-fontsize', 'default fontsize for music. DIM is assumed to be in points'),
- ('DIM', '', 'default-lilypond-fontsize', 'deprecated, use --default-music-fontsize'),
- ('DIM', '', 'force-music-fontsize', 'force fontsize for all inline lilypond. DIM is assumed be to in points'),
- ('DIM', '', 'force-lilypond-fontsize', 'deprecated, use --force-music-fontsize'),
- ('DIR', 'I', 'include', 'include path'),
- ('', 'M', 'dependencies', 'write dependencies'),
- ('PREF', '', 'dep-prefix', 'prepend PREF before each -M dependency'),
- ('', 'n', 'no-lily', 'don\'t run lilypond'),
- ('', '', 'no-pictures', "don\'t generate pictures"),
- ('', '', 'read-lys', "don't write ly files."),
- ('FILE', 'o', 'outname', 'filename main output file'),
- ('FILE', '', 'outdir', "where to place generated files"),
- ('', 'v', 'version', 'print version information' ),
- ('', 'h', 'help', 'print help'),
- ]
+ elif re.match ("^[0-9.]+$",value):
+ value = float (value)
-# format specific strings, ie. regex-es for input, and % strings for output
+ return value
+
+texi_linewidths = {
+ 'afourpaper': {12: mm2pt (160)},
+ 'afourwide': {12: in2pt (6.5)},
+ 'afourlatex': {12: mm2pt (150)},
+ 'smallbook': {12: in2pt (5)},
+ 'letterpaper': {12: in2pt (6)}}
+
+html_linewidths = {
+ 'afourpaper': {12: mm2pt (160)},
+ 'afourwide': {12: in2pt (6.5)},
+ 'afourlatex': {12: mm2pt (150)},
+ 'smallbook': {12: in2pt (5)},
+ 'letterpaper': {12: in2pt (6)}}
+
+
+################################################################
+# How to output various structures.
output_dict= {
+
+
+ 'html' : {
+
+ 'output-filename' : r'''
+<!-- %s >
+<a href="%s">
+<pre>%s</pre></a>:''',
+ 'output-lilypond-fragment': '''<lilypond%s>
+\context Staff\context Voice{ %s }
+</lilypond>''',
+ 'output-noinline': r'''
+<!-- generated: %(fn)s.png !-->
+''',
+ ## maybe <hr> ?
+ 'pagebreak': None,
+ # Verbatim text is always finished with \n. FIXME: For HTML,
+ # this newline should be removed.
+ 'output-verbatim': r'''<pre>
+%s</pre>''',
+ # Verbatim text is always finished with \n. FIXME: For HTML,
+ # this newline should be removed.
+ 'output-small-verbatim': r'''<font size=-1><pre>
+%s</pre></font>''',
+ ## Ugh we need to differentiate on origin:
+ ## lilypond-block origin wants an extra <p>, but
+ ## inline music doesn't.
+ ## possibly other center options?
+ 'output-html': r'''
+%(pageimages)s''',
+ },
+
+
'latex': {
- 'output-lilypond-fragment' : r"""\begin[eps,singleline,%s]{lilypond}
+
+ 'output-lilypond-fragment' : r'''\begin[eps,singleline,%s]{lilypond}
\context Staff <
\context Voice{
%s
}
>
-\end{lilypond}""",
- 'output-filename' : r'''
-
-\verb+%s+:''',
- 'output-lilypond': r"""\begin[%s]{lilypond}
-%s
-\end{lilypond}""",
- 'output-verbatim': "\\begin{verbatim}%s\\end{verbatim}",
+\end{lilypond}''',
+ 'output-filename' : r'''\verb+%s+:\\
+%% %s
+%% %s
+''',
+
+ # verbatim text is always finished with \n
+ 'output-verbatim': r'''\begin{verbatim}
+%s\end{verbatim}
+''',
+ # verbatim text is always finished with \n
+ 'output-small-verbatim': r'''{\small\begin{verbatim}
+%s\end{verbatim}}
+''',
'output-default-post': "\\def\postLilypondExample{}\n",
'output-default-pre': "\\def\preLilypondExample{}\n",
'usepackage-graphics': '\\usepackage{graphics}\n',
- 'output-eps': '\\noindent\\parbox{\\lilypondepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s.eps}}',
- 'output-tex': '{\\preLilypondExample \\input %(fn)s.tex \\postLilypondExample\n}',
+ 'output-eps': '\\noindent\\parbox{\\lilypondepswidth{%(fn)s.eps}}{\includegraphics{%(fn)s}}',
+ 'output-noinline': r'''
+%% generated: %(fn)s.eps
+''',
+ 'output-latex-quoted': r'''{\preLilypondExample
+\input %(fn)s.tex
+\postLilypondExample}''',
+ 'output-latex-noquote': r'''{\parindent 0pt
+\preLilypondExample
+\input %(fn)s.tex
+\postLilypondExample}''',
'pagebreak': r'\pagebreak',
},
- 'texi' : {'output-lilypond': """@lilypond[%s]
-%s
-@end lilypond
-""",
- 'output-filename' : r'''
-@file{%s}:''',
- 'output-lilypond-fragment': """@lilypond[%s]
-\context Staff\context Voice{ %s }
-@end lilypond """,
- 'pagebreak': None,
- 'output-verbatim': r"""@example
-%s
-@end example
-""",
-# do some tweaking: @ is needed in some ps stuff.
-# override EndLilyPondOutput, since @tex is done
-# in a sandbox, you can't do \input lilyponddefs at the
-# top of the document.
+ 'texi' : {
+
-# should also support fragment in
-
- 'output-all': r"""
+ 'output-filename' : r'''
+@ifnothtml
+@file{%s}:@*
+@end ifnothtml
+@ifhtml
+@uref{%s,@file{%s}}
+@end ifhtml
+''',
+ 'output-lilypond-fragment': '''@lilypond[%s]
+\context Staff\context Voice{ %s }
+@end lilypond ''',
+ 'output-noinline': r'''
+@c generated: %(fn)s.png
+''',
+ 'pagebreak': None,
+ # verbatim text is always finished with \n
+ 'output-small-verbatim': r'''@smallexample
+%s@end smallexample
+''',
+ # verbatim text is always finished with \n
+ 'output-verbatim': r'''@example
+%s@end example
+''',
+ # do some tweaking: @ is needed in some ps stuff.
+ #
+ # ugh, the <p> below breaks inline images...
+ 'output-texi-noquote': r'''@tex
+\catcode`\@=12
+\parindent 0pt
+\def\lilypondbook{}
+\input %(fn)s.tex
+\catcode`\@=0
+@end tex
+@html
+<p>%(htmlimages)s
+<p>
+@end html
+''',
+ 'output-texi-quoted': r'''@quotation
@tex
\catcode`\@=12
-\input lilyponddefs
-\def\EndLilyPondOutput{}
+\def\lilypondbook{}
\input %(fn)s.tex
\catcode`\@=0
@end tex
@html
+<p>%(htmlimages)s
<p>
-<a href="%(fn)s.png">
-<img border=0 src="%(fn)s.png" alt="[picture of music]">
-</a>
@end html
-""",
+@end quotation
+''',
}
+
}
-def output_verbatim (body):
- if __main__.format == 'texi':
- body = re.sub ('([@{}])', '@\\1', body)
- return get_output ('output-verbatim') % body
+def output_verbatim (body, small):
+ global format
+ if format == 'html':
+ body = re.sub ('&', '&', body)
+ body = re.sub ('>', '>', body)
+ body = re.sub ('<', '<', body)
+ elif format == 'texi':
+ # clumsy workaround for python 2.2 pre bug.
+ body = re.sub ('@', '@@', body)
+ body = re.sub ('{', '@{', body)
+ body = re.sub ('}', '@}', body)
+
+ if small:
+ key = 'output-small-verbatim'
+ else:
+ key = 'output-verbatim'
+ return get_output (key) % body
+
+
+################################################################
+# Recognize special sequences in the input
+# Warning: This uses extended regular expressions. Tread with care.
+#
+# legenda
+#
+# (?P<name>regex) -- assign result of REGEX to NAME
+# *? -- match non-greedily.
+# (?m) -- multiline regex: make ^ and $ match at each line
+# (?s) -- make the dot match all characters including newline
re_dict = {
- 'latex': {'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
- 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
- 'option-sep' : ',\s*',
- 'header': r"\\documentclass\s*(\[.*?\])?",
- 'geometry': r"^(?m)[^%\n]*?\\usepackage\s*(\[(?P<options>.*)\])?\s*{geometry}",
- 'preamble-end': r'(?P<code>\\begin{document})',
- 'verbatim': r"(?s)(?P<code>\\begin{verbatim}.*?\\end{verbatim})",
- 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
- 'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
- 'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
- 'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
- 'def-post-re': r"\\def\\postLilypondExample",
- 'def-pre-re': r"\\def\\preLilypondExample",
- 'usepackage-graphics': r"\usepackage{graphics}",
- 'intertext': r',?\s*intertext=\".*?\"',
- 'multiline-comment': no_match,
- 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
- 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
- },
-
-
- # why do we have distinction between @mbinclude and @include?
+ 'html': {
+ 'include': no_match,
+ 'input': no_match,
+ 'header': no_match,
+ 'preamble-end': no_match,
+ 'landscape': no_match,
+ 'verbatim': r'''(?s)(?P<code><pre>\s.*?</pre>\s)''',
+ 'verb': r'''(?P<code><pre>.*?</pre>)''',
+ 'lilypond-file': r'(?m)(?P<match><lilypondfile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</lilypondfile>)',
+ 'lilypond' : '(?m)(?P<match><lilypond((?P<options>[^:]*):)(?P<code>.*?)/>)',
+ 'lilypond-block': r'''(?ms)(?P<match><lilypond(?P<options>[^>]+)?>(?P<code>.*?)</lilypond>)''',
+ 'option-sep' : '\s*',
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P<code><!--\s.*?!-->)\s",
+ 'singleline-comment': no_match,
+ 'numcols': no_match,
+ 'multicols': no_match,
+ 'ly2dvi': r'(?m)(?P<match><ly2dvifile(?P<options>[^>]+)?>\s*(?P<filename>[^<]+)\s*</ly2dvifile>)',
+ },
+
+ 'latex': {
+ 'input': r'(?m)^[^%\n]*?(?P<match>\\mbinput{?([^}\t \n}]*))',
+ 'include': r'(?m)^[^%\n]*?(?P<match>\\mbinclude{(?P<filename>[^}]+)})',
+ 'option-sep' : ',\s*',
+ 'header': r"\n*\\documentclass\s*(\[.*?\])?",
+ 'preamble-end': r'(?P<code>\\begin\s*{document})',
+ 'verbatim': r"(?s)(?P<code>\\begin\s*{verbatim}.*?\\end{verbatim})",
+ 'verb': r"(?P<code>\\verb(?P<del>.).*?(?P=del))",
+ 'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
+ 'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
+ 'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
+ 'def-post-re': r"\\def\\postLilypondExample",
+ 'def-pre-re': r"\\def\\preLilypondExample",
+ 'usepackage-graphics': r"\usepackage\s*{graphics}",
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'multiline-comment': no_match,
+ 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>^%.*$\n+))",
+ 'numcols': r"(?P<code>\\(?P<num>one|two)column)",
+ 'multicols': r"(?P<code>\\(?P<be>begin|end)\s*{multicols}({(?P<num>\d+)?})?)",
+ 'ly2dvi': no_match,
+
+ },
+
+ # why do we have distinction between @mbinclude and @include?
+
'texi': {
- 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
- 'input': no_match,
- 'header': no_match,
- 'preamble-end': no_match,
- 'landscape': no_match,
- 'verbatim': r"""(?s)(?P<code>@example\s.*?@end example\s)""",
- 'verb': r"""(?P<code>@code{.*?})""",
- 'lilypond-file': '(?m)^(?!@c)(?P<match>@lilypondfile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
- 'lilypond' : '(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
-# pyton2.2b2 barfs on this
- 'lilypond-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s))""",
-
-# 1.5.2 barfs on this.
-# 'lilypond-block': r"""(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s)""",
- 'option-sep' : ',\s*',
- 'intertext': r',?\s*intertext=\".*?\"',
- 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
- 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
- 'numcols': no_match,
- }
+ 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
+ 'input': no_match,
+ 'header': no_match,
+ 'preamble-end': no_match,
+ 'landscape': no_match,
+ 'verbatim': r'''(?s)(?P<code>@example\s.*?@end example\s)''',
+ 'verb': r'''(?P<code>@code{.*?})''',
+ 'lilypond-file': '(?m)^(?P<match>@lilypondfile(\[(?P<options>[^]]*)\])?{(?P<filename>[^}]+)})',
+ 'lilypond' : '(?m)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?{(?P<code>.*?)})',
+ 'lilypond-block': r'''(?ms)^(?P<match>@lilypond(\[(?P<options>[^]]*)\])?\s(?P<code>.*?)@end lilypond)\s''',
+ 'option-sep' : ',\s*',
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
+ 'singleline-comment': r"(?m)^.*?(?P<match>(?P<code>@c.*$\n+))",
+ 'numcols': no_match,
+ 'multicols': no_match,
+ 'ly2dvi': no_match,
+ }
}
olddict = re_dict[r]
newdict = {}
for k in olddict.keys ():
- newdict[k] = re.compile (olddict[k])
+ try:
+ newdict[k] = re.compile (olddict[k])
+ except:
+ print 'invalid regexp: %s' % olddict[k]
+
+ ## we'd like to catch and reraise a more
+ ## detailed error, but alas, the exceptions
+ ## changed across the 1.5/2.1 boundary.
+
+ raise "Invalid re"
re_dict[r] = newdict
-
+
def uniq (list):
list.sort ()
s = list
if x not in list:
list.append (x)
return list
-
+
def get_output (name):
return output_dict[format][name]
def get_re (name):
return re_dict[format][name]
-def bounding_box_dimensions(fname):
+def bounding_box_dimensions (fname):
if g_outdir:
- fname = os.path.join(g_outdir, fname)
+ fname = os.path.join (g_outdir, fname)
try:
- fd = open(fname)
+ fd = open (fname)
except IOError:
error ("Error opening `%s'" % fname)
str = fd.read ()
- s = re.search('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
+ s = re.search ('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str)
if s:
- return (int (s.group (3) - s.group (1) + 0.5),
- int (s.group (4) - s.group (2) + 0.5))
+
+ gs = map (lambda x: string.atoi (x), s.groups ())
+ return (int (gs[2] - gs[0] + 0.5),
+ int (gs[3] - gs[1] + 0.5))
else:
return (0,0)
def error (str):
- sys.stderr.write (str + "\n Exiting ... \n\n")
+ sys.stderr.write ("\n\n" + str + "\nExiting ... \n\n")
raise 'Exiting.'
def compose_full_body (body, opts):
- """Construct the lilypond code to send to Lilypond.
- Add stuff to BODY using OPTS as options."""
+ '''Construct the lilypond code to send to Lilypond.
+ Add stuff to BODY using OPTS as options.'''
music_size = default_music_fontsize
- latex_size = default_text_fontsize
+ if g_force_music_fontsize:
+ music_size = g_force_music_fontsize
+ indent = ''
+ linewidth = ''
+ notime = ''
for o in opts:
- if g_force_lilypond_fontsize:
- music_size = g_force_lilypond_fontsize
- else:
+ if not g_force_music_fontsize:
m = re.match ('([0-9]+)pt', o)
if m:
- music_size = string.atoi(m.group (1))
+ music_size = string.atoi (m.group (1))
- m = re.match ('latexfontsize=([0-9]+)pt', o)
+ m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
if m:
- latex_size = string.atoi (m.group (1))
+ f = float (m.group (1))
+ indent = 'indent = %f\\%s' % (f, m.group (2))
+
+ m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o)
+ if m:
+ f = float (m.group (1))
+ linewidth = 'linewidth = %f\\%s' % (f, m.group (2))
if re.search ('\\\\score', body):
is_fragment = 0
is_fragment = 0
if is_fragment and not 'multiline' in opts:
- opts.append('singleline')
- if 'singleline' in opts:
- l = -1.0;
- else:
- l = __main__.paperguru.get_linewidth()
+ opts.append ('singleline')
+
+ if 'raggedright' in opts or 'singleline' in opts:
+ if not linewidth:
+ linewidth = 'raggedright = ##t'
+ if not indent:
+ indent = 'indent = 0.0\mm'
+ elif not linewidth:
+ global paperguru
+ l = paperguru.get_linewidth ()
+ linewidth = 'linewidth = %f\pt' % l
+
+ if 'noindent' in opts:
+ indent = 'indent = 0.0\mm'
+
+ if 'notime' in opts:
+ notime = r'''
+\translator {
+ \StaffContext
+ \remove Time_signature_engraver
+}
+'''
for o in opts:
m= re.search ('relative(.*)', o)
elif v > 0:
pitch = pitch + '\'' * v
- body = '\\relative %s { %s }' %(pitch, body)
-
+ body = '\\relative %s { %s }' % (pitch, body)
+
if is_fragment:
- body = r"""\score {
- \notes { %s }
- \paper { }
-}""" % body
+ body = r'''
+\score {
+ \notes {
+%s
+ }
+}
+''' % body
opts = uniq (opts)
optstring = string.join (opts, ' ')
optstring = re.sub ('\n', ' ', optstring)
- body = r"""
+ body = r'''
%% Generated automatically by: lilypond-book.py
-%% options are %s
+%% options are %s
\include "paper%d.ly"
-\paper { linewidth = %f \pt }
-""" % (optstring, music_size, l) + body
+\paper {
+ %s
+ %s
+ %s
+}
+''' % (optstring, music_size, linewidth, indent, notime) + body
# ughUGH not original options
return body
-def parse_options_string(s):
- d = {}
- r1 = re.compile("((\w+)={(.*?)})((,\s*)|$)")
- r2 = re.compile("((\w+)=(.*?))((,\s*)|$)")
- r3 = re.compile("(\w+?)((,\s*)|$)")
- while s:
- m = r1.match(s)
- if m:
- s = s[m.end():]
- d[m.group(2)] = re.split(",\s*", m.group(3))
- continue
- m = r2.match(s)
- if m:
- s = s[m.end():]
- d[m.group(2)] = m.group(3)
- continue
- m = r3.match(s)
- if m:
- s = s[m.end():]
- d[m.group(1)] = 1
- continue
-
- error ("format of option string invalid (was `%')" % s)
- return d
+def scan_html_preamble (chunks):
+ return
-def scan_latex_preamble(chunks):
- # first we want to scan the \documentclass line
- # it should be the first non-comment line
+def scan_latex_preamble (chunks):
+ # First we want to scan the \documentclass line
+ # it should be the first non-comment line.
+ # The only thing we really need to know about the \documentclass line
+ # is if there are one or two columns to begin with.
idx = 0
while 1:
if chunks[idx][0] == 'ignore':
idx = idx + 1
continue
- m = get_re ('header').match(chunks[idx][1])
- if m <> None and m.group (1):
- options = re.split (',[\n \t]*', m.group(1)[1:-1])
+ m = get_re ('header').match (chunks[idx][1])
+ if not m:
+ error ("Latex documents must start with a \documentclass command")
+ if m.group (1):
+ options = re.split (',[\n \t]*', m.group (1)[1:-1])
else:
options = []
- for o in options:
- if o == 'landscape':
- paperguru.m_landscape = 1
- m = re.match("(.*?)paper", o)
- if m:
- paperguru.m_papersize = m.group()
- else:
- m = re.match("(\d\d)pt", o)
- if m:
- paperguru.m_fontsize = int(m.group(1))
+ if 'twocolumn' in options:
+ paperguru.m_num_cols = 2
break
-
- while chunks[idx][0] != 'preamble-end':
+
+
+ # Then we add everything before \begin{document} to
+ # paperguru.m_document_preamble so that we can later write this header
+ # to a temporary file in find_latex_dims() to find textwidth.
+ while idx < len (chunks) and chunks[idx][0] != 'preamble-end':
if chunks[idx] == 'ignore':
idx = idx + 1
continue
- m = get_re ('geometry').search(chunks[idx][1])
- if m:
- paperguru.m_use_geometry = 1
- o = parse_options_string(m.group('options'))
- for k in o.keys():
- paperguru.set_geo_option(k, o[k])
+ paperguru.m_document_preamble.append (chunks[idx][1])
idx = idx + 1
+ if len (chunks) == idx:
+ error ("Didn't find end of preamble (\\begin{document})")
+
+ paperguru.find_latex_dims ()
+
def scan_texi_preamble (chunks):
# this is not bulletproof..., it checks the first 10 chunks
- for c in chunks[:10]:
+ for c in chunks[:10]:
if c[0] == 'input':
for s in ('afourpaper', 'afourwide', 'letterpaper',
'afourlatex', 'smallbook'):
- if string.find(c[1], "@%s" % s) != -1:
+ if string.find (c[1], "@%s" % s) != -1:
paperguru.m_papersize = s
+
def scan_preamble (chunks):
- if __main__.format == 'texi':
- scan_texi_preamble(chunks)
- else:
- assert __main__.format == 'latex'
- scan_latex_preamble(chunks)
-
+ global format
+ if format == 'html':
+ scan_html_preamble (chunks)
+ elif format == 'latex':
+ scan_latex_preamble (chunks)
+ elif format == 'texi':
+ scan_texi_preamble (chunks)
+
def completize_preamble (chunks):
- if __main__.format == 'texi':
+ global format
+ if format != 'latex':
return chunks
pre_b = post_b = graphics_b = None
for chunk in chunks:
if chunk[0] == 'preamble-end':
break
if chunk[0] == 'input':
- m = get_re('def-pre-re').search(chunk[1])
+ m = get_re ('def-pre-re').search (chunk[1])
if m:
pre_b = 1
if chunk[0] == 'input':
- m = get_re('def-post-re').search(chunk[1])
+ m = get_re ('def-post-re').search (chunk[1])
if m:
post_b = 1
+
if chunk[0] == 'input':
- m = get_re('usepackage-graphics').search(chunk[1])
+ m = get_re ('usepackage-graphics').search (chunk[1])
if m:
graphics_b = 1
x = 0
- while chunks[x][0] != 'preamble-end':
+ while x < len (chunks) and chunks[x][0] != 'preamble-end':
x = x + 1
+
+ if x == len (chunks):
+ return chunks
+
if not pre_b:
- chunks.insert(x, ('input', get_output ('output-default-pre')))
+ chunks.insert (x, ('input', get_output ('output-default-pre')))
if not post_b:
- chunks.insert(x, ('input', get_output ('output-default-post')))
+ chunks.insert (x, ('input', get_output ('output-default-post')))
if not graphics_b:
- chunks.insert(x, ('input', get_output ('usepackage-graphics')))
+ chunks.insert (x, ('input', get_output ('usepackage-graphics')))
+
return chunks
read_files = []
def find_file (name):
- """
+ '''
Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file.
- """
-
+ '''
+
+ if name == '-':
+ return (sys.stdin.read (), '<stdin>')
f = None
nm = ''
for a in include_path:
try:
nm = os.path.join (a, name)
f = open (nm)
- __main__.read_files.append (nm)
+ global read_files
+ read_files.append (nm)
break
except IOError:
pass
error ("File not found `%s'\n" % name)
return ('', '')
-def do_ignore(match_object):
- return [('ignore', match_object.group('code'))]
-def do_preamble_end(match_object):
- return [('preamble-end', match_object.group('code'))]
+def do_ignore (match_object):
+ return [('ignore', match_object.group ('code'))]
+def do_preamble_end (match_object):
+ return [('preamble-end', match_object.group ('code'))]
-def make_verbatim(match_object):
- return [('verbatim', match_object.group('code'))]
+def make_verbatim (match_object):
+ return [('verbatim', match_object.group ('code'))]
-def make_verb(match_object):
- return [('verb', match_object.group('code'))]
+def make_verb (match_object):
+ return [('verb', match_object.group ('code'))]
-def do_include_file(m):
+def do_include_file (m):
"m: MatchObject"
return [('input', get_output ('pagebreak'))] \
- + read_doc_file(m.group('filename')) \
- + [('input', get_output ('pagebreak'))]
+ + read_doc_file (m.group ('filename')) \
+ + [('input', get_output ('pagebreak'))]
-def do_input_file(m):
- return read_doc_file(m.group('filename'))
+def do_input_file (m):
+ return read_doc_file (m.group ('filename'))
-def make_lilypond(m):
- if m.group('options'):
- options = m.group('options')
+def make_lilypond (m):
+ if m.group ('options'):
+ options = m.group ('options')
else:
options = ''
- return [('input', get_output('output-lilypond-fragment') %
- (options, m.group('code')))]
+ return [('input', get_output ('output-lilypond-fragment') %
+ (options, m.group ('code')))]
-def make_lilypond_file(m):
- """
+def make_lilypond_file (m):
+ '''
Find @lilypondfile{bla.ly} occurences and substitute bla.ly
into a @lilypond .. @end lilypond block.
-
- """
-
- if m.group('options'):
- options = m.group('options')
+
+ '''
+
+ if m.group ('options'):
+ options = get_re ('option-sep').split (m.group ('options'))
else:
- options = ''
- (content, nm) = find_file(m.group('filename'))
- options = "filename=%s," % nm + options
+ options = []
+ (content, nm) = find_file (m.group ('filename'))
+ options.append ("filename=%s" % nm)
- return [('input', get_output('output-lilypond') %
- (options, content))]
-def make_lilypond_block(m):
- if m.group('options'):
- options = get_re('option-sep').split (m.group('options'))
+ return [('lilypond', content, options)]
+
+
+def make_ly2dvi_block (m):
+ '''
+
+ Find <ly2dvifile .. >
+ '''
+
+ return [('ly2dvi', m.group ('filename'), m.group ('options'))]
+
+
+def make_lilypond_block (m):
+ if not g_do_music:
+ return []
+
+ if m.group ('options'):
+ options = get_re ('option-sep').split (m.group ('options'))
else:
- options = []
- options = filter(lambda s: s != '', options)
- return [('lilypond', m.group('code'), options)]
+ options = []
+ options = filter (lambda s: s != '', options)
+ return [('lilypond', m.group ('code'), options)]
-def do_columns(m):
- if __main__.format != 'latex':
+
+def do_columns (m):
+ global format
+ if format != 'latex':
return []
- if m.group('num') == 'one':
- return [('numcols', m.group('code'), 1)]
- if m.group('num') == 'two':
- return [('numcols', m.group('code'), 2)]
-
-def chop_chunks(chunks, re_name, func, use_match=0):
- newchunks = []
- for c in chunks:
- if c[0] == 'input':
- str = c[1]
- while str:
- m = get_re (re_name).search (str)
- if m == None:
- newchunks.append (('input', str))
- str = ''
- else:
- if use_match:
- newchunks.append (('input', str[:m.start ('match')]))
- else:
- newchunks.append (('input', str[:m.start (0)]))
- #newchunks.extend(func(m))
- # python 1.5 compatible:
- newchunks = newchunks + func(m)
- str = str [m.end(0):]
- else:
- newchunks.append(c)
- return newchunks
+ if m.group ('num') == 'one':
+ return [('numcols', m.group ('code'), 1)]
+ if m.group ('num') == 'two':
+ return [('numcols', m.group ('code'), 2)]
+
+def do_multicols (m):
+ global format
+ if format != 'latex':
+ return []
+ if m.group ('be') == 'begin':
+ return [('multicols', m.group ('code'), int (m.group ('num')))]
+ else:
+ return [('multicols', m.group ('code'), 1)]
+ return []
+
+def chop_chunks (chunks, re_name, func, use_match=0):
+ newchunks = []
+ for c in chunks:
+ if c[0] == 'input':
+ str = c[1]
+ while str:
+ m = get_re (re_name).search (str)
+ if m == None:
+ newchunks.append (('input', str))
+ str = ''
+ else:
+ if use_match:
+ newchunks.append (('input', str[:m.start ('match')]))
+ else:
+ newchunks.append (('input', str[:m.start (0)]))
+ #newchunks.extend (func (m))
+ # python 1.5 compatible:
+ newchunks = newchunks + func (m)
+ str = str [m.end (0):]
+ else:
+ newchunks.append (c)
+ return newchunks
def determine_format (str):
- if __main__.format == '':
-
- latex = re.search ('\\\\document', str[:200])
- texinfo = re.search ('@node|@setfilename', str[:200])
+ """
+
+ SIDE EFFECT! This sets FORMAT and PAPERGURU
+
+ """
+
+ global format
+ if format == '':
+ html = re.search ('(?i)<[dh]tml', str[:200])
+ latex = re.search (r'''\\document''', str[:200])
+ texi = re.search ('@node|@setfilename', str[:200])
f = ''
g = None
-
- if texinfo and latex == None:
- f = 'texi'
- elif latex and texinfo == None:
+
+ if html and not latex and not texi:
+ f = 'html'
+ elif latex and not html and not texi:
f = 'latex'
+ elif texi and not html and not latex:
+ f = 'texi'
else:
- error("error: can't determine format, please specify")
- __main__.format = f
+ error ("can't determine format, please specify")
+ format = f
- if __main__.paperguru == None:
- if __main__.format == 'texi':
- g = TexiPaper()
- else:
- g = LatexPaper()
-
- __main__.paperguru = g
+ global paperguru
+ if paperguru == None:
+ if format == 'html':
+ g = HtmlPaper ()
+ elif format == 'latex':
+ g = LatexPaper ()
+ elif format == 'texi':
+ g = TexiPaper ()
+
+ paperguru = g
def read_doc_file (filename):
- """Read the input file, find verbatim chunks and do \input and \include
- """
- (str, path) = find_file(filename)
+ '''Read the input file, find verbatim chunks and do \input and \include
+ '''
+ (str, path) = find_file (filename)
determine_format (str)
-
+
chunks = [('input', str)]
-
+
# we have to check for verbatim before doing include,
# because we don't want to include files that are mentioned
# inside a verbatim environment
- chunks = chop_chunks(chunks, 'verbatim', make_verbatim)
- chunks = chop_chunks(chunks, 'verb', make_verb)
- chunks = chop_chunks(chunks, 'multiline-comment', do_ignore)
+ chunks = chop_chunks (chunks, 'verbatim', make_verbatim)
+
+ chunks = chop_chunks (chunks, 'verb', make_verb)
+ chunks = chop_chunks (chunks, 'multiline-comment', do_ignore)
#ugh fix input
- chunks = chop_chunks(chunks, 'include', do_include_file, 1)
- chunks = chop_chunks(chunks, 'input', do_input_file, 1)
+ chunks = chop_chunks (chunks, 'include', do_include_file, 1)
+ chunks = chop_chunks (chunks, 'input', do_input_file, 1)
return chunks
taken_file_names = {}
+
+def unique_file_name (body):
+ return 'lily-' + `abs (hash (body))`
+
def schedule_lilypond_block (chunk):
- """Take the body and options from CHUNK, figure out how the
- real .ly should look, and what should be left MAIN_STR (meant
- for the main file). The .ly is written, and scheduled in
+ '''Take the body and options from CHUNK, figure out how the
+ real .ly should look. The .ly is written, and scheduled in
TODO.
- Return: a chunk (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE)
+ Return: a single chunk.
+
+ The chunk pertaining to the lilypond output
+ has the format (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE),
+ where TODO has format [basename, extension, extension, ... ]
+ '''
- TODO has format [basename, extension, extension, ... ]
-
- """
(type, body, opts) = chunk
assert type == 'lilypond'
file_body = compose_full_body (body, opts)
- basename = 'lily-' + `abs(hash (file_body))`
+ ## Hmm, we should hash only lilypond source, and skip the
+ ## %options are ...
+ ## comment line
+ basename = unique_file_name (file_body)
for o in opts:
m = re.search ('filename="(.*?)"', o)
if m:
basename = m.group (1)
- if not taken_file_names.has_key(basename):
- taken_file_names[basename] = 0
+ if not taken_file_names.has_key (basename):
+ taken_file_names[basename] = 0
else:
- taken_file_names[basename] = taken_file_names[basename] + 1
- basename = basename + "-%i" % taken_file_names[basename]
- if not g_read_lys:
- update_file(file_body, os.path.join(g_outdir, basename) + '.ly')
+ taken_file_names[basename] = taken_file_names[basename] + 1
+ basename = basename + "-%i" % taken_file_names[basename]
+ update_file (file_body, os.path.join (g_outdir, basename) + '.ly')
needed_filetypes = ['tex']
- if format == 'texi':
- needed_filetypes.append('eps')
- needed_filetypes.append('png')
+ if format == 'html' or g_make_html:
+ needed_filetypes.append ('eps')
+ needed_filetypes.append ('png')
if 'eps' in opts and not ('eps' in needed_filetypes):
- needed_filetypes.append('eps')
+ needed_filetypes.append ('eps')
+
pathbase = os.path.join (g_outdir, basename)
- def f(base, ext1, ext2):
- a = os.path.isfile(base + ext2)
- if (os.path.isfile(base + ext1) and
- os.path.isfile(base + ext2) and
- os.stat(base+ext1)[stat.ST_MTIME] >
- os.stat(base+ext2)[stat.ST_MTIME]) or \
- not os.path.isfile(base + ext2):
+ def f (base, ext1, ext2):
+ a = os.path.isfile (base + ext2)
+ if (os.path.isfile (base + ext1) and
+ os.path.isfile (base + ext2) and
+ os.stat (base+ext1)[stat.ST_MTIME] >
+ os.stat (base+ext2)[stat.ST_MTIME]) or \
+ not os.path.isfile (base + ext2):
return 1
todo = []
- if 'tex' in needed_filetypes and f(pathbase, '.ly', '.tex'):
- todo.append('tex')
- if 'eps' in needed_filetypes and f(pathbase, '.tex', '.eps'):
- todo.append('eps')
- if 'png' in needed_filetypes and f(pathbase, '.eps', '.png'):
- todo.append('png')
- newbody = ''
+ if 'tex' in needed_filetypes and f (pathbase, '.ly', '.tex'):
+ todo.append ('tex')
+ if 'eps' in needed_filetypes and f (pathbase, '.tex', '.eps'):
+ todo.append ('eps')
+ if 'png' in needed_filetypes and f (pathbase, '.eps', '.png'):
+ todo.append ('png')
+
+ return ('lilypond', body, opts, todo, basename)
+
+def format_lilypond_block (chunk):
+ """
+
+ Figure out what should be left MAIN_STR (meant
+ for the main file) from a lilypond chunk: process
+ verbatim, and other options. Return: multiple chunks.
+
+
+ """
+
+
+ return_chunks = []
+ (type, body, opts, todo, basename) = chunk
+ assert type == 'lilypond'
+
+
+ newbody = ''
+ filename_chunk = None
if 'printfilename' in opts:
for o in opts:
m= re.match ("filename=(.*)", o)
if m:
- newbody = newbody + get_output ("output-filename") % m.group(1)
+ template = get_output ("output-filename")
+ b = basename + '.ly'
+ human_base = os.path.basename (m.group (1))
+
+ ## todo: include path, but strip
+ ## first part of the path.
+ filename_chunk = ('input', template % (human_base, b,human_base))
break
-
-
- if 'verbatim' in opts:
- newbody = output_verbatim (body)
+
+
+ if 'smallverbatim' in opts:
+ newbody += output_verbatim (body, 1)
+ elif 'verbatim' in opts:
+ newbody += output_verbatim (body, 0)
for o in opts:
m = re.search ('intertext="(.*?)"', o)
if m:
- newbody = newbody + m.group (1) + "\n\n"
- if format == 'latex':
+ newbody = newbody + "\n"
+ if format == 'texi':
+ newbody = newbody + "@noindent\n"
+ elif format == 'latex':
+ newbody = newbody + "\\noindent\n"
+ newbody = newbody + m.group (1) + "\n"
+
+ if 'noinline' in opts:
+ s = 'output-noinline'
+ elif format == 'latex':
if 'eps' in opts:
s = 'output-eps'
else:
- s = 'output-tex'
- else: # format == 'texi'
- s = 'output-all'
- newbody = newbody + get_output (s) % {'fn': basename }
- return ('lilypond', newbody, opts, todo, basename)
+ if 'quote' in opts:
+ s = 'output-latex-quoted'
+ else:
+ s = 'output-latex-noquote'
+ elif format == 'texi':
+ if 'quote' in opts:
+ s = 'output-texi-quoted'
+ else:
+ s = 'output-texi-noquote'
+ else: # format == 'html'
+ s = 'output-html'
+
+ def html_pages (basename):
+ pat = os.path.join (g_outdir, "%s-page*.png"% basename)
+
+ files = glob.glob (pat)
+
+
+ template = '''<img align="center" valign="center"
+ border="0" src="%s" alt="[picture of music]">'''
+
+ str = ''
+ if files == []:
+ files = [basename+'.png' ]
+ else:
+ files = map (os.path.basename, files)
+
+ for f in files:
+ str += template % f
+
+ str = '<a href="%s.ly">%s</a>' % (basename, str)
+
+ return str
+
+
+ newbody = newbody + get_output (s) % {'fn': basename,
+ 'htmlimages': html_pages(basename)
+ }
+
+ if filename_chunk:
+ return_chunks += [filename_chunk]
+
+ return_chunks += [('lilypond', newbody, opts, todo, basename)]
+
+ return return_chunks
+
+def format_lilypond_output_bodies (chunks):
+ newchunks = []
+ for c in chunks:
+
+ if c[0] == 'lilypond':
+ newchunks += format_lilypond_block (c)
+ else:
+ newchunks.append (c)
+
+ return newchunks
-def process_lilypond_blocks(outname, chunks):#ugh rename
+
+
+def process_lilypond_blocks (chunks):#ugh rename
newchunks = []
# Count sections/chapters.
for c in chunks:
c = schedule_lilypond_block (c)
elif c[0] == 'numcols':
paperguru.m_num_cols = c[2]
+ elif c[0] == 'multicols':
+ paperguru.m_multicols = c[2]
+
newchunks.append (c)
+
return newchunks
+def process_ly2dvi_blocks (chunks):
+
+ def process_ly2dvi_block (chunk):
+ """
+Run ly2dvi script on filename specified in CHUNK.
+This is only supported for HTML output.
-def system (cmd):
- sys.stderr.write ("invoking `%s'\n" % cmd)
- st = os.system (cmd)
- if st:
- error ('Error command exited with value %d\n' % st)
- return st
+In HTML output it will leave a download menu with ps/pdf/midi etc. in
+a separate HTML file, and a title + preview in the main html file,
+linking to the menu.
+ """
+ (tag, name, opts) = chunk
+ assert format == 'html'
+ (content, original_name) = find_file (name)
-def get_bbox (filename):
- f = open (filename)
- gr = []
- while 1:
- l =f.readline ()
- m = re.match ('^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', l)
- if m:
- gr = map (string.atoi, m.groups ())
- break
-
- return gr
-
-def make_pixmap (name):
- bbox = get_bbox (name + '.eps')
- margin = 3
- fo = open (name + '.trans.eps' , 'w')
- fo.write ('%d %d translate\n' % (-bbox[0]+margin, -bbox[1]+margin))
- fo.close ()
-
- res = 90
+ original_name = os.path.basename (original_name)
+
+ base = unique_file_name (content)
+ outname = base + '.ly'
+ changed = update_file (content, outname)
- x = (2* margin + bbox[2] - bbox[0]) * res / 72.
- y = (2* margin + bbox[3] - bbox[1]) * res / 72.
+ preview = base + ".png"
+ preview_page = base + '-page1.png'
+
+ if changed or not (os.path.isfile (preview) or
+ os.path.isfile (preview_page)):
+
+ ly.system ('%s --preview --postscript --verbose %s ' % (ly2dvi_binary, base) )
- cmd = r"""gs -g%dx%d -sDEVICE=pgm -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=- -r%d -dNOPAUSE %s %s -c quit | pnmtopng > %s"""
-
- cmd = cmd % (x, y, res, name + '.trans.eps', name + '.eps',name + '.png')
- try:
- status = system (cmd)
- except:
- os.unlink (name + '.png')
- error ("Removing output file")
+ ly.make_ps_images (base)
+ ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base))
+
+ def size_str (fn):
+ b = os.stat(fn)[stat.ST_SIZE]
+ if b < 1024:
+ return '%d bytes' % b
+ elif b < (2 << 20):
+ return '%d kb' % (b >> 10)
+ else:
+ return '%d mb' % (b >> 20)
+
+ exts = {
+ 'pdf' : "Print (PDF, %s)",
+ 'ps.gz' : "Print (gzipped PostScript, %s)",
+ 'png' : "View (PNG, %s)",
+ 'midi' : "Listen (MIDI, %s)",
+ 'ly' : "View source code (%s)",
+ }
+
+ menu = ''
+ page_files = glob.glob ('%s-page*.png' % base)
+
+ for p in string.split (page_files, '\n'):
+ p = p.strip()
+ if os.path.isfile (p):
+ sz = size_str (p)
+ page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p)
+ page = page % sz
+ menu += '<li><a href="%s">%s</a>' % (p, page)
+
+ ext_order = ['ly', 'pdf', 'ps.gz', 'midi']
+ for e in ext_order:
+ fn = base + '.' + e
+ print 'checking,' , fn
+ if not os.path.isfile (fn):
+ continue
+
+ entry = exts[e] % size_str (fn)
+
+ ## TODO: do something like
+ ## this for texinfo/latex as well ?
+
+ menu += '<li><a href="%s">%s</a>\n\n' % (fn, entry)
+
+
+ explanatory_para = """The pictures are 90dpi
+anti-aliased snapshots of the printed output, in PNG format. Both PDF and PS
+use scalable fonts and should look OK at any resolution."""
+
+ separate_menu =r'''
+<title>LilyPond example %s</title>
+
+<h1>%s</h1>
+<p><img src="%s">
+<p>%s
+<p>
+<ul>%s</ul>''' % (original_name,original_name, preview, explanatory_para, menu)
+
+ open (base + '.html','w'). write (separate_menu)
+
+ inline_menu = '<p/><a href="%s.html"><img src="%s"><p/></a>' % (base, original_name, preview)
+
+ return ('ly2dvi', inline_menu)
+
+ newchunks = []
+ for c in chunks:
+ if c[0] == 'ly2dvi':
+ c = process_ly2dvi_block (c)
+ newchunks.append (c)
+
+ return newchunks
def compile_all_files (chunks):
global foutn
png = []
for c in chunks:
- if c[0] <> 'lilypond':
+ if c[0] != 'lilypond':
continue
+
base = c[4]
exts = c[3]
for e in exts:
tex.append (base + '.ly')
elif e == 'png' and g_do_pictures:
png.append (base)
- d = os.getcwd()
+ d = os.getcwd ()
if g_outdir:
- os.chdir(g_outdir)
+ os.chdir (g_outdir)
if tex:
# fixme: be sys-independent.
def incl_opt (x):
- if g_outdir and x[0] <> '/' :
+ if g_outdir and x[0] != '/' :
x = os.path.join (g_here_dir, x)
return ' -I %s' % x
incs = map (incl_opt, include_path)
- lilyopts = string.join (incs, ' ' )
+ lilyopts = string.join (incs)
if do_deps:
- lilyopts = lilyopts + ' --dependencies '
+ lilyopts += ' --dependencies'
if g_outdir:
- lilyopts = lilyopts + '--dep-prefix=' + g_outdir + '/'
- texfiles = string.join (tex, ' ')
- system ('lilypond --header=texidoc %s %s' % (lilyopts, texfiles))
+ lilyopts += ' --dep-prefix=' + g_outdir + '/'
+ lilyopts += ' --header=texidoc'
+ texfiles = string.join (tex)
+ cmd = string.join ((lilypond_binary, lilyopts, g_extra_opts,
+ texfiles))
+ ly.system (cmd, ignore_error = 0, progress_p = 1)
#
# Ugh, fixing up dependencies for .tex generation
#
if do_deps:
- depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep', x), tex)
+ depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep',
+ x), tex)
+
for i in depfiles:
f =open (i)
text=f.read ()
f.close ()
- text=re.sub ('\n([^:\n]*):', '\n' + foutn + ':', text)
+ text=re.sub ('\n([^:\n]*):',
+ '\n' + foutn + ':', text)
f = open (i, 'w')
f.write (text)
f.close ()
- for e in eps:
- system(r"tex '\nonstopmode \input %s'" % e)
- system(r"dvips -E -o %s %s" % (e + '.eps', e))
-
- for g in png:
- make_pixmap (g)
-
+ def to_eps (file):
+ cmd = r"latex '\nonstopmode \input %s'" % file
+ # Ugh. (La)TeX writes progress and error messages on stdout
+ # Redirect to stderr
+ cmd += ' 1>/dev/stderr'
+ ly.system (cmd)
+ ly.system ("dvips -E -o %s.eps %s" % (file, file))
+ map (to_eps, eps)
+
+ map (ly.make_ps_images, map (lambda x: x + '.eps', png))
os.chdir (d)
def update_file (body, name):
- """
- write the body if it has changed
- """
+ '''
+ write the body if it has changed. Return whether BODY has changed.
+ '''
same = 0
try:
f = open (name)
f = open (name , 'w')
f.write (body)
f.close ()
-
- return not same
-
-
-def getopt_args (opts):
- "Construct arguments (LONG, SHORT) for getopt from list of options."
- short = ''
- long = []
- for o in opts:
- if o[1]:
- short = short + o[1]
- if o[0]:
- short = short + ':'
- if o[2]:
- l = o[2]
- if o[0]:
- l = l + '='
- long.append (l)
- return (short, long)
-
-def option_help_str (o):
- "Transform one option description (4-tuple ) into neatly formatted string"
- sh = ' '
- if o[1]:
- sh = '-%s' % o[1]
-
- sep = ' '
- if o[1] and o[2]:
- sep = ','
-
- long = ''
- if o[2]:
- long= '--%s' % o[2]
-
- arg = ''
- if o[0]:
- if o[2]:
- arg = '='
- arg = arg + o[0]
- return ' ' + sh + sep + long + arg
-
-
-def options_help_str (opts):
- "Convert a list of options into a neatly formatted string"
- w = 0
- strs =[]
- helps = []
-
- for o in opts:
- s = option_help_str (o)
- strs.append ((s, o[3]))
- if len (s) > w:
- w = len (s)
-
- str = ''
- for s in strs:
- str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
- return str
-
-def help():
- sys.stdout.write("""Usage: lilypond-book [options] FILE\n
-Generate hybrid LaTeX input from Latex + lilypond
-Options:
-""")
- sys.stdout.write (options_help_str (option_definitions))
- sys.stdout.write (r"""Warning all output is written in the CURRENT directory
-
-
-Report bugs to bug-gnu-music@gnu.org.
-
-Written by Tom Cato Amundsen <tca@gnu.org> and
-Han-Wen Nienhuys <hanwen@cs.uu.nl>
-""")
-
- sys.exit (0)
+ return not same
def write_deps (fn, target, chunks):
global read_files
- sys.stdout.write('Writing `%s\'\n' % os.path.join(g_outdir, fn))
- f = open (os.path.join(g_outdir, fn), 'w')
+ sys.stderr.write ('Writing `%s\'\n' % os.path.join (g_outdir, fn))
+ f = open (os.path.join (g_outdir, fn), 'w')
f.write ('%s%s: ' % (g_dep_prefix, target))
for d in read_files:
f.write ('%s ' % d)
- basenames=[]
- for c in chunks:
- if c[0] == 'lilypond':
- (type, body, opts, todo, basename) = c;
- basenames.append (basename)
- for d in basenames:
- if g_outdir:
- d=g_outdir + '/' + d
- if g_dep_prefix:
- #if not os.isfile (d): # thinko?
- if not re.search ('/', d):
- d = g_dep_prefix + d
- f.write ('%s.tex ' % d)
- f.write ('\n')
- #if len (basenames):
- # for d in basenames:
- # f.write ('%s.ly ' % d)
- # f.write (' : %s' % target)
- f.write ('\n')
- f.close ()
- read_files = []
-def identify():
- sys.stdout.write ('lilypond-book (GNU LilyPond) %s\n' % program_version)
-def print_version ():
- identify()
- sys.stdout.write (r"""Copyright 1998--1999
-Distributed under terms of the GNU General Public License. It comes with
-NO WARRANTY.
-""")
+ ## There used to be code to write .tex dependencies, but
+ ## that is silly: lilypond-book has its own dependency scheme
+ ## to ensure that all lily-XXX.tex files are there
+
+ f.write ('\n')
+ f.close ()
+ read_files = []
def check_texidoc (chunks):
+ ## TODO: put file name in front of texidoc.
+ ##
n = []
for c in chunks:
if c[0] == 'lilypond':
(type, body, opts, todo, basename) = c;
pathbase = os.path.join (g_outdir, basename)
- if os.path.isfile (pathbase + '.texidoc'):
- body = '\n@include %s.texidoc\n' % basename + body
- c = (type, body, opts, todo, basename)
+ if os.path.isfile (pathbase + '.texidoc') \
+ and 'notexidoc' not in opts:
+ n.append( ('input', '\n@include %s.texidoc\n' % basename))
n.append (c)
return n
def fix_epswidth (chunks):
newchunks = []
for c in chunks:
- if c[0] <> 'lilypond' or 'eps' not in c[2]:
+ if c[0] != 'lilypond' or 'eps' not in c[2]:
newchunks.append (c)
continue
dims = bounding_box_dimensions (filename)
return '%fpt' % (dims[0] *lmag)
-
- body = re.sub (r"""\\lilypondepswidth{(.*?)}""", replace_eps_dim, c[1])
- newchunks.append(('lilypond', body, c[2], c[3], c[4]))
-
+
+ body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
+ newchunks.append (('lilypond', body, c[2], c[3], c[4]))
+
return newchunks
+##docme: why global?
foutn=""
-def do_file(input_filename):
- global foutn
- file_settings = {}
- if outname:
- my_outname = outname
- else:
- my_outname = os.path.basename(os.path.splitext(input_filename)[0])
- my_depname = my_outname + '.dep'
-
- chunks = read_doc_file(input_filename)
- chunks = chop_chunks(chunks, 'lilypond', make_lilypond, 1)
- chunks = chop_chunks(chunks, 'lilypond-file', make_lilypond_file, 1)
- chunks = chop_chunks(chunks, 'lilypond-block', make_lilypond_block, 1)
- chunks = chop_chunks(chunks, 'singleline-comment', do_ignore, 1)
- chunks = chop_chunks(chunks, 'preamble-end', do_preamble_end)
- chunks = chop_chunks(chunks, 'numcols', do_columns)
- #print "-" * 50
- #for c in chunks: print "c:", c;
- #sys.exit()
- scan_preamble(chunks)
- chunks = process_lilypond_blocks(my_outname, chunks)
-
- foutn = os.path.join (g_outdir, my_outname + '.' + format)
+def do_file (input_filename):
+ chunks = read_doc_file (input_filename)
+ chunks = chop_chunks (chunks, 'ly2dvi', make_ly2dvi_block, 1)
+ chunks = chop_chunks (chunks, 'lilypond', make_lilypond, 1)
+ chunks = chop_chunks (chunks, 'lilypond-file', make_lilypond_file, 1)
+ chunks = chop_chunks (chunks, 'lilypond-block', make_lilypond_block, 1)
+ chunks = chop_chunks (chunks, 'singleline-comment', do_ignore, 1)
+ chunks = chop_chunks (chunks, 'preamble-end', do_preamble_end)
+ chunks = chop_chunks (chunks, 'numcols', do_columns)
+ chunks = chop_chunks (chunks, 'multicols', do_multicols)
+
+ scan_preamble (chunks)
+ chunks = process_lilypond_blocks (chunks)
+ chunks = process_ly2dvi_blocks (chunks)
+
# Do It.
- if __main__.g_run_lilypond:
+ global g_run_lilypond
+ if g_run_lilypond:
compile_all_files (chunks)
chunks = fix_epswidth (chunks)
- if __main__.format == 'texi':
+
+ chunks = format_lilypond_output_bodies (chunks)
+ global format
+ if format == 'texi':
chunks = check_texidoc (chunks)
+
x = 0
chunks = completize_preamble (chunks)
- sys.stderr.write ("Writing `%s'\n" % foutn)
- fout = open (foutn, 'w')
+
+ global foutn
+
+ if outname:
+ my_outname = outname
+ elif input_filename == '-' or input_filename == "/dev/stdin":
+ my_outname = '-'
+ else:
+ my_outname = os.path.basename (os.path.splitext (input_filename)[0]) + '.' + format
+ my_depname = my_outname + '.dep'
+
+ if my_outname == '-' or my_outname == '/dev/stdout':
+ fout = sys.stdout
+ foutn = "<stdout>"
+ global do_deps
+ do_deps = 0
+ else:
+ foutn = os.path.join (g_outdir, my_outname)
+ sys.stderr.write ("Writing `%s'\n" % foutn)
+ fout = open (foutn, 'w')
for c in chunks:
fout.write (c[1])
fout.close ()
if do_deps:
write_deps (my_depname, foutn, chunks)
-
outname = ''
try:
- (sh, long) = getopt_args (__main__.option_definitions)
- (options, files) = getopt.getopt(sys.argv[1:], sh, long)
+ (sh, long) = ly.getopt_args (option_definitions)
+ (options, files) = getopt.getopt (sys.argv[1:], sh, long)
+
except getopt.error, msg:
- sys.stderr.write("error: %s" % msg)
- sys.exit(1)
+ sys.stderr.write ('\n')
+ ly.error (_ ("getopt says: `%s\'" % s))
+ sys.stderr.write ('\n')
+ ly.help ()
+ ly.exit (2)
do_deps = 0
-for opt in options:
+for opt in options:
o = opt[0]
a = opt[1]
if o == '--include' or o == '-I':
include_path.append (a)
elif o == '--version' or o == '-v':
- print_version ()
- sys.exit (0)
+ ly.identify (sys.stdout)
+ sys.exit (0)
+ elif o == '--verbose' or o == '-V':
+ verbose_p = 1
elif o == '--format' or o == '-f':
- __main__.format = a
+ format = a
+ if a == 'texi-html':
+ format = 'texi'
+ g_make_html = 1
elif o == '--outname' or o == '-o':
- if len(files) > 1:
+ if len (files) > 1:
#HACK
- sys.stderr.write("Lilypond-book is confused by --outname on multiple files")
- sys.exit(1)
+ sys.stderr.write ("Lilypond-book is confused by --outname on multiple files")
+ sys.exit (1)
outname = a
elif o == '--help' or o == '-h':
- help ()
+ ly.help ()
+ sys.exit (0)
elif o == '--no-lily' or o == '-n':
- __main__.g_run_lilypond = 0
+ g_run_lilypond = 0
+ elif o == '--preview-resolution':
+ preview_resolution = string.atoi (a)
elif o == '--dependencies' or o == '-M':
do_deps = 1
elif o == '--default-music-fontsize':
elif o == '--default-lilypond-fontsize':
print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize"
default_music_fontsize = string.atoi (a)
+ elif o == '--extra-options':
+ g_extra_opts = a
elif o == '--force-music-fontsize':
- g_force_lilypond_fontsize = string.atoi(a)
+ g_force_music_fontsize = string.atoi (a)
elif o == '--force-lilypond-fontsize':
print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize"
- g_force_lilypond_fontsize = string.atoi(a)
+ g_force_music_fontsize = string.atoi (a)
elif o == '--dep-prefix':
g_dep_prefix = a
elif o == '--no-pictures':
g_do_pictures = 0
- elif o == '--read-lys':
- g_read_lys = 1
+ elif o == '--no-music':
+ g_do_music = 0
elif o == '--outdir':
g_outdir = a
+ elif o == '--warranty' or o == '-w':
+ #status = os.system ('lilypond -w')
+ if 1 or status:
+ ly.warranty ()
+ sys.exit (0)
+
+ly.identify (sys.stderr)
-identify()
if g_outdir:
- if os.path.isfile(g_outdir):
+ if os.path.isfile (g_outdir):
error ("outdir is a file: %s" % g_outdir)
- if not os.path.exists(g_outdir):
- os.mkdir(g_outdir)
-setup_environment ()
+ if not os.path.exists (g_outdir):
+ os.mkdir (g_outdir)
+
+if not files:
+ ly.help ()
+ ly.error (_ ("no files specified on command line"))
+ ly.exit (2)
+
+ly.setup_environment ()
+
+
for input_filename in files:
- do_file(input_filename)
-
+ do_file (input_filename)
+
+
#
# Petr, ik zou willen dat ik iets zinvoller deed,
# maar wat ik kan ik doen, het verandert toch niets?