1 # -*- coding: utf-8 -*-
6 import book_base as BookBase
7 from book_snippets import *
12 # Recognize special sequences in the input.
14 # (?P<name>regex) -- Assign result of REGEX to NAME.
15 # *? -- Match non-greedily.
16 # (?!...) -- Match if `...' doesn't match next (without consuming
19 # (?m) -- Multiline regex: Make ^ and $ match at each line.
20 # (?s) -- Make the dot match all characters including newline.
21 # (?x) -- Ignore whitespace in patterns.
23 # 'multiline_comment', 'verbatim', 'lilypond_block', 'singleline_comment',
24 # 'lilypond_file', 'include', 'lilypond', 'lilypondversion'
25 TexInfo_snippet_res = {
29 (?P<filename>\S+))''',
31 'lilypond': r'''(?smx)
32 ^[^\n]*?(?!@c\s+)[^\n]*?
36 \s*(?P<options>.*?)\s*
41 'lilypond_block': r'''(?msx)
45 \s*(?P<options>.*?)\s*
48 ^@end\s+lilypond)\s''',
50 'lilypond_file': r'''(?mx)
54 \s*(?P<options>.*?)\s*
59 'multiline_comment': r'''(?smx)
66 'musicxml_file': r'''(?mx)
70 \s*(?P<options>.*?)\s*
75 'singleline_comment': r'''(?mx)
79 @c([ \t][^\n]*|)\n))''',
81 # Don't do this: It interferes with @code{@{}.
82 # 'verb': r'''(?P<code>@code{.*?})''',
89 @end\s+example\s))''',
91 'lilypondversion': r'''(?mx)
93 @lilypondversion)[^a-zA-Z]''',
99 ADDVERSION: r'''@example
100 \version @w{"@version{}"}
104 FILTER: r'''@lilypond[%(options)s]
110 @include %(base)s-systems.texi
114 OUTPUTIMAGE: r'''@noindent
116 @image{%(info_image_path)s,,,%(alt)s,%(ext)s}
120 <a href="%(base)s%(ext)s">
132 <a href="%(base)s%(ext)s">
140 QUOTE: r'''@quotation
141 %(str)s@end quotation
144 VERBATIM: r'''@exampleindent 0
146 %(verb)s@end verbatim
149 VERSION: r'''%(program_version)s''',
153 texinfo_line_widths = {
154 '@afourpaper': '160\\mm',
155 '@afourwide': '6.5\\in',
156 '@afourlatex': '150\\mm',
157 '@smallbook': '5\\in',
158 '@letterpaper': '6\\in',
163 # Retrieve dimensions from texinfo
164 TEXINFO_INSPECTION_DOCUMENT = r'''
166 @setfilename Texinfo_width_test
167 @settitle Texinfo width test
170 @message{Global: textwidth=@the@hsize,exampleindent=@the@lispnarrowing}
175 def get_texinfo_width_indent (source, global_options):
176 #TODO: Check for end of header command "@c %**end of header"
177 # only use material before that comment ?
179 # extract all relevant papter settings from the input:
181 texinfo_paper_size_regexp = r'''(@(?:afourpaper|afourwide|afourlatex|afivepaper|smallbook|letterpaper))''';
182 m = re.search (texinfo_paper_size_regexp, source);
184 pagesize = m.group (1)
186 relevant_settings_regexp = r'''(@(?:fonttextsize|pagesizes|cropmarks|exampleindent).*)\n''';
187 m = re.findall (relevant_settings_regexp, source);
189 m.insert (0, pagesize);
190 # all relevant options to insert into the test document:
191 preamble = "\n".join (m);
193 texinfo_document = TEXINFO_INSPECTION_DOCUMENT % {'preamble': preamble}
195 (handle, tmpfile) = tempfile.mkstemp('.texi')
196 outfile = os.path.splitext (tmpfile)[0] + '.pdf'
198 tmp_handle = os.fdopen (handle,'w')
199 tmp_handle.write (texinfo_document)
202 # Work around a texi2pdf bug: if LANG=C is not given, a broken regexp is
203 # used to detect relative/absolute pathes, so the absolute path is not
204 # detected as such and this command fails:
205 progress (_ ("Running texi2pdf on file %s to detect default page settings.\n") % tmpfile);
207 # execute the command and pipe stdout to the parameter_string:
208 cmd = 'LC_ALL=C %s -c -o %s %s' % (global_options.texinfo_program, outfile, tmpfile);
209 if (global_options.verbose):
210 progress ("Executing: %s\n" % cmd);
212 proc = subprocess.Popen (cmd,
213 universal_newlines=True, shell=True,
214 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
215 (parameter_string, error_string) = proc.communicate ()
216 if proc.returncode != 0:
217 warning (_ ("Unable to auto-detect default settings:\n%s")
220 if os.path.exists(outfile):
223 # Find textwidth and exampleindent and format it as \\mm or \\in
224 # Use defaults if they cannot be extracted
226 m = re.search ('textwidth=([0-9.]+)pt', parameter_string)
228 val = float (m.group (1))/72.27
229 if pagesize and pagesize.startswith ("@afour"):
230 textwidth = "%g\\mm" % round (val*25.4, 3);
232 textwidth = "%g\\in" % round (val, 3);
234 textwidth = texinfo_line_widths.get(pagesize, "6\\in")
237 m = re.search ('exampleindent=([0-9.]+)pt', parameter_string)
239 val = float (m.group (1))/72.27
240 if pagesize and pagesize.startswith ("@afour"):
241 exampleindent = "%g\\mm" % round (val*25.4, 3);
243 exampleindent = "%g\\in" % round (val, 3);
245 exampleindent = "0.4\\in"
247 retval = {LINE_WIDTH: textwidth, EXAMPLEINDENT: exampleindent}
248 if (global_options.verbose):
249 progress ("Auto-detected values are: %s\n" % retval);
254 texinfo_lang_re = re.compile ('(?m)^@documentlanguage (.*?)( |$)')
256 class BookTexinfoOutputFormat (BookBase.BookOutputFormat):
258 BookBase.BookOutputFormat.__init__ (self)
259 self.format = "texinfo"
260 self.default_extension = ".texi"
261 self.snippet_res = TexInfo_snippet_res
262 self.output = TexInfo_output
263 self.handled_extensions = ['.itely', '.tely', '.texi', '.texinfo']
264 self.snippet_option_separator = '\s*,\s*'
266 def can_handle_format (self, format):
267 return (BookBase.BookOutputFormat.can_handle_format (self, format) or
268 (format in ['texi-html', 'texi']))
270 def process_options (self, global_options):
271 self.process_options_pdfnotdefault (global_options)
273 def get_document_language (self, source):
274 m = texinfo_lang_re.search (source)
275 if m and not m.group (1).startswith ('en'):
280 def init_default_snippet_options (self, source):
281 texinfo_defaults = get_texinfo_width_indent (source, self.global_options);
282 self.default_snippet_options.update (texinfo_defaults)
283 BookBase.BookOutputFormat.init_default_snippet_options (self, source)
285 def adjust_snippet_command (self, cmd):
286 if '--formats' not in cmd:
287 return cmd + ' --formats=png '
291 def output_info (self, basename, snippet):
293 rep = snippet.get_replacements ();
294 for image in snippet.get_images ():
295 rep1 = copy.copy (rep)
296 (rep1['base'], rep1['ext']) = os.path.splitext (image)
297 rep1['image'] = image
299 # URG, makeinfo implicitly prepends dot to extension.
300 # Specifying no extension is most robust.
302 rep1['alt'] = snippet.option_dict[ALT]
303 rep1['info_image_path'] = os.path.join (self.global_options.info_images_dir, rep1['base'])
304 str += self.output[OUTPUTIMAGE] % rep1
306 rep['base'] = basename
307 str += self.output[OUTPUT] % rep
310 def snippet_output (self, basename, snippet):
311 str = self.output_print_filename (basename, snippet)
313 if DOCTITLE in snippet.option_dict:
314 doctitle = base + '.doctitle'
315 translated_doctitle = doctitle + self.document_language
316 if os.path.exists (translated_doctitle):
317 str += '@lydoctitle %s\n\n' % open (translated_doctitle).read ()
318 elif os.path.exists (doctitle):
319 str += '@lydoctitle %s\n\n' % open (doctitle).read ()
320 if TEXIDOC in snippet.option_dict:
321 texidoc = base + '.texidoc'
322 translated_texidoc = texidoc + self.document_language
323 if os.path.exists (translated_texidoc):
324 str += '@include %(translated_texidoc)s\n\n' % vars ()
325 elif os.path.exists (texidoc):
326 str += '@include %(texidoc)s\n\n' % vars ()
329 rep = snippet.get_replacements ();
330 if VERBATIM in snippet.option_dict:
332 if ADDVERSION in snippet.option_dict:
333 rep['version'] = self.output[ADDVERSION]
334 rep['verb'] = snippet.verb_ly ()
335 substr = self.output[VERBATIM] % rep
336 substr += self.output_info (basename, snippet)
337 if QUOTE in snippet.option_dict:
338 substr = self.output[QUOTE] % {'str': substr}
341 # need par after image
346 def required_files (self, snippet, base, full, required_files):
347 return self.required_files_png (snippet, base, full, required_files)
351 BookBase.register_format (BookTexinfoOutputFormat ());