eric6/ThirdParty/Pygments/pygments/formatters/html.py

changeset 7701
25f42e208e08
parent 7547
21b0534faebc
child 7983
54c5cfbb1e29
diff -r a3cf077a8db3 -r 25f42e208e08 eric6/ThirdParty/Pygments/pygments/formatters/html.py
--- a/eric6/ThirdParty/Pygments/pygments/formatters/html.py	Tue Sep 15 18:46:58 2020 +0200
+++ b/eric6/ThirdParty/Pygments/pygments/formatters/html.py	Tue Sep 15 19:09:05 2020 +0200
@@ -1,880 +1,931 @@
-# -*- coding: utf-8 -*-
-"""
-    pygments.formatters.html
-    ~~~~~~~~~~~~~~~~~~~~~~~~
-
-    Formatter for HTML output.
-
-    :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS.
-    :license: BSD, see LICENSE for details.
-"""
-
-import os
-import sys
-import os.path
-from io import StringIO
-
-from pygments.formatter import Formatter
-from pygments.token import Token, Text, STANDARD_TYPES
-from pygments.util import get_bool_opt, get_int_opt, get_list_opt
-
-try:
-    import ctags
-except ImportError:
-    ctags = None
-
-__all__ = ['HtmlFormatter']
-
-
-_escape_html_table = {
-    ord('&'): u'&',
-    ord('<'): u'&lt;',
-    ord('>'): u'&gt;',
-    ord('"'): u'&quot;',
-    ord("'"): u'&#39;',
-}
-
-
-def escape_html(text, table=_escape_html_table):
-    """Escape &, <, > as well as single and double quotes for HTML."""
-    return text.translate(table)
-
-
-def webify(color):
-    if color.startswith('calc') or color.startswith('var'):
-        return color
-    else:
-        return '#' + color
-
-
-def _get_ttype_class(ttype):
-    fname = STANDARD_TYPES.get(ttype)
-    if fname:
-        return fname
-    aname = ''
-    while fname is None:
-        aname = '-' + ttype[-1] + aname
-        ttype = ttype.parent
-        fname = STANDARD_TYPES.get(ttype)
-    return fname + aname
-
-
-CSSFILE_TEMPLATE = '''\
-/*
-generated by Pygments <https://pygments.org/>
-Copyright 2006-2019 by the Pygments team.
-Licensed under the BSD license, see LICENSE for details.
-*/
-td.linenos { background-color: #f0f0f0; padding-right: 10px; }
-span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
-pre { line-height: 125%%; }
-%(styledefs)s
-'''
-
-DOC_HEADER = '''\
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
-   "http://www.w3.org/TR/html4/strict.dtd">
-<!--
-generated by Pygments <https://pygments.org/>
-Copyright 2006-2019 by the Pygments team.
-Licensed under the BSD license, see LICENSE for details.
--->
-<html>
-<head>
-  <title>%(title)s</title>
-  <meta http-equiv="content-type" content="text/html; charset=%(encoding)s">
-  <style type="text/css">
-''' + CSSFILE_TEMPLATE + '''
-  </style>
-</head>
-<body>
-<h2>%(title)s</h2>
-
-'''
-
-DOC_HEADER_EXTERNALCSS = '''\
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
-   "http://www.w3.org/TR/html4/strict.dtd">
-
-<html>
-<head>
-  <title>%(title)s</title>
-  <meta http-equiv="content-type" content="text/html; charset=%(encoding)s">
-  <link rel="stylesheet" href="%(cssfile)s" type="text/css">
-</head>
-<body>
-<h2>%(title)s</h2>
-
-'''
-
-DOC_FOOTER = '''\
-</body>
-</html>
-'''
-
-
-class HtmlFormatter(Formatter):
-    r"""
-    Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped
-    in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass`
-    option.
-
-    If the `linenos` option is set to ``"table"``, the ``<pre>`` is
-    additionally wrapped inside a ``<table>`` which has one row and two
-    cells: one containing the line numbers and one containing the code.
-    Example:
-
-    .. sourcecode:: html
-
-        <div class="highlight" >
-        <table><tr>
-          <td class="linenos" title="click to toggle"
-            onclick="with (this.firstChild.style)
-                     { display = (display == '') ? 'none' : '' }">
-            <pre>1
-            2</pre>
-          </td>
-          <td class="code">
-            <pre><span class="Ke">def </span><span class="NaFu">foo</span>(bar):
-              <span class="Ke">pass</span>
-            </pre>
-          </td>
-        </tr></table></div>
-
-    (whitespace added to improve clarity).
-
-    Wrapping can be disabled using the `nowrap` option.
-
-    A list of lines can be specified using the `hl_lines` option to make these
-    lines highlighted (as of Pygments 0.11).
-
-    With the `full` option, a complete HTML 4 document is output, including
-    the style definitions inside a ``<style>`` tag, or in a separate file if
-    the `cssfile` option is given.
-
-    When `tagsfile` is set to the path of a ctags index file, it is used to
-    generate hyperlinks from names to their definition.  You must enable
-    `lineanchors` and run ctags with the `-n` option for this to work.  The
-    `python-ctags` module from PyPI must be installed to use this feature;
-    otherwise a `RuntimeError` will be raised.
-
-    The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string
-    containing CSS rules for the CSS classes used by the formatter. The
-    argument `arg` can be used to specify additional CSS selectors that
-    are prepended to the classes. A call `fmter.get_style_defs('td .code')`
-    would result in the following CSS classes:
-
-    .. sourcecode:: css
-
-        td .code .kw { font-weight: bold; color: #00FF00 }
-        td .code .cm { color: #999999 }
-        ...
-
-    If you have Pygments 0.6 or higher, you can also pass a list or tuple to the
-    `get_style_defs()` method to request multiple prefixes for the tokens:
-
-    .. sourcecode:: python
-
-        formatter.get_style_defs(['div.syntax pre', 'pre.syntax'])
-
-    The output would then look like this:
-
-    .. sourcecode:: css
-
-        div.syntax pre .kw,
-        pre.syntax .kw { font-weight: bold; color: #00FF00 }
-        div.syntax pre .cm,
-        pre.syntax .cm { color: #999999 }
-        ...
-
-    Additional options accepted:
-
-    `nowrap`
-        If set to ``True``, don't wrap the tokens at all, not even inside a ``<pre>``
-        tag. This disables most other options (default: ``False``).
-
-    `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: ``''``).
-
-    `style`
-        The style to use, can be a string or a Style subclass (default:
-        ``'default'``). This option has no effect if the `cssfile`
-        and `noclobber_cssfile` option are given and the file specified in
-        `cssfile` exists.
-
-    `noclasses`
-        If set to true, token ``<span>`` tags will not use CSS classes, but
-        inline styles. This is not recommended for larger pieces of code since
-        it increases output size by quite a bit (default: ``False``).
-
-    `classprefix`
-        Since the token types use relatively short class names, they may clash
-        with some of your own class names. In this case you can use the
-        `classprefix` option to give a string to prepend to all Pygments-generated
-        CSS class names for token types.
-        Note that this option also affects the output of `get_style_defs()`.
-
-    `cssclass`
-        CSS class for the wrapping ``<div>`` tag (default: ``'highlight'``).
-        If you set this option, the default selector for `get_style_defs()`
-        will be this class.
-
-        .. versionadded:: 0.9
-           If you select the ``'table'`` line numbers, the wrapping table will
-           have a CSS class of this string plus ``'table'``, the default is
-           accordingly ``'highlighttable'``.
-
-    `cssstyles`
-        Inline CSS styles for the wrapping ``<div>`` tag (default: ``''``).
-
-    `prestyles`
-        Inline CSS styles for the ``<pre>`` tag (default: ``''``).
-
-        .. versionadded:: 0.11
-
-    `cssfile`
-        If the `full` option is true and this option is given, it must be the
-        name of an external file. If the filename does not include an absolute
-        path, the file's path will be assumed to be relative to the main output
-        file's path, if the latter can be found. The stylesheet is then written
-        to this file instead of the HTML file.
-
-        .. versionadded:: 0.6
-
-    `noclobber_cssfile`
-        If `cssfile` is given and the specified file exists, the css file will
-        not be overwritten. This allows the use of the `full` option in
-        combination with a user specified css file. Default is ``False``.
-
-        .. versionadded:: 1.1
-
-    `linenos`
-        If set to ``'table'``, output line numbers as a table with two cells,
-        one containing the line numbers, the other the whole code.  This is
-        copy-and-paste-friendly, but may cause alignment problems with some
-        browsers or fonts.  If set to ``'inline'``, the line numbers will be
-        integrated in the ``<pre>`` tag that contains the code (that setting
-        is *new in Pygments 0.8*).
-
-        For compatibility with Pygments 0.7 and earlier, every true value
-        except ``'inline'`` means the same as ``'table'`` (in particular, that
-        means also ``True``).
-
-        The default value is ``False``, which means no line numbers at all.
-
-        **Note:** with the default ("table") line number mechanism, the line
-        numbers and code can have different line heights in Internet Explorer
-        unless you give the enclosing ``<pre>`` tags an explicit ``line-height``
-        CSS property (you get the default line spacing with ``line-height:
-        125%``).
-
-    `hl_lines`
-        Specify a list of lines to be highlighted.
-
-        .. versionadded:: 0.11
-
-    `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.
-
-    `linenospecial`
-        If set to a number n > 0, every nth line number is given the CSS
-        class ``"special"`` (default: ``0``).
-
-    `nobackground`
-        If set to ``True``, the formatter won't output the background color
-        for the wrapping element (this automatically defaults to ``False``
-        when there is no wrapping element [eg: no argument for the
-        `get_syntax_defs` method given]) (default: ``False``).
-
-        .. versionadded:: 0.6
-
-    `lineseparator`
-        This string is output between lines of code. It defaults to ``"\n"``,
-        which is enough to break a line inside ``<pre>`` tags, but you can
-        e.g. set it to ``"<br>"`` to get HTML line breaks.
-
-        .. versionadded:: 0.7
-
-    `lineanchors`
-        If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
-        output line in an anchor tag with a ``name`` of ``foo-linenumber``.
-        This allows easy linking to certain lines.
-
-        .. versionadded:: 0.9
-
-    `linespans`
-        If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
-        output line in a span tag with an ``id`` of ``foo-linenumber``.
-        This allows easy access to lines via javascript.
-
-        .. versionadded:: 1.6
-
-    `anchorlinenos`
-        If set to `True`, will wrap line numbers in <a> tags. Used in
-        combination with `linenos` and `lineanchors`.
-
-    `tagsfile`
-        If set to the path of a ctags file, wrap names in anchor tags that
-        link to their definitions. `lineanchors` should be used, and the
-        tags file should specify line numbers (see the `-n` option to ctags).
-
-        .. versionadded:: 1.6
-
-    `tagurlformat`
-        A string formatting pattern used to generate links to ctags definitions.
-        Available variables are `%(path)s`, `%(fname)s` and `%(fext)s`.
-        Defaults to an empty string, resulting in just `#prefix-number` links.
-
-        .. versionadded:: 1.6
-
-    `filename`
-        A string used to generate a filename when rendering ``<pre>`` blocks,
-        for example if displaying source code.
-
-        .. versionadded:: 2.1
-
-    `wrapcode`
-        Wrap the code inside ``<pre>`` blocks using ``<code>``, as recommended
-        by the HTML5 specification.
-
-        .. versionadded:: 2.4
-
-
-    **Subclassing the HTML formatter**
-
-    .. versionadded:: 0.7
-
-    The HTML formatter is now built in a way that allows easy subclassing, thus
-    customizing the output HTML code. The `format()` method calls
-    `self._format_lines()` which returns a generator that yields tuples of ``(1,
-    line)``, where the ``1`` indicates that the ``line`` is a line of the
-    formatted source code.
-
-    If the `nowrap` option is set, the generator is the iterated over and the
-    resulting HTML is output.
-
-    Otherwise, `format()` calls `self.wrap()`, which wraps the generator with
-    other generators. These may add some HTML code to the one generated by
-    `_format_lines()`, either by modifying the lines generated by the latter,
-    then yielding them again with ``(1, line)``, and/or by yielding other HTML
-    code before or after the lines, with ``(0, html)``. The distinction between
-    source lines and other code makes it possible to wrap the generator multiple
-    times.
-
-    The default `wrap()` implementation adds a ``<div>`` and a ``<pre>`` tag.
-
-    A custom `HtmlFormatter` subclass could look like this:
-
-    .. sourcecode:: python
-
-        class CodeHtmlFormatter(HtmlFormatter):
-
-            def wrap(self, source, outfile):
-                return self._wrap_code(source)
-
-            def _wrap_code(self, source):
-                yield 0, '<code>'
-                for i, t in source:
-                    if i == 1:
-                        # it's a line of formatted code
-                        t += '<br>'
-                    yield i, t
-                yield 0, '</code>'
-
-    This results in wrapping the formatted lines with a ``<code>`` tag, where the
-    source lines are broken using ``<br>`` tags.
-
-    After calling `wrap()`, the `format()` method also adds the "line numbers"
-    and/or "full document" wrappers if the respective options are set. Then, all
-    HTML yielded by the wrapped generator is output.
-    """
-
-    name = 'HTML'
-    aliases = ['html']
-    filenames = ['*.html', '*.htm']
-
-    def __init__(self, **options):
-        Formatter.__init__(self, **options)
-        self.title = self._decodeifneeded(self.title)
-        self.nowrap = get_bool_opt(options, 'nowrap', False)
-        self.noclasses = get_bool_opt(options, 'noclasses', False)
-        self.classprefix = options.get('classprefix', '')
-        self.cssclass = self._decodeifneeded(options.get('cssclass', 'highlight'))
-        self.cssstyles = self._decodeifneeded(options.get('cssstyles', ''))
-        self.prestyles = self._decodeifneeded(options.get('prestyles', ''))
-        self.cssfile = self._decodeifneeded(options.get('cssfile', ''))
-        self.noclobber_cssfile = get_bool_opt(options, 'noclobber_cssfile', False)
-        self.tagsfile = self._decodeifneeded(options.get('tagsfile', ''))
-        self.tagurlformat = self._decodeifneeded(options.get('tagurlformat', ''))
-        self.filename = self._decodeifneeded(options.get('filename', ''))
-        self.wrapcode = get_bool_opt(options, 'wrapcode', False)
-
-        if self.tagsfile:
-            if not ctags:
-                raise RuntimeError('The "ctags" package must to be installed '
-                                   'to be able to use the "tagsfile" feature.')
-            self._ctags = ctags.CTags(self.tagsfile)
-
-        linenos = options.get('linenos', False)
-        if linenos == 'inline':
-            self.linenos = 2
-        elif linenos:
-            # compatibility with <= 0.7
-            self.linenos = 1
-        else:
-            self.linenos = 0
-        self.linenostart = abs(get_int_opt(options, 'linenostart', 1))
-        self.linenostep = abs(get_int_opt(options, 'linenostep', 1))
-        self.linenospecial = abs(get_int_opt(options, 'linenospecial', 0))
-        self.nobackground = get_bool_opt(options, 'nobackground', False)
-        self.lineseparator = options.get('lineseparator', u'\n')
-        self.lineanchors = options.get('lineanchors', '')
-        self.linespans = options.get('linespans', '')
-        self.anchorlinenos = options.get('anchorlinenos', False)
-        self.hl_lines = set()
-        for lineno in get_list_opt(options, 'hl_lines', []):
-            try:
-                self.hl_lines.add(int(lineno))
-            except ValueError:
-                pass
-
-        self._create_stylesheet()
-
-    def _get_css_class(self, ttype):
-        """Return the css class of this token type prefixed with
-        the classprefix option."""
-        ttypeclass = _get_ttype_class(ttype)
-        if ttypeclass:
-            return self.classprefix + ttypeclass
-        return ''
-
-    def _get_css_classes(self, ttype):
-        """Return the css classes of this token type prefixed with
-        the classprefix option."""
-        cls = self._get_css_class(ttype)
-        while ttype not in STANDARD_TYPES:
-            ttype = ttype.parent
-            cls = self._get_css_class(ttype) + ' ' + cls
-        return cls
-
-    def _create_stylesheet(self):
-        t2c = self.ttype2class = {Token: ''}
-        c2s = self.class2style = {}
-        for ttype, ndef in self.style:
-            name = self._get_css_class(ttype)
-            style = ''
-            if ndef['color']:
-                style += 'color: %s; ' % webify(ndef['color'])
-            if ndef['bold']:
-                style += 'font-weight: bold; '
-            if ndef['italic']:
-                style += 'font-style: italic; '
-            if ndef['underline']:
-                style += 'text-decoration: underline; '
-            if ndef['bgcolor']:
-                style += 'background-color: %s; ' % webify(ndef['bgcolor'])
-            if ndef['border']:
-                style += 'border: 1px solid %s; ' % webify(ndef['border'])
-            if style:
-                t2c[ttype] = name
-                # save len(ttype) to enable ordering the styles by
-                # hierarchy (necessary for CSS cascading rules!)
-                c2s[name] = (style[:-2], ttype, len(ttype))
-
-    def get_style_defs(self, arg=None):
-        """
-        Return CSS style definitions for the classes produced by the current
-        highlighting style. ``arg`` can be a string or list of selectors to
-        insert before the token type classes.
-        """
-        if arg is None:
-            arg = ('cssclass' in self.options and '.'+self.cssclass or '')
-        if isinstance(arg, str):
-            args = [arg]
-        else:
-            args = list(arg)
-
-        def prefix(cls):
-            if cls:
-                cls = '.' + cls
-            tmp = []
-            for arg in args:
-                tmp.append((arg and arg + ' ' or '') + cls)
-            return ', '.join(tmp)
-
-        styles = [(level, ttype, cls, style)
-                  for cls, (style, ttype, level) in self.class2style.items()
-                  if cls and style]
-        styles.sort()
-        lines = ['%s { %s } /* %s */' % (prefix(cls), style, repr(ttype)[6:])
-                 for (level, ttype, cls, style) in styles]
-        if arg and not self.nobackground and \
-           self.style.background_color is not None:
-            text_style = ''
-            if Text in self.ttype2class:
-                text_style = ' ' + self.class2style[self.ttype2class[Text]][0]
-            lines.insert(0, '%s { background: %s;%s }' %
-                         (prefix(''), self.style.background_color, text_style))
-        if self.style.highlight_color is not None:
-            lines.insert(0, '%s.hll { background-color: %s }' %
-                         (prefix(''), self.style.highlight_color))
-        return '\n'.join(lines)
-
-    def _decodeifneeded(self, value):
-        if isinstance(value, bytes):
-            if self.encoding:
-                return value.decode(self.encoding)
-            return value.decode()
-        return value
-
-    def _wrap_full(self, inner, outfile):
-        if self.cssfile:
-            if os.path.isabs(self.cssfile):
-                # it's an absolute filename
-                cssfilename = self.cssfile
-            else:
-                try:
-                    filename = outfile.name
-                    if not filename or filename[0] == '<':
-                        # pseudo files, e.g. name == '<fdopen>'
-                        raise AttributeError
-                    cssfilename = os.path.join(os.path.dirname(filename),
-                                               self.cssfile)
-                except AttributeError:
-                    print('Note: Cannot determine output file name, '
-                          'using current directory as base for the CSS file name',
-                          file=sys.stderr)
-                    cssfilename = self.cssfile
-            # write CSS file only if noclobber_cssfile isn't given as an option.
-            try:
-                if not os.path.exists(cssfilename) or not self.noclobber_cssfile:
-                    with open(cssfilename, "w") as cf:
-                        cf.write(CSSFILE_TEMPLATE %
-                                 {'styledefs': self.get_style_defs('body')})
-            except IOError as err:
-                err.strerror = 'Error writing CSS file: ' + err.strerror
-                raise
-
-            yield 0, (DOC_HEADER_EXTERNALCSS %
-                      dict(title=self.title,
-                           cssfile=self.cssfile,
-                           encoding=self.encoding))
-        else:
-            yield 0, (DOC_HEADER %
-                      dict(title=self.title,
-                           styledefs=self.get_style_defs('body'),
-                           encoding=self.encoding))
-
-        for t, line in inner:
-            yield t, line
-        yield 0, DOC_FOOTER
-
-    def _wrap_tablelinenos(self, inner):
-        dummyoutfile = StringIO()
-        lncount = 0
-        for t, line in inner:
-            if t:
-                lncount += 1
-            dummyoutfile.write(line)
-
-        fl = self.linenostart
-        mw = len(str(lncount + fl - 1))
-        sp = self.linenospecial
-        st = self.linenostep
-        la = self.lineanchors
-        aln = self.anchorlinenos
-        nocls = self.noclasses
-        if sp:
-            lines = []
-
-            for i in range(fl, fl+lncount):
-                if i % st == 0:
-                    if i % sp == 0:
-                        if aln:
-                            lines.append('<a href="#%s-%d" class="special">%*d</a>' %
-                                         (la, i, mw, i))
-                        else:
-                            lines.append('<span class="special">%*d</span>' % (mw, i))
-                    else:
-                        if aln:
-                            lines.append('<a href="#%s-%d">%*d</a>' % (la, i, mw, i))
-                        else:
-                            lines.append('%*d' % (mw, i))
-                else:
-                    lines.append('')
-            ls = '\n'.join(lines)
-        else:
-            lines = []
-            for i in range(fl, fl+lncount):
-                if i % st == 0:
-                    if aln:
-                        lines.append('<a href="#%s-%d">%*d</a>' % (la, i, mw, i))
-                    else:
-                        lines.append('%*d' % (mw, i))
-                else:
-                    lines.append('')
-            ls = '\n'.join(lines)
-
-        # in case you wonder about the seemingly redundant <div> here: since the
-        # content in the other cell also is wrapped in a div, some browsers in
-        # some configurations seem to mess up the formatting...
-        if nocls:
-            yield 0, ('<table class="%stable">' % self.cssclass +
-                      '<tr><td><div class="linenodiv" '
-                      'style="background-color: #f0f0f0; padding-right: 10px">'
-                      '<pre style="line-height: 125%">' +
-                      ls + '</pre></div></td><td class="code">')
-        else:
-            yield 0, ('<table class="%stable">' % self.cssclass +
-                      '<tr><td class="linenos"><div class="linenodiv"><pre>' +
-                      ls + '</pre></div></td><td class="code">')
-        yield 0, dummyoutfile.getvalue()
-        yield 0, '</td></tr></table>'
-
-    def _wrap_inlinelinenos(self, inner):
-        # need a list of lines since we need the width of a single number :(
-        lines = list(inner)
-        sp = self.linenospecial
-        st = self.linenostep
-        num = self.linenostart
-        mw = len(str(len(lines) + num - 1))
-
-        if self.noclasses:
-            if sp:
-                for t, line in lines:
-                    if num % sp == 0:
-                        style = 'background-color: #ffffc0; padding: 0 5px 0 5px'
-                    else:
-                        style = 'background-color: #f0f0f0; padding: 0 5px 0 5px'
-                    yield 1, '<span style="%s">%*s </span>' % (
-                        style, mw, (num % st and ' ' or num)) + line
-                    num += 1
-            else:
-                for t, line in lines:
-                    yield 1, ('<span style="background-color: #f0f0f0; '
-                              'padding: 0 5px 0 5px">%*s </span>' % (
-                                  mw, (num % st and ' ' or num)) + line)
-                    num += 1
-        elif sp:
-            for t, line in lines:
-                yield 1, '<span class="lineno%s">%*s </span>' % (
-                    num % sp == 0 and ' special' or '', mw,
-                    (num % st and ' ' or num)) + line
-                num += 1
-        else:
-            for t, line in lines:
-                yield 1, '<span class="lineno">%*s </span>' % (
-                    mw, (num % st and ' ' or num)) + line
-                num += 1
-
-    def _wrap_lineanchors(self, inner):
-        s = self.lineanchors
-        # subtract 1 since we have to increment i *before* yielding
-        i = self.linenostart - 1
-        for t, line in inner:
-            if t:
-                i += 1
-                yield 1, '<a name="%s-%d"></a>' % (s, i) + line
-            else:
-                yield 0, line
-
-    def _wrap_linespans(self, inner):
-        s = self.linespans
-        i = self.linenostart - 1
-        for t, line in inner:
-            if t:
-                i += 1
-                yield 1, '<span id="%s-%d">%s</span>' % (s, i, line)
-            else:
-                yield 0, line
-
-    def _wrap_div(self, inner):
-        style = []
-        if (self.noclasses and not self.nobackground and
-                self.style.background_color is not None):
-            style.append('background: %s' % (self.style.background_color,))
-        if self.cssstyles:
-            style.append(self.cssstyles)
-        style = '; '.join(style)
-
-        yield 0, ('<div' + (self.cssclass and ' class="%s"' % self.cssclass) +
-                  (style and (' style="%s"' % style)) + '>')
-        for tup in inner:
-            yield tup
-        yield 0, '</div>\n'
-
-    def _wrap_pre(self, inner):
-        style = []
-        if self.prestyles:
-            style.append(self.prestyles)
-        if self.noclasses:
-            style.append('line-height: 125%')
-        style = '; '.join(style)
-
-        if self.filename:
-            yield 0, ('<span class="filename">' + self.filename + '</span>')
-
-        # the empty span here is to keep leading empty lines from being
-        # ignored by HTML parsers
-        yield 0, ('<pre' + (style and ' style="%s"' % style) + '><span></span>')
-        for tup in inner:
-            yield tup
-        yield 0, '</pre>'
-
-    def _wrap_code(self, inner):
-        yield 0, '<code>'
-        for tup in inner:
-            yield tup
-        yield 0, '</code>'
-
-    def _format_lines(self, tokensource):
-        """
-        Just format the tokens, without any wrapping tags.
-        Yield individual lines.
-        """
-        nocls = self.noclasses
-        lsep = self.lineseparator
-        # for <span style=""> lookup only
-        getcls = self.ttype2class.get
-        c2s = self.class2style
-        escape_table = _escape_html_table
-        tagsfile = self.tagsfile
-
-        lspan = ''
-        line = []
-        for ttype, value in tokensource:
-            if nocls:
-                cclass = getcls(ttype)
-                while cclass is None:
-                    ttype = ttype.parent
-                    cclass = getcls(ttype)
-                cspan = cclass and '<span style="%s">' % c2s[cclass][0] or ''
-            else:
-                cls = self._get_css_classes(ttype)
-                cspan = cls and '<span class="%s">' % cls or ''
-
-            parts = value.translate(escape_table).split('\n')
-
-            if tagsfile and ttype in Token.Name:
-                filename, linenumber = self._lookup_ctag(value)
-                if linenumber:
-                    base, filename = os.path.split(filename)
-                    if base:
-                        base += '/'
-                    filename, extension = os.path.splitext(filename)
-                    url = self.tagurlformat % {'path': base, 'fname': filename,
-                                               'fext': extension}
-                    parts[0] = "<a href=\"%s#%s-%d\">%s" % \
-                        (url, self.lineanchors, linenumber, parts[0])
-                    parts[-1] = parts[-1] + "</a>"
-
-            # for all but the last line
-            for part in parts[:-1]:
-                if line:
-                    if lspan != cspan:
-                        line.extend(((lspan and '</span>'), cspan, part,
-                                     (cspan and '</span>'), lsep))
-                    else:  # both are the same
-                        line.extend((part, (lspan and '</span>'), lsep))
-                    yield 1, ''.join(line)
-                    line = []
-                elif part:
-                    yield 1, ''.join((cspan, part, (cspan and '</span>'), lsep))
-                else:
-                    yield 1, lsep
-            # for the last line
-            if line and parts[-1]:
-                if lspan != cspan:
-                    line.extend(((lspan and '</span>'), cspan, parts[-1]))
-                    lspan = cspan
-                else:
-                    line.append(parts[-1])
-            elif parts[-1]:
-                line = [cspan, parts[-1]]
-                lspan = cspan
-            # else we neither have to open a new span nor set lspan
-
-        if line:
-            line.extend(((lspan and '</span>'), lsep))
-            yield 1, ''.join(line)
-
-    def _lookup_ctag(self, token):
-        entry = ctags.TagEntry()
-        if self._ctags.find(entry, token, 0):
-            return entry['file'], entry['lineNumber']
-        else:
-            return None, None
-
-    def _highlight_lines(self, tokensource):
-        """
-        Highlighted the lines specified in the `hl_lines` option by
-        post-processing the token stream coming from `_format_lines`.
-        """
-        hls = self.hl_lines
-
-        for i, (t, value) in enumerate(tokensource):
-            if t != 1:
-                yield t, value
-            if i + 1 in hls:  # i + 1 because Python indexes start at 0
-                if self.noclasses:
-                    style = ''
-                    if self.style.highlight_color is not None:
-                        style = (' style="background-color: %s"' %
-                                 (self.style.highlight_color,))
-                    yield 1, '<span%s>%s</span>' % (style, value)
-                else:
-                    yield 1, '<span class="hll">%s</span>' % value
-            else:
-                yield 1, value
-
-    def wrap(self, source, outfile):
-        """
-        Wrap the ``source``, which is a generator yielding
-        individual lines, in custom generators. See docstring
-        for `format`. Can be overridden.
-        """
-        if self.wrapcode:
-            return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
-        else:
-            return self._wrap_div(self._wrap_pre(source))
-
-    def format_unencoded(self, tokensource, outfile):
-        """
-        The formatting process uses several nested generators; which of
-        them are used is determined by the user's options.
-
-        Each generator should take at least one argument, ``inner``,
-        and wrap the pieces of text generated by this.
-
-        Always yield 2-tuples: (code, text). If "code" is 1, the text
-        is part of the original tokensource being highlighted, if it's
-        0, the text is some piece of wrapping. This makes it possible to
-        use several different wrappers that process the original source
-        linewise, e.g. line number generators.
-        """
-        source = self._format_lines(tokensource)
-        if self.hl_lines:
-            source = self._highlight_lines(source)
-        if not self.nowrap:
-            if self.linenos == 2:
-                source = self._wrap_inlinelinenos(source)
-            if self.lineanchors:
-                source = self._wrap_lineanchors(source)
-            if self.linespans:
-                source = self._wrap_linespans(source)
-            source = self.wrap(source, outfile)
-            if self.linenos == 1:
-                source = self._wrap_tablelinenos(source)
-            if self.full:
-                source = self._wrap_full(source, outfile)
-
-        for t, piece in source:
-            outfile.write(piece)
+# -*- coding: utf-8 -*-
+"""
+    pygments.formatters.html
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Formatter for HTML output.
+
+    :copyright: Copyright 2006-2020 by the Pygments team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+import os
+import sys
+import os.path
+from io import StringIO
+
+from pygments.formatter import Formatter
+from pygments.token import Token, Text, STANDARD_TYPES
+from pygments.util import get_bool_opt, get_int_opt, get_list_opt
+
+try:
+    import ctags
+except ImportError:
+    ctags = None
+
+__all__ = ['HtmlFormatter']
+
+
+_escape_html_table = {
+    ord('&'): '&amp;',
+    ord('<'): '&lt;',
+    ord('>'): '&gt;',
+    ord('"'): '&quot;',
+    ord("'"): '&#39;',
+}
+
+
+def escape_html(text, table=_escape_html_table):
+    """Escape &, <, > as well as single and double quotes for HTML."""
+    return text.translate(table)
+
+
+def webify(color):
+    if color.startswith('calc') or color.startswith('var'):
+        return color
+    else:
+        return '#' + color
+
+
+def _get_ttype_class(ttype):
+    fname = STANDARD_TYPES.get(ttype)
+    if fname:
+        return fname
+    aname = ''
+    while fname is None:
+        aname = '-' + ttype[-1] + aname
+        ttype = ttype.parent
+        fname = STANDARD_TYPES.get(ttype)
+    return fname + aname
+
+
+CSSFILE_TEMPLATE = '''\
+/*
+generated by Pygments <https://pygments.org/>
+Copyright 2006-2020 by the Pygments team.
+Licensed under the BSD license, see LICENSE for details.
+*/
+%(styledefs)s
+'''
+
+DOC_HEADER = '''\
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+   "http://www.w3.org/TR/html4/strict.dtd">
+<!--
+generated by Pygments <https://pygments.org/>
+Copyright 2006-2020 by the Pygments team.
+Licensed under the BSD license, see LICENSE for details.
+-->
+<html>
+<head>
+  <title>%(title)s</title>
+  <meta http-equiv="content-type" content="text/html; charset=%(encoding)s">
+  <style type="text/css">
+''' + CSSFILE_TEMPLATE + '''
+  </style>
+</head>
+<body>
+<h2>%(title)s</h2>
+
+'''
+
+DOC_HEADER_EXTERNALCSS = '''\
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+   "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+<head>
+  <title>%(title)s</title>
+  <meta http-equiv="content-type" content="text/html; charset=%(encoding)s">
+  <link rel="stylesheet" href="%(cssfile)s" type="text/css">
+</head>
+<body>
+<h2>%(title)s</h2>
+
+'''
+
+DOC_FOOTER = '''\
+</body>
+</html>
+'''
+
+
+class HtmlFormatter(Formatter):
+    r"""
+    Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped
+    in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass`
+    option.
+
+    If the `linenos` option is set to ``"table"``, the ``<pre>`` is
+    additionally wrapped inside a ``<table>`` which has one row and two
+    cells: one containing the line numbers and one containing the code.
+    Example:
+
+    .. sourcecode:: html
+
+        <div class="highlight" >
+        <table><tr>
+          <td class="linenos" title="click to toggle"
+            onclick="with (this.firstChild.style)
+                     { display = (display == '') ? 'none' : '' }">
+            <pre>1
+            2</pre>
+          </td>
+          <td class="code">
+            <pre><span class="Ke">def </span><span class="NaFu">foo</span>(bar):
+              <span class="Ke">pass</span>
+            </pre>
+          </td>
+        </tr></table></div>
+
+    (whitespace added to improve clarity).
+
+    Wrapping can be disabled using the `nowrap` option.
+
+    A list of lines can be specified using the `hl_lines` option to make these
+    lines highlighted (as of Pygments 0.11).
+
+    With the `full` option, a complete HTML 4 document is output, including
+    the style definitions inside a ``<style>`` tag, or in a separate file if
+    the `cssfile` option is given.
+
+    When `tagsfile` is set to the path of a ctags index file, it is used to
+    generate hyperlinks from names to their definition.  You must enable
+    `lineanchors` and run ctags with the `-n` option for this to work.  The
+    `python-ctags` module from PyPI must be installed to use this feature;
+    otherwise a `RuntimeError` will be raised.
+
+    The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string
+    containing CSS rules for the CSS classes used by the formatter. The
+    argument `arg` can be used to specify additional CSS selectors that
+    are prepended to the classes. A call `fmter.get_style_defs('td .code')`
+    would result in the following CSS classes:
+
+    .. sourcecode:: css
+
+        td .code .kw { font-weight: bold; color: #00FF00 }
+        td .code .cm { color: #999999 }
+        ...
+
+    If you have Pygments 0.6 or higher, you can also pass a list or tuple to the
+    `get_style_defs()` method to request multiple prefixes for the tokens:
+
+    .. sourcecode:: python
+
+        formatter.get_style_defs(['div.syntax pre', 'pre.syntax'])
+
+    The output would then look like this:
+
+    .. sourcecode:: css
+
+        div.syntax pre .kw,
+        pre.syntax .kw { font-weight: bold; color: #00FF00 }
+        div.syntax pre .cm,
+        pre.syntax .cm { color: #999999 }
+        ...
+
+    Additional options accepted:
+
+    `nowrap`
+        If set to ``True``, don't wrap the tokens at all, not even inside a ``<pre>``
+        tag. This disables most other options (default: ``False``).
+
+    `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: ``''``).
+
+    `style`
+        The style to use, can be a string or a Style subclass (default:
+        ``'default'``). This option has no effect if the `cssfile`
+        and `noclobber_cssfile` option are given and the file specified in
+        `cssfile` exists.
+
+    `noclasses`
+        If set to true, token ``<span>`` tags (as well as line number elements)
+        will not use CSS classes, but inline styles. This is not recommended
+        for larger pieces of code since it increases output size by quite a bit
+        (default: ``False``).
+
+    `classprefix`
+        Since the token types use relatively short class names, they may clash
+        with some of your own class names. In this case you can use the
+        `classprefix` option to give a string to prepend to all Pygments-generated
+        CSS class names for token types.
+        Note that this option also affects the output of `get_style_defs()`.
+
+    `cssclass`
+        CSS class for the wrapping ``<div>`` tag (default: ``'highlight'``).
+        If you set this option, the default selector for `get_style_defs()`
+        will be this class.
+
+        .. versionadded:: 0.9
+           If you select the ``'table'`` line numbers, the wrapping table will
+           have a CSS class of this string plus ``'table'``, the default is
+           accordingly ``'highlighttable'``.
+
+    `cssstyles`
+        Inline CSS styles for the wrapping ``<div>`` tag (default: ``''``).
+
+    `prestyles`
+        Inline CSS styles for the ``<pre>`` tag (default: ``''``).
+
+        .. versionadded:: 0.11
+
+    `cssfile`
+        If the `full` option is true and this option is given, it must be the
+        name of an external file. If the filename does not include an absolute
+        path, the file's path will be assumed to be relative to the main output
+        file's path, if the latter can be found. The stylesheet is then written
+        to this file instead of the HTML file.
+
+        .. versionadded:: 0.6
+
+    `noclobber_cssfile`
+        If `cssfile` is given and the specified file exists, the css file will
+        not be overwritten. This allows the use of the `full` option in
+        combination with a user specified css file. Default is ``False``.
+
+        .. versionadded:: 1.1
+
+    `linenos`
+        If set to ``'table'``, output line numbers as a table with two cells,
+        one containing the line numbers, the other the whole code.  This is
+        copy-and-paste-friendly, but may cause alignment problems with some
+        browsers or fonts.  If set to ``'inline'``, the line numbers will be
+        integrated in the ``<pre>`` tag that contains the code (that setting
+        is *new in Pygments 0.8*).
+
+        For compatibility with Pygments 0.7 and earlier, every true value
+        except ``'inline'`` means the same as ``'table'`` (in particular, that
+        means also ``True``).
+
+        The default value is ``False``, which means no line numbers at all.
+
+        **Note:** with the default ("table") line number mechanism, the line
+        numbers and code can have different line heights in Internet Explorer
+        unless you give the enclosing ``<pre>`` tags an explicit ``line-height``
+        CSS property (you get the default line spacing with ``line-height:
+        125%``).
+
+    `hl_lines`
+        Specify a list of lines to be highlighted.
+
+        .. versionadded:: 0.11
+
+    `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.
+
+    `linenospecial`
+        If set to a number n > 0, every nth line number is given the CSS
+        class ``"special"`` (default: ``0``).
+
+    `nobackground`
+        If set to ``True``, the formatter won't output the background color
+        for the wrapping element (this automatically defaults to ``False``
+        when there is no wrapping element [eg: no argument for the
+        `get_syntax_defs` method given]) (default: ``False``).
+
+        .. versionadded:: 0.6
+
+    `lineseparator`
+        This string is output between lines of code. It defaults to ``"\n"``,
+        which is enough to break a line inside ``<pre>`` tags, but you can
+        e.g. set it to ``"<br>"`` to get HTML line breaks.
+
+        .. versionadded:: 0.7
+
+    `lineanchors`
+        If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
+        output line in an anchor tag with a ``name`` of ``foo-linenumber``.
+        This allows easy linking to certain lines.
+
+        .. versionadded:: 0.9
+
+    `linespans`
+        If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
+        output line in a span tag with an ``id`` of ``foo-linenumber``.
+        This allows easy access to lines via javascript.
+
+        .. versionadded:: 1.6
+
+    `anchorlinenos`
+        If set to `True`, will wrap line numbers in <a> tags. Used in
+        combination with `linenos` and `lineanchors`.
+
+    `tagsfile`
+        If set to the path of a ctags file, wrap names in anchor tags that
+        link to their definitions. `lineanchors` should be used, and the
+        tags file should specify line numbers (see the `-n` option to ctags).
+
+        .. versionadded:: 1.6
+
+    `tagurlformat`
+        A string formatting pattern used to generate links to ctags definitions.
+        Available variables are `%(path)s`, `%(fname)s` and `%(fext)s`.
+        Defaults to an empty string, resulting in just `#prefix-number` links.
+
+        .. versionadded:: 1.6
+
+    `filename`
+        A string used to generate a filename when rendering ``<pre>`` blocks,
+        for example if displaying source code.
+
+        .. versionadded:: 2.1
+
+    `wrapcode`
+        Wrap the code inside ``<pre>`` blocks using ``<code>``, as recommended
+        by the HTML5 specification.
+
+        .. versionadded:: 2.4
+
+
+    **Subclassing the HTML formatter**
+
+    .. versionadded:: 0.7
+
+    The HTML formatter is now built in a way that allows easy subclassing, thus
+    customizing the output HTML code. The `format()` method calls
+    `self._format_lines()` which returns a generator that yields tuples of ``(1,
+    line)``, where the ``1`` indicates that the ``line`` is a line of the
+    formatted source code.
+
+    If the `nowrap` option is set, the generator is the iterated over and the
+    resulting HTML is output.
+
+    Otherwise, `format()` calls `self.wrap()`, which wraps the generator with
+    other generators. These may add some HTML code to the one generated by
+    `_format_lines()`, either by modifying the lines generated by the latter,
+    then yielding them again with ``(1, line)``, and/or by yielding other HTML
+    code before or after the lines, with ``(0, html)``. The distinction between
+    source lines and other code makes it possible to wrap the generator multiple
+    times.
+
+    The default `wrap()` implementation adds a ``<div>`` and a ``<pre>`` tag.
+
+    A custom `HtmlFormatter` subclass could look like this:
+
+    .. sourcecode:: python
+
+        class CodeHtmlFormatter(HtmlFormatter):
+
+            def wrap(self, source, outfile):
+                return self._wrap_code(source)
+
+            def _wrap_code(self, source):
+                yield 0, '<code>'
+                for i, t in source:
+                    if i == 1:
+                        # it's a line of formatted code
+                        t += '<br>'
+                    yield i, t
+                yield 0, '</code>'
+
+    This results in wrapping the formatted lines with a ``<code>`` tag, where the
+    source lines are broken using ``<br>`` tags.
+
+    After calling `wrap()`, the `format()` method also adds the "line numbers"
+    and/or "full document" wrappers if the respective options are set. Then, all
+    HTML yielded by the wrapped generator is output.
+    """
+
+    name = 'HTML'
+    aliases = ['html']
+    filenames = ['*.html', '*.htm']
+
+    def __init__(self, **options):
+        Formatter.__init__(self, **options)
+        self.title = self._decodeifneeded(self.title)
+        self.nowrap = get_bool_opt(options, 'nowrap', False)
+        self.noclasses = get_bool_opt(options, 'noclasses', False)
+        self.classprefix = options.get('classprefix', '')
+        self.cssclass = self._decodeifneeded(options.get('cssclass', 'highlight'))
+        self.cssstyles = self._decodeifneeded(options.get('cssstyles', ''))
+        self.prestyles = self._decodeifneeded(options.get('prestyles', ''))
+        self.cssfile = self._decodeifneeded(options.get('cssfile', ''))
+        self.noclobber_cssfile = get_bool_opt(options, 'noclobber_cssfile', False)
+        self.tagsfile = self._decodeifneeded(options.get('tagsfile', ''))
+        self.tagurlformat = self._decodeifneeded(options.get('tagurlformat', ''))
+        self.filename = self._decodeifneeded(options.get('filename', ''))
+        self.wrapcode = get_bool_opt(options, 'wrapcode', False)
+
+        if self.tagsfile:
+            if not ctags:
+                raise RuntimeError('The "ctags" package must to be installed '
+                                   'to be able to use the "tagsfile" feature.')
+            self._ctags = ctags.CTags(self.tagsfile)
+
+        linenos = options.get('linenos', False)
+        if linenos == 'inline':
+            self.linenos = 2
+        elif linenos:
+            # compatibility with <= 0.7
+            self.linenos = 1
+        else:
+            self.linenos = 0
+        self.linenostart = abs(get_int_opt(options, 'linenostart', 1))
+        self.linenostep = abs(get_int_opt(options, 'linenostep', 1))
+        self.linenospecial = abs(get_int_opt(options, 'linenospecial', 0))
+        self.nobackground = get_bool_opt(options, 'nobackground', False)
+        self.lineseparator = options.get('lineseparator', '\n')
+        self.lineanchors = options.get('lineanchors', '')
+        self.linespans = options.get('linespans', '')
+        self.anchorlinenos = get_bool_opt(options, 'anchorlinenos', False)
+        self.hl_lines = set()
+        for lineno in get_list_opt(options, 'hl_lines', []):
+            try:
+                self.hl_lines.add(int(lineno))
+            except ValueError:
+                pass
+
+        self._create_stylesheet()
+
+    def _get_css_class(self, ttype):
+        """Return the css class of this token type prefixed with
+        the classprefix option."""
+        ttypeclass = _get_ttype_class(ttype)
+        if ttypeclass:
+            return self.classprefix + ttypeclass
+        return ''
+
+    def _get_css_classes(self, ttype):
+        """Return the css classes of this token type prefixed with
+        the classprefix option."""
+        cls = self._get_css_class(ttype)
+        while ttype not in STANDARD_TYPES:
+            ttype = ttype.parent
+            cls = self._get_css_class(ttype) + ' ' + cls
+        return cls
+
+    def _create_stylesheet(self):
+        t2c = self.ttype2class = {Token: ''}
+        c2s = self.class2style = {}
+        for ttype, ndef in self.style:
+            name = self._get_css_class(ttype)
+            style = ''
+            if ndef['color']:
+                style += 'color: %s; ' % webify(ndef['color'])
+            if ndef['bold']:
+                style += 'font-weight: bold; '
+            if ndef['italic']:
+                style += 'font-style: italic; '
+            if ndef['underline']:
+                style += 'text-decoration: underline; '
+            if ndef['bgcolor']:
+                style += 'background-color: %s; ' % webify(ndef['bgcolor'])
+            if ndef['border']:
+                style += 'border: 1px solid %s; ' % webify(ndef['border'])
+            if style:
+                t2c[ttype] = name
+                # save len(ttype) to enable ordering the styles by
+                # hierarchy (necessary for CSS cascading rules!)
+                c2s[name] = (style[:-2], ttype, len(ttype))
+
+    def get_style_defs(self, arg=None):
+        """
+        Return CSS style definitions for the classes produced by the current
+        highlighting style. ``arg`` can be a string or list of selectors to
+        insert before the token type classes.
+        """
+        style_lines = []
+
+        style_lines.extend(self.get_linenos_style_defs())
+        style_lines.extend(self.get_background_style_defs(arg))
+        style_lines.extend(self.get_token_style_defs(arg))
+
+        return '\n'.join(style_lines)
+
+    def get_token_style_defs(self, arg=None):
+        prefix = self.get_css_prefix(arg)
+
+        styles = [
+            (level, ttype, cls, style)
+            for cls, (style, ttype, level) in self.class2style.items()
+            if cls and style
+        ]
+        styles.sort()
+
+        lines = [
+            '%s { %s } /* %s */' % (prefix(cls), style, repr(ttype)[6:])
+            for (level, ttype, cls, style) in styles
+        ]
+
+        return lines
+
+    def get_background_style_defs(self, arg=None):
+        prefix = self.get_css_prefix(arg)
+        bg_color = self.style.background_color
+        hl_color = self.style.highlight_color
+
+        lines = []
+
+        if arg and not self.nobackground and bg_color is not None:
+            text_style = ''
+            if Text in self.ttype2class:
+                text_style = ' ' + self.class2style[self.ttype2class[Text]][0]
+            lines.insert(
+                0, '%s{ background: %s;%s }' % (
+                    prefix(''), bg_color, text_style
+                )
+            )
+        if hl_color is not None:
+            lines.insert(
+                0, '%s { background-color: %s }' % (prefix('hll'), hl_color)
+            )
+
+        return lines
+
+    def get_linenos_style_defs(self):
+        lines = [
+            'pre { %s }' % self._pre_style,
+            'td.linenos pre { %s }' % self._linenos_style,
+            'span.linenos { %s }' % self._linenos_style,
+            'td.linenos pre.special { %s }' % self._linenos_special_style,
+            'span.linenos.special { %s }' % self._linenos_special_style,
+        ]
+
+        return lines
+
+    def get_css_prefix(self, arg):
+        if arg is None:
+            arg = ('cssclass' in self.options and '.'+self.cssclass or '')
+        if isinstance(arg, str):
+            args = [arg]
+        else:
+            args = list(arg)
+
+        def prefix(cls):
+            if cls:
+                cls = '.' + cls
+            tmp = []
+            for arg in args:
+                tmp.append((arg and arg + ' ' or '') + cls)
+            return ', '.join(tmp)
+
+        return prefix
+
+    @property
+    def _pre_style(self):
+        return 'line-height: 125%; margin: 0;'
+
+    @property
+    def _linenos_style(self):
+        return 'color: %s; background-color: %s; padding: 0 5px 0 5px;' % (
+            self.style.line_number_color,
+            self.style.line_number_background_color
+        )
+
+    @property
+    def _linenos_special_style(self):
+        return 'color: %s; background-color: %s; padding: 0 5px 0 5px;' % (
+            self.style.line_number_special_color,
+            self.style.line_number_special_background_color
+        )
+
+    def _decodeifneeded(self, value):
+        if isinstance(value, bytes):
+            if self.encoding:
+                return value.decode(self.encoding)
+            return value.decode()
+        return value
+
+    def _wrap_full(self, inner, outfile):
+        if self.cssfile:
+            if os.path.isabs(self.cssfile):
+                # it's an absolute filename
+                cssfilename = self.cssfile
+            else:
+                try:
+                    filename = outfile.name
+                    if not filename or filename[0] == '<':
+                        # pseudo files, e.g. name == '<fdopen>'
+                        raise AttributeError
+                    cssfilename = os.path.join(os.path.dirname(filename),
+                                               self.cssfile)
+                except AttributeError:
+                    print('Note: Cannot determine output file name, '
+                          'using current directory as base for the CSS file name',
+                          file=sys.stderr)
+                    cssfilename = self.cssfile
+            # write CSS file only if noclobber_cssfile isn't given as an option.
+            try:
+                if not os.path.exists(cssfilename) or not self.noclobber_cssfile:
+                    with open(cssfilename, "w") as cf:
+                        cf.write(CSSFILE_TEMPLATE %
+                                 {'styledefs': self.get_style_defs('body')})
+            except IOError as err:
+                err.strerror = 'Error writing CSS file: ' + err.strerror
+                raise
+
+            yield 0, (DOC_HEADER_EXTERNALCSS %
+                      dict(title=self.title,
+                           cssfile=self.cssfile,
+                           encoding=self.encoding))
+        else:
+            yield 0, (DOC_HEADER %
+                      dict(title=self.title,
+                           styledefs=self.get_style_defs('body'),
+                           encoding=self.encoding))
+
+        yield from inner
+        yield 0, DOC_FOOTER
+
+    def _wrap_tablelinenos(self, inner):
+        dummyoutfile = StringIO()
+        lncount = 0
+        for t, line in inner:
+            if t:
+                lncount += 1
+            dummyoutfile.write(line)
+
+        fl = self.linenostart
+        mw = len(str(lncount + fl - 1))
+        sp = self.linenospecial
+        st = self.linenostep
+        la = self.lineanchors
+        aln = self.anchorlinenos
+        nocls = self.noclasses
+
+        lines = []
+
+        for i in range(fl, fl+lncount):
+            print_line = i % st == 0
+            special_line = sp and i % sp == 0
+
+            if print_line:
+                line = '%*d' % (mw, i)
+                if aln:
+                    line = '<a href="#%s-%d">%s</a>' % (la, i, line)
+            else:
+                line = ' ' * mw
+
+            if nocls:
+                if special_line:
+                    style = ' style="%s"' % self._linenos_special_style
+                else:
+                    style = ' style="%s"' % self._linenos_style
+            else:
+                if special_line:
+                    style = ' class="special"'
+                else:
+                    style = ''
+
+            if style:
+                line = '<span%s>%s</span>' % (style, line)
+
+            lines.append(line)
+
+        ls = '\n'.join(lines)
+
+        # in case you wonder about the seemingly redundant <div> here: since the
+        # content in the other cell also is wrapped in a div, some browsers in
+        # some configurations seem to mess up the formatting...
+        yield 0, (
+            '<table class="%stable">' % self.cssclass +
+            '<tr><td class="linenos"><div class="linenodiv"><pre>' +
+            ls + '</pre></div></td><td class="code">'
+        )
+        yield 0, dummyoutfile.getvalue()
+        yield 0, '</td></tr></table>'
+
+    def _wrap_inlinelinenos(self, inner):
+        # need a list of lines since we need the width of a single number :(
+        inner_lines = list(inner)
+        sp = self.linenospecial
+        st = self.linenostep
+        num = self.linenostart
+        mw = len(str(len(inner_lines) + num - 1))
+        nocls = self.noclasses
+
+        for _, inner_line in inner_lines:
+            print_line = num % st == 0
+            special_line = sp and num % sp == 0
+
+            if print_line:
+                line = '%*d' % (mw, num)
+            else:
+                line = ' ' * mw
+
+            if nocls:
+                if special_line:
+                    style = ' style="%s"' % self._linenos_special_style
+                else:
+                    style = ' style="%s"' % self._linenos_style
+            else:
+                if special_line:
+                    style = ' class="linenos special"'
+                else:
+                    style = ' class="linenos"'
+
+            if style:
+                yield 1, '<span%s>%s</span>' % (style, line) + inner_line
+            else:
+                yield 1, line +  inner_line
+            num += 1
+
+    def _wrap_lineanchors(self, inner):
+        s = self.lineanchors
+        # subtract 1 since we have to increment i *before* yielding
+        i = self.linenostart - 1
+        for t, line in inner:
+            if t:
+                i += 1
+                yield 1, '<a name="%s-%d"></a>' % (s, i) + line
+            else:
+                yield 0, line
+
+    def _wrap_linespans(self, inner):
+        s = self.linespans
+        i = self.linenostart - 1
+        for t, line in inner:
+            if t:
+                i += 1
+                yield 1, '<span id="%s-%d">%s</span>' % (s, i, line)
+            else:
+                yield 0, line
+
+    def _wrap_div(self, inner):
+        style = []
+        if (self.noclasses and not self.nobackground and
+                self.style.background_color is not None):
+            style.append('background: %s' % (self.style.background_color,))
+        if self.cssstyles:
+            style.append(self.cssstyles)
+        style = '; '.join(style)
+
+        yield 0, ('<div' + (self.cssclass and ' class="%s"' % self.cssclass) +
+                  (style and (' style="%s"' % style)) + '>')
+        yield from inner
+        yield 0, '</div>\n'
+
+    def _wrap_pre(self, inner):
+        style = []
+        if self.prestyles:
+            style.append(self.prestyles)
+        if self.noclasses:
+            style.append(self._pre_style)
+        style = '; '.join(style)
+
+        if self.filename:
+            yield 0, ('<span class="filename">' + self.filename + '</span>')
+
+        # the empty span here is to keep leading empty lines from being
+        # ignored by HTML parsers
+        yield 0, ('<pre' + (style and ' style="%s"' % style) + '><span></span>')
+        yield from inner
+        yield 0, '</pre>'
+
+    def _wrap_code(self, inner):
+        yield 0, '<code>'
+        yield from inner
+        yield 0, '</code>'
+
+    def _format_lines(self, tokensource):
+        """
+        Just format the tokens, without any wrapping tags.
+        Yield individual lines.
+        """
+        nocls = self.noclasses
+        lsep = self.lineseparator
+        # for <span style=""> lookup only
+        getcls = self.ttype2class.get
+        c2s = self.class2style
+        escape_table = _escape_html_table
+        tagsfile = self.tagsfile
+
+        lspan = ''
+        line = []
+        for ttype, value in tokensource:
+            if nocls:
+                cclass = getcls(ttype)
+                while cclass is None:
+                    ttype = ttype.parent
+                    cclass = getcls(ttype)
+                cspan = cclass and '<span style="%s">' % c2s[cclass][0] or ''
+            else:
+                cls = self._get_css_classes(ttype)
+                cspan = cls and '<span class="%s">' % cls or ''
+
+            parts = value.translate(escape_table).split('\n')
+
+            if tagsfile and ttype in Token.Name:
+                filename, linenumber = self._lookup_ctag(value)
+                if linenumber:
+                    base, filename = os.path.split(filename)
+                    if base:
+                        base += '/'
+                    filename, extension = os.path.splitext(filename)
+                    url = self.tagurlformat % {'path': base, 'fname': filename,
+                                               'fext': extension}
+                    parts[0] = "<a href=\"%s#%s-%d\">%s" % \
+                        (url, self.lineanchors, linenumber, parts[0])
+                    parts[-1] = parts[-1] + "</a>"
+
+            # for all but the last line
+            for part in parts[:-1]:
+                if line:
+                    if lspan != cspan:
+                        line.extend(((lspan and '</span>'), cspan, part,
+                                     (cspan and '</span>'), lsep))
+                    else:  # both are the same
+                        line.extend((part, (lspan and '</span>'), lsep))
+                    yield 1, ''.join(line)
+                    line = []
+                elif part:
+                    yield 1, ''.join((cspan, part, (cspan and '</span>'), lsep))
+                else:
+                    yield 1, lsep
+            # for the last line
+            if line and parts[-1]:
+                if lspan != cspan:
+                    line.extend(((lspan and '</span>'), cspan, parts[-1]))
+                    lspan = cspan
+                else:
+                    line.append(parts[-1])
+            elif parts[-1]:
+                line = [cspan, parts[-1]]
+                lspan = cspan
+            # else we neither have to open a new span nor set lspan
+
+        if line:
+            line.extend(((lspan and '</span>'), lsep))
+            yield 1, ''.join(line)
+
+    def _lookup_ctag(self, token):
+        entry = ctags.TagEntry()
+        if self._ctags.find(entry, token, 0):
+            return entry['file'], entry['lineNumber']
+        else:
+            return None, None
+
+    def _highlight_lines(self, tokensource):
+        """
+        Highlighted the lines specified in the `hl_lines` option by
+        post-processing the token stream coming from `_format_lines`.
+        """
+        hls = self.hl_lines
+
+        for i, (t, value) in enumerate(tokensource):
+            if t != 1:
+                yield t, value
+            if i + 1 in hls:  # i + 1 because Python indexes start at 0
+                if self.noclasses:
+                    style = ''
+                    if self.style.highlight_color is not None:
+                        style = (' style="background-color: %s"' %
+                                 (self.style.highlight_color,))
+                    yield 1, '<span%s>%s</span>' % (style, value)
+                else:
+                    yield 1, '<span class="hll">%s</span>' % value
+            else:
+                yield 1, value
+
+    def wrap(self, source, outfile):
+        """
+        Wrap the ``source``, which is a generator yielding
+        individual lines, in custom generators. See docstring
+        for `format`. Can be overridden.
+        """
+        if self.wrapcode:
+            return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
+        else:
+            return self._wrap_div(self._wrap_pre(source))
+
+    def format_unencoded(self, tokensource, outfile):
+        """
+        The formatting process uses several nested generators; which of
+        them are used is determined by the user's options.
+
+        Each generator should take at least one argument, ``inner``,
+        and wrap the pieces of text generated by this.
+
+        Always yield 2-tuples: (code, text). If "code" is 1, the text
+        is part of the original tokensource being highlighted, if it's
+        0, the text is some piece of wrapping. This makes it possible to
+        use several different wrappers that process the original source
+        linewise, e.g. line number generators.
+        """
+        source = self._format_lines(tokensource)
+        if self.hl_lines:
+            source = self._highlight_lines(source)
+        if not self.nowrap:
+            if self.linenos == 2:
+                source = self._wrap_inlinelinenos(source)
+            if self.lineanchors:
+                source = self._wrap_lineanchors(source)
+            if self.linespans:
+                source = self._wrap_linespans(source)
+            source = self.wrap(source, outfile)
+            if self.linenos == 1:
+                source = self._wrap_tablelinenos(source)
+            if self.full:
+                source = self._wrap_full(source, outfile)
+
+        for t, piece in source:
+            outfile.write(piece)

eric ide

mercurial