X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=python%2Fbook_snippets.py;h=cbf09a7a28f59bcf47cb8103883c2d511bedc510;hb=015aa1a31460db92a554f9d59190acdc5c39057b;hp=a19a5796d7e330eb74ab87053791963b6d40450d;hpb=7e222406df49d159a021ee88610589e7f73086d1;p=lilypond.git diff --git a/python/book_snippets.py b/python/book_snippets.py index a19a5796d7..cbf09a7a28 100644 --- a/python/book_snippets.py +++ b/python/book_snippets.py @@ -38,14 +38,11 @@ EXAMPLEINDENT = 'exampleindent' FILENAME = 'filename' FILTER = 'filter' FRAGMENT = 'fragment' -LANG = 'lang' ## TODO: This is handled nowhere! LAYOUT = 'layout' -LILYQUOTE = 'lilyquote' LINE_WIDTH = 'line-width' NOFRAGMENT = 'nofragment' NOGETTEXT = 'nogettext' NOINDENT = 'noindent' -NOQUOTE = 'noquote' INDENT = 'indent' NORAGGED_RIGHT = 'noragged-right' NOTES = 'body' @@ -53,6 +50,7 @@ NOTIME = 'notime' OUTPUT = 'output' OUTPUTIMAGE = 'outputimage' PAPER = 'paper' +PAPERSIZE = 'papersize' PREAMBLE = 'preamble' PRINTFILENAME = 'printfilename' QUOTE = 'quote' @@ -67,7 +65,6 @@ VERSION = 'lilypondversion' # NOTIME and NOGETTEXT have no opposite so they aren't part of this # dictionary. -# NOQUOTE is used internally only. no_options = { NOFRAGMENT: FRAGMENT, NOINDENT: INDENT, @@ -91,7 +88,6 @@ simple_options = [ PRINTFILENAME, DOCTITLE, TEXIDOC, - LANG, VERBATIM, FILENAME, ALT, @@ -112,10 +108,10 @@ snippet_options = { ## PAPER: { + PAPERSIZE: r'''#(set-paper-size "%(papersize)s")''', INDENT: r'''indent = %(indent)s''', LINE_WIDTH: r'''line-width = %(line-width)s''', QUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''', - LILYQUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''', RAGGED_RIGHT: r'''ragged-right = ##t''', NORAGGED_RIGHT: r'''ragged-right = ##f''', }, @@ -143,24 +139,9 @@ snippet_options = { -FRAGMENT_LY = r''' -%(notes_string)s -{ - - -%% **************************************************************** -%% ly snippet contents follows: -%% **************************************************************** -%(code)s - - -%% **************************************************************** -%% end ly snippet -%% **************************************************************** -} -''' - def classic_lilypond_book_compatibility (key, value): + if key == 'lilyquote': + return (QUOTE, value) if key == 'singleline' and value == None: return (RAGGED_RIGHT, None) @@ -181,6 +162,8 @@ def classic_lilypond_book_compatibility (key, value): return (None, None) +# TODO: Remove the 1mm additional padding in the line-width, once lilypond +# creates tighter cropped images! PREAMBLE_LY = '''%%%% Generated by %(program_name)s %%%% Options: [%(option_string)s] \\include "lilypond-book-preamble.ly" @@ -194,13 +177,16 @@ PREAMBLE_LY = '''%%%% Generated by %(program_name)s \paper { %(paper_string)s - force-assignment = #"" - line-width = #(- line-width (* mm %(padding_mm)f)) + %% offset the left padding, also add 1mm as lilypond creates cropped + %% images with a little space on the right + line-width = #(- line-width (* mm %(padding_mm)f) (* mm 1)) } \layout { %(layout_string)s } + +%(safe_mode_string)s ''' @@ -218,9 +204,22 @@ FULL_LY = ''' %% **************************************************************** ''' +FRAGMENT_LY = r''' +%(notes_string)s +{ + +%% **************************************************************** +%% ly snippet contents follows: +%% **************************************************************** +%(code)s +%% **************************************************************** +%% end ly snippet +%% **************************************************************** +} +''' @@ -396,13 +395,13 @@ class LilypondSnippet (Snippet): self.option_dict[option] = None - # If LINE_WIDTH is used without parameter, set it to default. + # Store if we have an explicit line-width given has_line_width = self.option_dict.has_key (LINE_WIDTH) if has_line_width and self.option_dict[LINE_WIDTH] == None: has_line_width = False del self.option_dict[LINE_WIDTH] - # TODO: Can't we do that more efficiently (built-in python func?) + # Use default options (i.e. auto-detected line-width, etc) for k in self.formatter.default_snippet_options: if k not in self.option_dict: self.option_dict[k] = self.formatter.default_snippet_options[k] @@ -413,22 +412,6 @@ class LilypondSnippet (Snippet): if has_relative and not self.option_dict.has_key (FRAGMENT): self.option_dict[FRAGMENT] = None - if not has_line_width: - if type == 'lilypond' or FRAGMENT in self.option_dict: - self.option_dict[RAGGED_RIGHT] = None - - if type == 'lilypond': - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] - else: - if RAGGED_RIGHT in self.option_dict: - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] - - if QUOTE in self.option_dict or type == 'lilypond': - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] - if not INDENT in self.option_dict: self.option_dict[INDENT] = '0\\mm' @@ -439,8 +422,7 @@ class LilypondSnippet (Snippet): # all settings before writing them in the \paper block. if not LINE_WIDTH in self.option_dict: if not QUOTE in self.option_dict: - if not LILYQUOTE in self.option_dict: - self.option_dict[LINE_WIDTH] = "#(- paper-width \ + self.option_dict[LINE_WIDTH] = "#(- paper-width \ left-margin-default right-margin-default)" def get_option_list (self): @@ -456,10 +438,6 @@ left-margin-default right-margin-default)" return self.option_list def compose_ly (self, code): - if FRAGMENT in self.option_dict: - body = FRAGMENT_LY - else: - body = FULL_LY # Defaults. relative = 1 @@ -551,15 +529,29 @@ left-margin-default right-margin-default)" elif relative > 0: relative_quotes += "'" * relative + # put paper-size first, if it exists + for i,elem in enumerate(compose_dict[PAPER]): + if elem.startswith("#(set-paper-size"): + compose_dict[PAPER].insert(0, compose_dict[PAPER].pop(i)) + break + paper_string = '\n '.join (compose_dict[PAPER]) % override layout_string = '\n '.join (compose_dict[LAYOUT]) % override notes_string = '\n '.join (compose_dict[NOTES]) % vars () preamble_string = '\n '.join (compose_dict[PREAMBLE]) % override padding_mm = self.global_options.padding_mm + if self.global_options.safe_mode: + safe_mode_string = "#(ly:set-option 'safe #t)" + else: + safe_mode_string = "" d = globals().copy() d.update (locals()) d.update (self.global_options.information) + if FRAGMENT in self.option_dict: + body = FRAGMENT_LY + else: + body = FULL_LY return (PREAMBLE_LY + body) % d def get_checksum (self): @@ -645,6 +637,11 @@ printing diff against existing file." % filename) os.makedirs (dst_path) os.link (src, dst) + def additional_files_to_consider (self, base, full): + return [] + def additional_files_required (self, base, full): + return [] + def all_output_files (self, output_dir, output_dir_files): """Return all files generated in lily_output_dir, a set. @@ -708,6 +705,8 @@ printing diff against existing file." % filename) if 'ddump-signature' in self.global_options.process_cmd: consider_file (systemfile + '.signature') + map (consider_file, self.additional_files_to_consider (base, full)) + map (require_file, self.additional_files_required (base, full)) return (result, missing) @@ -719,7 +718,7 @@ printing diff against existing file." % filename) """Pass input through cmd, and return the result.""" if self.global_options.verbose: - progress (_ ("Opening filter `%s'\n") % cmd) + progress (_ ("Running through filter `%s'\n") % cmd) # TODO: Use Popen once we resolve the problem with msvcrt in Windows: (stdin, stdout, stderr) = os.popen3 (cmd) @@ -732,16 +731,16 @@ printing diff against existing file." % filename) status = 0 output = stdout.read () status = stdout.close () - error = stderr.read () + err = stderr.read () if not status: status = 0 signal = 0x0f & status - if status or (not output and error): + if status or (not output and err): exit_status = status >> 8 ly.error (_ ("`%s' failed (%d)") % (cmd, exit_status)) ly.error (_ ("The error log is as follows:")) - ly.stderr_write (error) + ly.stderr_write (err) ly.stderr_write (stderr.read ()) exit (status) @@ -794,7 +793,9 @@ re_end_verbatim = re.compile (r'\s+%.*?end verbatim.*$', re.M) class LilypondFileSnippet (LilypondSnippet): def __init__ (self, type, match, formatter, line_number, global_options): LilypondSnippet.__init__ (self, type, match, formatter, line_number, global_options) - self.contents = file (BookBase.find_file (self.substring ('filename'), global_options.include_path)).read () + self.filename = self.substring ('filename') + self.ext = os.path.splitext (os.path.basename (self.filename))[1] + self.contents = file (BookBase.find_file (self.filename, global_options.include_path)).read () def get_snippet_code (self): return self.contents; @@ -810,18 +811,113 @@ class LilypondFileSnippet (LilypondSnippet): return s def ly (self): - name = self.substring ('filename') + name = self.filename return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s' % (name, self.contents)) def final_basename (self): if self.global_options.use_source_file_names: - base = os.path.splitext (os.path.basename (self.substring ('filename')))[0] + base = os.path.splitext (os.path.basename (self.filename))[0] return base else: return self.basename () +class MusicXMLFileSnippet (LilypondFileSnippet): + def __init__ (self, type, match, formatter, line_number, global_options): + LilypondFileSnippet.__init__ (self, type, match, formatter, line_number, global_options) + self.compressed = False + self.converted_ly = None + self.musicxml_options_dict = { + 'verbose': '--verbose', + 'lxml': '--lxml', + 'compressed': '--compressed', + 'relative': '--relative', + 'absolute': '--absolute', + 'no-articulation-directions': '--no-articulation-directions', + 'no-rest-positions': '--no-rest-positions', + 'no-page-layout': '--no-page-layout', + 'no-beaming': '--no-beaming', + 'language': '--language', + } + + def snippet_options (self): + return self.musicxml_options_dict.keys () + + def convert_from_musicxml (self): + name = self.filename + xml2ly_option_list = [] + for (key, value) in self.option_dict.items (): + cmd_key = self.musicxml_options_dict.get (key, None) + if cmd_key == None: + continue + if value == None: + xml2ly_option_list.append (cmd_key) + else: + xml2ly_option_list.append (cmd_key + '=' + value) + if ('.mxl' in name) and ('--compressed' not in xml2ly_option_list): + xml2ly_option_list.append ('--compressed') + self.compressed = True + opts = " ".join (xml2ly_option_list) + progress (_ ("Converting MusicXML file `%s'...\n") % self.filename) + + ly_code = self.filter_pipe (self.contents, 'musicxml2ly %s --out=- - ' % opts) + return ly_code + + def ly (self): + if self.converted_ly == None: + self.converted_ly = self.convert_from_musicxml () + name = self.filename + return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s' + % (name, self.converted_ly)) + + def additional_files_required (self, base, full): + result = []; + if self.compressed: + result.append (base + '.mxl') + else: + result.append (base + '.xml') + return result + + def write_ly (self): + base = self.basename () + path = os.path.join (self.global_options.lily_output_dir, base) + directory = os.path.split(path)[0] + if not os.path.isdir (directory): + os.makedirs (directory) + + # First write the XML to a file (so we can link it!) + if self.compressed: + xmlfilename = path + '.mxl' + else: + xmlfilename = path + '.xml' + if os.path.exists (xmlfilename): + diff_against_existing = self.filter_pipe (self.contents, 'diff -u %s - ' % xmlfilename) + if diff_against_existing: + warning (_ ("%s: duplicate filename but different contents of orginal file,\n\ +printing diff against existing file.") % xmlfilename) + ly.stderr_write (diff_against_existing) + else: + out = file (xmlfilename, 'w') + out.write (self.contents) + out.close () + + # also write the converted lilypond + filename = path + '.ly' + if os.path.exists (filename): + diff_against_existing = self.filter_pipe (self.full_ly (), 'diff -u %s -' % filename) + if diff_against_existing: + warning (_ ("%s: duplicate filename but different contents of converted lilypond file,\n\ +printing diff against existing file.") % filename) + ly.stderr_write (diff_against_existing) + else: + out = file (filename, 'w') + out.write (self.full_ly ()) + out.close () + file (path + '.txt', 'w').write ('image of music') + + + class LilyPondVersionString (Snippet): """A string that does not require extra memory.""" def __init__ (self, type, match, formatter, line_number, global_options): @@ -837,4 +933,5 @@ snippet_type_to_class = { 'lilypond': LilypondSnippet, 'include': IncludeSnippet, 'lilypondversion': LilyPondVersionString, + 'musicxml_file': MusicXMLFileSnippet, }