X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Flilypond-book.py;h=65c025feda91412b8098c027b216cfd7c837c5a0;hb=44da0becc0a2288abf9fd8c8cae324bf3443a33d;hp=7578ef81a4abd4d29b715fb3ce7e4280b5d30dde;hpb=2086beff8cd9949318c97a2a531edb8f04f45f8c;p=lilypond.git
diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py
index 7578ef81a4..65c025feda 100644
--- a/scripts/lilypond-book.py
+++ b/scripts/lilypond-book.py
@@ -1,1539 +1,1461 @@
#!@PYTHON@
-# vim: set noexpandtab:
-# 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.
-#
+'''
+Example usage:
-#
-# 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 build step by step: first ignore and verbatim commands are handled,
-# delivering a list of chunks.
-#
-# then all chunks containing lilypnod 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.
-#
+test:
+ lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK
+convert-ly on book:
+ lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK
-# This is was the idea for handling of comments:
+classic lilypond-book:
+ lilypond-book --process="lilypond" BOOK.tely
+TODO:
+ * ly-options: intertext?
+ * --linewidth?
+ * eps in latex / eps by lilypond -b ps?
+ * check latex parameters, twocolumn, multicolumn?
+ * use --png --ps --pdf for making images?
-# 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.
-#
+ * Converting from lilypond-book source, substitute:
+ @mbinclude foo.itely -> @include foo.itely
+ \mbinput -> \input
-# 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.
-#
-# Then lines that are commented out with % (latex) and @c (Texinfo)
-# are put into chunks marked 'ignore'. This cannot be done before
-# searching for the lilypond-blocks because % is also the comment character
-# for lilypond.
-#
-# The the rest of the rexeces are searched for. They don't have to test
-# if they are on a commented out line.
+'''
+import __main__
import glob
import stat
import string
-
-################################################################
# Users of python modules should include this snippet
# and customize variables below.
-# We'll suffer this path init stuff as long as we don't install our
-# python packages in .*?)
+ />)''',
+
+ 'lilypond_block':
+ r'''(?msx)
+ (?P
.*?)
+
)
+ \s)''',
+
+ 'singleline_comment':
+ no_match,
+
+ 'verb':
+ r'''(?x)
+ (?P
.*?
))''',
+
+ 'verbatim':
+ r'''(?x)
+ (?s)
+ (?P\s.*?
\s))''',
+ },
+
+ ##
+ LATEX: {
+ 'include':
+ r'''(?smx)
+ ^[^%\n]*?
+ (?P.*?)
+ })''',
+
+ 'lilypond_block':
+ r'''(?smx)
+ ^[^%\n]*?
+ (?P
.*?)
+ ^[^%\n]*?
+ \\end\s*{lilypond})''',
+
+ 'lilypond_file':
+ r'''(?smx)
+ ^[^%\n]*?
+ (?P
+ %.*$\n+))''',
+
+ 'verb':
+ r'''(?mx)
+ ^[^%\n]*?
+ (?P
+ \\verb(?P
.)
+ .*?
+ (?P=del)))''',
+
+ 'verbatim':
+ r'''(?msx)
+ ^[^%\n]*?
+ (?P
+ \\begin\s*{verbatim}
+ .*?
+ \\end\s*{verbatim}))''',
+ },
+
+ ##
+ TEXINFO: {
+ 'include':
+ r'''(?mx)
+ ^(?P
.*?)
+ })''',
+
+ 'lilypond_block':
+ r'''(?msx)
+ ^(?P
.*?)
+ ^@end\s+lilypond)\s''',
+
+ 'lilypond_file':
+ r'''(?mx)
+ ^(?P
+ @ignore\s
+ .*?
+ @end\s+ignore))\s''',
+
+ 'singleline_comment':
+ r'''(?mx)
+ ^.*
+ (?P
+ @c([ \t][^\n]*|)\n))''',
+
+ # Don't do this: It interferes with @code{@{}.
+ # 'verb': r'''(?P
@code{.*?})''',
+
+ 'verbatim':
+ r'''(?sx)
+ (?P
+ @example
+ \s.*?
+ @end\s+example\s))''',
+ },
+}
-default_music_fontsize = 16
-default_text_fontsize = 12
-paperguru = None
-
-################################################################
-# Dimension handling for LaTeX.
-#
-class LatexPaper:
- def __init__ (self):
- self.m_document_preamble = []
- self.m_num_cols = 1
- self.m_multicols = 1
-
- def find_latex_dims (self):
- if g_outdir:
- fname = os.path.join (g_outdir, "lily-tmp.tex")
- else:
- 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:"))
-
- #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])
-
- 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!'
-
- def get_linewidth (self):
- if self.m_num_cols == 1:
- w = self.m_textwidth
- else:
- 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):
- self.m_papersize = 'letterpaper'
- self.m_fontsize = 12
- def get_linewidth (self):
- return texi_linewidths[self.m_papersize][self.m_fontsize]
-
-def mm2pt (x):
- return x * 2.8452756
-def in2pt (x):
- return x * 72.26999
-def em2pt (x, fontsize = 10):
- return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x
-def ex2pt (x, fontsize = 10):
- return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x
-
-def pt2pt (x):
- return x
-
-dimension_conversion_dict ={
- 'mm': mm2pt,
- 'cm': lambda x: mm2pt (10*x),
- 'in': in2pt,
- 'em': em2pt,
- 'ex': ex2pt,
- 'pt': pt2pt
- }
-
-# 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)]
-
- value = conv (num)
+format_res = {
+ HTML: {
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'option_sep': '\s*',
+ },
- elif re.match ("^[0-9.]+$",value):
- value = float (value)
+ LATEX: {
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'option_sep': '\s*,\s*',
+ },
- return value
+ TEXINFO: {
+ 'intertext': r',?\s*intertext=\".*?\"',
+ 'option_sep': '\s*,\s*',
+ },
+}
-texi_linewidths = {
- 'afourpaper': {12: mm2pt (160)},
- 'afourwide': {12: in2pt (6.5)},
- 'afourlatex': {12: mm2pt (150)},
- 'smallbook': {12: in2pt (5)},
- 'letterpaper': {12: in2pt (6)}}
+# Options without a pattern in ly_options.
+simple_options = [
+ EXAMPLEINDENT,
+ FRAGMENT,
+ NOFRAGMENT,
+ NOINDENT,
+ PRINTFILENAME,
+ TEXIDOC,
+ VERBATIM
+]
+
+ly_options = {
+ ##
+ NOTES: {
+ RELATIVE: r'''\relative c%(relative_quotes)s''',
+ },
+
+ ##
+ PAPER: {
+ INDENT: r'''indent = %(indent)s''',
+
+ LINEWIDTH: r'''linewidth = %(linewidth)s''',
+
+ QUOTE: r'''linewidth = %(linewidth)s - 2.0 * %(exampleindent)s''',
+
+ RAGGEDRIGHT: r'''raggedright = ##t''',
+ },
+
+ ##
+ LAYOUT: {
+ NOTIME: r'''\context {
+ \Staff
+ \remove Time_signature_engraver
+ }''',
+ },
+
+ ##
+ PREAMBLE: {
+ STAFFSIZE: r'''#(set-global-staff-size %(staffsize)s)''',
+ },
+}
-html_linewidths = {
- 'afourpaper': {12: mm2pt (160)},
- 'afourwide': {12: in2pt (6.5)},
- 'afourlatex': {12: mm2pt (150)},
- 'smallbook': {12: in2pt (5)},
- 'letterpaper': {12: in2pt (6)}}
+output = {
+ ##
+ HTML: {
+ FILTER: r'''
+ ''',
+ OUTPUT: r'''
+ , but
- ## inline music doesn't.
- ## possibly other center options?
- 'output-html': r'''
-
- below breaks inline images...
- 'output-texi-noquote': r'''@tex
-\catcode`\@=12
+ ##
+ LATEX: {
+ OUTPUT: r'''{%%
\parindent 0pt
-\def\lilypondbook{}
-\input %(fn)s.tex
-\catcode`\@=0
-@end tex
-@html
-
-@end html
-''',
- 'output-texi-quoted': r'''@quotation
-@tex
\catcode`\@=12
-\def\lilypondbook{}
-\input %(fn)s.tex
-\catcode`\@=0
-@end tex
-@html
-
- %s
-
-''',
- 'html' : {
+ PRINTFILENAME: '',
- '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
+ QUOTE: r'''
+%(str)s
+
''',
- },
+ VERBATIM: r'''
+%(verb)s
''',
+ },
- 'latex': {
-
- 'output-lilypond-fragment' : r'''\begin[eps,singleline,%s]{lilypond}
- \context Staff <
- \context Voice{
- %s
- }
- >
-\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}}',
- '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-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
-
-@end html
-@end quotation
+\ifx\preLilyPondExample \undefined
+ \relax
+\else
+ \preLilyPondExample
+\fi
+\def\lilypondbook{}%%
+\input %(base)s.tex
+\ifx\postLilyPondExample \undefined
+ \relax
+\else
+ \postLilyPondExample
+\fi
+}''',
+
+ PRINTFILENAME: '''\\texttt{%(filename)s}
+ ''',
+
+ QUOTE: r'''\begin{quotation}
+%(str)s
+\end{quotation}
''',
- }
-
- }
-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
\s.*?
\s)''',
- 'verb': r'''(?P.*?
)''',
- 'lilypond-file': r'(?m)(?P.*?)/>)',
- 'lilypond-block': r'''(?ms)(?P
.*?)
)\s",
- 'singleline-comment': no_match,
- 'numcols': no_match,
- 'multicols': no_match,
- 'ly2dvi': r'(?m)(?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.*?)})',
- 'lilypond-block': r"(?sm)^[^%\n]*?(?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
^%.*$\n+))",
- 'numcols': r"(?P
\\(?P
\\(?P
@example\s.*?@end example\s)''',
- 'verb': r'''(?P
@code{.*?})''',
- 'lilypond-file': '(?m)^(?P
.*?)})',
- 'lilypond-block': r'''(?ms)^(?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
@c.*$\n+))",
- 'numcols': no_match,
- 'multicols': no_match,
- 'ly2dvi': no_match,
- }
- }
+ VERBATIM: r'''\noindent
+\begin{verbatim}
+%(verb)s\end{verbatim}
+''',
+ FILTER: r'''\begin{lilypond}[%(options)s]
+%(code)s
+\end{lilypond}''',
+ },
-for r in re_dict.keys ():
- olddict = re_dict[r]
- newdict = {}
- for k in olddict.keys ():
- try:
- newdict[k] = re.compile (olddict[k])
- except:
- print 'invalid regexp: %s' % olddict[k]
+ ##
+ TEXINFO: {
+ FILTER: r'''@lilypond[%(options)s]
+%(code)s
+@lilypond''',
- ## we'd like to catch and reraise a more
- ## detailed error, but alas, the exceptions
- ## changed across the 1.5/2.1 boundary.
+ OUTPUT: r'''@noindent
+@image{%(base)s,,,[image of music],%(ext)s}''',
- raise "Invalid re"
- re_dict[r] = newdict
+ PRINTFILENAME: '''@file{%(filename)s}
+ ''',
+ QUOTE: r'''@quotation
+%(str)s@end quotation
+''',
-def uniq (list):
- list.sort ()
- s = list
- list = []
- for x in s:
- if x not in list:
- list.append (x)
- return list
+ NOQUOTE: r'''@format
+%(str)s@end format
+''',
+ VERBATIM: r'''@exampleindent 0
+@example
+%(verb)s@end example
+''',
+ },
+}
-def get_output (name):
- return output_dict[format][name]
+PREAMBLE_LY = r'''%%%% Generated by %(program_name)s
+%%%% Options: [%(option_string)s]
-def get_re (name):
- return re_dict[format][name]
+#(set! toplevel-score-handler ly:parser-print-score)
+#(set! toplevel-music-handler (lambda (p m)
+ (ly:parser-print-score
+ p (ly:music-scorify m p))))
-def bounding_box_dimensions (fname):
- if g_outdir:
- fname = os.path.join (g_outdir, fname)
- try:
- 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)
- 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))
- else:
- return (0,0)
-
-def error (str):
- 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.'''
- music_size = default_music_fontsize
- if g_force_music_fontsize:
- music_size = g_force_music_fontsize
- indent = ''
- linewidth = ''
- notime = ''
- for o in opts:
- if not g_force_music_fontsize:
- m = re.match ('([0-9]+)pt', o)
- if m:
- music_size = string.atoi (m.group (1))
-
- m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o)
- if m:
- f = float (m.group (1))
- indent = 'indent = %f\\%s' % (f, m.group (2))
+#(define version-seen? #t)
+%(preamble_string)s
- 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))
+\paper {
+ #(define dump-extents #t)
+ %(paper_string)s
+}
- if re.search ('\\\\score', body):
- is_fragment = 0
- else:
- is_fragment = 1
- if 'fragment' in opts:
- is_fragment = 1
- if 'nofragment' in opts:
- is_fragment = 0
-
- if is_fragment and not 'multiline' in opts:
- opts.append ('singleline')
-
- if '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
+\layout {
+ %(layout_string)s
}
'''
- for o in opts:
- m= re.search ('relative(.*)', o)
- v = 0
- if m:
- try:
- v = string.atoi (m.group (1))
- except ValueError:
- pass
-
- v = v + 1
- pitch = 'c'
- if v < 0:
- pitch = pitch + '\,' * v
- elif v > 0:
- pitch = pitch + '\'' * v
-
- body = '\\relative %s { %s }' % (pitch, body)
-
- if is_fragment:
- body = r'''
-\score {
- \notes {
-%s
- }
-}
-''' % body
-
- opts = uniq (opts)
- optstring = string.join (opts, ' ')
- optstring = re.sub ('\n', ' ', optstring)
- body = r'''
-%% Generated automatically by: lilypond-book.py
-%% options are %s
-\include "paper%d.ly"
-\paper {
- %s
- %s
- %s
+FRAGMENT_LY = r'''
+%(notes_string)s
+{
+%% ly snippet contents follows:
+%(code)s
+%% end ly snippet
}
-''' % (optstring, music_size, linewidth, indent, notime) + body
-
- # ughUGH not original options
- return body
-
-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.
- # 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 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 = []
- if 'twocolumn' in options:
- paperguru.m_num_cols = 2
- break
-
-
- # 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
- 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]:
- if c[0] == 'input':
- for s in ('afourpaper', 'afourwide', 'letterpaper',
- 'afourlatex', 'smallbook'):
- if string.find (c[1], "@%s" % s) != -1:
- paperguru.m_papersize = s
-
-
-def scan_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):
- 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])
- if m:
- pre_b = 1
- if chunk[0] == 'input':
- 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])
- if m:
- graphics_b = 1
- x = 0
- 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')))
- if not post_b:
- chunks.insert (x, ('input', get_output ('output-default-post')))
- if not graphics_b:
- 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 (), '
%s
-
-
%s
''' % (original_name,original_name, preview, explanatory_para, menu)
-
- open (base + '.html','w'). write (separate_menu)
-
- inline_menu = '' % (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
- eps = []
- tex = []
- png = []
-
- for c in chunks:
- if c[0] != 'lilypond':
- continue
- base = c[4]
- exts = c[3]
- for e in exts:
- if e == 'eps':
- eps.append (base)
- elif e == 'tex':
- #ugh
- if base + '.ly' not in tex:
- tex.append (base + '.ly')
- elif e == 'png' and g_do_pictures:
- png.append (base)
- d = os.getcwd ()
- if g_outdir:
- os.chdir (g_outdir)
- if tex:
- # fixme: be sys-independent.
- def incl_opt (x):
- 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)
- if do_deps:
- lilyopts += ' --dependencies'
- if g_outdir:
- 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)
-
- for i in depfiles:
- f =open (i)
- text=f.read ()
- f.close ()
- text=re.sub ('\n([^:\n]*):',
- '\n' + foutn + ':', text)
- f = open (i, 'w')
- f.write (text)
- f.close ()
-
- 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_preview, png)
- os.chdir (d)
-
-
-def update_file (body, name):
- '''
- write the body if it has changed. Return whether BODY has changed.
- '''
- same = 0
- try:
- f = open (name)
- fs = f.read (-1)
- same = (fs == body)
- except:
- pass
+ if not status:
+ status = 0
+ output = stdout.read ()
+ status = stdout.close ()
+ error = stderr.read ()
- if not same:
- f = open (name , 'w')
- f.write (body)
- f.close ()
+ if not status:
+ status = 0
+ signal = 0x0f & status
+ if status or (not output and error):
+ exit_status = status >> 8
+ ly.error (_ ("`%s' failed (%d)") % (cmd, exit_status))
+ ly.error (_ ("The error log is as follows:"))
+ sys.stderr.write (error)
+ sys.stderr.write (stderr.read ())
+ ly.exit (status)
- return not same
+ if verbose_p:
+ ly.progress ('\n')
+ return output
-def write_deps (fn, target, chunks):
- global read_files
- 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)
+def run_filter (s):
+ return filter_pipe (s, filter_cmd)
+def is_derived_class (cl, baseclass):
+ if cl == baseclass:
+ return 1
+ for b in cl.__bases__:
+ if is_derived_class (b, baseclass):
+ return 1
+ return 0
- ## 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
-
+def process_snippets (cmd, ly_snippets, texstr_snippets, png_snippets):
+ ly_names = filter (lambda x: x,
+ map (Lilypond_snippet.basename, ly_snippets))
+ texstr_names = filter (lambda x: x,
+ map (Lilypond_snippet.basename, texstr_snippets))
+ png_names = filter (lambda x: x,
+ map (Lilypond_snippet.basename, png_snippets))
- f.write ('\n')
- f.close ()
- read_files = []
+ status = 0
+ def my_system (cmd):
+ status = ly.system (cmd,
+ ignore_error = 1, progress_p = 1)
-def check_texidoc (chunks):
- 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') \
- and 'notexidoc' not in opts:
- body = '\n@include %s.texidoc\n' % basename + body
- c = (type, body, opts, todo, basename)
- n.append (c)
- return n
+ if status:
+ ly.error ('Process %s exited unsuccessfully.' % cmd)
+ raise Compile_error
+ # UGH
+ # the --process=CMD switch is a bad idea
+ # it is too generic for lilypond-book.
+ if texstr_names and re.search ('^[0-9A-Za-z/]*lilypond', cmd):
+
+ my_system (string.join ([cmd + ' --backend texstr ' ] + texstr_names))
+ for l in texstr_names:
+ my_system ('latex %s.texstr' % l)
+
-## what's this? Docme --hwn
-##
-def fix_epswidth (chunks):
- newchunks = []
- for c in chunks:
- if c[0] != 'lilypond' or 'eps' not in c[2]:
- newchunks.append (c)
- continue
+ if ly_names:
+ my_system (string.join ([cmd] + ly_names))
+
- mag = 1.0
- for o in c[2]:
- m = re.match ('magnification=([0-9.]+)', o)
- if m:
- mag = string.atof (m.group (1))
- def replace_eps_dim (match, lmag = mag):
- filename = match.group (1)
- dims = bounding_box_dimensions (filename)
+ if format == HTML or format == TEXINFO:
+ for i in png_names:
+ if not os.path.exists (i + '.eps') \
+ and os.path.exists (i + '.tex'):
+ to_eps (i)
+ ly.make_ps_images (i + '.eps',
+ resolution = 110)
- return '%fpt' % (dims[0] *lmag)
+# elif os.path.exists (i + '.ps'):
+# ly.make_ps_images (i + '.ps', resolution = 110)
- body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1])
- newchunks.append (('lilypond', body, c[2], c[3], c[4]))
+LATEX_DOCUMENT = r'''
+%(preamble)s
+\begin{document}
+\typeout{textwidth=\the\textwidth}
+\typeout{columnsep=\the\columnsep}
+\makeatletter\if@twocolumn\typeout{columns=2}\fi\makeatother
+\end{document}
+'''
- return newchunks
+# Do we need anything else besides `textwidth'?
+def get_latex_textwidth (source):
+ m = re.search (r'''(?P