Fix #1194.
[lilypond/mpolesky.git] / python / book_latex.py
blobdfb6fc0ac741617c530ef69701a43a1eaa2790c9
1 # -*- coding: utf-8 -*-
3 import re
4 import tempfile
5 import os
6 import book_base as BookBase
7 from book_snippets import *
8 import lilylib as ly
10 # Recognize special sequences in the input.
12 # (?P<name>regex) -- Assign result of REGEX to NAME.
13 # *? -- Match non-greedily.
14 # (?!...) -- Match if `...' doesn't match next (without consuming
15 # the string).
17 # (?m) -- Multiline regex: Make ^ and $ match at each line.
18 # (?s) -- Make the dot match all characters including newline.
19 # (?x) -- Ignore whitespace in patterns.
20 # Possible keys are:
21 # 'multiline_comment', 'verbatim', 'lilypond_block', 'singleline_comment',
22 # 'lilypond_file', 'include', 'lilypond', 'lilypondversion'
23 Latex_snippet_res = {
24 'include':
25 r'''(?smx)
26 ^[^%\n]*?
27 (?P<match>
28 \\input\s*{
29 (?P<filename>\S+?)
30 })''',
32 'lilypond':
33 r'''(?smx)
34 ^[^%\n]*?
35 (?P<match>
36 \\lilypond\s*(
38 \s*(?P<options>.*?)\s*
39 \])?\s*{
40 (?P<code>.*?)
41 })''',
43 'lilypond_block':
44 r'''(?smx)
45 ^[^%\n]*?
46 (?P<match>
47 \\begin\s*(?P<env>{lilypond}\s*)?(
49 \s*(?P<options>.*?)\s*
50 \])?(?(env)|\s*{lilypond})
51 (?P<code>.*?)
52 ^[^%\n]*?
53 \\end\s*{lilypond})''',
55 'lilypond_file':
56 r'''(?smx)
57 ^[^%\n]*?
58 (?P<match>
59 \\lilypondfile\s*(
61 \s*(?P<options>.*?)\s*
62 \])?\s*\{
63 (?P<filename>\S+?)
64 })''',
66 'singleline_comment':
67 r'''(?mx)
68 ^.*?
69 (?P<match>
70 (?P<code>
71 %.*$\n+))''',
73 'verb':
74 r'''(?mx)
75 ^[^%\n]*?
76 (?P<match>
77 (?P<code>
78 \\verb(?P<del>.)
79 .*?
80 (?P=del)))''',
82 'verbatim':
83 r'''(?msx)
84 ^[^%\n]*?
85 (?P<match>
86 (?P<code>
87 \\begin\s*{verbatim}
88 .*?
89 \\end\s*{verbatim}))''',
91 'lilypondversion':
92 r'''(?smx)
93 (?P<match>
94 \\lilypondversion)[^a-zA-Z]''',
97 Latex_output = {
98 FILTER: r'''\begin{lilypond}[%(options)s]
99 %(code)s
100 \end{lilypond}''',
102 OUTPUT: r'''{%%
103 \parindent 0pt
104 \ifx\preLilyPondExample \undefined
105 \else
106 \expandafter\preLilyPondExample
108 \def\lilypondbook{}%%
109 \input %(base)s-systems.tex
110 \ifx\postLilyPondExample \undefined
111 \else
112 \expandafter\postLilyPondExample
114 }''',
116 PRINTFILENAME: '''\\texttt{%(filename)s}
117 ''',
119 QUOTE: r'''\begin{quotation}
120 %(str)s
121 \end{quotation}''',
123 VERBATIM: r'''\noindent
124 \begin{verbatim}%(verb)s\end{verbatim}
125 ''',
127 VERSION: r'''%(program_version)s''',
135 # Retrieve dimensions from LaTeX
136 LATEX_INSPECTION_DOCUMENT = r'''
137 \nonstopmode
138 %(preamble)s
139 \begin{document}
140 \typeout{textwidth=\the\textwidth}
141 \typeout{columnsep=\the\columnsep}
142 \makeatletter\if@twocolumn\typeout{columns=2}\fi\makeatother
143 \end{document}
146 # Do we need anything else besides `textwidth'?
147 def get_latex_textwidth (source, global_options):
148 m = re.search (r'''(?P<preamble>\\begin\s*{document})''', source)
149 if m == None:
150 warning (_ ("cannot find \\begin{document} in LaTeX document"))
152 ## what's a sensible default?
153 return 550.0
155 preamble = source[:m.start (0)]
156 latex_document = LATEX_INSPECTION_DOCUMENT % {'preamble': preamble}
158 (handle, tmpfile) = tempfile.mkstemp('.tex')
159 logfile = os.path.splitext (tmpfile)[0] + '.log'
160 logfile = os.path.split (logfile)[1]
162 tmp_handle = os.fdopen (handle,'w')
163 tmp_handle.write (latex_document)
164 tmp_handle.close ()
166 ly.system ('%s %s' % (global_options.latex_program, tmpfile),
167 be_verbose=global_options.verbose)
168 parameter_string = file (logfile).read()
170 os.unlink (tmpfile)
171 os.unlink (logfile)
173 columns = 0
174 m = re.search ('columns=([0-9.]+)', parameter_string)
175 if m:
176 columns = int (m.group (1))
178 columnsep = 0
179 m = re.search ('columnsep=([0-9.]+)pt', parameter_string)
180 if m:
181 columnsep = float (m.group (1))
183 textwidth = 0
184 m = re.search ('textwidth=([0-9.]+)pt', parameter_string)
185 if m:
186 textwidth = float (m.group (1))
187 if columns:
188 textwidth = (textwidth - columnsep) / columns
190 return textwidth
193 def modify_preamble (chunk):
194 str = chunk.replacement_text ()
195 if (re.search (r"\\begin *{document}", str)
196 and not re.search ("{graphic[sx]", str)):
197 str = re.sub (r"\\begin{document}",
198 r"\\usepackage{graphics}" + '\n'
199 + r"\\begin{document}",
200 str)
201 chunk.override_text = str
208 class BookLatexOutputFormat (BookBase.BookOutputFormat):
209 def __init__ (self):
210 BookBase.BookOutputFormat.__init__ (self)
211 self.format = "latex"
212 self.default_extension = ".tex"
213 self.snippet_res = Latex_snippet_res
214 self.output = Latex_output
215 self.handled_extensions = ['.latex', '.lytex', '.tex']
216 self.image_formats = "ps"
217 self.snippet_option_separator = '\s*,\s*'
219 def process_options (self, global_options):
220 self.process_options_pdfnotdefault (global_options)
222 def get_line_width (self, source):
223 textwidth = get_latex_textwidth (source, self.global_options)
224 return '%.0f\\pt' % textwidth
226 def input_fullname (self, input_filename):
227 # Use kpsewhich if available, otherwise fall back to the default:
228 if ly.search_exe_path ('kpsewhich'):
229 return os.popen ('kpsewhich ' + input_filename).read()[:-1]
230 else:
231 return BookBase.BookOutputFormat.input_fullname (self, input_filename)
233 def process_chunks (self, chunks):
234 for c in chunks:
235 if (c.is_plain () and
236 re.search (r"\\begin *{document}", c.replacement_text())):
237 modify_preamble (c)
238 break
239 return chunks
241 def snippet_output (self, basename, snippet):
242 str = ''
243 rep = snippet.get_replacements ();
244 rep['base'] = basename
245 str += self.output_print_filename (basename, snippet)
246 if VERBATIM in snippet.option_dict:
247 rep['verb'] = snippet.verb_ly ()
248 str += self.output[VERBATIM] % rep
250 str += self.output[OUTPUT] % rep
252 ## todo: maintain breaks
253 if 0:
254 breaks = snippet.ly ().count ("\n")
255 str += "".ljust (breaks, "\n").replace ("\n","%\n")
257 if QUOTE in snippet.option_dict:
258 str = self.output[QUOTE] % {'str': str}
259 return str
264 BookBase.register_format (BookLatexOutputFormat ());