X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Flilypond-book.py;h=c0ca09a5537a3aab397da096459f3d33a3d50219;hb=1b91955adaf3c89540c8ffff7228f0ec7a31dbe4;hp=cf10c42f20c5ce06d1459ee828596409249723aa;hpb=7cacca4ac9e71dc19ba1c1fc600d2bd4ac4b9b26;p=lilypond.git diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index cf10c42f20..c0ca09a553 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -1,28 +1,61 @@ #!@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 + + when all chunks have their final form, all bodies from lilypond blocks are + extracted, and if applicable, written do disk and run through lilypond. + -# This is was the idea for handling of comments: +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. @@ -35,77 +68,113 @@ # 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 /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] -# 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', -} +sys.path.insert (0, os.path.join (datadir, 'python')) -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 +# Customize these +#if __name__ == '__main__': - for key in non_path_environment.keys (): - val = non_path_environment[key] - print '%s=%s' % (key,val) - os.environ[key] = val +import lilylib as ly +global _;_=ly._ +global re;re = ly.re + +# lilylib globals +program_version = '@TOPLEVEL_VERSION@' +program_name = 'lilypond-book' +verbose_p = 0 +pseudo_filter_p = 0 +original_dir = os.getcwd () + + +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 ', + 'Han-Wen Nienhuys ') + +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 to be in points")), + (_ ("DIM"), '', 'force-lilypond-fontsize', _ ("deprecated, use --force-music-fontsize")), + ('', 'h', 'help', _ ("print 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', _ ("be 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 ()] + +#lilypond_binary = 'valgrind --suppressions=/home/hanwen/usr/src/guile-1.6.supp --num-callers=10 /home/hanwen/usr/src/lilypond/lily/out/lilypond' + +lilypond_binary = os.path.join ('@bindir@', 'lilypond-bin') + +# only use installed binary when we're installed too. +if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary): + lilypond_binary = 'lilypond-bin' + + + +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' -include_path = [os.getcwd()] -# g_ is for global (?) 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 @@ -115,388 +184,393 @@ default_music_fontsize = 16 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)] - - value = conv(num) + self.m_multicols = 1 - 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 = '(( %s >&2 ) >&- )' % cmd + 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.m_use_geometry: - return latex_linewidths[self.m_papersize][self.m_fontsize] + if not self.__dict__.has_key ('m_textwidth'): + raise 'foo!' + + 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'), - ('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'), - ('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''' + +''', + ## maybe
? + 'pagebreak': None, + # Verbatim text is always finished with \n. FIXME: For HTML, + # this newline should be removed. + 'output-verbatim': r'''
+%s
''', + # Verbatim text is always finished with \n. FIXME: For HTML, + # this newline should be removed. + 'output-small-verbatim': r'''
+%s
''', + ## Ugh we need to differentiate on origin: + ## lilypond-block origin wants an extra

, but + ## inline music doesn't. + ## possibly other center options? + 'output-html': r''' +%(htmlimages)s''', + }, + + 'latex': { - 'output-lilypond-fragment' : r"""\begin[eps,singleline,%s]{lilypond} - \context Staff < + + 'output-lilypond-fragment' : r'''\begin[singleline,%s]{lilypond} \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}", - 'output-default-post': "\\def\postLilypondExample{}\n", - 'output-default-pre': "\\def\preLilypondExample{}\n", +\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-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

