1 # -*- coding: utf-8 -*-
7 import book_base as BookBase
8 from book_snippets import *
13 # Recognize special sequences in the input.
15 # (?P<name>regex) -- Assign result of REGEX to NAME.
16 # *? -- Match non-greedily.
17 # (?!...) -- Match if `...' doesn't match next (without consuming
20 # (?m) -- Multiline regex: Make ^ and $ match at each line.
21 # (?s) -- Make the dot match all characters including newline.
22 # (?x) -- Ignore whitespace in patterns.
24 # 'multiline_comment', 'verbatim', 'lilypond_block', 'singleline_comment',
25 # 'lilypond_file', 'include', 'lilypond', 'lilypondversion'
26 TexInfo_snippet_res = {
30 (?P<filename>\S+))''',
32 'lilypond': r'''(?smx)
33 ^[^\n]*?(?!@c\s+)[^\n]*?
37 \s*(?P<options>.*?)\s*
42 'lilypond_block': r'''(?msx)
46 \s*(?P<options>.*?)\s*
49 ^@end\s+lilypond)\s''',
51 'lilypond_file': r'''(?mx)
55 \s*(?P<options>.*?)\s*
60 'multiline_comment': r'''(?smx)
67 'musicxml_file': r'''(?mx)
71 \s*(?P<options>.*?)\s*
76 'singleline_comment': r'''(?mx)
80 @c([ \t][^\n]*|)\n))''',
82 # Don't do this: It interferes with @code{@{}.
83 # 'verb': r'''(?P<code>@code{.*?})''',
90 @end\s+example\s))''',
92 'lilypondversion': r'''(?mx)
94 @lilypondversion)[^a-zA-Z]''',
100 ADDVERSION: r'''@example
101 \version @w{"@version{}"}
105 FILTER: r'''@lilypond[%(options)s]
111 @include %(base)s-systems.texi
115 OUTPUTIMAGE: r'''@noindent
117 @image{%(info_image_path)s,,,%(alt)s,}
121 <a href="%(base)s%(ext)s">
133 <a href="%(base)s%(ext)s">
141 QUOTE: r'''@quotation
142 %(str)s@end quotation
145 VERBATIM: r'''@exampleindent 0
147 %(verb)s@end verbatim
150 VERSION: r'''%(program_version)s''',
154 texinfo_line_widths = {
155 '@afourpaper': '160\\mm',
156 '@afourwide': '6.5\\in',
157 '@afourlatex': '150\\mm',
158 '@smallbook': '5\\in',
159 '@letterpaper': '6\\in',
164 # Retrieve dimensions from texinfo
165 TEXINFO_INSPECTION_DOCUMENT = r'''
167 @setfilename Texinfo_width_test
168 @settitle Texinfo width test
171 @message{Global: textwidth=@the@hsize,exampleindent=@the@lispnarrowing}
178 def get_texinfo_width_indent (source, global_options):
179 #TODO: Check for end of header command "@c %**end of header"
180 # only use material before that comment ?
182 # extract all relevant papter settings from the input:
184 texinfo_paper_size_regexp = r'''(@(?:afourpaper|afourwide|afourlatex|afivepaper|smallbook|letterpaper))''';
185 m = re.search (texinfo_paper_size_regexp, source);
187 pagesize = m.group (1)
189 relevant_settings_regexp = r'''(@(?:fonttextsize|pagesizes|cropmarks|exampleindent).*)\n''';
190 m = re.findall (relevant_settings_regexp, source);
192 m.insert (0, pagesize);
193 # all relevant options to insert into the test document:
194 preamble = "\n".join (m);
196 texinfo_document = TEXINFO_INSPECTION_DOCUMENT % {'preamble': preamble}
198 (handle, tmpfile) = tempfile.mkstemp('.texi')
199 outfile = os.path.splitext (tmpfile)[0] + '.pdf'
201 tmp_handle = os.fdopen (handle,'w')
202 tmp_handle.write (texinfo_document)
205 # Work around a texi2pdf bug: if LANG=C is not given, a broken regexp is
206 # used to detect relative/absolute paths, so the absolute path is not
207 # detected as such and this command fails:
208 progress (_ ("Running texi2pdf on file %s to detect default page settings.\n") % tmpfile);
210 # execute the command and pipe stdout to the parameter_string:
211 cmd = '%s -c -o %s %s' % (global_options.texinfo_program, outfile, tmpfile);
212 ly.debug_output ("Executing: %s\n" % cmd);
213 run_env = os.environ.copy()
214 run_env['LC_ALL'] = 'C'
216 ### unknown why this is necessary
217 universal_newlines = True
218 if sys.platform == 'mingw32':
219 universal_newlines = False
220 ### use os.system to avoid weird sleep() problems on
221 ### GUB's python 2.4.2 on mingw
222 # make file to write to
223 output_dir = tempfile.mkdtemp()
224 output_filename = os.path.join(output_dir, 'output.txt')
226 cmd += " > %s" % output_filename
227 returncode = os.system(cmd)
228 parameter_string = open(output_filename).read()
230 warning (_ ("Unable to auto-detect default settings:\n"))
232 os.remove(output_filename)
235 proc = subprocess.Popen (cmd,
237 universal_newlines=universal_newlines,
239 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
240 (parameter_string, error_string) = proc.communicate ()
241 if proc.returncode != 0:
242 warning (_ ("Unable to auto-detect default settings:\n%s")
245 if os.path.exists(outfile):
248 # Find textwidth and exampleindent and format it as \\mm or \\in
249 # Use defaults if they cannot be extracted
251 m = re.search ('textwidth=([0-9.]+)pt', parameter_string)
253 val = float (m.group (1))/72.27
254 if pagesize and pagesize.startswith ("@afour"):
255 textwidth = "%g\\mm" % round (val*25.4, 3);
257 textwidth = "%g\\in" % round (val, 3);
259 textwidth = texinfo_line_widths.get(pagesize, "6\\in")
262 m = re.search ('exampleindent=([0-9.]+)pt', parameter_string)
264 val = float (m.group (1))/72.27
265 if pagesize and pagesize.startswith ("@afour"):
266 exampleindent = "%g\\mm" % round (val*25.4, 3);
268 exampleindent = "%g\\in" % round (val, 3);
270 exampleindent = "0.4\\in"
272 retval = {LINE_WIDTH: textwidth, EXAMPLEINDENT: exampleindent}
273 ly.debug_output ("Auto-detected values are: %s\n" % retval);
278 texinfo_lang_re = re.compile ('(?m)^@documentlanguage (.*?)( |$)')
280 class BookTexinfoOutputFormat (BookBase.BookOutputFormat):
282 BookBase.BookOutputFormat.__init__ (self)
283 self.format = "texinfo"
284 self.default_extension = ".texi"
285 self.snippet_res = TexInfo_snippet_res
286 self.output = TexInfo_output
287 self.handled_extensions = ['.itely', '.tely', '.texi', '.texinfo']
288 self.snippet_option_separator = '\s*,\s*'
290 def can_handle_format (self, format):
291 return (BookBase.BookOutputFormat.can_handle_format (self, format) or
292 (format in ['texi-html', 'texi']))
294 def process_options (self, global_options):
295 self.process_options_pdfnotdefault (global_options)
297 def get_document_language (self, source):
298 m = texinfo_lang_re.search (source)
299 if m and not m.group (1).startswith ('en'):
304 def init_default_snippet_options (self, source):
305 texinfo_defaults = get_texinfo_width_indent (source, self.global_options);
306 self.default_snippet_options.update (texinfo_defaults)
307 BookBase.BookOutputFormat.init_default_snippet_options (self, source)
309 def adjust_snippet_command (self, cmd):
310 if '--formats' not in cmd:
311 return cmd + ' --formats=png '
315 def output_info (self, basename, snippet):
317 rep = snippet.get_replacements ();
318 rep['base'] = basename
319 rep['filename'] = os.path.basename (snippet.filename)
320 rep['ext'] = snippet.ext
321 for image in snippet.get_images ():
322 rep1 = copy.copy (rep)
323 rep1['base'] = os.path.splitext (image)[0]
324 rep1['image'] = image
325 rep1['alt'] = snippet.option_dict[ALT]
326 rep1['info_image_path'] = os.path.join (self.global_options.info_images_dir, rep1['base'])
327 str += self.output[OUTPUTIMAGE] % rep1
329 str += self.output[OUTPUT] % rep
332 def snippet_output (self, basename, snippet):
335 if DOCTITLE in snippet.option_dict:
336 doctitle = base + '.doctitle'
337 translated_doctitle = doctitle + self.document_language
338 if os.path.exists (translated_doctitle):
339 str += '\n@lydoctitle %s\n\n' % open (translated_doctitle).read ()
340 elif os.path.exists (doctitle):
341 str += '\n@lydoctitle %s\n\n' % open (doctitle).read ()
342 if TEXIDOC in snippet.option_dict:
343 texidoc = base + '.texidoc'
344 translated_texidoc = texidoc + self.document_language
345 if os.path.exists (translated_texidoc):
346 str += '@include %(translated_texidoc)s\n\n' % vars ()
347 elif os.path.exists (texidoc):
348 str += '@include %(texidoc)s\n\n' % vars ()
349 str += self.output_print_filename (basename, snippet)
352 rep = snippet.get_replacements ();
353 if VERBATIM in snippet.option_dict:
355 if ADDVERSION in snippet.option_dict:
356 rep['version'] = self.output[ADDVERSION]
357 rep['verb'] = snippet.verb_ly ()
358 substr = self.output[VERBATIM] % rep
359 substr += self.output_info (basename, snippet)
360 if QUOTE in snippet.option_dict:
361 substr = self.output[QUOTE] % {'str': substr}
364 # need par after image
369 def required_files (self, snippet, base, full, required_files):
370 return self.required_files_png (snippet, base, full, required_files)
374 BookBase.register_format (BookTexinfoOutputFormat ());