3 pygments.formatters.latex |
3 pygments.formatters.latex |
4 ~~~~~~~~~~~~~~~~~~~~~~~~~ |
4 ~~~~~~~~~~~~~~~~~~~~~~~~~ |
5 |
5 |
6 Formatter for LaTeX fancyvrb output. |
6 Formatter for LaTeX fancyvrb output. |
7 |
7 |
8 :copyright: Copyright 2006-2009 by the Pygments team, see AUTHORS. |
8 :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS. |
9 :license: BSD, see LICENSE for details. |
9 :license: BSD, see LICENSE for details. |
10 """ |
10 """ |
11 |
11 |
12 from pygments.formatter import Formatter |
12 from pygments.formatter import Formatter |
13 from pygments.token import Token, STANDARD_TYPES |
13 from pygments.token import Token, STANDARD_TYPES |
16 |
16 |
17 __all__ = ['LatexFormatter'] |
17 __all__ = ['LatexFormatter'] |
18 |
18 |
19 |
19 |
20 def escape_tex(text, commandprefix): |
20 def escape_tex(text, commandprefix): |
21 return text.replace('@', '\x00'). \ |
21 return text.replace('\\', '\x00'). \ |
22 replace('[', '\x01'). \ |
22 replace('{', '\x01'). \ |
23 replace(']', '\x02'). \ |
23 replace('}', '\x02'). \ |
24 replace('\x00', '@%sZat[]' % commandprefix).\ |
24 replace('^', '\x03'). \ |
25 replace('\x01', '@%sZlb[]' % commandprefix).\ |
25 replace('_', '\x04'). \ |
26 replace('\x02', '@%sZrb[]' % commandprefix) |
26 replace('\x00', r'\%sZbs{}' % commandprefix). \ |
|
27 replace('\x01', r'\%sZob{}' % commandprefix). \ |
|
28 replace('\x02', r'\%sZcb{}' % commandprefix). \ |
|
29 replace('\x03', r'\%sZca{}' % commandprefix). \ |
|
30 replace('\x04', r'\%sZus{}' % commandprefix) |
27 |
31 |
28 |
32 |
29 DOC_TEMPLATE = r''' |
33 DOC_TEMPLATE = r''' |
30 \documentclass{%(docclass)s} |
34 \documentclass{%(docclass)s} |
31 \usepackage{fancyvrb} |
35 \usepackage{fancyvrb} |
90 \%(cp)s@it{\%(cp)s@bf{\%(cp)s@ff{#1}}}}}}} |
94 \%(cp)s@it{\%(cp)s@bf{\%(cp)s@ff{#1}}}}}}} |
91 \def\%(cp)s#1#2{\%(cp)s@reset\%(cp)s@toks#1+\relax+\%(cp)s@do{#2}} |
95 \def\%(cp)s#1#2{\%(cp)s@reset\%(cp)s@toks#1+\relax+\%(cp)s@do{#2}} |
92 |
96 |
93 %(styles)s |
97 %(styles)s |
94 |
98 |
|
99 \def\%(cp)sZbs{\char`\\} |
|
100 \def\%(cp)sZus{\char`\_} |
|
101 \def\%(cp)sZob{\char`\{} |
|
102 \def\%(cp)sZcb{\char`\}} |
|
103 \def\%(cp)sZca{\char`\^} |
|
104 %% for compatibility with earlier versions |
95 \def\%(cp)sZat{@} |
105 \def\%(cp)sZat{@} |
96 \def\%(cp)sZlb{[} |
106 \def\%(cp)sZlb{[} |
97 \def\%(cp)sZrb{]} |
107 \def\%(cp)sZrb{]} |
98 \makeatother |
108 \makeatother |
99 ''' |
109 ''' |
175 The LaTeX commands used to produce colored output are constructed |
185 The LaTeX commands used to produce colored output are constructed |
176 using this prefix and some letters (default: ``'PY'``). |
186 using this prefix and some letters (default: ``'PY'``). |
177 *New in Pygments 0.7.* |
187 *New in Pygments 0.7.* |
178 |
188 |
179 *New in Pygments 0.10:* the default is now ``'PY'`` instead of ``'C'``. |
189 *New in Pygments 0.10:* the default is now ``'PY'`` instead of ``'C'``. |
|
190 |
|
191 `texcomments` |
|
192 If set to ``True``, enables LaTeX comment lines. That is, LaTex markup |
|
193 in comment tokens is not escaped so that LaTeX can render it (default: |
|
194 ``False``). *New in Pygments 1.2.* |
|
195 |
|
196 `mathescape` |
|
197 If set to ``True``, enables LaTeX math mode escape in comments. That |
|
198 is, ``'$...$'`` inside a comment will trigger math mode (default: |
|
199 ``False``). *New in Pygments 1.2.* |
180 """ |
200 """ |
181 name = 'LaTeX' |
201 name = 'LaTeX' |
182 aliases = ['latex', 'tex'] |
202 aliases = ['latex', 'tex'] |
183 filenames = ['*.tex'] |
203 filenames = ['*.tex'] |
184 |
204 |
190 self.linenostart = abs(get_int_opt(options, 'linenostart', 1)) |
210 self.linenostart = abs(get_int_opt(options, 'linenostart', 1)) |
191 self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) |
211 self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) |
192 self.verboptions = options.get('verboptions', '') |
212 self.verboptions = options.get('verboptions', '') |
193 self.nobackground = get_bool_opt(options, 'nobackground', False) |
213 self.nobackground = get_bool_opt(options, 'nobackground', False) |
194 self.commandprefix = options.get('commandprefix', 'PY') |
214 self.commandprefix = options.get('commandprefix', 'PY') |
|
215 self.texcomments = get_bool_opt(options, 'texcomments', False) |
|
216 self.mathescape = get_bool_opt(options, 'mathescape', False) |
195 |
217 |
196 self._create_stylesheet() |
218 self._create_stylesheet() |
197 |
219 |
198 |
220 |
199 def _create_stylesheet(self): |
221 def _create_stylesheet(self): |
258 |
280 |
259 if self.full: |
281 if self.full: |
260 realoutfile = outfile |
282 realoutfile = outfile |
261 outfile = StringIO() |
283 outfile = StringIO() |
262 |
284 |
263 outfile.write(r'\begin{Verbatim}[commandchars=@\[\]') |
285 outfile.write(r'\begin{Verbatim}[commandchars=\\\{\}') |
264 if self.linenos: |
286 if self.linenos: |
265 start, step = self.linenostart, self.linenostep |
287 start, step = self.linenostart, self.linenostep |
266 outfile.write(',numbers=left' + |
288 outfile.write(',numbers=left' + |
267 (start and ',firstnumber=%d' % start or '') + |
289 (start and ',firstnumber=%d' % start or '') + |
268 (step and ',stepnumber=%d' % step or '')) |
290 (step and ',stepnumber=%d' % step or '')) |
|
291 if self.mathescape or self.texcomments: |
|
292 outfile.write(r',codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8}') |
269 if self.verboptions: |
293 if self.verboptions: |
270 outfile.write(',' + self.verboptions) |
294 outfile.write(',' + self.verboptions) |
271 outfile.write(']\n') |
295 outfile.write(']\n') |
272 |
296 |
273 for ttype, value in tokensource: |
297 for ttype, value in tokensource: |
274 value = escape_tex(value, self.commandprefix) |
298 if ttype in Token.Comment: |
|
299 if self.texcomments: |
|
300 # Try to guess comment starting lexeme and escape it ... |
|
301 start = value[0:1] |
|
302 for i in range(1, len(value)): |
|
303 if start[0] != value[i]: |
|
304 break |
|
305 start += value[i] |
|
306 |
|
307 value = value[len(start):] |
|
308 start = escape_tex(start, self.commandprefix) |
|
309 |
|
310 # ... but do not escape inside comment. |
|
311 value = start + value |
|
312 elif self.mathescape: |
|
313 # Only escape parts not inside a math environment. |
|
314 parts = value.split('$') |
|
315 in_math = False |
|
316 for i, part in enumerate(parts): |
|
317 if not in_math: |
|
318 parts[i] = escape_tex(part, self.commandprefix) |
|
319 in_math = not in_math |
|
320 value = '$'.join(parts) |
|
321 else: |
|
322 value = escape_tex(value, self.commandprefix) |
|
323 else: |
|
324 value = escape_tex(value, self.commandprefix) |
275 styles = [] |
325 styles = [] |
276 while ttype is not Token: |
326 while ttype is not Token: |
277 try: |
327 try: |
278 styles.append(t2n[ttype]) |
328 styles.append(t2n[ttype]) |
279 except KeyError: |
329 except KeyError: |
283 styleval = '+'.join(reversed(styles)) |
333 styleval = '+'.join(reversed(styles)) |
284 if styleval: |
334 if styleval: |
285 spl = value.split('\n') |
335 spl = value.split('\n') |
286 for line in spl[:-1]: |
336 for line in spl[:-1]: |
287 if line: |
337 if line: |
288 outfile.write("@%s[%s][%s]" % (cp, styleval, line)) |
338 outfile.write("\\%s{%s}{%s}" % (cp, styleval, line)) |
289 outfile.write('\n') |
339 outfile.write('\n') |
290 if spl[-1]: |
340 if spl[-1]: |
291 outfile.write("@%s[%s][%s]" % (cp, styleval, spl[-1])) |
341 outfile.write("\\%s{%s}{%s}" % (cp, styleval, spl[-1])) |
292 else: |
342 else: |
293 outfile.write(value) |
343 outfile.write(value) |
294 |
344 |
295 outfile.write('\\end{Verbatim}\n') |
345 outfile.write('\\end{Verbatim}\n') |
296 |
346 |