Back to index

moin  1.9.0~rc2
latex.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003     pygments.formatters.latex
00004     ~~~~~~~~~~~~~~~~~~~~~~~~~
00005 
00006     Formatter for LaTeX fancyvrb output.
00007 
00008     :copyright: Copyright 2006-2009 by the Pygments team, see AUTHORS.
00009     :license: BSD, see LICENSE for details.
00010 """
00011 
00012 from pygments.formatter import Formatter
00013 from pygments.token import Token, STANDARD_TYPES
00014 from pygments.util import get_bool_opt, get_int_opt, StringIO
00015 
00016 
00017 __all__ = ['LatexFormatter']
00018 
00019 
00020 def escape_tex(text, commandprefix):
00021     return text.replace('@', '\x00').    \
00022                 replace('[', '\x01').    \
00023                 replace(']', '\x02').    \
00024                 replace('\x00', '@%sZat[]' % commandprefix).\
00025                 replace('\x01', '@%sZlb[]' % commandprefix).\
00026                 replace('\x02', '@%sZrb[]' % commandprefix)
00027 
00028 
00029 DOC_TEMPLATE = r'''
00030 \documentclass{%(docclass)s}
00031 \usepackage{fancyvrb}
00032 \usepackage{color}
00033 \usepackage[%(encoding)s]{inputenc}
00034 %(preamble)s
00035 
00036 %(styledefs)s
00037 
00038 \begin{document}
00039 
00040 \section*{%(title)s}
00041 
00042 %(code)s
00043 \end{document}
00044 '''
00045 
00046 ## Small explanation of the mess below :)
00047 #
00048 # The previous version of the LaTeX formatter just assigned a command to
00049 # each token type defined in the current style.  That obviously is
00050 # problematic if the highlighted code is produced for a different style
00051 # than the style commands themselves.
00052 #
00053 # This version works much like the HTML formatter which assigns multiple
00054 # CSS classes to each <span> tag, from the most specific to the least
00055 # specific token type, thus falling back to the parent token type if one
00056 # is not defined.  Here, the classes are there too and use the same short
00057 # forms given in token.STANDARD_TYPES.
00058 #
00059 # Highlighted code now only uses one custom command, which by default is
00060 # \PY and selectable by the commandprefix option (and in addition the
00061 # escapes \PYZat, \PYZlb and \PYZrb which haven't been renamed for
00062 # backwards compatibility purposes).
00063 #
00064 # \PY has two arguments: the classes, separated by +, and the text to
00065 # render in that style.  The classes are resolved into the respective
00066 # style commands by magic, which serves to ignore unknown classes.
00067 #
00068 # The magic macros are:
00069 # * \PY@it, \PY@bf, etc. are unconditionally wrapped around the text
00070 #   to render in \PY@do.  Their definition determines the style.
00071 # * \PY@reset resets \PY@it etc. to do nothing.
00072 # * \PY@toks parses the list of classes, using magic inspired by the
00073 #   keyval package (but modified to use plusses instead of commas
00074 #   because fancyvrb redefines commas inside its environments).
00075 # * \PY@tok processes one class, calling the \PY@tok@classname command
00076 #   if it exists.
00077 # * \PY@tok@classname sets the \PY@it etc. to reflect the chosen style
00078 #   for its class.
00079 # * \PY resets the style, parses the classnames and then calls \PY@do.
00080 
00081 STYLE_TEMPLATE = r'''
00082 \makeatletter
00083 \def\%(cp)s@reset{\let\%(cp)s@it=\relax \let\%(cp)s@bf=\relax%%
00084     \let\%(cp)s@ul=\relax \let\%(cp)s@tc=\relax%%
00085     \let\%(cp)s@bc=\relax \let\%(cp)s@ff=\relax}
00086 \def\%(cp)s@tok#1{\csname %(cp)s@tok@#1\endcsname}
00087 \def\%(cp)s@toks#1+{\ifx\relax#1\empty\else%%
00088     \%(cp)s@tok{#1}\expandafter\%(cp)s@toks\fi}
00089 \def\%(cp)s@do#1{\%(cp)s@bc{\%(cp)s@tc{\%(cp)s@ul{%%
00090     \%(cp)s@it{\%(cp)s@bf{\%(cp)s@ff{#1}}}}}}}
00091 \def\%(cp)s#1#2{\%(cp)s@reset\%(cp)s@toks#1+\relax+\%(cp)s@do{#2}}
00092 
00093 %(styles)s
00094 
00095 \def\%(cp)sZat{@}
00096 \def\%(cp)sZlb{[}
00097 \def\%(cp)sZrb{]}
00098 \makeatother
00099 '''
00100 
00101 
00102 def _get_ttype_name(ttype):
00103     fname = STANDARD_TYPES.get(ttype)
00104     if fname:
00105         return fname
00106     aname = ''
00107     while fname is None:
00108         aname = ttype[-1] + aname
00109         ttype = ttype.parent
00110         fname = STANDARD_TYPES.get(ttype)
00111     return fname + aname
00112 
00113 
00114 class LatexFormatter(Formatter):
00115     r"""
00116     Format tokens as LaTeX code. This needs the `fancyvrb` and `color`
00117     standard packages.
00118 
00119     Without the `full` option, code is formatted as one ``Verbatim``
00120     environment, like this:
00121 
00122     .. sourcecode:: latex
00123 
00124         \begin{Verbatim}[commandchars=@\[\]]
00125         @PY[k][def ]@PY[n+nf][foo](@PY[n][bar]):
00126             @PY[k][pass]
00127         \end{Verbatim}
00128 
00129     The special command used here (``@PY``) and all the other macros it needs
00130     are output by the `get_style_defs` method.
00131 
00132     With the `full` option, a complete LaTeX document is output, including
00133     the command definitions in the preamble.
00134 
00135     The `get_style_defs()` method of a `LatexFormatter` returns a string
00136     containing ``\def`` commands defining the macros needed inside the
00137     ``Verbatim`` environments.
00138 
00139     Additional options accepted:
00140 
00141     `style`
00142         The style to use, can be a string or a Style subclass (default:
00143         ``'default'``).
00144 
00145     `full`
00146         Tells the formatter to output a "full" document, i.e. a complete
00147         self-contained document (default: ``False``).
00148 
00149     `title`
00150         If `full` is true, the title that should be used to caption the
00151         document (default: ``''``).
00152 
00153     `docclass`
00154         If the `full` option is enabled, this is the document class to use
00155         (default: ``'article'``).
00156 
00157     `preamble`
00158         If the `full` option is enabled, this can be further preamble commands,
00159         e.g. ``\usepackage`` (default: ``''``).
00160 
00161     `linenos`
00162         If set to ``True``, output line numbers (default: ``False``).
00163 
00164     `linenostart`
00165         The line number for the first line (default: ``1``).
00166 
00167     `linenostep`
00168         If set to a number n > 1, only every nth line number is printed.
00169 
00170     `verboptions`
00171         Additional options given to the Verbatim environment (see the *fancyvrb*
00172         docs for possible values) (default: ``''``).
00173 
00174     `commandprefix`
00175         The LaTeX commands used to produce colored output are constructed
00176         using this prefix and some letters (default: ``'PY'``).
00177         *New in Pygments 0.7.*
00178 
00179         *New in Pygments 0.10:* the default is now ``'PY'`` instead of ``'C'``.
00180     """
00181     name = 'LaTeX'
00182     aliases = ['latex', 'tex']
00183     filenames = ['*.tex']
00184 
00185     def __init__(self, **options):
00186         Formatter.__init__(self, **options)
00187         self.docclass = options.get('docclass', 'article')
00188         self.preamble = options.get('preamble', '')
00189         self.linenos = get_bool_opt(options, 'linenos', False)
00190         self.linenostart = abs(get_int_opt(options, 'linenostart', 1))
00191         self.linenostep = abs(get_int_opt(options, 'linenostep', 1))
00192         self.verboptions = options.get('verboptions', '')
00193         self.nobackground = get_bool_opt(options, 'nobackground', False)
00194         self.commandprefix = options.get('commandprefix', 'PY')
00195 
00196         self._create_stylesheet()
00197 
00198 
00199     def _create_stylesheet(self):
00200         t2n = self.ttype2name = {Token: ''}
00201         c2d = self.cmd2def = {}
00202         cp = self.commandprefix
00203 
00204         def rgbcolor(col):
00205             if col:
00206                 return ','.join(['%.2f' %(int(col[i] + col[i + 1], 16) / 255.0)
00207                                  for i in (0, 2, 4)])
00208             else:
00209                 return '1,1,1'
00210 
00211         for ttype, ndef in self.style:
00212             name = _get_ttype_name(ttype)
00213             cmndef = ''
00214             if ndef['bold']:
00215                 cmndef += r'\let\$$@bf=\textbf'
00216             if ndef['italic']:
00217                 cmndef += r'\let\$$@it=\textit'
00218             if ndef['underline']:
00219                 cmndef += r'\let\$$@ul=\underline'
00220             if ndef['roman']:
00221                 cmndef += r'\let\$$@ff=\textrm'
00222             if ndef['sans']:
00223                 cmndef += r'\let\$$@ff=\textsf'
00224             if ndef['mono']:
00225                 cmndef += r'\let\$$@ff=\textsf'
00226             if ndef['color']:
00227                 cmndef += (r'\def\$$@tc##1{\textcolor[rgb]{%s}{##1}}' %
00228                            rgbcolor(ndef['color']))
00229             if ndef['border']:
00230                 cmndef += (r'\def\$$@bc##1{\fcolorbox[rgb]{%s}{%s}{##1}}' %
00231                            (rgbcolor(ndef['border']),
00232                             rgbcolor(ndef['bgcolor'])))
00233             elif ndef['bgcolor']:
00234                 cmndef += (r'\def\$$@bc##1{\colorbox[rgb]{%s}{##1}}' %
00235                            rgbcolor(ndef['bgcolor']))
00236             if cmndef == '':
00237                 continue
00238             cmndef = cmndef.replace('$$', cp)
00239             t2n[ttype] = name
00240             c2d[name] = cmndef
00241 
00242     def get_style_defs(self, arg=''):
00243         """
00244         Return the command sequences needed to define the commands
00245         used to format text in the verbatim environment. ``arg`` is ignored.
00246         """
00247         cp = self.commandprefix
00248         styles = []
00249         for name, definition in self.cmd2def.iteritems():
00250             styles.append(r'\def\%s@tok@%s{%s}' % (cp, name, definition))
00251         return STYLE_TEMPLATE % {'cp': self.commandprefix,
00252                                  'styles': '\n'.join(styles)}
00253 
00254     def format_unencoded(self, tokensource, outfile):
00255         # TODO: add support for background colors
00256         t2n = self.ttype2name
00257         cp = self.commandprefix
00258 
00259         if self.full:
00260             realoutfile = outfile
00261             outfile = StringIO()
00262 
00263         outfile.write(r'\begin{Verbatim}[commandchars=@\[\]')
00264         if self.linenos:
00265             start, step = self.linenostart, self.linenostep
00266             outfile.write(',numbers=left' +
00267                           (start and ',firstnumber=%d' % start or '') +
00268                           (step and ',stepnumber=%d' % step or ''))
00269         if self.verboptions:
00270             outfile.write(',' + self.verboptions)
00271         outfile.write(']\n')
00272 
00273         for ttype, value in tokensource:
00274             value = escape_tex(value, self.commandprefix)
00275             styles = []
00276             while ttype is not Token:
00277                 try:
00278                     styles.append(t2n[ttype])
00279                 except KeyError:
00280                     # not in current style
00281                     styles.append(_get_ttype_name(ttype))
00282                 ttype = ttype.parent
00283             styleval = '+'.join(reversed(styles))
00284             if styleval:
00285                 spl = value.split('\n')
00286                 for line in spl[:-1]:
00287                     if line:
00288                         outfile.write("@%s[%s][%s]" % (cp, styleval, line))
00289                     outfile.write('\n')
00290                 if spl[-1]:
00291                     outfile.write("@%s[%s][%s]" % (cp, styleval, spl[-1]))
00292             else:
00293                 outfile.write(value)
00294 
00295         outfile.write('\\end{Verbatim}\n')
00296 
00297         if self.full:
00298             realoutfile.write(DOC_TEMPLATE %
00299                 dict(docclass  = self.docclass,
00300                      preamble  = self.preamble,
00301                      title     = self.title,
00302                      encoding  = self.encoding or 'latin1',
00303                      styledefs = self.get_style_defs(),
00304                      code      = outfile.getvalue()))