From: Jan Nieuwenhuizen Date: Sun, 25 Jan 2004 10:31:56 +0000 (+0000) Subject: Add script. X-Git-Tag: release/2.1.23~177 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=7a17091051ccce50a24ebcd7604d2f527e8c6de2;p=lilypond.git Add script. --- diff --git a/ChangeLog b/ChangeLog index 6258d86f2f..ba397ec07a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2004-01-25 Jan Nieuwenhuizen + + * scripts/filter-lilypond-book.py: Add script. + 2004-01-23 Jan Nieuwenhuizen * ly/engraver-init.ly: Set enclose_bounds to #1 (was: ##t). diff --git a/scripts/filter-lilypond-book.py b/scripts/filter-lilypond-book.py new file mode 100644 index 0000000000..4d92e4f9ad --- /dev/null +++ b/scripts/filter-lilypond-book.py @@ -0,0 +1,398 @@ +#!@PYTHON@ + +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 /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'] + while datadir[-1] == os.sep: + datadir= datadir[:-1] + +sys.path.insert (0, os.path.join (datadir, 'python')) + +# Customize these +#if __name__ == '__main__': + +import lilylib as ly +global _;_=ly._ +global re;re = ly.re + +# lilylib globals +program_version = '@TOPLEVEL_VERSION@' +#program_name = 'new-book' +program_name = 'filter-lilypond-book' +verbose_p = 0 +pseudo_filter_p = 0 +original_dir = os.getcwd () + + +# help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document") +help_summary = _ ("""Process ly snippets from lilypond-book source. Example usage: + + filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK + filter-lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK + +""") +copyright = ('Tom Cato Amundsen ', + 'Han-Wen Nienhuys ') + +option_definitions = [ + (_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")), + (_ ("FILTER"), 'F', 'filter', _ ("pipe snippets through FILTER [convert-ly -n -]")), + ('', 'h', 'help', _ ("print this help")), + (_ ("COMMAND"), 'P', 'process', _ ("process ly_files using COMMAND FILE...")), + ('', 'V', 'verbose', _ ("be verbose")), + ('', 'v', 'version', _ ("print version information")), + ('', 'w', 'warranty', _ ("show warranty and copyright")), + ] + +include_path = [os.getcwd ()] + +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' + + +format = 'latex' +filter_cmd = 'convert-ly --no-version --from=2.0.0 -' +#filter_cmd = 0 +#process_cmd = 'convert-ly --no-version --from=2.0.0' +process_cmd = 0 + +################################################################ +# 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 +no_match = 'a\ba' +re_dict = { + '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\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, + } + } + +def compose_ly (code, options): + m = re.search (r'''\\score''', code) + if not m and (not options \ + or not 'nofragment' in options \ + or 'fragment' in options): + body = r'''\score{\notes{ %(code)s }}''' % vars () + else: + body = code + ### todo: add options + return body + +## make source, index statics of Snippet? +index = 0 + +class Snippet: + def __init__ (self, type, index, match): + self.type = type + self.index = index + self.match = match + self.hash = 0 + + def start (self, s): + return self.index + self.match.start (s) + + def end (self, s): + return self.index + self.match.end (s) + + def substring (self, source, s): + return source[self.start (s):self.end (s)] + + def ly (self, source): + if self.type == 'lilypond-block' or self.type == 'lilypond': + return compose_ly (self.substring (source, 'code'), + self.match.group ('options')) + return '' + + def get_hash (self, source): + if not self.hash: + self.hash = abs (hash (self.substring (source, + 'code'))) + return self.hash + + def filename (self, source): + return 'lily-%d.ly' % self.get_hash (source) + + def write_ly (self, source): + h = open (self.filename (source), 'w') + h.write (self.ly (source)) + h.close () + + def outdated_p (self, source): + if 1: + return self + return None + +def find_snippets (s, type): + re = ly.re.compile (re_dict[format][type]) + i = 0 + snippets = [] + m = re.search (s[i:]) + while m: + snippets.append (Snippet (type, i, m)) + i = i + m.end (0) + m = re.search (s[i:]) + return snippets + +def filter_pipe (input, cmd): + if verbose_p: + ly.progress (_ ("Opening filter `%s\'") % cmd) + + stdin, stdout, stderr = os.popen3 (cmd) + stdin.write (input) + status = stdin.close () + + if not status: + status = 0 + output = stdout.read () + status = stdout.close () + error = stderr.read () + + 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) + + if verbose_p: + ly.progress ('\n') + + return output + +def run_filter (s): + return filter_pipe (s, filter_cmd) + +def compare_index (a, b): + return a.start (0) - b.start (0) + +# apply FUNC to every toplevel block in SNIPPETS, ie, enclosed +# snippets are skipped. return list with all non-empty return values +# of FUNC + +# Hmm, do we need enclosed snippets at all? Maybe use MAP_SNIPPETS +# once and use simple filter/map on that resulting toplevel list iso +# silly map_snippets/do_snippets. +def map_snippets (source, snippets, func): + global index + index = 0 + lst = [] + for i in snippets: + if i.start (0) < index: + continue + # lst.append (func (i, source)) + x = func (i, source) + if x: + lst.append (x) + index = i.end (0) + return lst + +# apply FUNC to every toplevel block in SNIPPETS, ie, enclosed +# snippets are skipped. return last snippet's index +def do_snippets (source, snippets, func): + global index + index = 0 + for i in snippets: + if i.start (0) < index: + continue + func (i, source) + # ugr, moved to FUNC + #index = i.end ('code') + return index + +def process_snippets (source, snippets, cmd): + outdated = map_snippets (source, snippets, Snippet.outdated_p) + names = map_snippets (source, outdated, Snippet.filename) + if names: + ly.system (string.join ([cmd] + names)) + +def do_file (input_filename): + h = sys.stdin + if input_filename != '-': + h = open (input_filename) + source = h.read () + + #snippet_types = ('lilypond', 'lilypond-block') + snippet_types = ('verbatim', 'verb', 'multiline-comment', + 'lilypond', 'lilypond-block') + snippets = [] + for i in snippet_types: + snippets += find_snippets (source, i) + + snippets.sort (compare_index) + + h = sys.stdout + ext = '.tex' + + def filter_source (snippet, source): + global index + # Hmm, why is verbatim's group called 'code'; rename to 'verb'? + #if snippet.match.group ('code'): + # urg + if snippet.type == 'lilypond' or snippet.type == 'lilypond-block': + h.write (source[index:snippet.start ('code')]) + h.write (run_filter (snippet.substring (source, 'code'))) + #index = snippet.end ('code') + h.write (source[snippet.end ('code'):snippet.end (0)]) + else: + h.write (source[index:snippet.end (0)]) + index = snippet.end (0) + + # TODO: output dict? + def compile_output (snippet, source): + global index + # Hmm, why is verbatim's group called 'code'; rename to 'verb'? + #if snippet.match.group ('code'): + # urg + if snippet.type == 'lilypond' or snippet.type == 'lilypond-block': + h.write (source[index:snippet.start (0)]) + fn = os.path.basename (os.path.splitext (snippet.filename (source))[0]) + ext + h.write (open (fn).read ()) + index = snippet.end (0) + + global index + if filter_cmd: + index = do_snippets (source, snippets, filter_source) + h.write (source[index:]) + elif process_cmd: + do_snippets (source, snippets, Snippet.write_ly) + process_snippets (source, snippets, process_cmd) + do_snippets (source, snippets, compile_output) + h.write (source[index:]) + +(sh, long) = ly.getopt_args (option_definitions) +try: + (options, files) = getopt.getopt (sys.argv[1:], sh, long) +except getopt.error, s: + sys.stderr.write ('\n') + ly.error (_ ("getopt says: `%s\'" % s)) + sys.stderr.write ('\n') + ly.help () + ly.exit (2) + +for opt in options: + o = opt[0] + a = opt[1] + + if 0: + pass + elif o == '--version' or o == '-v': + ly.identify (sys.stdout) + sys.exit (0) + elif o == '--verbose' or o == '-V': + verbose_p = 1 + elif o == '--filter' or o == '-F': + filter_cmd = a + process_cmd = 0 + elif o == '--format' or o == '-f': + format = a + if a == 'texi-html': + format = 'texi' + elif o == '--help' or o == '-h': + ly.help () + sys.exit (0) + elif o == '--process' or o == '-P': + process_cmd = a + filter_cmd = 0 + elif o == '--warranty' or o == '-w': + if 1 or status: + ly.warranty () + sys.exit (0) + +ly.identify (sys.stderr) + +ly.setup_environment () + +for input_filename in files: + do_file (input_filename) diff --git a/scripts/lilypond.py b/scripts/lilypond.py index 9d34ad5c6a..861c6c66af 100644 --- a/scripts/lilypond.py +++ b/scripts/lilypond.py @@ -2,23 +2,23 @@ # # lilypond.py -- Run LilyPond, add titles to bare score, generate printable # document -# Invokes: lilypond, latex (or pdflatex), dvips, ps2pdf, gs +# Invokes: lilypond-bin, latex (or pdflatex), dvips, ps2pdf, gs # # source file of the GNU LilyPond music typesetter # # (c) 1998--2003 Han-Wen Nienhuys # Jan Nieuwenhuizen -# This is the third incarnation of lilypond, now renamed lilypond. +# This is the third incarnation of ly2dvi, now renamed lilypond. # # Earlier incarnations of lilypond were written by # Jeffrey B. Reed (Python version) # Jan Arne Fagertun (Bourne shell script) # -# Note: gettext work best if we use ' for docstrings and " +# Note: gettext work best if we use ' for program/docstrings and " # for gettextable strings. -# --> DO NOT USE ''' for docstrings. +# USE ''' for docstrings. '''