# -*- coding: utf-8 -*-
"""
pygments.formatters.latex
~~~~~~~~~~~~~~~~~~~~~~~~~
Formatter for LaTeX fancyvrb output.
:copyright: 2006-2008 by Georg Brandl.
:license: BSD, see LICENSE for more details.
"""
import StringIO
from pygments.formatter import Formatter
from pygments.token import Token
from pygments.util import get_bool_opt,get_int_opt
__all__ = ['LatexFormatter']
def escape_tex(text, commandprefix):
return text.replace('@', '\x00'). \
replace('[', '\x01'). \
replace(']', '\x02'). \
replace('\x00', '@%sZat[]' % commandprefix).\
replace('\x01', '@%sZlb[]' % commandprefix).\
replace('\x02', '@%sZrb[]' % commandprefix)
DOC_TEMPLATE = r'''
\documentclass{%(docclass)s}
\usepackage{fancyvrb}
\usepackage{color}
\usepackage[%(encoding)s]{inputenc}
%(preamble)s
%(styledefs)s
\begin{document}
\section*{%(title)s}
%(code)s
\end{document}
'''
class LatexFormatter(Formatter):
r"""
Format tokens as LaTeX code. This needs the `fancyvrb` and `color`
standard packages.
Without the `full` option, code is formatted as one ``Verbatim``
environment, like this:
.. sourcecode:: latex
\begin{Verbatim}[commandchars=@\[\]]
@PYan[def ]@PYax[foo](bar):
@PYan[pass]
\end{Verbatim}
The command sequences used here (``@PYan`` etc.) are generated from the given
`style` and can be retrieved using the `get_style_defs` method.
With the `full` option, a complete LaTeX document is output, including
the command definitions in the preamble.
The `get_style_defs()` method of a `LatexFormatter` returns a string
containing ``\newcommand`` commands defining the commands used inside the
``Verbatim`` environments.
Additional options accepted:
`style`
The style to use, can be a string or a Style subclass (default:
``'default'``).
`full`
Tells the formatter to output a "full" document, i.e. a complete
self-contained document (default: ``False``).
`title`
If `full` is true, the title that should be used to caption the
document (default: ``''``).
`docclass`
If the `full` option is enabled, this is the document class to use
(default: ``'article'``).
`preamble`
If the `full` option is enabled, this can be further preamble commands,
e.g. ``\usepackage`` (default: ``''``).
`linenos`
If set to ``True``, output line numbers (default: ``False``).
`linenostart`
The line number for the first line (default: ``1``).
`linenostep`
If set to a number n > 1, only every nth line number is printed.
`verboptions`
Additional options given to the Verbatim environment (see the *fancyvrb*
docs for possible values) (default: ``''``).
`commandprefix`
The LaTeX commands used to produce colored output are constructed
using this prefix and some letters (default: ``'PY'``).
*New in Pygments 0.7.*
*New in Pygments 0.10:* the default is now ``'PY'`` instead of ``'C'``.
"""
name = 'LaTeX'
aliases = ['latex', 'tex']
filenames = ['*.tex']
def __init__(self, **options):
Formatter.__init__(self, **options)
self.docclass = options.get('docclass', 'article')
self.preamble = options.get('preamble', '')
self.linenos = get_bool_opt(options, 'linenos', False)
self.linenostart = abs(get_int_opt(options, 'linenostart', 1))
self.linenostep = abs(get_int_opt(options, 'linenostep', 1))
self.verboptions = options.get('verboptions', '')
self.nobackground = get_bool_opt(options, 'nobackground', False)
self.commandprefix = options.get('commandprefix', 'PY')
self._create_stylecmds()
def _create_stylecmds(self):
t2c = self.ttype2cmd = {Token: ''}
c2d = self.cmd2def = {}
cp = self.commandprefix
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
first = iter(letters)
second = iter(letters)
firstl = first.next()
def rgbcolor(col):
if col:
return ','.join(['%.2f' %(int(col[i] + col[i + 1], 16) / 255.0)
for i in (0, 2, 4)])
else:
return '1,1,1'
for ttype, ndef in self.style:
cmndef = '#1'
if ndef['bold']:
cmndef = r'\textbf{' + cmndef + '}'
if ndef['italic']:
cmndef = r'\textit{' + cmndef + '}'
if ndef['underline']:
cmndef = r'\underline{' + cmndef + '}'
if ndef['roman']:
cmndef = r'\textrm{' + cmndef + '}'
if ndef['sans']:
cmndef = r'\textsf{' + cmndef + '}'
if ndef['mono']:
cmndef = r'\texttt{' + cmndef + '}'
if ndef['color']:
cmndef = r'\textcolor[rgb]{%s}{%s}' % (
rgbcolor(ndef['color']),
cmndef
)
if ndef['border']:
cmndef = r'\fcolorbox[rgb]{%s}{%s}{%s}' % (
rgbcolor(ndef['border']),
rgbcolor(ndef['bgcolor']),
cmndef
)
elif ndef['bgcolor']:
cmndef = r'\colorbox[rgb]{%s}{%s}' % (
rgbcolor(ndef['bgcolor']),
cmndef
)
if cmndef == '#1':
continue
try:
alias = cp + firstl + second.next()
except StopIteration:
firstl = first.next()
second = iter(letters)
alias = cp + firstl + second.next()
t2c[ttype] = alias
c2d[alias] = cmndef
def get_style_defs(self, arg=''):
"""
Return the \\newcommand sequences needed to define the commands
used to format text in the verbatim environment. ``arg`` is ignored.
"""
nc = '\\newcommand'
cp = self.commandprefix
return (
'%s\\%sZat{@}\n%s\\%sZlb{[}\n%s\\%sZrb{]}\n' % (nc, cp, nc, cp, nc, cp) +
'\n'.join(['\\newcommand\\%s[1]{%s}' % (alias, cmndef)
for alias, cmndef in self.cmd2def.iteritems()
if cmndef != '#1']))
def format(self, tokensource, outfile):
# TODO: add support for background colors
enc = self.encoding
if self.full:
realoutfile = outfile
outfile = StringIO.StringIO()
outfile.write(r'\begin{Verbatim}[commandchars=@\[\]')
if self.linenos:
start, step = self.linenostart, self.linenostep
outfile.write(',numbers=left' +
(start and ',firstnumber=%d' % start or '') +
(step and ',stepnumber=%d' % step or ''))
if self.verboptions:
outfile.write(',' + self.verboptions)
outfile.write(']\n')
for ttype, value in tokensource:
if enc:
value = value.encode(enc)
value = escape_tex(value, self.commandprefix)
cmd = self.ttype2cmd.get(ttype)
while cmd is None:
ttype = ttype.parent
cmd = self.ttype2cmd.get(ttype)
if cmd:
spl = value.split('\n')
for line in spl[:-1]:
if line:
outfile.write("@%s[%s]" % (cmd, line))
outfile.write('\n')
if spl[-1]:
outfile.write("@%s[%s]" % (cmd, spl[-1]))
else:
outfile.write(value)
outfile.write('\\end{Verbatim}\n')
if self.full:
realoutfile.write(DOC_TEMPLATE %
dict(docclass = self.docclass,
preamble = self.preamble,
title = self.title,
encoding = self.encoding or 'latin1',
styledefs = self.get_style_defs(),
code = outfile.getvalue()))
|