ThirdParty/Pygments/pygments/formatters/latex.py

changeset 4172
4f20dba37ab6
parent 3079
0233bbe9a9c4
child 4697
c2e9bf425554
equal deleted inserted replaced
4170:8bc578136279 4172:4f20dba37ab6
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-2013 by the Pygments team, see AUTHORS. 8 :copyright: Copyright 2006-2014 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 __future__ import division
13
12 from pygments.formatter import Formatter 14 from pygments.formatter import Formatter
15 from pygments.lexer import Lexer
13 from pygments.token import Token, STANDARD_TYPES 16 from pygments.token import Token, STANDARD_TYPES
14 from pygments.util import get_bool_opt, get_int_opt, StringIO 17 from pygments.util import get_bool_opt, get_int_opt, StringIO, xrange, \
18 iteritems
15 19
16 20
17 __all__ = ['LatexFormatter'] 21 __all__ = ['LatexFormatter']
18 22
19 23
150 Without the `full` option, code is formatted as one ``Verbatim`` 154 Without the `full` option, code is formatted as one ``Verbatim``
151 environment, like this: 155 environment, like this:
152 156
153 .. sourcecode:: latex 157 .. sourcecode:: latex
154 158
155 \begin{Verbatim}[commandchars=\\{\}] 159 \begin{Verbatim}[commandchars=\\\{\}]
156 \PY{k}{def }\PY{n+nf}{foo}(\PY{n}{bar}): 160 \PY{k}{def }\PY{n+nf}{foo}(\PY{n}{bar}):
157 \PY{k}{pass} 161 \PY{k}{pass}
158 \end{Verbatim} 162 \end{Verbatim}
159 163
160 The special command used here (``\PY``) and all the other macros it needs 164 The special command used here (``\PY``) and all the other macros it needs
203 docs for possible values) (default: ``''``). 207 docs for possible values) (default: ``''``).
204 208
205 `commandprefix` 209 `commandprefix`
206 The LaTeX commands used to produce colored output are constructed 210 The LaTeX commands used to produce colored output are constructed
207 using this prefix and some letters (default: ``'PY'``). 211 using this prefix and some letters (default: ``'PY'``).
208 *New in Pygments 0.7.* 212
209 213 .. versionadded:: 0.7
210 *New in Pygments 0.10:* the default is now ``'PY'`` instead of ``'C'``. 214 .. versionchanged:: 0.10
215 The default is now ``'PY'`` instead of ``'C'``.
211 216
212 `texcomments` 217 `texcomments`
213 If set to ``True``, enables LaTeX comment lines. That is, LaTex markup 218 If set to ``True``, enables LaTeX comment lines. That is, LaTex markup
214 in comment tokens is not escaped so that LaTeX can render it (default: 219 in comment tokens is not escaped so that LaTeX can render it (default:
215 ``False``). *New in Pygments 1.2.* 220 ``False``).
221
222 .. versionadded:: 1.2
216 223
217 `mathescape` 224 `mathescape`
218 If set to ``True``, enables LaTeX math mode escape in comments. That 225 If set to ``True``, enables LaTeX math mode escape in comments. That
219 is, ``'$...$'`` inside a comment will trigger math mode (default: 226 is, ``'$...$'`` inside a comment will trigger math mode (default:
220 ``False``). *New in Pygments 1.2.* 227 ``False``).
228
229 .. versionadded:: 1.2
230
231 `escapeinside`
232 If set to a string of length 2, enables escaping to LaTeX. Text
233 delimited by these 2 characters is read as LaTeX code and
234 typeset accordingly. It has no effect in string literals. It has
235 no effect in comments if `texcomments` or `mathescape` is
236 set. (default: ``''``).
237
238 .. versionadded:: 2.0
239
240 `envname`
241 Allows you to pick an alternative environment name replacing Verbatim.
242 The alternate environment still has to support Verbatim's option syntax.
243 (default: ``'Verbatim'``).
244
245 .. versionadded:: 2.0
221 """ 246 """
222 name = 'LaTeX' 247 name = 'LaTeX'
223 aliases = ['latex', 'tex'] 248 aliases = ['latex', 'tex']
224 filenames = ['*.tex'] 249 filenames = ['*.tex']
225 250
233 self.verboptions = options.get('verboptions', '') 258 self.verboptions = options.get('verboptions', '')
234 self.nobackground = get_bool_opt(options, 'nobackground', False) 259 self.nobackground = get_bool_opt(options, 'nobackground', False)
235 self.commandprefix = options.get('commandprefix', 'PY') 260 self.commandprefix = options.get('commandprefix', 'PY')
236 self.texcomments = get_bool_opt(options, 'texcomments', False) 261 self.texcomments = get_bool_opt(options, 'texcomments', False)
237 self.mathescape = get_bool_opt(options, 'mathescape', False) 262 self.mathescape = get_bool_opt(options, 'mathescape', False)
263 self.escapeinside = options.get('escapeinside', '')
264 if len(self.escapeinside) == 2:
265 self.left = self.escapeinside[0]
266 self.right = self.escapeinside[1]
267 else:
268 self.escapeinside = ''
269 self.envname = options.get('envname', u'Verbatim')
238 270
239 self._create_stylesheet() 271 self._create_stylesheet()
240
241 272
242 def _create_stylesheet(self): 273 def _create_stylesheet(self):
243 t2n = self.ttype2name = {Token: ''} 274 t2n = self.ttype2name = {Token: ''}
244 c2d = self.cmd2def = {} 275 c2d = self.cmd2def = {}
245 cp = self.commandprefix 276 cp = self.commandprefix
246 277
247 def rgbcolor(col): 278 def rgbcolor(col):
248 if col: 279 if col:
249 return ','.join(['%.2f' %(int(col[i] + col[i + 1], 16) / 255.0) 280 return ','.join(['%.2f' % (int(col[i] + col[i + 1], 16) / 255.0)
250 for i in (0, 2, 4)]) 281 for i in (0, 2, 4)])
251 else: 282 else:
252 return '1,1,1' 283 return '1,1,1'
253 284
254 for ttype, ndef in self.style: 285 for ttype, ndef in self.style:
289 Return the command sequences needed to define the commands 320 Return the command sequences needed to define the commands
290 used to format text in the verbatim environment. ``arg`` is ignored. 321 used to format text in the verbatim environment. ``arg`` is ignored.
291 """ 322 """
292 cp = self.commandprefix 323 cp = self.commandprefix
293 styles = [] 324 styles = []
294 for name, definition in self.cmd2def.items(): 325 for name, definition in iteritems(self.cmd2def):
295 styles.append(r'\expandafter\def\csname %s@tok@%s\endcsname{%s}' % 326 styles.append(r'\expandafter\def\csname %s@tok@%s\endcsname{%s}' %
296 (cp, name, definition)) 327 (cp, name, definition))
297 return STYLE_TEMPLATE % {'cp': self.commandprefix, 328 return STYLE_TEMPLATE % {'cp': self.commandprefix,
298 'styles': '\n'.join(styles)} 329 'styles': '\n'.join(styles)}
299 330
304 335
305 if self.full: 336 if self.full:
306 realoutfile = outfile 337 realoutfile = outfile
307 outfile = StringIO() 338 outfile = StringIO()
308 339
309 outfile.write(r'\begin{Verbatim}[commandchars=\\\{\}') 340 outfile.write(u'\\begin{' + self.envname + u'}[commandchars=\\\\\\{\\}')
310 if self.linenos: 341 if self.linenos:
311 start, step = self.linenostart, self.linenostep 342 start, step = self.linenostart, self.linenostep
312 outfile.write(',numbers=left' + 343 outfile.write(u',numbers=left' +
313 (start and ',firstnumber=%d' % start or '') + 344 (start and u',firstnumber=%d' % start or u'') +
314 (step and ',stepnumber=%d' % step or '')) 345 (step and u',stepnumber=%d' % step or u''))
315 if self.mathescape or self.texcomments: 346 if self.mathescape or self.texcomments or self.escapeinside:
316 outfile.write(r',codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8}') 347 outfile.write(u',codes={\\catcode`\\$=3\\catcode`\\^=7\\catcode`\\_=8}')
317 if self.verboptions: 348 if self.verboptions:
318 outfile.write(',' + self.verboptions) 349 outfile.write(u',' + self.verboptions)
319 outfile.write(']\n') 350 outfile.write(u']\n')
320 351
321 for ttype, value in tokensource: 352 for ttype, value in tokensource:
322 if ttype in Token.Comment: 353 if ttype in Token.Comment:
323 if self.texcomments: 354 if self.texcomments:
324 # Try to guess comment starting lexeme and escape it ... 355 # Try to guess comment starting lexeme and escape it ...
325 start = value[0:1] 356 start = value[0:1]
326 for i in range(1, len(value)): 357 for i in xrange(1, len(value)):
327 if start[0] != value[i]: 358 if start[0] != value[i]:
328 break 359 break
329 start += value[i] 360 start += value[i]
330 361
331 value = value[len(start):] 362 value = value[len(start):]
340 for i, part in enumerate(parts): 371 for i, part in enumerate(parts):
341 if not in_math: 372 if not in_math:
342 parts[i] = escape_tex(part, self.commandprefix) 373 parts[i] = escape_tex(part, self.commandprefix)
343 in_math = not in_math 374 in_math = not in_math
344 value = '$'.join(parts) 375 value = '$'.join(parts)
376 elif self.escapeinside:
377 text = value
378 value = ''
379 while len(text) > 0:
380 a, sep1, text = text.partition(self.left)
381 if len(sep1) > 0:
382 b, sep2, text = text.partition(self.right)
383 if len(sep2) > 0:
384 value += escape_tex(a, self.commandprefix) + b
385 else:
386 value += escape_tex(a + sep1 + b, self.commandprefix)
387 else:
388 value = value + escape_tex(a, self.commandprefix)
345 else: 389 else:
346 value = escape_tex(value, self.commandprefix) 390 value = escape_tex(value, self.commandprefix)
347 else: 391 elif ttype not in Token.Escape:
348 value = escape_tex(value, self.commandprefix) 392 value = escape_tex(value, self.commandprefix)
349 styles = [] 393 styles = []
350 while ttype is not Token: 394 while ttype is not Token:
351 try: 395 try:
352 styles.append(t2n[ttype]) 396 styles.append(t2n[ttype])
364 if spl[-1]: 408 if spl[-1]:
365 outfile.write("\\%s{%s}{%s}" % (cp, styleval, spl[-1])) 409 outfile.write("\\%s{%s}{%s}" % (cp, styleval, spl[-1]))
366 else: 410 else:
367 outfile.write(value) 411 outfile.write(value)
368 412
369 outfile.write('\\end{Verbatim}\n') 413 outfile.write(u'\\end{' + self.envname + u'}\n')
370 414
371 if self.full: 415 if self.full:
372 realoutfile.write(DOC_TEMPLATE % 416 realoutfile.write(DOC_TEMPLATE %
373 dict(docclass = self.docclass, 417 dict(docclass = self.docclass,
374 preamble = self.preamble, 418 preamble = self.preamble,
375 title = self.title, 419 title = self.title,
376 encoding = self.encoding or 'latin1', 420 encoding = self.encoding or 'utf8',
377 styledefs = self.get_style_defs(), 421 styledefs = self.get_style_defs(),
378 code = outfile.getvalue())) 422 code = outfile.getvalue()))
423
424
425 class LatexEmbeddedLexer(Lexer):
426 r"""
427
428 This lexer takes one lexer as argument, the lexer for the language
429 being formatted, and the left and right delimiters for escaped text.
430
431 First everything is scanned using the language lexer to obtain
432 strings and comments. All other consecutive tokens are merged and
433 the resulting text is scanned for escaped segments, which are given
434 the Token.Escape type. Finally text that is not escaped is scanned
435 again with the language lexer.
436 """
437 def __init__(self, left, right, lang, **options):
438 self.left = left
439 self.right = right
440 self.lang = lang
441 Lexer.__init__(self, **options)
442
443 def get_tokens_unprocessed(self, text):
444 buf = ''
445 idx = 0
446 for i, t, v in self.lang.get_tokens_unprocessed(text):
447 if t in Token.Comment or t in Token.String:
448 if buf:
449 for x in self.get_tokens_aux(idx, buf):
450 yield x
451 buf = ''
452 yield i, t, v
453 else:
454 if not buf:
455 idx = i
456 buf += v
457 if buf:
458 for x in self.get_tokens_aux(idx, buf):
459 yield x
460
461 def get_tokens_aux(self, index, text):
462 while text:
463 a, sep1, text = text.partition(self.left)
464 if a:
465 for i, t, v in self.lang.get_tokens_unprocessed(a):
466 yield index + i, t, v
467 index += len(a)
468 if sep1:
469 b, sep2, text = text.partition(self.right)
470 if sep2:
471 yield index + len(sep1), Token.Escape, b
472 index += len(sep1) + len(b) + len(sep2)
473 else:
474 yield index, Token.Error, sep1
475 index += len(sep1)
476 text = b

eric ide

mercurial