-
-# python version of mudela-book. WIP.
-
-# TODO: center option
-
+#!@PYTHON@
+#
+# The bugs you find are made by Tom Cato Amundsen <tomcato@xoommail.com>
+# Send patches/questions/bugreports to a mailinglist:
+# gnu-music-discuss@gnu.org
+# bug-gnu-music@gnu.org
+# help-gnu-music@gnu.org
+#
+# TODO:
+# * center option (??)
+# * make mudela-book understand usepackage{geometry}
+# * check that linewidth set in \paper is not wider than actual linewidth?
+# * the following fails because mudelabook doesn't care that the
+# last } after \end{mudela} finishes the marginpar:
+# \marginpar{
+# \begin{mudela}
+# c d e f g
+# \end{mudela}}
+# * force-verbatim is maybe not that useful since latex fails with footnotes,
+# marginpars and others
# log:
-
# 0.3:
# rewrite in Python.
-
+# 0.4:
+# much rewritten by new author. I think the work has been split more
+# logical between different classes.
+# 0.4.1:
+# - cleanup
+# - speedup, do all mudela parsing at the same time to avoid multiple
+# guile startup that takes some seconds on my computer
+# 0.4.2:
+# - fixed default latex fontsize, it should be 10pt not 11pt
+# - verbatim option no longer visible
+# - mudela-book produces .dvi output
+# - change to use castingalgorithm = \Gourlay instead of \Wordwrap. It gives
+# better result on small linewidths.
+# - mudela-book-doc.doc rewritten
+# 0.5:
+# - junked floating and fragment options, added eps option
+# - mudela-book will scan the mudela code to find out if it has to add
+# paper-definition and \score{\notes{...}}
+# - possible to define commands that look like this: \mudela{ c d e }
+# - don't produce .dvi output, it was a silly idea...
+# 0.5.1:
+# - removed init/mudela-book-defs.py, \mudela is defined inside mudela-book
+# - fragment and nonfragment options will override autodetection of type of
+# in mudela-block (voice contents or complete code)
+# 0.5.2:
+# - fixed verbatim option behaviour: don't show \begin{mudela} \end{mudela}
+# and show both mudela code and music
+# - veryverbatim option, same as verbatim but show \begin{mudela}
+# and \end{mudela}. (saves keystrokes in mudela-book-doc.doc)
+# - intertext="bla bla bla" option
+# - mudela-book now understand latex \begin{verbatim}
+# 0.5.3:
+# - bf: \mudela{ \times 2/3{...} }
+# * \t in \times is not tab character and
+# * dont treat the first '}' as command ending
+# 0.5.4: (Mats B)
+# - .fly and .sly files in \mudelafile{} are treated as standalone Lilypond.
+# - Fragments, .fly and .sly files are in \relative mode.
+# 0.5.5: (Mats B)
+# - bf: Default fragments have linewidth=-1.0
+# - Added 'singleline' and 'multiline' options.
+# 0.5.6:
+# - \mudelafile{} set linewidth correct, -1 for .sly and texlinewidth for .fly
+# - changes to Mudela_output
+# - changed RE to search for pre/postMudelaExample to make it possible to
+# comment out a definition.
+# - use sys.stderr and sys.stdout instead of print
import os
import string
-import regex
+import re
import getopt
import sys
-import regsub
-
-outdir = 'out/'
-program_version = '0.3'
-
-
+outdir = 'out'
+initfile = ''
+program_version = '0.5.6'
+include_path = ['.']
+
+out_files = []
+
+fontsize_i2a = {11:'eleven', 13:'thirteen', 16:'sixteen',
+ 20:'twenty', 26:'twentysix'}
+fontsize_pt2i = {'11pt':11, '13pt':13, '16pt':16, '20pt':20, '26pt':26}
+
+# perhaps we can do without this?
+
+begin_mudela_re = re.compile ('^ *\\\\begin{mudela}')
+begin_verbatim_re = re.compile ('^ *\\\\begin{verbatim}')
+end_verbatim_re = re.compile ('^ *\\\\end{verbatim}')
+extract_papersize_re = re.compile('\\\\documentclass[\[, ]*(\w*)paper[\w ,]*\]\{\w*\}')
+extract_fontsize_re = re.compile('[ ,\[]*([0-9]*)pt')
+begin_mudela_opts_re = re.compile('\[[^\]]*\]')
+end_mudela_re = re.compile ('^ *\\\\end{mudela}')
+section_re = re.compile ('\\\\section')
+chapter_re = re.compile ('\\\\chapter')
+input_re = re.compile ('^\\\\input{([^}]*)')
+include_re = re.compile ('^\\\\include{([^}]*)')
+begin_document_re = re.compile ('^ *\\\\begin{document}')
+documentclass_re = re.compile('\\\\documentclass')
+twocolumn_re = re.compile('\\\\twocolumn')
+onecolumn_re = re.compile('\\\\onecolumn')
+mudela_file_re = re.compile('\\\\mudelafile{([^}]+)}')
+file_ext_re = re.compile('.+\\.([^.}]+$)')
+preMudelaExample_re = re.compile('^\s*\\\\def\\\\preMudelaExample')
+postMudelaExample_re = re.compile('^\s*\\\\def\\\\postMudelaExample')
+boundingBox_re = re.compile('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)')
+intertext_re = re.compile("intertext=\"([^\"]*)\"")
def file_exist_b(name):
try:
f.close ()
return 1
-class CompileStatus:
- pass
+def ps_dimention(fname):
+ fd = open(fname)
+ lines = fd.readlines()
+ for line in lines:
+ s = boundingBox_re.search(line)
+ if s:
+ break
+ return (int(s.groups()[2])-int(s.groups()[0]),
+ int(s.groups()[3])-int(s.groups()[1]))
-def file_mtime (name):
- return os.stat (name)[8] #mod time
-def compile (command, infile, outfile):
- indate = file_mtime (infile)
+def find_file (name):
+ for a in include_path:
try:
- outdate = file_mtime (outfile)
- recompile = indate > outdate
-
- except os.error:
- recompile = 1
+ nm = os.path.join (a, name)
+ f = open (nm)
+ return nm
+ except IOError:
+ pass
+ return ''
- if recompile:
- sys.stderr.write ('invoking `%s\'\n' % command)
-
- status = os.system (command)
- if status:
- raise CompileStatus
-
-
-class Mudela_output:
- def __init__ (self):
- self.basename = ''
- self.fragment = 0
- self.size = 16
-
- def open (self, basename):
- self.basename = basename
- self.temp_file = "%s/%s" %(outdir, 'mudela-temp.ly')
- self.file = open (self.temp_file, 'w')
- self.file.write ('\\include \"paper%d.ly\"\n' % self.size)
- if self.size == 16:
- s = 'sixteen'
- else:
- s = 'twenty'
-
- self.file.write ('default_paper = \\paper { \\paper_%s\n linewidth = -15.\\cm; }\n' % s)
-
- if self.fragment:
- self.file.write ('\\score { \\melodic { ')
-
- def write (self,s):
- self.file.write (s)
-
- def close (self):
- if self.fragment:
- self.file.write (
- '}\n \\paper { linewidth = -1.0\\cm;\n' +
- 'castingalgorithm = \\Wordwrap; } }\n')
+class CompileStatus:
+ pass
+class SomethingIsSeriouslyBroken:
+ pass
- self.file.close ()
+def file_mtime (name):
+ return os.stat (name)[8] #mod time
- inf=self.basename + '.ly'
- outf = self.basename + '.tex'
- if not file_exist_b (inf):
- status = 1
- else:
-# print 'invoking %s' %('diff %s %s' % (self.temp_file, inf))
- status = os.system ('diff -q %s %s' % (self.temp_file, inf))
-# print 'status %d' % status
+def need_recompile_b(infile, outfile):
+ indate = file_mtime (infile)
+ try:
+ outdate = file_mtime (outfile)
+ return indate > outdate
+ except os.error:
+ return 1
+
+#
+# executes os.system(command) if infile is newer than
+# outfile or outfile don't exist
+#
+def compile (command, workingdir, infile, outfile):
+ "Test if infile is newer than outfile. If so, cd to workingdir"
+ "and execute command"
+ indate = file_mtime (workingdir+infile)
+ try:
+ outdate = file_mtime (workingdir+outfile)
+ recompile = indate > outdate
+
+ except os.error:
+ recompile = 1
+
+ if recompile:
+ sys.stderr.write ('invoking `%s\'\n' % command)
+ if workingdir == '':
+ status = os.system (command)
+ else:
+ status = os.system ('cd %s; %s' %(workingdir, command))
+ if status:
+ raise CompileStatus
+
+class Properties:
+ #
+ # init
+ #
+ def __init__(self):
+ self.__linewidth = {
+ 1: {'a4':{10: 345, 11: 360, 12: 390},
+ 'a5':{10: 276, 11: 276, 12: 276},
+ 'b5':{10: 345, 11: 356, 12: 356},
+ 'letter':{10: 345, 11: 360, 12: 390},
+ 'legal': {10: 345, 11: 360, 12: 390},
+ 'executive':{10: 345, 11: 360, 12: 379}},
+ 2: {'a4':{10: 167, 11: 175, 12: 190},
+ 'a5':{10: 133, 11: 133, 12: 133},
+ 'b5':{10: 167, 11: 173, 12: 173},
+ 'letter':{10: 167, 11: 175, 12: 190},
+ 'legal':{10: 167, 11: 175, 12: 190},
+ 'executive':{10: 167, 11: 175, 12: 184}}}
+ # >0 --> force all mudela to this pt size
+ self.force_mudela_fontsize = 0
+ self.force_verbatim_b = 0
+ self.__data = {
+ 'mudela-fontsize' : {'init': 16},
+ 'papersize' : {'init': 'a4'},
+ 'num-column' : {'init': 1},
+ 'tex-fontsize' : {'init': 10}
+ }
+ def clear_for_new_file(self):
+ for var in self.__data.keys():
+ self.__data[var] = {'init': self.__data[var]['init']}
+ def clear_for_new_block(self):
+ for var in self.__data.keys():
+ if self.__data[var].has_key('block'):
+ del self.__data[var]['block']
+ def __get_variable(self, var):
+ if self.__data[var].has_key('block'):
+ return self.__data[var]['block']
+ elif self.__data[var].has_key('file'):
+ return self.__data[var]['file']
+ else:
+ return self.__data[var]['init']
+ def setPapersize(self, size, requester):
+ self.__data['papersize'][requester] = size
+ def getPapersize(self):
+ return self.__get_variable('papersize')
+ def setMudelaFontsize(self, size, requester):
+ self.__data['mudela-fontsize'][requester] = size
+ def getMudelaFontsize(self):
+ if self.force_mudela_fontsize:
+ return self.force_mudela_fontsize
+ return self.__get_variable('mudela-fontsize')
+ def setTexFontsize(self, size, requester):
+ self.__data['tex-fontsize'][requester] = size
+ def getTexFontsize(self):
+ return self.__get_variable('tex-fontsize')
+ def setNumColumn(self, num, requester):
+ self.__data['num-column'][requester] = num
+ def getNumColumn(self):
+ return self.__get_variable('num-column')
+ def getLineWidth(self):
+ return self.__linewidth[self.getNumColumn()][self.getPapersize()][self.getTexFontsize()]
- if status:
- os.rename (self.temp_file, inf)
- compile ('lilypond -o %s %s'% (self.basename, inf), inf, outf)
-# os.rename (self.basename + '.tex', outdir +)
-
-
+class Mudela_output:
+ """ Using only self.code_type to deside both value of linewith and
+ if we have to put code into \score{...} was silly. Now we use:
+ self.code_type: show us what need to be added.
+ None : init value
+ 'NOTES' : add \context Voice{ ... }
+ 'CONTEXT' : add \score{ ... }
+ 'COMPLETE' : jupp
+ self.single_line_b: 0 : linewidth=-1 1: linewith=textwidth
+ """
+ def __init__ (self, basename):
+ self.basename = basename
+ self.temp_filename = "%s/%s" %(outdir, 'mudela-temp.ly')
+ self.file = open (self.temp_filename, 'w')
+ self.__lines = []
+ # 'tex' or 'eps'
+ self.graphic_type = 'tex'
+ self.code_type = None
+ self.single_line_b = 1
+ self.optlist = []
+ def write (self, line):
+ # match only if there is nothing but whitespace before \begin.
+ # we should not have to do this RE for every line
+ if re.search('^\s*\\\\begin{mudela}', line):
+ r = begin_mudela_opts_re.search(line)
+ if r:
+ o = r.group()[1:-1]
+ self.optlist = re.compile('[\s,]*').split(o)
+ else:
+ self.optlist = []
+ else: # ugh this is NOT bulletproof...
+ if not self.code_type:
+ if re.search('^\s*%', line) or re.search('^\s*$', line):
+ pass
+ elif re.search('^\s*\\\\context', line):
+ self.code_type = 'CONTEXT'
+ self.single_line_b = 0
+ elif re.search('^\s*\\\\score', line) or \
+ re.search('^\s*\\\\paper', line) or \
+ re.search('^\s*\\\\header', line) or \
+ re.search('^\s*\\\\version', line) or \
+ re.search('^\s*\\\\include', line) or \
+ re.search('^\s*[A-Za-z]*\s*=', line):
+ self.code_type = 'COMPLETE'
+ self.single_line_b = 0
+ else:
+ self.code_type = 'NOTES'
+ self.single_line_b = 1
+ self.__lines.append(line)
+ def write_red_tape(self):
+ if 'eps' in self.optlist:
+ self.graphic_type = 'eps'
+ #self.single_line_b = 1
+ if 'fragment' in self.optlist:
+ self.code_type = 'NOTES'
+ if 'nonfragment' in self.optlist:
+ self.code_type = 'COMPLETE'
+ if 'multiline' in self.optlist:
+ self.single_line_b = 0
+ for pt in fontsize_pt2i.keys():
+ if pt in self.optlist:
+ Props.setMudelaFontsize(fontsize_pt2i[pt], 'block')
+ self.file.write ('\\include \"paper%d.ly\"\n' \
+ % Props.getMudelaFontsize())
+
+ s = fontsize_i2a[Props.getMudelaFontsize()]
+ if 'singleline' in self.optlist:
+ self.single_line_b = 1
+ if self.single_line_b:
+ linewidth_str = 'linewidth = -1.\cm;'
+ else:
+ linewidth_str = 'linewidth = %i.\\pt;' % Props.getLineWidth()
+ self.file.write("\\paper {"
+ + "\\paper_%s " % s
+ + linewidth_str
+ + "castingalgorithm = \Gourlay; \n}")
+ #+ "castingalgorithm = \Wordwrap; indent = 2.\cm; \n}")
+ if self.code_type == 'CONTEXT':
+ self.file.write('\\score{\n\\notes\\relative c{')
+ if self.code_type == 'NOTES' :
+ self.file.write('\\score{\n\\notes\\relative c{\\context Voice{')
+ def close (self):
+ self.write_red_tape()
+ for l in self.__lines:
+ self.file.write(l)
+ if self.code_type == 'CONTEXT':
+ self.file.write('}}')
+ elif self.code_type == 'NOTES':
+ self.file.write('}}}')
+ self.file.close()
+
+ inf = outdir + self.basename + '.ly'
+ outf = outdir + self.basename + '.tex'
+ if not os.path.isfile(inf):
+ status = 1
+ else:
+ status = os.system ('diff -q %s %s' % (self.temp_filename, inf))
+ if status:
+ os.rename (self.temp_filename, inf)
+
+ recompile_b = need_recompile_b(inf, outf)
+ if recompile_b:
+ out_files.append((self.graphic_type, inf))
+ return recompile_b
+
+ def insert_me_string(self):
+ "ugh the name of this function is wrong"
+ if self.graphic_type == 'tex':
+ return ['tex', self.basename]
+ elif self.graphic_type == 'eps':
+ return ['eps', self.basename]
+ else:
+ raise SomethingIsSeriouslyBroken
class Tex_output:
- def __init__ (self, name):
- self.output_fn = '%s/%s' % (outdir, name)
- self.mudela = 0
- self.file = open (self.output_fn , 'w')
- self.verbatim = 0
- def open_mudela (self, basename):
- self.mudela_basename =basename
- if self.verbatim:
- self.file.write ('\\begin{verbatim}\n')
- self.mudela = 1
-
- def write (self, s):
- self.file.write (s)
-
- def write_mudela (self, s):
- if self.verbatim:
- self.file.write (s)
-
- def close_mudela (self):
- if self.verbatim:
- self.file.write ('\\end{verbatim}\n')
- self.verbatim = 0
-
- self.file.write (
- '\\preMudelaExample\\input %s\n\postMudelaExample' %(self.mudela_basename))
- self.mudela = 0
-
-
-
-
-
-begin_mudela_re = regex.compile ('^ *\\\\begin{mudela}')
-begin_mudela_opts_re = regex.compile ('^ *\\\\begin{mudela}\[\(.*\)\]')
-end_mudela_re = regex.compile ('^ *\\\\end{mudela}')
-section_re = regex.compile ('\\\\section')
-chapter_re = regex.compile ('\\\\chapter')
-input_re = regex.compile ('^\\\\input[ \t\n]+\\(.*\\)$')
+ def __init__ (self, name):
+ self.output_fn = '%s/%s' % (outdir, name)
+ self.__lines = []
+ def open_verbatim (self, line, level):
+ self.__lines.append('\\begin{verbatim}\n')
+ if level == 2:
+ s = re.sub('veryverbatim[\s,]*', '', line)
+ s = re.sub('intertext=\"([^\"]*)\"[\s,]*', '', s)
+ s = re.sub(',\s*\]', ']', s)
+ s = re.sub('\[\]', '', s)
+ self.__lines.append(s);
+ def close_verbatim (self):
+ self.__lines.append('\\end{verbatim}\n')
+ def write (self, s):
+ self.__lines.append(s)
+ def create_graphics(self):
+ s = ''
+ g_vec = []
+ for line in self.__lines:
+ if type(line)==type([]):
+ g_vec.append(line)
+ for g in g_vec:
+ if need_recompile_b(outdir+g[1]+'.ly', outdir+g[1]+'.tex'):
+ s = s + ' ' + g[1]+'.ly'
+ if s != '':
+ e = os.system('cd %s; lilypond %s' %(outdir, s))
+ if e:
+ sys.stderr.write("error: lilypond exited with value %i\n" % e)
+ sys.exit(e)
+ for g in g_vec:
+ if g[0] == 'eps':
+ compile('tex %s' % g[1]+'.tex', outdir, g[1]+'.tex', g[1]+'.dvi')
+ compile('dvips -E -o %s %s' %(g[1]+'.eps', g[1]+'.dvi'), outdir,
+ g[1]+'.dvi', g[1]+'.eps')
+ def write_outfile(self):
+ file = open(self.output_fn+'.latex', 'w')
+ file.write('% Created by mudela-book\n')
+ last_line = None
+ for line in self.__lines:
+ if type(line)==type([]):
+ if last_line == '\n':
+ file.write(r'\vspace{0.5cm}')
+ if line[0] == 'tex':
+ file.write('\\preMudelaExample \\input %s \\postMudelaExample\n'\
+ % (line[1]+'.tex'))
+ if line[0] == 'eps':
+ ps_dim = ps_dimention(outdir+line[1]+'.eps')
+ file.write('\\noindent\\parbox{%ipt}{\includegraphics{%s}}\n' \
+ % (ps_dim[0], line[1]+'.eps'))
+ else:
+ file.write(line)
+ if type(last_line)==type([]):
+ if line=='\n':
+ file.write(r'\vspace{0.5cm}')
+ last_line = line
+ file.close()
+
+# given parameter s="\mudela[some options]{CODE} some text and commands"
+# it returns a tuple:
+# (CODE, integer)
+# where the last number is the index of the ending '}'
+def extract_command(s):
+ start_found_b = 0
+ count = 0
+ start = 0
+ for idx in range(len(s)):
+ if s[idx] == '{':
+ if not start_found_b:
+ start = idx
+ start_found_b = 1
+ count = count + 1
+ if s[idx] == '}':
+ count = count - 1
+ if (start_found_b == 1) and (count == 0):
+ break
+ return s[start+1:idx], idx
class Tex_input:
- def __init__ (self,name):
- if regex.search ('\\.[^/\\\\]+',name) == -1:
- name = name + '.tex'
- print 'opening %s' % name
- self.filename = name
- self.infile = open (name)
-
- def get_lines (self):
- lines = self.infile.readlines ()
- (retlines, retdeps) = ([],[self.filename])
- for line in lines:
- if input_re.search (line) <> -1:
- t = Tex_input (input_re.group (1))
- ls =t.get_lines ()
- retlines = retlines + ls[0]
- retdeps = retdeps + ls[1]
- else:
- retlines.append (line)
-
- return (retlines, retdeps)
+ def __init__ (self, filename):
+ for fn in [filename, filename+'.tex', filename+'.doc']:
+ try:
+ self.infile = open (fn)
+ self.filename = fn
+ return
+ except:
+ continue
+ raise IOError
+
+ def get_lines (self):
+ lines = self.infile.readlines ()
+ (retlines, retdeps) = ([],[self.filename])
+ for line in lines:
+ r_inp = input_re.search (line)
+ r_inc = include_re.search (line)
+
+ # Filename rules for \input :
+ # input: no .tex ext
+ # 1. will search for file with exact that name (tex-input.my will be found)
+ # 2. will search for file with .tex ext, (tex-input.my
+ # will find tex-input.my.tex)
+ # input: with .tex ext
+ # 1. will find exact match
+
+ # Filename rules for \include :
+ # 1. will only find files with name given to \include + .tex ext
+ if r_inp:
+ try:
+ t = Tex_input (r_inp.groups()[0])
+ ls = t.get_lines ()
+ retlines = retlines + ls[0]
+ retdeps = retdeps + ls[1]
+ except:
+ sys.stderr.write("warning: can't find %s, let's hope latex will\n" % r_inp.groups()[0])
+ retlines.append (line)
+ elif r_inc:
+ try:
+ t = Tex_input (r_inc.groups()[0]+'.tex')
+ ls =t.get_lines ()
+ ls[0].insert(0, '\\newpage\n')
+ ls[0].append('\\newpage\n')
+ retlines = retlines + ls[0]
+ retdeps = retdeps + ls[1]
+ except:
+ sys.stderr.write("warning: can't find %s, let's hope latex will" % r_inc.groups()[0])
+ retlines.append (line)
+ else:
+ # This code should be rewritten, it looks terrible
+ r_mud = defined_mudela_cmd_re.search(line)
+ if r_mud:
+ # TODO document this
+ ss = "\\\\verb(?P<xx>[^a-zA-Z])\s*\\\\%s\s*(?P=xx)" \
+ % re.escape(r_mud.group()[1:])
+ # just append the line if the command is inside \verb|..|
+ if re.search(ss, line):
+ retlines.append(line)
+ continue
+ while 1:
+ opts = r_mud.groups()[2]
+ cmd_start_idx = r_mud.span()[0]
+ if cmd_start_idx > 0:
+ retlines.append(line[:cmd_start_idx])
+
+ cmd_data, rest_idx = extract_command(line[cmd_start_idx:])
+ rest_idx = rest_idx + cmd_start_idx + 1
+ if opts == None:
+ opts = ''
+ else:
+ opts = ', '+opts
+
+ v = string.split(defined_mudela_cmd[r_mud.groups()[0]], '\n')
+ for l in v[1:-1]:
+ l = string.replace(l, '\\fontoptions', opts)
+ l = string.replace(l, '\\maininput', cmd_data)
+ retlines.append(l)
+ r_mud = defined_mudela_cmd_re.search(line[rest_idx:])
+ if not r_mud:
+ rs = line[rest_idx:]
+ while rs[0] == " ":
+ rs = rs[1:]
+ if rs != "\n":
+ retlines.append(line[rest_idx:])
+ break;
+ line = line[rest_idx:]
+ else:
+ retlines.append (line)
+ return (retlines, retdeps)
+
class Main_tex_input(Tex_input):
- def __init__ (self, name, outname):
-
- Tex_input.__init__ (self, name) # ugh
-
- self.outname = outname
- self.chapter = 0
- self.section = 0
- self.fine_count =0
- self.mudtex = Tex_output (self.outname)
- self.mudela = None
- self.deps = []
- def set_sections (self, l):
- if section_re.search (l) <> -1:
- self.section = self.section + 1
- if chapter_re.search (l) <> -1:
- self.section = 0
- self.chapter = self.chapter + 1
-
-
- def gulp_mudela (self):
- pass
-
- def gen_basename (self):
- return '%s/%s-%d.%d.%d' % (outdir, self.outname,self.chapter,self.section,self.fine_count)
-
- def do_it(self):
- (lines, self.deps) = self.get_lines ()
- for line in lines:
- if begin_mudela_re.search (line) <> -1:
- if begin_mudela_opts_re.search (line) <> -1:
- opts = begin_mudela_opts_re.group (1)
- else:
- opts = ''
- optlist = string.split (opts, ',')
- self.mudela = Mudela_output ()
- if 'fragment' in optlist:
- self.mudela.fragment = 1
- if '16pt' in optlist:
- self.mudela.size = 16
- if '20pt' in optlist:
- self.mudela.size = 20
-
- if 'verbatim' in optlist:
- self.mudtex.verbatim = 1
-
- b = self.gen_basename ()
- self.mudtex.open_mudela (b)
- self.mudela.open (b)
-
-
- continue
- elif end_mudela_re.search (line) <> -1:
- self.mudela.close ()
- self.mudtex.close_mudela ()
- self.mudela = None
- self.fine_count = self.fine_count + 1
- continue
-
- if self.mudela:
- self.mudela.write (line)
- self.mudtex.write_mudela (line)
- else:
- self.mudtex.write (line)
- self.set_sections(line)
- del self.mudtex
+ def __init__ (self, name, outname):
+
+ Tex_input.__init__ (self, name) # ugh
+ self.outname = outname
+ self.chapter = 0
+ self.section = 0
+ self.fine_count =0
+ self.mudtex = Tex_output (self.outname)
+ self.mudela = None
+ self.deps = []
+ self.verbatim = 0
+ # set to 'mudela' when we are processing mudela code,
+ # both verbatim and graphic-to-be
+ self.mode = 'latex'
+ def set_sections (self, l):
+ if section_re.search (l):
+ self.section = self.section + 1
+ if chapter_re.search (l):
+ self.section = 0
+ self.chapter = self.chapter + 1
+
+ def gen_basename (self):
+ return '%s-%d.%d.%d' % (self.outname, self.chapter,
+ self.section, self.fine_count)
+ def extract_papersize_from_documentclass(self, line):
+ pre = extract_papersize_re.search(line)
+ if not pre:
+ return None
+ return pre.groups()[0]
+ def extract_fontsize_from_documentclass(self, line):
+ r = extract_fontsize_re.search(line)
+ if r:
+ return int(r.groups()[0])
+ def do_it(self):
+ preMudelaDef = postMudelaDef = 0
+ (lines, self.deps) = self.get_lines ()
+ #HACK
+ latex_verbatim = 0
+ for line in lines:
+ if documentclass_re.search (line):
+ p = self.extract_papersize_from_documentclass (line)
+ if p:
+ Props.setPapersize(p, 'file')
+ f = self.extract_fontsize_from_documentclass (line)
+ if f:
+ Props.setTexFontsize (f, 'file')
+ elif twocolumn_re.search (line):
+ Props.setNumColumn (2, 'file')
+ elif onecolumn_re.search (line):
+ Props.setNumColumn (1, 'file')
+ elif preMudelaExample_re.search (line):
+ preMudelaDef = 1
+ elif postMudelaExample_re.search (line):
+ postMudelaDef = 1
+ elif begin_verbatim_re.search (line):
+ latex_verbatim = 1
+ elif end_verbatim_re.search (line):
+ latex_verbatim = 0
+ elif begin_document_re.search (line):
+ if not preMudelaDef:
+ self.mudtex.write ('\\def\\preMudelaExample{}\n')
+ if not postMudelaDef:
+ self.mudtex.write ('\\def\\postMudelaExample{}\n')
+
+ elif mudela_file_re.search(line):
+ r = mudela_file_re.search(line)
+
+ self.mudela = Mudela_output(self.gen_basename())
+ fn = r.group (1)
+ full_path = find_file (fn)
+ if not full_path:
+ sys.stderr.write("error: can't find file '%s'\n" % fn)
+ sys.exit (1)
+
+ f = open (full_path, 'r')
+ lines =f.readlines ()
+ self.mudela.write ('%% This is a copy of file %s\n' % full_path)
+ for x in lines:
+ self.mudela.write (x)
+ r = file_ext_re.search(fn)
+ if r:
+ if r.group(1) == 'fly':
+ self.mudela.optlist.append('multiline')
+ stat =self.mudela.close ()
+ if stat:
+ sys.stdout.write("(File %s needs recompiling)\n" % full_path)
+ self.mudtex.write (self.mudela.insert_me_string())
+ self.deps.append (full_path)
+ del self.mudela
+ self.mudela = None
+ self.fine_count = self.fine_count + 1
+ continue
+ elif begin_mudela_re.search (line) and not latex_verbatim:
+ Props.clear_for_new_block()
+ if __debug__:
+ if self.mode == 'mudela':
+ raise AssertionError
+ self.mode = 'mudela'
+ r = begin_mudela_opts_re.search (line)
+ if r:
+ o = r.group()[1:][:-1]
+ optlist = re.compile('[ ,]*').split(o)
+ m = intertext_re.search(r.group())
+ if m:
+ self.intertext = m.groups()[0]
+ else:
+ self.intertext = None
+ else:
+ optlist = []
+ if ('veryverbatim' in optlist):
+ self.verbatim = 2
+ elif ('verbatim' in optlist) or (Props.force_verbatim_b):
+ self.verbatim = 1
+ else:
+ self.verbatim = 0
+ if self.verbatim:
+ self.mudtex.open_verbatim (line, self.verbatim)
+ self.mudela = Mudela_output (self.gen_basename ())
+ self.mudela.write (line)
+ continue
+ elif end_mudela_re.search (line) and not latex_verbatim:
+ if __debug__:
+ if self.mode != 'mudela':
+ raise AssertionError
+
+ if self.verbatim:
+ if self.verbatim == 2:
+ self.mudtex.write (line)
+ self.mudtex.close_verbatim ()
+ self.mudela.close ()
+ if self.verbatim and self.intertext:
+ self.mudtex.write(self.intertext)
+ self.mudtex.write (self.mudela.insert_me_string())
+ del self.mudela
+ self.mudela = None
+ self.fine_count = self.fine_count + 1
+ self.mode = 'latex'
+ continue
+
+
+ if self.mode == 'mudela':
+ self.mudela.write (line)
+ if self.verbatim:
+ self.mudtex.write (line)
+ else:
+ self.mudtex.write (line)
+ self.set_sections(line)
+ self.mudtex.create_graphics()
+ self.mudtex.write_outfile()
+ del self.mudtex
def help():
- sys.stdout.write("Usage: mudela-book [options] FILE\n"
- + "Generate hybrid LaTeX input from Latex + mudela"
- + "Options:\n"
- + " -h, --help print this help\n"
- + " -d, --outdir=DIR prefix directory\n"
- + " -o, --outname=FILE prefix for filenames\n"
+ sys.stdout.write("""Usage: mudela-book [options] FILE\n
+Generate hybrid LaTeX input from Latex + mudela
+Options:\n
+ -h, --help print this help
+ -d, --outdir=DIR directory to put generated files
+ -o, --outname=FILE prefix for filenames
+ --default-mudela-fontsize=??pt default fontsize for music
+ --force-mudela-fontsize=??pt force fontsize for all inline mudela
+ --force-verbatim make all mudela verbatim\n
+ --dependencies write dependencies
+ --include include path
+ --init mudela-book initfile
+ """
)
sys.exit (0)
-
-sys.stderr.write ('This is %s version %s\n' % ('mudela-book', program_version))
-
-outname = ''
-(options, files) = getopt.getopt(
- sys.argv[1:], 'hd:o:', [ 'outdir=', 'outname=', 'help', 'dependencies'])
-
-do_deps = 0
-for opt in options:
- o = opt[0]
- a = opt[1]
- if o == '--outname' or o == '-o':
- outname = a
- if o == '--outdir' or o == '-d':
- outdir = a
- if o == '--help' or o == '-h':
- help ()
- if o == '--dependencies':
- do_deps = 1
-
def write_deps (fn, out, deps):
- out_fn = outdir + '/' + fn
- print '\`writing \`%s\'\n\'' % out_fn
+ out_fn = os.path.join (outdir, fn)
+
+ sys.stdout.write('writing `%s\'\n' % out_fn)
f = open (out_fn, 'w')
- f.write ('%s: %s\n'% (outdir + '/' + out + '.dvi',
+ target = re.sub (os.sep + os.sep, os.sep, os.path.join (outdir, out + '.latex'))
+ f.write ('%s: %s\n'% (target,
reduce (lambda x,y: x + ' '+ y, deps)))
f.close ()
-
-for f in files:
- my_outname = outname
- if not my_outname:
- my_outname = regsub.sub ('\\(.*\\)\\.doc', '\\1', f)
-
- my_depname = my_outname + '.dep'
-
- inp = Main_tex_input (f, my_outname)
- inp.do_it ()
-
- if do_deps:
- write_deps (my_depname, my_outname, inp.deps)
-
-
+def identify():
+ sys.stderr.write ('This is %s version %s\n' % ('mudela-book', program_version))
+
+def main():
+ global outdir, initfile, defined_mudela_cmd, defined_mudela_cmd_re
+ outname = ''
+ try:
+ (options, files) = getopt.getopt(
+ sys.argv[1:], 'hd:o:I:', ['outdir=', 'outname=',
+ 'default-mudela-fontsize=',
+ 'force-mudela-fontsize=',
+ 'help', 'dependencies', 'include=',
+ 'force-verbatim', 'init='])
+ except getopt.error, msg:
+ sys.stderr.write("error: %s" % msg)
+ sys.exit(1)
+
+ do_deps = 0
+ for opt in options:
+ o = opt[0]
+ a = opt[1]
+ if o == '--include' or o == '-I':
+ include_path.append (a)
+ elif o == '--outname' or o == '-o':
+ if len(files) > 1:
+ #HACK
+ sys.stderr.write("Mudela-book is confused by --outname on multiple files")
+ sys.exit(1)
+ outname = a
+ elif o == '--outdir' or o == '-d':
+ outdir = a
+ elif o == '--help' or o == '-h':
+ help ()
+ elif o == '--dependencies':
+ do_deps = 1
+ elif o == '--default-mudela-fontsize':
+ if not fontsize_pt2i.has_key(a):
+ sys.stderr.write("Error: invalid fontsize: %s" % a)
+ sys.stderr.write(" accepted fontsizes are: 11pt, 13pt, 16pt, 20pt, 26pt")
+ sys.exit()
+ Props.setMudelaFontsize(fontsize_pt2i[a], 'init')
+ elif o == '--force-mudela-fontsize':
+ if not fontsize_pt2i.has_key(a):
+ sys.stderr.write("Error: invalid fontsize: %s" % a)
+ sys.stderr.write(" accepted fontsizes are: 11pt, 13pt, 16pt, 20pt, 26pt")
+ sys.exit()
+ Props.force_mudela_fontsize = fontsize_pt2i[a]
+ elif o == '--force-verbatim':
+ Props.force_verbatim_b = 1
+ elif o == '--init':
+ initfile = a
+ if outdir[-1:] != '/':
+ outdir = outdir + '/'
+
+ # r""" ... """ means: leave escape seqs alone.
+ defined_mudela_cmd = {'mudela': r"""
+\begin{mudela}[eps, singleline \fontoptions]
+ \context Staff <
+ \context Voice{
+ \maininput
+ }
+ >
+\end{mudela}
+"""}
+ if initfile != '':
+ f = open(initfile)
+ s = f.read()
+ f.close()
+ d = eval(s)
+ for i in d.keys():
+ defined_mudela_cmd[i] = d[i]
+ del d
+
+ c = string.join (defined_mudela_cmd.keys(), '|')
+
+ defined_mudela_cmd_re = re.compile("\\\\(%s)(\[(\d*pt)\])*{([^}]*)}" %c)
+
+ if not os.path.isdir(outdir):
+ os.system('mkdir %s' % outdir)
+
+ for input_filename in files:
+ Props.clear_for_new_file()
+ if outname:
+ my_outname = outname
+ else:
+ my_outname = os.path.basename(os.path.splitext(input_filename)[0])
+ my_depname = my_outname + '.dep'
+ inp = Main_tex_input (input_filename, my_outname)
+ inp.do_it ()
+ if do_deps:
+ write_deps (my_depname, my_outname, inp.deps)
+
+identify()
+Props = Properties()
+main()