/console/app/pygments/formatters/latex.py
Python | 248 lines | 226 code | 11 blank | 11 comment | 16 complexity | e91a94f0c2e5f3009ed7d394f23eb201 MD5 | raw file
Possible License(s): GPL-3.0
1# -*- coding: utf-8 -*-
2"""
3 pygments.formatters.latex
4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Formatter for LaTeX fancyvrb output.
7
8 :copyright: 2006-2007 by Georg Brandl.
9 :license: BSD, see LICENSE for more details.
10"""
11import StringIO
12
13from pygments.formatter import Formatter
14from pygments.token import Token
15from pygments.util import get_bool_opt, get_int_opt
16
17
18__all__ = ['LatexFormatter']
19
20
21def escape_tex(text):
22 return text.replace('@', '\x00'). \
23 replace('[', '\x01'). \
24 replace(']', '\x02'). \
25 replace('\x00', '@at[]').\
26 replace('\x01', '@lb[]').\
27 replace('\x02', '@rb[]')
28
29
30DOC_TEMPLATE = r'''
31\documentclass{%(docclass)s}
32\usepackage{fancyvrb}
33\usepackage{color}
34\usepackage[%(encoding)s]{inputenc}
35%(preamble)s
36
37%(styledefs)s
38
39\begin{document}
40
41\section*{%(title)s}
42
43%(code)s
44\end{document}
45'''
46
47
48class LatexFormatter(Formatter):
49 r"""
50 Format tokens as LaTeX code. This needs the `fancyvrb` and `color`
51 standard packages.
52
53 Without the `full` option, code is formatted as one ``Verbatim``
54 environment, like this:
55
56 .. sourcecode:: latex
57
58 \begin{Verbatim}[commandchars=@\[\]]
59 @PYan[def ]@PYax[foo](bar):
60 @PYan[pass]
61 \end{Verbatim}
62
63 The command sequences used here (``@PYan`` etc.) are generated from the given
64 `style` and can be retrieved using the `get_style_defs` method.
65
66 With the `full` option, a complete LaTeX document is output, including
67 the command definitions in the preamble.
68
69 The `get_style_defs()` method of a `LatexFormatter` returns a string
70 containing ``\newcommand`` commands defining the commands used inside the
71 ``Verbatim`` environments.
72
73 Additional options accepted:
74
75 `style`
76 The style to use, can be a string or a Style subclass (default:
77 ``'default'``).
78
79 `full`
80 Tells the formatter to output a "full" document, i.e. a complete
81 self-contained document (default: ``False``).
82
83 `title`
84 If `full` is true, the title that should be used to caption the
85 document (default: ``''``).
86
87 `docclass`
88 If the `full` option is enabled, this is the document class to use
89 (default: ``'article'``).
90
91 `preamble`
92 If the `full` option is enabled, this can be further preamble commands,
93 e.g. ``\usepackage`` (default: ``''``).
94
95 `linenos`
96 If set to ``True``, output line numbers (default: ``False``).
97
98 `linenostart`
99 The line number for the first line (default: ``1``).
100
101 `linenostep`
102 If set to a number n > 1, only every nth line number is printed.
103
104 `verboptions`
105 Additional options given to the Verbatim environment (see the *fancyvrb*
106 docs for possible values) (default: ``''``).
107
108 `commandprefix`
109 The LaTeX commands used to produce colored output are constructed
110 using this prefix and some letters (default: ``'PY'``).
111 *New in Pygments 0.7.*
112
113 *New in Pygments 0.10:* the default is now ``'PY'`` instead of ``'C'``.
114 """
115 name = 'LaTeX'
116 aliases = ['latex', 'tex']
117 filenames = ['*.tex']
118
119 def __init__(self, **options):
120 Formatter.__init__(self, **options)
121 self.docclass = options.get('docclass', 'article')
122 self.preamble = options.get('preamble', '')
123 self.linenos = get_bool_opt(options, 'linenos', False)
124 self.linenostart = abs(get_int_opt(options, 'linenostart', 1))
125 self.linenostep = abs(get_int_opt(options, 'linenostep', 1))
126 self.verboptions = options.get('verboptions', '')
127 self.nobackground = get_bool_opt(options, 'nobackground', False)
128 self.commandprefix = options.get('commandprefix', 'PY')
129
130 self._create_stylecmds()
131
132
133 def _create_stylecmds(self):
134 t2c = self.ttype2cmd = {Token: ''}
135 c2d = self.cmd2def = {}
136 cp = self.commandprefix
137
138 letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
139 first = iter(letters)
140 second = iter(letters)
141 firstl = first.next()
142
143 def rgbcolor(col):
144 if col:
145 return ','.join(['%.2f' %(int(col[i] + col[i + 1], 16) / 255.0)
146 for i in (0, 2, 4)])
147 else:
148 return '1,1,1'
149
150 for ttype, ndef in self.style:
151 cmndef = '#1'
152 if ndef['bold']:
153 cmndef = r'\textbf{' + cmndef + '}'
154 if ndef['italic']:
155 cmndef = r'\textit{' + cmndef + '}'
156 if ndef['underline']:
157 cmndef = r'\underline{' + cmndef + '}'
158 if ndef['roman']:
159 cmndef = r'\textrm{' + cmndef + '}'
160 if ndef['sans']:
161 cmndef = r'\textsf{' + cmndef + '}'
162 if ndef['mono']:
163 cmndef = r'\texttt{' + cmndef + '}'
164 if ndef['color']:
165 cmndef = r'\textcolor[rgb]{%s}{%s}' % (
166 rgbcolor(ndef['color']),
167 cmndef
168 )
169 if ndef['border']:
170 cmndef = r'\fcolorbox[rgb]{%s}{%s}{%s}' % (
171 rgbcolor(ndef['border']),
172 rgbcolor(ndef['bgcolor']),
173 cmndef
174 )
175 elif ndef['bgcolor']:
176 cmndef = r'\colorbox[rgb]{%s}{%s}' % (
177 rgbcolor(ndef['bgcolor']),
178 cmndef
179 )
180 if cmndef == '#1':
181 continue
182 try:
183 alias = cp + firstl + second.next()
184 except StopIteration:
185 firstl = first.next()
186 second = iter(letters)
187 alias = cp + firstl + second.next()
188 t2c[ttype] = alias
189 c2d[alias] = cmndef
190
191 def get_style_defs(self, arg=''):
192 """
193 Return the \\newcommand sequences needed to define the commands
194 used to format text in the verbatim environment. ``arg`` is ignored.
195 """
196 nc = '\\newcommand'
197 return '%s\\at{@}\n%s\\lb{[}\n%s\\rb{]}\n' % (nc, nc, nc) + \
198 '\n'.join(['\\newcommand\\%s[1]{%s}' % (alias, cmndef)
199 for alias, cmndef in self.cmd2def.iteritems()
200 if cmndef != '#1'])
201
202 def format(self, tokensource, outfile):
203 # TODO: add support for background colors
204 enc = self.encoding
205
206 if self.full:
207 realoutfile = outfile
208 outfile = StringIO.StringIO()
209
210 outfile.write(r'\begin{Verbatim}[commandchars=@\[\]')
211 if self.linenos:
212 start, step = self.linenostart, self.linenostep
213 outfile.write(',numbers=left' +
214 (start and ',firstnumber=%d' % start or '') +
215 (step and ',stepnumber=%d' % step or ''))
216 if self.verboptions:
217 outfile.write(',' + self.verboptions)
218 outfile.write(']\n')
219
220 for ttype, value in tokensource:
221 if enc:
222 value = value.encode(enc)
223 value = escape_tex(value)
224 cmd = self.ttype2cmd.get(ttype)
225 while cmd is None:
226 ttype = ttype.parent
227 cmd = self.ttype2cmd.get(ttype)
228 if cmd:
229 spl = value.split('\n')
230 for line in spl[:-1]:
231 if line:
232 outfile.write("@%s[%s]" % (cmd, line))
233 outfile.write('\n')
234 if spl[-1]:
235 outfile.write("@%s[%s]" % (cmd, spl[-1]))
236 else:
237 outfile.write(value)
238
239 outfile.write('\\end{Verbatim}\n')
240
241 if self.full:
242 realoutfile.write(DOC_TEMPLATE %
243 dict(docclass = self.docclass,
244 preamble = self.preamble,
245 title = self.title,
246 encoding = self.encoding or 'latin1',
247 styledefs = self.get_style_defs(),
248 code = outfile.getvalue()))