#!@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.
-#
+ 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.)
-#
-# 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.
-#
+ 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 is was the idea for handling of comments:
+ 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.
+
+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
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 ()
-#temp_dir = os.path.join (original_dir, '%s.dir' % program_name)
-#urg
-temp_dir = '/tmp'
-keep_temp_dir_p = 0
+
+
preview_resolution = 90
## FIXME
-## ly2dvi: silly name?
## do -P or -p by default?
##help_summary = _ ("Run LilyPond using LaTeX for titling")
help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document")
(_ ("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-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', _ ("this help")),
+ ('', '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")),
- ('', '', 'read-lys', _ ("don't write ly files.")),
(_ ("FILE"), 'o', 'outname', _ ("filename main output file")),
(_ ("FILE"), '', 'outdir', _ ("where to place generated files")),
(_ ('RES'), '', 'preview-resolution',
_ ("set the resolution of the preview to RES")),
- ('', 'V', 'verbose', _ ("verbose")),
+ ('', 'V', 'verbose', _ ("be verbose")),
('', 'v', 'version', _ ("print version information")),
('', 'w', 'warranty', _ ("show warranty and copyright")),
]
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')
+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'
+ lilypond_binary = 'lilypond-bin'
g_dep_prefix = ''
g_outdir = ''
g_force_music_fontsize = 0
-g_read_lys = 0
g_do_pictures = 1
g_do_music = 1
g_make_html = 0
cmd = "latex '\\nonstopmode \input %s'" % fname
# Ugh. (La)TeX writes progress and error messages on stdout
# Redirect to stderr
- cmd += ' 1>/dev/stderr'
+ cmd = '(( %s >&2 ) >&- )' % cmd
status = ly.system (cmd, ignore_error = 1)
signal = 0xf & status
exit_status = status >> 8
ly.error (_ ("LaTeX failed."))
ly.error (_ ("The error log is as follows:"))
- #URG see ly2dvi
+ #URG see lilypond
try:
lns = open ('lily-tmp.log').readlines ()
except:
## inline music doesn't.
## possibly other center options?
'output-html': r'''
-<a href="%(fn)s.png">
-<img align="center" valign="center" border="0" src="%(fn)s.png" alt="[picture of music]"></a>
-''',
+%(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+:\\
%% %s
'output-small-verbatim': r'''{\small\begin{verbatim}
%s\end{verbatim}}
''',
- 'output-default-post': "\\def\postLilypondExample{}\n",
- 'output-default-pre': "\\def\preLilypondExample{}\n",
+ '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-eps': '\\noindent\includegraphics{%(fn)s}',
'output-noinline': r'''
%% generated: %(fn)s.eps
''',
- 'output-latex-quoted': r'''{\preLilypondExample
+ 'output-latex-quoted': r'''{\preLilyPondExample
+\def\lilypondbook{}
\input %(fn)s.tex
-\postLilypondExample}''',
+\postLilyPondExample}''',
'output-latex-noquote': r'''{\parindent 0pt
-\preLilypondExample
+\preLilyPondExample
+\def\lilypondbook{}
\input %(fn)s.tex
-\postLilypondExample}''',
+\postLilyPondExample}''',
'pagebreak': r'\pagebreak',
},
'texi' : {
- 'output-filename' : r'''@ifnothtml
+ 'output-filename' : r'''
+@ifnothtml
@file{%s}:@*
@end ifnothtml
@ifhtml
\catcode`\@=0
@end tex
@html
-<p><a href="%(fn)s.png">
-<img border=0 src="%(fn)s.png" alt="[picture of music]">
-</a><p>
+<p>%(htmlimages)s
+<p>
@end html
''',
'output-texi-quoted': r'''@quotation
\catcode`\@=0
@end tex
@html
-<a href="%(fn)s.png">
-<img border=0 src="%(fn)s.png" alt="[picture of music]">
-</a>
+<p>%(htmlimages)s
+<p>
@end html
@end quotation
''',
'lilypond-file': r'(?m)^[^%\n]*?(?P<match>\\lilypondfile\s*(\[(?P<options>.*?)\])?\s*\{(?P<filename>.+)})',
'lilypond' : r'(?m)^[^%\n]*?(?P<match>\\lilypond\s*(\[(?P<options>.*?)\])?\s*{(?P<code>.*?)})',
'lilypond-block': r"(?sm)^[^%\n]*?(?P<match>\\begin\s*(\[(?P<options>.*?)\])?\s*{lilypond}(?P<code>.*?)\\end{lilypond})",
- 'def-post-re': r"\\def\\postLilypondExample",
- 'def-pre-re': r"\\def\\preLilypondExample",
+ '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,
# why do we have distinction between @mbinclude and @include?
'texi': {
- 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude[ \n\t]+(?P<filename>[^\t \n]*))',
+ 'include': '(?m)^[^%\n]*?(?P<match>@mbinclude\s+(?P<filename>\S*))',
'input': no_match,
'header': no_match,
'preamble-end': no_match,
def compose_full_body (body, opts):
- '''Construct the lilypond code to send to Lilypond.
+ '''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:
if is_fragment and not 'multiline' in opts:
opts.append ('singleline')
- if 'singleline' in opts:
+ if 'raggedright' in opts or 'singleline' in opts:
if not linewidth:
linewidth = 'raggedright = ##t'
if not indent:
}
'''
+ orig_name = ''
for o in opts:
m= re.search ('relative(.*)', o)
v = 0
pitch = pitch + '\'' * v
body = '\\relative %s { %s }' % (pitch, body)
-
+ m =re.search ("filename=(.*)", o)
+ if m:
+ orig_name = m.group (1)
+
if is_fragment:
body = r'''
\score {
body = r'''
%% Generated automatically by: lilypond-book.py
%% options are %s
-\include "paper%d.ly"
+#(set-global-staff-size %d)
+
\paper {
%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
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])
+ options = re.split (r',\s*', m.group (1)[1:-1])
else:
options = []
if 'twocolumn' in options:
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)]
+
def make_ly2dvi_block (m):
'''
return newchunks
def determine_format (str):
+ """
+
+ SIDE EFFECT! This sets FORMAT and PAPERGURU
+
+ """
+
global format
if format == '':
html = re.search ('(?i)<[dh]tml', str[:200])
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
+ 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.
- TODO has format [basename, extension, extension, ... ]
+ The chunk pertaining to the lilypond output
+ has the format (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE),
+ where TODO has format [basename, extension, extension, ... ]
'''
+
(type, body, opts) = chunk
assert type == 'lilypond'
file_body = compose_full_body (body, opts)
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')
+ basename = basename + "-t%i" % taken_file_names[basename]
+ update_file (file_body, os.path.join (g_outdir, basename) + '.ly')
needed_filetypes = ['tex']
if format == 'html' or g_make_html:
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'):
+ if 'tex' in needed_filetypes and must_rebuild (pathbase, '.ly', '.tex'):
todo.append ('tex')
- if 'eps' in needed_filetypes and f (pathbase, '.tex', '.eps'):
+ if 'eps' in needed_filetypes and must_rebuild (pathbase, '.tex', '.eps'):
todo.append ('eps')
- if 'png' in needed_filetypes and f (pathbase, '.eps', '.png'):
+ if 'png' in needed_filetypes and must_rebuild (pathbase, '.eps', '.png'):
todo.append ('png')
- newbody = ''
+ 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), basename + '.ly', 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 'smallverbatim' in opts:
- newbody = newbody + output_verbatim (body, 1)
+ newbody += output_verbatim (body, 1)
elif 'verbatim' in opts:
- newbody = newbody + output_verbatim (body, 0)
+ newbody += output_verbatim (body, 0)
for o in opts:
m = re.search ('intertext="(.*?)"', o)
if 'noinline' in opts:
s = 'output-noinline'
elif format == 'latex':
- if 'eps' in opts:
+ if 'quote' in opts:
+ s = 'output-latex-quoted'
+ elif 'eps' in opts:
s = 'output-eps'
else:
- if 'quote' in opts:
- s = 'output-latex-quoted'
- else:
- s = 'output-latex-noquote'
+ s = 'output-latex-noquote'
elif format == 'texi':
if 'quote' in opts:
s = 'output-texi-quoted'
s = 'output-texi-noquote'
else: # format == 'html'
s = 'output-html'
- newbody = newbody + get_output (s) % {'fn': basename }
- return ('lilypond', newbody, opts, todo, basename)
+ def html_pages (basename):
+ pat = os.path.join (g_outdir, "%s-page*.png"% basename)
+
+ files = glob.glob (pat)
+
+
+ template = '''<img align="center" valign="center"
+ border="0" src="%s" alt="[picture of music]">'''
+
+ str = ''
+ if files == []:
+ files = [basename+'.png' ]
+ else:
+ files = map (os.path.basename, files)
+
+ for f in files:
+ str += template % f
+
+ str = '<a href="%s.ly">%s</a>' % (basename, str)
+
+ return str
+
+
+ newbody = newbody + get_output (s) % {'fn': basename,
+ 'htmlimages': html_pages(basename)
+ }
+
+ if filename_chunk:
+ return_chunks += [filename_chunk]
+
+ return_chunks += [('lilypond', newbody, opts, todo, basename)]
+
+ return return_chunks
+
+def format_lilypond_output_bodies (chunks):
+ newchunks = []
+ for c in chunks:
+
+ if c[0] == 'lilypond':
+ newchunks += format_lilypond_block (c)
+ else:
+ newchunks.append (c)
+
+ return newchunks
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):
outname = base + '.ly'
changed = update_file (content, outname)
- preview = base + ".png"
- if changed or not os.path.isfile (preview):
+ 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_page_images (base)
+ ly.make_ps_images (base + '.ps')
ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base))
def size_str (fn):
menu = ''
page_files = glob.glob ('%s-page*.png' % base)
- for p in string.split (page_files, '\n'):
+ for p in page_files:
p = p.strip()
if os.path.isfile (p):
sz = size_str (p)
open (base + '.html','w'). write (separate_menu)
- inline_menu = '<p/><a href="%s.html"><img src="%s"><p/></a>' % (base, original_name, preview)
+ inline_menu = '<p/><a href="%s.html"><img alt="%s" src="%s"></a><p/>' % (base, original_name, preview)
return ('ly2dvi', inline_menu)
for c in chunks:
if c[0] != 'lilypond':
continue
+
base = c[4]
exts = c[3]
for e in exts:
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)
#
cmd = r"latex '\nonstopmode \input %s'" % file
# Ugh. (La)TeX writes progress and error messages on stdout
# Redirect to stderr
- cmd += ' 1>/dev/stderr'
+ cmd = '(( %s >&2 ) >&- )' % cmd
+
ly.system (cmd)
- ly.system ("dvips -E -o %s.eps %s" % (file, file))
+ ly.system ("dvips -Ppdf -u+lilypond.map -E -o %s.eps %s" % (file, file))
map (to_eps, eps)
- map (ly.make_preview, png)
+ for p in png:
+ ly.make_ps_images (p + '.eps', resolution=110)
os.chdir (d)
read_files = []
def check_texidoc (chunks):
+ ## TODO: put file name in front of texidoc.
+ ##
n = []
for c in chunks:
if c[0] == 'lilypond':
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( ('input', '\n@include %s.texidoc\n\n' % basename))
n.append (c)
return n
chunks = chop_chunks (chunks, 'preamble-end', do_preamble_end)
chunks = chop_chunks (chunks, 'numcols', do_columns)
chunks = chop_chunks (chunks, 'multicols', do_multicols)
- #print "-" * 50
- #for c in chunks: print "c:", c;
- #sys.exit ()
+
scan_preamble (chunks)
chunks = process_lilypond_blocks (chunks)
chunks = process_ly2dvi_blocks (chunks)
compile_all_files (chunks)
chunks = fix_epswidth (chunks)
+
+ chunks = format_lilypond_output_bodies (chunks)
global format
if format == 'texi':
chunks = check_texidoc (chunks)
+
x = 0
chunks = completize_preamble (chunks)
elif o == '--outname' or o == '-o':
if len (files) > 1:
#HACK
- sys.stderr.write ("Lilypond-book is confused by --outname on multiple files")
+ sys.stderr.write ("lilypond-book is confused by --outname on multiple files")
sys.exit (1)
outname = a
elif o == '--help' or o == '-h':
g_do_pictures = 0
elif o == '--no-music':
g_do_music = 0
- elif o == '--read-lys':
- g_read_lys = 1
elif o == '--outdir':
g_outdir = a
elif o == '--warranty' or o == '-w':
ly.setup_environment ()
+
for input_filename in files:
do_file (input_filename)