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