below breaks inline images... + 'output-texi-noquote': r'''@tex +\catcode`\@=12 +\parindent 0pt +\def\lilypondbook{} +\input %(fn)s.tex +\catcode`\@=0 +@end tex +@html +

%(htmlimages)s +

+@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 +

%(htmlimages)s

- -[picture of music] - @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 +# +# (?Pregex) -- 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\\mbinput{?([^}\t \n}]*))', - 'include': r'(?m)^[^%\n]*?(?P\\mbinclude{(?P[^}]+)})', - 'option-sep' : ',\s*', - 'header': r"\\documentclass\s*(\[.*?\])?", - 'geometry': r"^(?m)[^%\n]*?\\usepackage\s*(\[(?P.*)\])?\s*{geometry}", - 'preamble-end': r'(?P\\begin{document})', - 'verbatim': r"(?s)(?P\\begin{verbatim}.*?\\end{verbatim})", - 'verb': r"(?P\\verb(?P.).*?(?P=del))", - 'lilypond-file': r'(?m)^[^%\n]*?(?P\\lilypondfile\s*(\[(?P.*?)\])?\s*\{(?P.+)})', - 'lilypond' : r'(?m)^[^%\n]*?(?P\\lilypond\s*(\[(?P.*?)\])?\s*{(?P.*?)})', - 'lilypond-block': r"(?sm)^[^%\n]*?(?P\\begin\s*(\[(?P.*?)\])?\s*{lilypond}(?P.*?)\\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(?P^%.*$\n+))", - 'numcols': r"(?P\\(?Pone|two)column)", - }, + 'html': { + 'include': no_match, + 'input': no_match, + 'header': no_match, + 'preamble-end': no_match, + 'landscape': no_match, + 'verbatim': r'''(?s)(?P

\s.*?
\s)''', + 'verb': r'''(?P
.*?
)''', + 'lilypond-file': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', + 'lilypond' : '(?m)(?P[^:]*):)(?P.*?)/>)', + 'lilypond-block': r'''(?ms)(?P[^>]+)?>(?P.*?))''', + 'option-sep' : '\s*', + 'intertext': r',?\s*intertext=\".*?\"', + 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P)\s", + 'singleline-comment': no_match, + 'numcols': no_match, + 'multicols': no_match, + 'ly2dvi': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', + }, + + 'latex': { + 'input': r'(?m)^[^%\n]*?(?P\\mbinput{?([^}\t \n}]*))', + 'include': r'(?m)^[^%\n]*?(?P\\mbinclude{(?P[^}]+)})', + 'option-sep' : ',\s*', + 'header': r"\n*\\documentclass\s*(\[.*?\])?", + 'preamble-end': r'(?P\\begin\s*{document})', + 'verbatim': r"(?s)(?P\\begin\s*{verbatim}.*?\\end{verbatim})", + 'verb': r"(?P\\verb(?P.).*?(?P=del))", + 'lilypond-file': r'(?m)^[^%\n]*?(?P\\lilypondfile\s*(\[(?P.*?)\])?\s*\{(?P.+)})', + 'lilypond' : r'(?m)^[^%\n]*?(?P\\lilypond\s*(\[(?P.*?)\])?\s*{(?P.*?)})', + 'lilypond-block': r"(?sm)^[^%\n]*?(?P\\begin\s*(\[(?P.*?)\])?\s*{lilypond}(?P.*?)\\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(?P^%.*$\n+))", + 'numcols': r"(?P\\(?Pone|two)column)", + 'multicols': r"(?P\\(?Pbegin|end)\s*{multicols}({(?P\d+)?})?)", + 'ly2dvi': no_match, + }, # why do we have distinction between @mbinclude and @include? - 'texi': { - 'include': '(?m)^[^%\n]*?(?P@mbinclude[ \n\t]+(?P[^\t \n]*))', - 'input': no_match, - 'header': no_match, - 'preamble-end': no_match, - 'landscape': no_match, - 'verbatim': r"""(?s)(?P@example\s.*?@end example\s)""", - 'verb': r"""(?P@code{.*?})""", - 'lilypond-file': '(?m)^(?P@lilypondfile(\[(?P[^]]*)\])?{(?P[^}]+)})', - 'lilypond' : '(?m)^(?P@lilypond(\[(?P[^]]*)\])?{(?P.*?)})', - 'lilypond-block': r"""(?ms)^(?P@lilypond(\[(?P[^]]*)\])?\s(?P.*?)@end lilypond)\s""", - 'option-sep' : ',\s*', - 'intertext': r',?\s*intertext=\".*?\"', - 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P@ignore\s.*?@end ignore)\s", - 'singleline-comment': r"(?m)^.*?(?P(?P@c.*$\n+))", - 'numcols': no_match, - } + 'include': '(?m)^[^%\n]*?(?P@mbinclude\s+(?P\S*))', + 'input': no_match, + 'header': no_match, + 'preamble-end': no_match, + 'landscape': no_match, + 'verbatim': r'''(?s)(?P@example\s.*?@end example\s)''', + 'verb': r'''(?P@code{.*?})''', + 'lilypond-file': '(?m)^(?P@lilypondfile(\[(?P[^]]*)\])?{(?P[^}]+)})', + 'lilypond' : '(?m)^(?P@lilypond(\[(?P[^]]*)\])?{(?P.*?)})', + 'lilypond-block': r'''(?ms)^(?P@lilypond(\[(?P[^]]*)\])?\s(?P.*?)@end lilypond)\s''', + 'option-sep' : ',\s*', + 'intertext': r',?\s*intertext=\".*?\"', + 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P@ignore\s.*?@end ignore)\s", + 'singleline-comment': r"(?m)^.*?(?P(?P@c.*$\n+))", + 'numcols': no_match, + 'multicols': no_match, + 'ly2dvi': no_match, + } } @@ -509,12 +583,14 @@ for r in re_dict.keys (): 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. + ## 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 @@ -523,7 +599,7 @@ def uniq (list): if x not in list: list.append (x) return list - + def get_output (name): return output_dict[format][name] @@ -531,17 +607,17 @@ def get_output (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: - + gs = map (lambda x: string.atoi (x), s.groups ()) return (int (gs[2] - gs[0] + 0.5), int (gs[3] - gs[1] + 0.5)) @@ -549,26 +625,34 @@ def bounding_box_dimensions(fname): 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 @@ -580,12 +664,30 @@ def compose_full_body (body, opts): 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 +} +''' + orig_name = '' for o in opts: m= re.search ('relative(.*)', o) v = 0 @@ -602,150 +704,155 @@ def compose_full_body (body, opts): elif v > 0: pitch = pitch + '\'' * v - body = '\\relative %s { %s }' %(pitch, body) - + body = '\\relative %s { %s }' % (pitch, body) + m =re.search ("filename=(.*)", o) + if m: + orig_name = m.group (1) + 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 + + if orig_name: + body = '\\renameinput \"%s\"\n%s' % (orig_name, 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 (r',\s*', 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 (), '') 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 @@ -756,215 +863,361 @@ def find_file (name): 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 = get_re ('option-sep').split (m.group ('options')) + else: + options = [] + (content, nm) = find_file (m.group ('filename')) + options.append ("filename=%s" % nm) + (path, base) = os.path.split (nm) - """ + if path not in include_path: + include_path.append (path) + + return [('lilypond', content, options)] - if m.group('options'): - options = m.group('options') - else: - options = '' - (content, nm) = find_file(m.group('filename')) - options = "filename=%s," % nm + options - return [('input', get_output('output-lilypond') % - (options, content))] +def make_ly2dvi_block (m): + ''' + + Find + ''' + + return [('ly2dvi', m.group ('filename'), m.group ('options'))] + + +def make_lilypond_block (m): + if not g_do_music: + return [] -def make_lilypond_block(m): - if m.group('options'): - options = get_re('option-sep').split (m.group('options')) + 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 + "-t%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 must_rebuild (base, ext1, ext2): + + f2 = base + ext2 + f1 = base + ext1 + fp2 = base + '-page1' + ext2 + + isfile2 = os.path.isfile (f2) + + if not isfile2 and os.path.isfile (fp2): + f2 = fp2 + isfile2 = os.path.isfile (fp2) + + if (os.path.isfile (f2) and isfile2 and + os.stat (f1)[stat.ST_MTIME] > + os.stat (f2)[stat.ST_MTIME]) or \ + not isfile2: + 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 must_rebuild (pathbase, '.ly', '.tex'): + todo.append ('tex') + if 'eps' in needed_filetypes and must_rebuild (pathbase, '.tex', '.eps'): + todo.append ('eps') + if 'png' in needed_filetypes and must_rebuild (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': - if 'eps' in opts: - s = 'output-eps' + 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 'quote' in opts: + s = 'output-latex-quoted' else: - s = 'output-tex' - else: # format == 'texi' - s = 'output-all' - newbody = newbody + get_output (s) % {'fn': basename } - return ('lilypond', newbody, opts, todo, basename) + 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 = '''[picture of music]''' + + str = '' + if files == []: + files = [basename+'.png' ] + else: + files = map (os.path.basename, files) + + for f in files: + str += template % f -def process_lilypond_blocks(outname, chunks):#ugh rename + str = '%s' % (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 (chunks):#ugh rename newchunks = [] # Count sections/chapters. for c in chunks: @@ -972,50 +1225,116 @@ def process_lilypond_blocks(outname, chunks):#ugh rename 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): - system ('gs -sDEVICE=bbox -q -sOutputFile=- -dNOPAUSE %s -c quit > %s.bbox 2>&1 ' % (filename, filename)) + original_name = os.path.basename (original_name) + + base = unique_file_name (content) + outname = base + '.ly' + changed = update_file (content, outname) - box = open (filename + '.bbox').read() - m = re.match ('^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', box) - gr = [] - if m: - gr = map (string.atoi, m.groups ()) - - return gr - -def make_pixmap (name): - bbox = get_bbox (name + '.eps') - margin = 0 - fo = open (name + '.trans.eps' , 'w') - fo.write ('%d %d translate\n' % (-bbox[0]+margin, -bbox[1]+margin)) - fo.close () - - res = 90 + preview = base + ".preview.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) ) + + ly.make_ps_images (base + '.ps') + 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 page_files: + 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 += '
  • %s' % (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 += '
  • %s\n\n' % (fn, entry) - x = (2* margin + bbox[2] - bbox[0]) * res / 72. - y = (2* margin + bbox[3] - bbox[1]) * res / 72. - 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") + 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''' +LilyPond example %s + +

    %s

    +

    +

    %s +

    +

      %s
    ''' % (original_name,original_name, preview, explanatory_para, menu) + + open (base + '.html','w'). write (separate_menu) + + inline_menu = '

    %s

    ' % (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 @@ -1024,8 +1343,9 @@ def compile_all_files (chunks): png = [] for c in chunks: - if c[0] <> 'lilypond': + if c[0] != 'lilypond': continue + base = c[4] exts = c[3] for e in exts: @@ -1037,53 +1357,66 @@ def compile_all_files (chunks): 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 %s' % (lilyopts, g_extra_opts, texfiles)) + lilyopts += ' --dep-prefix=' + g_outdir + '/' + lilyopts += ' --header=texidoc' + texfiles = string.join (tex) + cmd = string.join ((lilypond_binary, lilyopts, g_extra_opts, + texfiles)) + + ly.lilypond_version_check (lilypond_binary, '@TOPLEVEL_VERSION@') + + 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 = '(( %s >&2 ) >&- )' % cmd + 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) @@ -1096,133 +1429,39 @@ def update_file (body, 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-lilypond@gnu.org. - -Written by Tom Cato Amundsen and -Han-Wen Nienhuys -""") - - 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\n' % basename)) n.append (c) return n @@ -1232,7 +1471,7 @@ def check_texidoc (chunks): 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 @@ -1247,50 +1486,66 @@ def fix_epswidth (chunks): 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 = "" + 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 () @@ -1299,37 +1554,48 @@ def do_file(input_filename): 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': @@ -1340,29 +1606,44 @@ for opt in options: 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?