def test_default_highlight(logger):
    bridge = PygmentsBridge('html')

    # default: highlights as python3
    ret = bridge.highlight_block('print "Hello sphinx world"', 'default')
    assert ret == (
        '<div class="highlight"><pre><span></span><span class="nb">print</span> '
        '<span class="s2">&quot;Hello sphinx world&quot;</span>\n</pre></div>\n'
    )

    # default: fallbacks to none if highlighting failed
    ret = bridge.highlight_block('reST ``like`` text', 'default')
    assert ret == '<div class="highlight"><pre><span></span>reST ``like`` text\n</pre></div>\n'

    # python3: highlights as python3
    ret = bridge.highlight_block('print "Hello sphinx world"', 'python3')
    assert ret == (
        '<div class="highlight"><pre><span></span><span class="nb">print</span> '
        '<span class="s2">&quot;Hello sphinx world&quot;</span>\n</pre></div>\n'
    )

    # python3: raises error if highlighting failed
    ret = bridge.highlight_block('reST ``like`` text', 'python3')
    logger.warning.assert_called_with(
        'Could not lex literal_block as "%s". '
        'Highlighting skipped.',
        'python3',
        type='misc',
        subtype='highlighting_failure',
        location=None)
Beispiel #2
0
def test_default_highlight():
    bridge = PygmentsBridge('html')

    # default: highlights as python3
    ret = bridge.highlight_block('print "Hello sphinx world"', 'default')
    assert ret == (
        '<div class="highlight"><pre><span></span><span class="nb">print</span> '
        '<span class="s2">&quot;Hello sphinx world&quot;</span>\n</pre></div>\n'
    )

    # default: fallbacks to none if highlighting failed
    ret = bridge.highlight_block('reST ``like`` text', 'default')
    assert ret == '<div class="highlight"><pre><span></span>reST ``like`` text\n</pre></div>\n'

    # python3: highlights as python3
    ret = bridge.highlight_block('print "Hello sphinx world"', 'python3')
    assert ret == (
        '<div class="highlight"><pre><span></span><span class="nb">print</span> '
        '<span class="s2">&quot;Hello sphinx world&quot;</span>\n</pre></div>\n'
    )

    # python3: raises error if highlighting failed
    try:
        ret = bridge.highlight_block('reST ``like`` text', 'python3')
        assert False, "highlight_block() does not raise any exceptions"
    except ErrorToken:
        pass  # raise parsing error
Beispiel #3
0
def test_set_formatter():
    PygmentsBridge.html_formatter = MyFormatter
    try:
        bridge = PygmentsBridge('html')
        ret = bridge.highlight_block('foo\n', 'python')
        assert ret == 'foo\n'
    finally:
        PygmentsBridge.html_formatter = HtmlFormatter
Beispiel #4
0
def test_trim_doctest_flags():
    PygmentsBridge.html_formatter = MyFormatter
    try:
        bridge = PygmentsBridge("html", trim_doctest_flags=True)
        ret = bridge.highlight_block(">>> 1+2 # doctest: SKIP\n3\n", "pycon")
        assert ret == ">>> 1+2 \n3\n"
    finally:
        PygmentsBridge.html_formatter = HtmlFormatter
Beispiel #5
0
def test_set_formatter():
    PygmentsBridge.html_formatter = MyFormatter
    try:
        bridge = PygmentsBridge("html")
        ret = bridge.highlight_block("foo\n", "python")
        assert ret == "foo\n"
    finally:
        PygmentsBridge.html_formatter = HtmlFormatter
Beispiel #6
0
def test_trim_doctest_flags():
    PygmentsBridge.html_formatter = MyFormatter
    try:
        bridge = PygmentsBridge('html', trim_doctest_flags=True)
        ret = bridge.highlight_block('>>> 1+2 # doctest: SKIP\n3\n', 'pycon')
        assert ret == '>>> 1+2 \n3\n'
    finally:
        PygmentsBridge.html_formatter = HtmlFormatter
def test_set_formatter():
    PygmentsBridge.html_formatter = MyFormatter
    try:
        bridge = PygmentsBridge('html')
        ret = bridge.highlight_block('foo\n', 'python')
        assert ret == 'foo\n'
    finally:
        PygmentsBridge.html_formatter = HtmlFormatter
def test_trim_doctest_flags():
    PygmentsBridge.html_formatter = MyFormatter
    try:
        bridge = PygmentsBridge('html', trim_doctest_flags=True)
        ret = bridge.highlight_block('>>> 1+2 # doctest: SKIP\n3\n', 'pycon')
        assert ret == '>>> 1+2 \n3\n'
    finally:
        PygmentsBridge.html_formatter = HtmlFormatter
Beispiel #9
0
def test_default_highlight(logger):
    bridge = PygmentsBridge('html')

    # default: highlights as python3
    ret = bridge.highlight_block('print "Hello sphinx world"', 'default')
    assert ret == ('<div class="highlight"><pre><span></span><span class="nb">print</span> '
                   '<span class="s2">&quot;Hello sphinx world&quot;</span>\n</pre></div>\n')

    # default: fallbacks to none if highlighting failed
    ret = bridge.highlight_block('reST ``like`` text', 'default')
    assert ret == '<div class="highlight"><pre><span></span>reST ``like`` text\n</pre></div>\n'

    # python3: highlights as python3
    ret = bridge.highlight_block('print "Hello sphinx world"', 'python3')
    assert ret == ('<div class="highlight"><pre><span></span><span class="nb">print</span> '
                   '<span class="s2">&quot;Hello sphinx world&quot;</span>\n</pre></div>\n')

    # python3: raises error if highlighting failed
    ret = bridge.highlight_block('reST ``like`` text', 'python3')
    logger.warning.assert_called_with('Could not lex literal_block as "%s". '
                                      'Highlighting skipped.', 'python3',
                                      type='misc', subtype='highlighting_failure',
                                      location=None)
Beispiel #10
0
def test_default_highlight():
    bridge = PygmentsBridge('html')

    # default: highlights as python3
    ret = bridge.highlight_block('print "Hello sphinx world"', 'default')
    assert ret == ('<div class="highlight"><pre><span></span><span class="nb">print</span> '
                   '<span class="s2">&quot;Hello sphinx world&quot;</span>\n</pre></div>\n')

    # default: fallbacks to none if highlighting failed
    ret = bridge.highlight_block('reST ``like`` text', 'default')
    assert ret == '<div class="highlight"><pre><span></span>reST ``like`` text\n</pre></div>\n'

    # python3: highlights as python3
    ret = bridge.highlight_block('print "Hello sphinx world"', 'python3')
    assert ret == ('<div class="highlight"><pre><span></span><span class="nb">print</span> '
                   '<span class="s2">&quot;Hello sphinx world&quot;</span>\n</pre></div>\n')

    # python3: raises error if highlighting failed
    try:
        ret = bridge.highlight_block('reST ``like`` text', 'python3')
        assert False, "highlight_block() does not raise any exceptions"
    except ErrorToken:
        pass  # raise parsing error
Beispiel #11
0
def test_add_lexer(app):
    app.add_lexer('test', MyLexer())

    bridge = PygmentsBridge('html')
    ret = bridge.highlight_block('ab', 'test')
    assert '<span class="n">a</span>b' in ret
Beispiel #12
0
class HTMLTranslator(BaseTranslator):
    """
    Our custom HTML translator.
    """
    def __init__(self, builder, *args, **kwds):
        BaseTranslator.__init__(self, *args, **kwds)
        self.highlighter = PygmentsBridge('html',
                                          builder.config.pygments_style)
        self.no_smarty = 0
        self.builder = builder
        self.highlightlang = builder.config.highlight_language
        self.highlightlinenothreshold = sys.maxint
        self.protect_literal_text = 0

    def visit_desc(self, node):
        self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))

    def depart_desc(self, node):
        self.body.append('</dl>\n\n')

    def visit_desc_signature(self, node):
        # the id is set automatically
        self.body.append(self.starttag(node, 'dt'))
        # anchor for per-desc interactive data
        if node.parent['desctype'] != 'describe' and node['ids'] and node[
                'first']:
            self.body.append('<!--[%s]-->' % node['ids'][0])
        if node.parent['desctype'] in ('class', 'exception'):
            self.body.append('%s ' % node.parent['desctype'])

    def depart_desc_signature(self, node):
        if node['ids'] and self.builder.add_definition_links:
            self.body.append(
                u'<a class="headerlink" href="#%s" ' % node['ids'][0] +
                u'title="%s">\u00B6</a>' % _('Permalink to this definition'))
        self.body.append('</dt>\n')

    def visit_desc_addname(self, node):
        self.body.append(self.starttag(node, 'tt', '', CLASS='descclassname'))

    def depart_desc_addname(self, node):
        self.body.append('</tt>')

    def visit_desc_type(self, node):
        pass

    def depart_desc_type(self, node):
        pass

    def visit_desc_name(self, node):
        self.body.append(self.starttag(node, 'tt', '', CLASS='descname'))

    def depart_desc_name(self, node):
        self.body.append('</tt>')

    def visit_desc_parameterlist(self, node):
        self.body.append('<big>(</big>')
        self.first_param = 1

    def depart_desc_parameterlist(self, node):
        self.body.append('<big>)</big>')

    def visit_desc_parameter(self, node):
        if not self.first_param:
            self.body.append(', ')
        else:
            self.first_param = 0
        if not node.hasattr('noemph'):
            self.body.append('<em>')

    def depart_desc_parameter(self, node):
        if not node.hasattr('noemph'):
            self.body.append('</em>')

    def visit_desc_optional(self, node):
        self.body.append('<span class="optional">[</span>')

    def depart_desc_optional(self, node):
        self.body.append('<span class="optional">]</span>')

    def visit_desc_annotation(self, node):
        self.body.append(self.starttag(node, 'em', CLASS='property'))

    def depart_desc_annotation(self, node):
        self.body.append('</em>')

    def visit_desc_content(self, node):
        self.body.append(self.starttag(node, 'dd', ''))

    def depart_desc_content(self, node):
        self.body.append('</dd>')

    def visit_refcount(self, node):
        self.body.append(self.starttag(node, 'em', '', CLASS='refcount'))

    def depart_refcount(self, node):
        self.body.append('</em>')

    def visit_versionmodified(self, node):
        self.body.append(self.starttag(node, 'p'))
        text = versionlabels[node['type']] % node['version']
        if len(node):
            text += ': '
        else:
            text += '.'
        self.body.append('<span class="versionmodified">%s</span>' % text)

    def depart_versionmodified(self, node):
        self.body.append('</p>\n')

    # overwritten
    def visit_reference(self, node):
        BaseTranslator.visit_reference(self, node)
        if node.hasattr('reftitle'):
            # ugly hack to add a title attribute
            starttag = self.body[-1]
            if not starttag.startswith('<a '):
                return
            self.body[-1] = '<a title="%s"' % self.attval(node['reftitle']) + \
                            starttag[2:]

    # overwritten -- we don't want source comments to show up in the HTML
    def visit_comment(self, node):
        raise nodes.SkipNode

    # overwritten
    def visit_admonition(self, node, name=''):
        self.body.append(
            self.starttag(node, 'div', CLASS=('admonition ' + name)))
        if name and name != 'seealso':
            node.insert(0, nodes.title(name, admonitionlabels[name]))
        self.set_first_last(node)

    def visit_seealso(self, node):
        self.visit_admonition(node, 'seealso')

    def depart_seealso(self, node):
        self.depart_admonition(node)

    # overwritten for docutils 0.4
    if hasattr(BaseTranslator, 'start_tag_with_title'):

        def visit_section(self, node):
            # the 0.5 version, to get the id attribute in the <div> tag
            self.section_level += 1
            self.body.append(self.starttag(node, 'div', CLASS='section'))

        def visit_title(self, node):
            # don't move the id attribute inside the <h> tag
            BaseTranslator.visit_title(self, node, move_ids=0)

    # overwritten
    def visit_literal_block(self, node):
        if node.rawsource != node.astext():
            # most probably a parsed-literal block -- don't highlight
            return BaseTranslator.visit_literal_block(self, node)
        lang = self.highlightlang
        linenos = node.rawsource.count(
            '\n') >= self.highlightlinenothreshold - 1
        if node.has_key('language'):
            # code-block directives
            lang = node['language']
        if node.has_key('linenos'):
            linenos = node['linenos']
        self.body.append(
            self.highlighter.highlight_block(node.rawsource, lang, linenos))
        raise nodes.SkipNode

    def visit_doctest_block(self, node):
        self.visit_literal_block(node)

    # overwritten
    def visit_literal(self, node):
        if len(node.children) == 1 and \
               node.children[0] in ('None', 'True', 'False'):
            node['classes'].append('xref')
        self.body.append(
            self.starttag(node, 'tt', '', CLASS='docutils literal'))
        self.protect_literal_text += 1

    def depart_literal(self, node):
        self.protect_literal_text -= 1
        self.body.append('</tt>')

    def visit_productionlist(self, node):
        self.body.append(self.starttag(node, 'pre'))
        names = []
        for production in node:
            names.append(production['tokenname'])
        maxlen = max(len(name) for name in names)
        for production in node:
            if production['tokenname']:
                lastname = production['tokenname'].ljust(maxlen)
                self.body.append(self.starttag(production, 'strong', ''))
                self.body.append(lastname + '</strong> ::= ')
            else:
                self.body.append('%s     ' % (' ' * len(lastname)))
            production.walkabout(self)
            self.body.append('\n')
        self.body.append('</pre>\n')
        raise nodes.SkipNode

    def depart_productionlist(self, node):
        pass

    def visit_production(self, node):
        pass

    def depart_production(self, node):
        pass

    def visit_centered(self, node):
        self.body.append(
            self.starttag(node, 'p', CLASS="centered") + '<strong>')

    def depart_centered(self, node):
        self.body.append('</strong></p>')

    def visit_compact_paragraph(self, node):
        pass

    def depart_compact_paragraph(self, node):
        pass

    def visit_highlightlang(self, node):
        self.highlightlang = node['lang']
        self.highlightlinenothreshold = node['linenothreshold']

    def depart_highlightlang(self, node):
        pass

    # overwritten
    def visit_image(self, node):
        olduri = node['uri']
        # rewrite the URI if the environment knows about it
        if olduri in self.builder.images:
            node['uri'] = posixpath.join(self.builder.imgpath,
                                         self.builder.images[olduri])
        BaseTranslator.visit_image(self, node)

    def visit_toctree(self, node):
        # this only happens when formatting a toc from env.tocs -- in this
        # case we don't want to include the subtree
        raise nodes.SkipNode

    def visit_index(self, node):
        raise nodes.SkipNode

    def visit_tabular_col_spec(self, node):
        raise nodes.SkipNode

    def visit_glossary(self, node):
        pass

    def depart_glossary(self, node):
        pass

    def visit_acks(self, node):
        pass

    def depart_acks(self, node):
        pass

    def visit_module(self, node):
        pass

    def depart_module(self, node):
        pass

    def bulk_text_processor(self, text):
        return text

    # overwritten
    def visit_Text(self, node):
        text = node.astext()
        encoded = self.encode(text)
        if self.protect_literal_text:
            # moved here from base class's visit_literal to support
            # more formatting in literal nodes
            for token in self.words_and_spaces.findall(encoded):
                if token.strip():
                    # protect literal text from line wrapping
                    self.body.append('<span class="pre">%s</span>' % token)
                elif token in ' \n':
                    # allow breaks at whitespace
                    self.body.append(token)
                else:
                    # protect runs of multiple spaces; the last one can wrap
                    self.body.append('&nbsp;' * (len(token) - 1) + ' ')
        else:
            if self.in_mailto and self.settings.cloak_email_addresses:
                encoded = self.cloak_email(encoded)
            else:
                encoded = self.bulk_text_processor(encoded)
            self.body.append(encoded)

    # these are all for docutils 0.5 compatibility

    def visit_note(self, node):
        self.visit_admonition(node, 'note')

    def depart_note(self, node):
        self.depart_admonition(node)

    def visit_warning(self, node):
        self.visit_admonition(node, 'warning')

    def depart_warning(self, node):
        self.depart_admonition(node)

    def visit_attention(self, node):
        self.visit_admonition(node, 'attention')

    def depart_attention(self, node):
        self.depart_admonition()

    def visit_caution(self, node):
        self.visit_admonition(node, 'caution')

    def depart_caution(self, node):
        self.depart_admonition()

    def visit_danger(self, node):
        self.visit_admonition(node, 'danger')

    def depart_danger(self, node):
        self.depart_admonition()

    def visit_error(self, node):
        self.visit_admonition(node, 'error')

    def depart_error(self, node):
        self.depart_admonition()

    def visit_hint(self, node):
        self.visit_admonition(node, 'hint')

    def depart_hint(self, node):
        self.depart_admonition()

    def visit_important(self, node):
        self.visit_admonition(node, 'important')

    def depart_important(self, node):
        self.depart_admonition()

    def visit_tip(self, node):
        self.visit_admonition(node, 'tip')

    def depart_tip(self, node):
        self.depart_admonition()

    # these are only handled specially in the SmartyPantsHTMLTranslator
    def visit_literal_emphasis(self, node):
        return self.visit_emphasis(node)

    def depart_literal_emphasis(self, node):
        return self.depart_emphasis(node)

    def depart_title(self, node):
        close_tag = self.context[-1]
        if self.builder.add_header_links and \
               (close_tag.startswith('</h') or
                close_tag.startswith('</a></h')) and \
               node.parent.hasattr('ids') and node.parent['ids']:
            aname = node.parent['ids'][0]
            # add permalink anchor
            self.body.append(u'<a class="headerlink" href="#%s" ' % aname +
                             u'title="%s">\u00B6</a>' %
                             _('Permalink to this headline'))
        BaseTranslator.depart_title(self, node)

    def unknown_visit(self, node):
        raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
Beispiel #13
0
def test_add_lexer(app, status, warning):
    app.add_lexer("test", MyLexer())

    bridge = PygmentsBridge("html")
    ret = bridge.highlight_block("ab", "test")
    assert '<span class="n">a</span>b' in ret
Beispiel #14
0
def test_lexer_options():
    bridge = PygmentsBridge("html")
    ret = bridge.highlight_block("//comment", "php", opts={"startinline": True})
    assert '<span class="c1">//comment</span>' in ret
Beispiel #15
0
class HTMLTranslator(BaseTranslator):
    """
    Our custom HTML translator.
    """

    def __init__(self, builder, *args, **kwds):
        BaseTranslator.__init__(self, *args, **kwds)
        self.highlighter = PygmentsBridge('html', builder.config.pygments_style)
        self.no_smarty = 0
        self.builder = builder
        self.highlightlang = 'python'
        self.highlightlinenothreshold = sys.maxint
        self.language.labels['warning'] = 'Caveat'

    def visit_desc(self, node):
        self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))
    def depart_desc(self, node):
        self.body.append('</dl>\n\n')

    def visit_desc_signature(self, node):
        # the id is set automatically
        self.body.append(self.starttag(node, 'dt'))
        # anchor for per-desc interactive data
        if node.parent['desctype'] != 'describe' and node['ids'] and node['first']:
            self.body.append('<!--#%s#-->' % node['ids'][0])
        if node.parent['desctype'] in ('class', 'exception'):
            self.body.append('%s ' % node.parent['desctype'])
    def depart_desc_signature(self, node):
        if node['ids'] and self.builder.name != 'htmlhelp':
            self.body.append(u'<a class="headerlink" href="#%s" ' % node['ids'][0] +
                             u'title="Permalink to this definition">\u00B6</a>')
        self.body.append('</dt>\n')

    def visit_desc_classname(self, node):
        self.body.append(self.starttag(node, 'tt', '', CLASS='descclassname'))
    def depart_desc_classname(self, node):
        self.body.append('</tt>')

    def visit_desc_type(self, node):
        # return type of C functions -- nothing to do here
        pass
    def depart_desc_type(self, node):
        pass

    def visit_desc_name(self, node):
        self.body.append(self.starttag(node, 'tt', '', CLASS='descname'))
    def depart_desc_name(self, node):
        self.body.append('</tt>')

    def visit_desc_parameterlist(self, node):
        self.body.append('<big>(</big>')
        self.first_param = 1
    def depart_desc_parameterlist(self, node):
        self.body.append('<big>)</big>')

    def visit_desc_parameter(self, node):
        if not self.first_param:
            self.body.append(', ')
        else:
            self.first_param = 0
        if not node.hasattr('noemph'):
            self.body.append('<em>')
    def depart_desc_parameter(self, node):
        if not node.hasattr('noemph'):
            self.body.append('</em>')

    def visit_desc_optional(self, node):
        self.body.append('<span class="optional">[</span>')
    def depart_desc_optional(self, node):
        self.body.append('<span class="optional">]</span>')

    def visit_desc_content(self, node):
        self.body.append(self.starttag(node, 'dd', ''))
    def depart_desc_content(self, node):
        self.body.append('</dd>')

    def visit_refcount(self, node):
        self.body.append(self.starttag(node, 'em', '', CLASS='refcount'))
    def depart_refcount(self, node):
        self.body.append('</em>')

    def visit_versionmodified(self, node):
        self.body.append(self.starttag(node, 'p'))
        text = version_text[node['type']] % node['version']
        if len(node):
            text += ': '
        else:
            text += '.'
        self.body.append('<span class="versionmodified">%s</span>' % text)
    def depart_versionmodified(self, node):
        self.body.append('</p>\n')

    # overwritten
    def visit_reference(self, node):
        BaseTranslator.visit_reference(self, node)
        if node.hasattr('reftitle'):
            # ugly hack to add a title attribute
            starttag = self.body[-1]
            if not starttag.startswith('<a '):
                return
            self.body[-1] = '<a title="%s"' % self.attval(node['reftitle']) + \
                            starttag[2:]

    # overwritten -- we don't want source comments to show up in the HTML
    def visit_comment(self, node):
        raise nodes.SkipNode

    # overwritten
    def visit_admonition(self, node, name=''):
        self.body.append(self.starttag(
            node, 'div', CLASS=('admonition ' + name)))
        if name and name != 'seealso':
            node.insert(0, nodes.title(name, self.language.labels[name]))
        self.set_first_last(node)

    def visit_seealso(self, node):
        self.visit_admonition(node, 'seealso')
    def depart_seealso(self, node):
        self.depart_admonition(node)

    # overwritten (args/kwds due to docutils 0.4/0.5 incompatibility)
    def visit_title(self, node, *args, **kwds):
        # if we have a section we do our own processing in order
        # to have ids in the hN-tags and not in additional a-tags
        if isinstance(node.parent, nodes.section):
            h_level = self.section_level + self.initial_header_level - 1
            if node.parent.get('ids'):
                attrs = {'ids': node.parent['ids']}
            else:
                attrs = {}
            self.body.append(self.starttag(node, 'h%d' % h_level, '', **attrs))
            self.context.append('</h%d>\n' % h_level)
        else:
            BaseTranslator.visit_title(self, node, *args, **kwds)

    # overwritten
    def visit_literal_block(self, node):
        if node.rawsource != node.astext():
            # most probably a parsed-literal block -- don't highlight
            return BaseTranslator.visit_literal_block(self, node)
        lang = self.highlightlang
        linenos = node.rawsource.count('\n') >= self.highlightlinenothreshold - 1
        if node.has_key('language'):
            # code-block directives
            lang = node['language']
        if node.has_key('linenos'):
            linenos = node['linenos']
        self.body.append(self.highlighter.highlight_block(node.rawsource,
                                                          lang, linenos))
        raise nodes.SkipNode

    def visit_doctest_block(self, node):
        self.visit_literal_block(node)

    # overwritten
    def visit_literal(self, node):
        if len(node.children) == 1 and \
               node.children[0] in ('None', 'True', 'False'):
            node['classes'].append('xref')
        BaseTranslator.visit_literal(self, node)

    def visit_productionlist(self, node):
        self.body.append(self.starttag(node, 'pre'))
        names = []
        for production in node:
            names.append(production['tokenname'])
        maxlen = max(len(name) for name in names)
        for production in node:
            if production['tokenname']:
                self.body.append(self.starttag(production, 'strong', ''))
                self.body.append(production['tokenname'].ljust(maxlen) +
                                 '</strong> ::= ')
                lastname = production['tokenname']
            else:
                self.body.append('%s     ' % (' '*len(lastname)))
            production.walkabout(self)
            self.body.append('\n')
        self.body.append('</pre>\n')
        raise nodes.SkipNode
    def depart_productionlist(self, node):
        pass

    def visit_production(self, node):
        pass
    def depart_production(self, node):
        pass

    def visit_centered(self, node):
        self.body.append(self.starttag(node, 'p', CLASS="centered") + '<strong>')
    def depart_centered(self, node):
        self.body.append('</strong></p>')

    def visit_compact_paragraph(self, node):
        pass
    def depart_compact_paragraph(self, node):
        pass

    def visit_highlightlang(self, node):
        self.highlightlang = node['lang']
        self.highlightlinenothreshold = node['linenothreshold']
    def depart_highlightlang(self, node):
        pass

    # overwritten
    def visit_image(self, node):
        olduri = node['uri']
        # rewrite the URI if the environment knows about it
        if olduri in self.builder.env.images:
            node['uri'] = posixpath.join(self.builder.imgpath,
                                         self.builder.env.images[olduri][1])
        BaseTranslator.visit_image(self, node)

    def visit_toctree(self, node):
        # this only happens when formatting a toc from env.tocs -- in this
        # case we don't want to include the subtree
        raise nodes.SkipNode

    def visit_index(self, node):
        raise nodes.SkipNode

    def visit_tabular_col_spec(self, node):
        raise nodes.SkipNode

    def visit_glossary(self, node):
        pass
    def depart_glossary(self, node):
        pass

    def visit_acks(self, node):
        pass
    def depart_acks(self, node):
        pass

    def visit_module(self, node):
        pass
    def depart_module(self, node):
        pass

    # docutils 0.5 compatibility
    def visit_note(self, node):
        self.visit_admonition(node, 'note')
    def depart_note(self, node):
        self.depart_admonition(node)

    # docutils 0.5 compatibility
    def visit_warning(self, node):
        self.visit_admonition(node, 'warning')
    def depart_warning(self, node):
        self.depart_admonition(node)

    # these are only handled specially in the SmartyPantsHTMLTranslator
    def visit_literal_emphasis(self, node):
        return self.visit_emphasis(node)
    def depart_literal_emphasis(self, node):
        return self.depart_emphasis(node)

    def depart_title(self, node):
        close_tag = self.context[-1]
        if self.builder.name != 'htmlhelp' and \
               (close_tag.startswith('</h') or
                close_tag.startswith('</a></h')) and \
               node.parent.hasattr('ids') and node.parent['ids']:
            aname = node.parent['ids'][0]
            # add permalink anchor
            self.body.append(u'<a class="headerlink" href="#%s" ' % aname +
                             u'title="Permalink to this headline">\u00B6</a>')
        BaseTranslator.depart_title(self, node)
Beispiel #16
0
def test_lexer_options():
    bridge = PygmentsBridge('html')
    ret = bridge.highlight_block('//comment',
                                 'php',
                                 opts={'startinline': True})
    assert '<span class="c1">//comment</span>' in ret
Beispiel #17
0
def test_add_lexer(app, status, warning):
    app.add_lexer('test', MyLexer())

    bridge = PygmentsBridge('html')
    ret = bridge.highlight_block('ab', 'test')
    assert '<span class="n">a</span>b' in ret
Beispiel #18
0
class HTMLTranslator(BaseTranslator):
    """
    Our custom HTML translator.
    """

    def __init__(self, builder, *args, **kwds):
        BaseTranslator.__init__(self, *args, **kwds)
        self.highlighter = PygmentsBridge('html', builder.config.pygments_style)
        self.no_smarty = 0
        self.builder = builder
        self.highlightlang = 'python'
        self.highlightlinenothreshold = sys.maxint
        self.protect_literal_text = 0

    def visit_desc(self, node):
        self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))
    def depart_desc(self, node):
        self.body.append('</dl>\n\n')

    def visit_desc_signature(self, node):
        # the id is set automatically
        self.body.append(self.starttag(node, 'dt'))
        # anchor for per-desc interactive data
        if node.parent['desctype'] != 'describe' and node['ids'] and node['first']:
            self.body.append('<!--[%s]-->' % node['ids'][0])
        if node.parent['desctype'] in ('class', 'exception'):
            self.body.append('%s ' % node.parent['desctype'])
    def depart_desc_signature(self, node):
        if node['ids'] and self.builder.name != 'htmlhelp':
            self.body.append(u'<a class="headerlink" href="#%s" ' % node['ids'][0] +
                             u'title="Permalink to this definition">\u00B6</a>')
        self.body.append('</dt>\n')

    def visit_desc_addname(self, node):
        self.body.append(self.starttag(node, 'tt', '', CLASS='descclassname'))
    def depart_desc_addname(self, node):
        self.body.append('</tt>')

    def visit_desc_type(self, node):
        pass
    def depart_desc_type(self, node):
        pass

    def visit_desc_name(self, node):
        self.body.append(self.starttag(node, 'tt', '', CLASS='descname'))
    def depart_desc_name(self, node):
        self.body.append('</tt>')

    def visit_desc_parameterlist(self, node):
        self.body.append('<big>(</big>')
        self.first_param = 1
    def depart_desc_parameterlist(self, node):
        self.body.append('<big>)</big>')

    def visit_desc_parameter(self, node):
        if not self.first_param:
            self.body.append(', ')
        else:
            self.first_param = 0
        if not node.hasattr('noemph'):
            self.body.append('<em>')
    def depart_desc_parameter(self, node):
        if not node.hasattr('noemph'):
            self.body.append('</em>')

    def visit_desc_optional(self, node):
        self.body.append('<span class="optional">[</span>')
    def depart_desc_optional(self, node):
        self.body.append('<span class="optional">]</span>')

    def visit_desc_annotation(self, node):
        self.body.append(self.starttag(node, 'em', CLASS='property'))
    def depart_desc_annotation(self, node):
        self.body.append('</em>')

    def visit_desc_content(self, node):
        self.body.append(self.starttag(node, 'dd', ''))
    def depart_desc_content(self, node):
        self.body.append('</dd>')

    def visit_refcount(self, node):
        self.body.append(self.starttag(node, 'em', '', CLASS='refcount'))
    def depart_refcount(self, node):
        self.body.append('</em>')

    def visit_versionmodified(self, node):
        self.body.append(self.starttag(node, 'p'))
        text = version_text[node['type']] % node['version']
        if len(node):
            text += ': '
        else:
            text += '.'
        self.body.append('<span class="versionmodified">%s</span>' % text)
    def depart_versionmodified(self, node):
        self.body.append('</p>\n')

    # overwritten
    def visit_reference(self, node):
        BaseTranslator.visit_reference(self, node)
        if node.hasattr('reftitle'):
            # ugly hack to add a title attribute
            starttag = self.body[-1]
            if not starttag.startswith('<a '):
                return
            self.body[-1] = '<a title="%s"' % self.attval(node['reftitle']) + \
                            starttag[2:]

    # overwritten -- we don't want source comments to show up in the HTML
    def visit_comment(self, node):
        raise nodes.SkipNode

    # overwritten
    def visit_admonition(self, node, name=''):
        self.body.append(self.starttag(
            node, 'div', CLASS=('admonition ' + name)))
        if name and name != 'seealso':
            node.insert(0, nodes.title(name, self.language.labels[name]))
        self.set_first_last(node)

    def visit_seealso(self, node):
        self.visit_admonition(node, 'seealso')
    def depart_seealso(self, node):
        self.depart_admonition(node)

    # overwritten for docutils 0.4
    if hasattr(BaseTranslator, 'start_tag_with_title'):
        def visit_section(self, node):
            # the 0.5 version, to get the id attribute in the <div> tag
            self.section_level += 1
            self.body.append(self.starttag(node, 'div', CLASS='section'))

        def visit_title(self, node):
            # don't move the id attribute inside the <h> tag
            BaseTranslator.visit_title(self, node, move_ids=0)

    # overwritten
    def visit_literal_block(self, node):
        if node.rawsource != node.astext():
            # most probably a parsed-literal block -- don't highlight
            return BaseTranslator.visit_literal_block(self, node)
        lang = self.highlightlang
        linenos = node.rawsource.count('\n') >= self.highlightlinenothreshold - 1
        if node.has_key('language'):
            # code-block directives
            lang = node['language']
        if node.has_key('linenos'):
            linenos = node['linenos']
        self.body.append(self.highlighter.highlight_block(node.rawsource,
                                                          lang, linenos))
        raise nodes.SkipNode

    def visit_doctest_block(self, node):
        self.visit_literal_block(node)

    # overwritten
    def visit_literal(self, node):
        if len(node.children) == 1 and \
               node.children[0] in ('None', 'True', 'False'):
            node['classes'].append('xref')
        self.body.append(self.starttag(node, 'tt', '', CLASS='docutils literal'))
        self.protect_literal_text += 1
    def depart_literal(self, node):
        self.protect_literal_text -= 1
        self.body.append('</tt>')

    def visit_productionlist(self, node):
        self.body.append(self.starttag(node, 'pre'))
        names = []
        for production in node:
            names.append(production['tokenname'])
        maxlen = max(len(name) for name in names)
        for production in node:
            if production['tokenname']:
                lastname = production['tokenname'].ljust(maxlen)
                self.body.append(self.starttag(production, 'strong', ''))
                self.body.append(lastname + '</strong> ::= ')
            else:
                self.body.append('%s     ' % (' '*len(lastname)))
            production.walkabout(self)
            self.body.append('\n')
        self.body.append('</pre>\n')
        raise nodes.SkipNode
    def depart_productionlist(self, node):
        pass

    def visit_production(self, node):
        pass
    def depart_production(self, node):
        pass

    def visit_centered(self, node):
        self.body.append(self.starttag(node, 'p', CLASS="centered") + '<strong>')
    def depart_centered(self, node):
        self.body.append('</strong></p>')

    def visit_compact_paragraph(self, node):
        pass
    def depart_compact_paragraph(self, node):
        pass

    def visit_highlightlang(self, node):
        self.highlightlang = node['lang']
        self.highlightlinenothreshold = node['linenothreshold']
    def depart_highlightlang(self, node):
        pass

    # overwritten
    def visit_image(self, node):
        olduri = node['uri']
        # rewrite the URI if the environment knows about it
        if olduri in self.builder.images:
            node['uri'] = posixpath.join(self.builder.imgpath,
                                         self.builder.images[olduri])
        BaseTranslator.visit_image(self, node)

    def visit_toctree(self, node):
        # this only happens when formatting a toc from env.tocs -- in this
        # case we don't want to include the subtree
        raise nodes.SkipNode

    def visit_index(self, node):
        raise nodes.SkipNode

    def visit_tabular_col_spec(self, node):
        raise nodes.SkipNode

    def visit_glossary(self, node):
        pass
    def depart_glossary(self, node):
        pass

    def visit_acks(self, node):
        pass
    def depart_acks(self, node):
        pass

    def visit_module(self, node):
        pass
    def depart_module(self, node):
        pass

    def bulk_text_processor(self, text):
        return text

    # overwritten
    def visit_Text(self, node):
        text = node.astext()
        encoded = self.encode(text)
        if self.protect_literal_text:
            # moved here from base class's visit_literal to support
            # more formatting in literal nodes
            for token in self.words_and_spaces.findall(encoded):
                if token.strip():
                    # protect literal text from line wrapping
                    self.body.append('<span class="pre">%s</span>' % token)
                elif token in ' \n':
                    # allow breaks at whitespace
                    self.body.append(token)
                else:
                    # protect runs of multiple spaces; the last one can wrap
                    self.body.append('&nbsp;' * (len(token)-1) + ' ')
        else:
            if self.in_mailto and self.settings.cloak_email_addresses:
                encoded = self.cloak_email(encoded)
            else:
                encoded = self.bulk_text_processor(encoded)
            self.body.append(encoded)

    # these are all for docutils 0.5 compatibility

    def visit_note(self, node):
        self.visit_admonition(node, 'note')
    def depart_note(self, node):
        self.depart_admonition(node)

    def visit_warning(self, node):
        self.visit_admonition(node, 'warning')
    def depart_warning(self, node):
        self.depart_admonition(node)

    def visit_attention(self, node):
        self.visit_admonition(node, 'attention')

    def depart_attention(self, node):
        self.depart_admonition()

    def visit_caution(self, node):
        self.visit_admonition(node, 'caution')
    def depart_caution(self, node):
        self.depart_admonition()

    def visit_danger(self, node):
        self.visit_admonition(node, 'danger')
    def depart_danger(self, node):
        self.depart_admonition()

    def visit_error(self, node):
        self.visit_admonition(node, 'error')
    def depart_error(self, node):
        self.depart_admonition()

    def visit_hint(self, node):
        self.visit_admonition(node, 'hint')
    def depart_hint(self, node):
        self.depart_admonition()

    def visit_important(self, node):
        self.visit_admonition(node, 'important')
    def depart_important(self, node):
        self.depart_admonition()

    def visit_tip(self, node):
        self.visit_admonition(node, 'tip')
    def depart_tip(self, node):
        self.depart_admonition()

    # these are only handled specially in the SmartyPantsHTMLTranslator
    def visit_literal_emphasis(self, node):
        return self.visit_emphasis(node)
    def depart_literal_emphasis(self, node):
        return self.depart_emphasis(node)

    def depart_title(self, node):
        close_tag = self.context[-1]
        if self.builder.name != 'htmlhelp' and \
               (close_tag.startswith('</h') or
                close_tag.startswith('</a></h')) and \
               node.parent.hasattr('ids') and node.parent['ids']:
            aname = node.parent['ids'][0]
            # add permalink anchor
            self.body.append(u'<a class="headerlink" href="#%s" ' % aname +
                             u'title="Permalink to this headline">\u00B6</a>')
        BaseTranslator.depart_title(self, node)

    def unknown_visit(self, node):
        raise NotImplementedError("Unknown node: " + node.__class__.__name__)
Beispiel #19
0
def test_lexer_options():
    bridge = PygmentsBridge('html')
    ret = bridge.highlight_block('//comment', 'php', opts={'startinline': True})
    assert '<span class="c1">//comment</span>' in ret
Beispiel #20
0
class HTMLTranslator(BaseTranslator):
    """
    Our custom HTML translator.
    """
    def __init__(self, builder, *args, **kwds):
        BaseTranslator.__init__(self, *args, **kwds)
        self.highlighter = PygmentsBridge('html',
                                          builder.config.pygments_style)
        self.no_smarty = 0
        self.builder = builder
        self.highlightlang = 'python'
        self.highlightlinenothreshold = sys.maxint

    def visit_desc(self, node):
        self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))

    def depart_desc(self, node):
        self.body.append('</dl>\n\n')

    def visit_desc_signature(self, node):
        # the id is set automatically
        self.body.append(self.starttag(node, 'dt'))
        # anchor for per-desc interactive data
        if node.parent['desctype'] != 'describe' and node['ids'] and node[
                'first']:
            self.body.append('<!--[%s]-->' % node['ids'][0])
        if node.parent['desctype'] in ('class', 'exception'):
            self.body.append('%s ' % node.parent['desctype'])

    def depart_desc_signature(self, node):
        if node['ids'] and self.builder.name != 'htmlhelp':
            self.body.append(
                u'<a class="headerlink" href="#%s" ' % node['ids'][0] +
                u'title="Permalink to this definition">\u00B6</a>')
        self.body.append('</dt>\n')

    def visit_desc_addname(self, node):
        self.body.append(self.starttag(node, 'tt', '', CLASS='descclassname'))

    def depart_desc_addname(self, node):
        self.body.append('</tt>')

    def visit_desc_type(self, node):
        pass

    def depart_desc_type(self, node):
        pass

    def visit_desc_name(self, node):
        self.body.append(self.starttag(node, 'tt', '', CLASS='descname'))

    def depart_desc_name(self, node):
        self.body.append('</tt>')

    def visit_desc_parameterlist(self, node):
        self.body.append('<big>(</big>')
        self.first_param = 1

    def depart_desc_parameterlist(self, node):
        self.body.append('<big>)</big>')

    def visit_desc_parameter(self, node):
        if not self.first_param:
            self.body.append(', ')
        else:
            self.first_param = 0
        if not node.hasattr('noemph'):
            self.body.append('<em>')

    def depart_desc_parameter(self, node):
        if not node.hasattr('noemph'):
            self.body.append('</em>')

    def visit_desc_optional(self, node):
        self.body.append('<span class="optional">[</span>')

    def depart_desc_optional(self, node):
        self.body.append('<span class="optional">]</span>')

    def visit_desc_annotation(self, node):
        self.body.append(self.starttag(node, 'em', CLASS='property'))

    def depart_desc_annotation(self, node):
        self.body.append('</em>')

    def visit_desc_content(self, node):
        self.body.append(self.starttag(node, 'dd', ''))

    def depart_desc_content(self, node):
        self.body.append('</dd>')

    def visit_refcount(self, node):
        self.body.append(self.starttag(node, 'em', '', CLASS='refcount'))

    def depart_refcount(self, node):
        self.body.append('</em>')

    def visit_versionmodified(self, node):
        self.body.append(self.starttag(node, 'p'))
        text = version_text[node['type']] % node['version']
        if len(node):
            text += ': '
        else:
            text += '.'
        self.body.append('<span class="versionmodified">%s</span>' % text)

    def depart_versionmodified(self, node):
        self.body.append('</p>\n')

    # overwritten
    def visit_reference(self, node):
        BaseTranslator.visit_reference(self, node)
        if node.hasattr('reftitle'):
            # ugly hack to add a title attribute
            starttag = self.body[-1]
            if not starttag.startswith('<a '):
                return
            self.body[-1] = '<a title="%s"' % self.attval(node['reftitle']) + \
                            starttag[2:]

    # overwritten -- we don't want source comments to show up in the HTML
    def visit_comment(self, node):
        raise nodes.SkipNode

    # overwritten
    def visit_admonition(self, node, name=''):
        self.body.append(
            self.starttag(node, 'div', CLASS=('admonition ' + name)))
        if name and name != 'seealso':
            node.insert(0, nodes.title(name, self.language.labels[name]))
        self.set_first_last(node)

    def visit_seealso(self, node):
        self.visit_admonition(node, 'seealso')

    def depart_seealso(self, node):
        self.depart_admonition(node)

    # overwritten (args/kwds due to docutils 0.4/0.5 incompatibility)
    def visit_title(self, node, *args, **kwds):
        # if we have a section we do our own processing in order
        # to have ids in the hN-tags and not in additional a-tags
        if isinstance(node.parent, nodes.section):
            h_level = self.section_level + self.initial_header_level - 1
            if node.parent.get('ids'):
                attrs = {'ids': node.parent['ids']}
            else:
                attrs = {}
            self.body.append(self.starttag(node, 'h%d' % h_level, '', **attrs))
            self.context.append('</h%d>\n' % h_level)
        else:
            BaseTranslator.visit_title(self, node, *args, **kwds)

    # overwritten
    def visit_literal_block(self, node):
        if node.rawsource != node.astext():
            # most probably a parsed-literal block -- don't highlight
            return BaseTranslator.visit_literal_block(self, node)
        lang = self.highlightlang
        linenos = node.rawsource.count(
            '\n') >= self.highlightlinenothreshold - 1
        if node.has_key('language'):
            # code-block directives
            lang = node['language']
        if node.has_key('linenos'):
            linenos = node['linenos']
        self.body.append(
            self.highlighter.highlight_block(node.rawsource, lang, linenos))
        raise nodes.SkipNode

    def visit_doctest_block(self, node):
        self.visit_literal_block(node)

    # overwritten
    def visit_literal(self, node):
        if len(node.children) == 1 and \
               node.children[0] in ('None', 'True', 'False'):
            node['classes'].append('xref')
        BaseTranslator.visit_literal(self, node)

    def visit_productionlist(self, node):
        self.body.append(self.starttag(node, 'pre'))
        names = []
        for production in node:
            names.append(production['tokenname'])
        maxlen = max(len(name) for name in names)
        for production in node:
            if production['tokenname']:
                self.body.append(self.starttag(production, 'strong', ''))
                self.body.append(production['tokenname'].ljust(maxlen) +
                                 '</strong> ::= ')
                lastname = production['tokenname']
            else:
                self.body.append('%s     ' % (' ' * len(lastname)))
            production.walkabout(self)
            self.body.append('\n')
        self.body.append('</pre>\n')
        raise nodes.SkipNode

    def depart_productionlist(self, node):
        pass

    def visit_production(self, node):
        pass

    def depart_production(self, node):
        pass

    def visit_centered(self, node):
        self.body.append(
            self.starttag(node, 'p', CLASS="centered") + '<strong>')

    def depart_centered(self, node):
        self.body.append('</strong></p>')

    def visit_compact_paragraph(self, node):
        pass

    def depart_compact_paragraph(self, node):
        pass

    def visit_highlightlang(self, node):
        self.highlightlang = node['lang']
        self.highlightlinenothreshold = node['linenothreshold']

    def depart_highlightlang(self, node):
        pass

    # overwritten
    def visit_image(self, node):
        olduri = node['uri']
        # rewrite the URI if the environment knows about it
        if olduri in self.builder.images:
            node['uri'] = posixpath.join(self.builder.imgpath,
                                         self.builder.images[olduri])
        BaseTranslator.visit_image(self, node)

    def visit_toctree(self, node):
        # this only happens when formatting a toc from env.tocs -- in this
        # case we don't want to include the subtree
        raise nodes.SkipNode

    def visit_index(self, node):
        raise nodes.SkipNode

    def visit_tabular_col_spec(self, node):
        raise nodes.SkipNode

    def visit_glossary(self, node):
        pass

    def depart_glossary(self, node):
        pass

    def visit_acks(self, node):
        pass

    def depart_acks(self, node):
        pass

    def visit_module(self, node):
        pass

    def depart_module(self, node):
        pass

    # docutils 0.5 compatibility
    def visit_note(self, node):
        self.visit_admonition(node, 'note')

    def depart_note(self, node):
        self.depart_admonition(node)

    # docutils 0.5 compatibility
    def visit_warning(self, node):
        self.visit_admonition(node, 'warning')

    def depart_warning(self, node):
        self.depart_admonition(node)

    # these are only handled specially in the SmartyPantsHTMLTranslator
    def visit_literal_emphasis(self, node):
        return self.visit_emphasis(node)

    def depart_literal_emphasis(self, node):
        return self.depart_emphasis(node)

    def depart_title(self, node):
        close_tag = self.context[-1]
        if self.builder.name != 'htmlhelp' and \
               (close_tag.startswith('</h') or
                close_tag.startswith('</a></h')) and \
               node.parent.hasattr('ids') and node.parent['ids']:
            aname = node.parent['ids'][0]
            # add permalink anchor
            self.body.append(u'<a class="headerlink" href="#%s" ' % aname +
                             u'title="Permalink to this headline">\u00B6</a>')
        BaseTranslator.depart_title(self, node)

    def unknown_visit(self, node):
        raise NotImplementedError("Unknown node: " + node.__class__.__name__)
Beispiel #21
0
class HTMLTranslator(BaseTranslator):
    """
    Our custom HTML translator.
    """

    def __init__(self, builder, *args, **kwds):
        BaseTranslator.__init__(self, *args, **kwds)
        self.highlighter = PygmentsBridge("html", builder.config.pygments_style)
        self.no_smarty = 0
        self.builder = builder
        self.highlightlang = builder.config.highlight_language
        self.highlightlinenothreshold = sys.maxint
        self.protect_literal_text = 0

    def visit_desc(self, node):
        self.body.append(self.starttag(node, "dl", CLASS=node["desctype"]))

    def depart_desc(self, node):
        self.body.append("</dl>\n\n")

    def visit_desc_signature(self, node):
        # the id is set automatically
        self.body.append(self.starttag(node, "dt"))
        # anchor for per-desc interactive data
        if node.parent["desctype"] != "describe" and node["ids"] and node["first"]:
            self.body.append("<!--[%s]-->" % node["ids"][0])
        if node.parent["desctype"] in ("class", "exception"):
            self.body.append("%s " % node.parent["desctype"])

    def depart_desc_signature(self, node):
        if node["ids"] and self.builder.add_definition_links:
            self.body.append(
                u'<a class="headerlink" href="#%s" ' % node["ids"][0]
                + u'title="%s">\u00B6</a>' % _("Permalink to this definition")
            )
        self.body.append("</dt>\n")

    def visit_desc_addname(self, node):
        self.body.append(self.starttag(node, "tt", "", CLASS="descclassname"))

    def depart_desc_addname(self, node):
        self.body.append("</tt>")

    def visit_desc_type(self, node):
        pass

    def depart_desc_type(self, node):
        pass

    def visit_desc_name(self, node):
        self.body.append(self.starttag(node, "tt", "", CLASS="descname"))

    def depart_desc_name(self, node):
        self.body.append("</tt>")

    def visit_desc_parameterlist(self, node):
        self.body.append("<big>(</big>")
        self.first_param = 1

    def depart_desc_parameterlist(self, node):
        self.body.append("<big>)</big>")

    def visit_desc_parameter(self, node):
        if not self.first_param:
            self.body.append(", ")
        else:
            self.first_param = 0
        if not node.hasattr("noemph"):
            self.body.append("<em>")

    def depart_desc_parameter(self, node):
        if not node.hasattr("noemph"):
            self.body.append("</em>")

    def visit_desc_optional(self, node):
        self.body.append('<span class="optional">[</span>')

    def depart_desc_optional(self, node):
        self.body.append('<span class="optional">]</span>')

    def visit_desc_annotation(self, node):
        self.body.append(self.starttag(node, "em", CLASS="property"))

    def depart_desc_annotation(self, node):
        self.body.append("</em>")

    def visit_desc_content(self, node):
        self.body.append(self.starttag(node, "dd", ""))

    def depart_desc_content(self, node):
        self.body.append("</dd>")

    def visit_refcount(self, node):
        self.body.append(self.starttag(node, "em", "", CLASS="refcount"))

    def depart_refcount(self, node):
        self.body.append("</em>")

    def visit_versionmodified(self, node):
        self.body.append(self.starttag(node, "p"))
        text = versionlabels[node["type"]] % node["version"]
        if len(node):
            text += ": "
        else:
            text += "."
        self.body.append('<span class="versionmodified">%s</span>' % text)

    def depart_versionmodified(self, node):
        self.body.append("</p>\n")

    # overwritten
    def visit_reference(self, node):
        BaseTranslator.visit_reference(self, node)
        if node.hasattr("reftitle"):
            # ugly hack to add a title attribute
            starttag = self.body[-1]
            if not starttag.startswith("<a "):
                return
            self.body[-1] = '<a title="%s"' % self.attval(node["reftitle"]) + starttag[2:]

    # overwritten -- we don't want source comments to show up in the HTML
    def visit_comment(self, node):
        raise nodes.SkipNode

    # overwritten
    def visit_admonition(self, node, name=""):
        self.body.append(self.starttag(node, "div", CLASS=("admonition " + name)))
        if name and name != "seealso":
            node.insert(0, nodes.title(name, admonitionlabels[name]))
        self.set_first_last(node)

    def visit_seealso(self, node):
        self.visit_admonition(node, "seealso")

    def depart_seealso(self, node):
        self.depart_admonition(node)

    # overwritten for docutils 0.4
    if hasattr(BaseTranslator, "start_tag_with_title"):

        def visit_section(self, node):
            # the 0.5 version, to get the id attribute in the <div> tag
            self.section_level += 1
            self.body.append(self.starttag(node, "div", CLASS="section"))

        def visit_title(self, node):
            # don't move the id attribute inside the <h> tag
            BaseTranslator.visit_title(self, node, move_ids=0)

    # overwritten
    def visit_literal_block(self, node):
        if node.rawsource != node.astext():
            # most probably a parsed-literal block -- don't highlight
            return BaseTranslator.visit_literal_block(self, node)
        lang = self.highlightlang
        linenos = node.rawsource.count("\n") >= self.highlightlinenothreshold - 1
        if node.has_key("language"):
            # code-block directives
            lang = node["language"]
        if node.has_key("linenos"):
            linenos = node["linenos"]
        highlighted = self.highlighter.highlight_block(node.rawsource, lang, linenos)
        starttag = self.starttag(node, "div", suffix="", CLASS="highlight-%s" % lang)
        self.body.append(starttag + highlighted + "</div>\n")
        raise nodes.SkipNode

    def visit_doctest_block(self, node):
        self.visit_literal_block(node)

    # overwritten
    def visit_literal(self, node):
        if len(node.children) == 1 and node.children[0] in ("None", "True", "False"):
            node["classes"].append("xref")
        self.body.append(self.starttag(node, "tt", "", CLASS="docutils literal"))
        self.protect_literal_text += 1

    def depart_literal(self, node):
        self.protect_literal_text -= 1
        self.body.append("</tt>")

    def visit_productionlist(self, node):
        self.body.append(self.starttag(node, "pre"))
        names = []
        for production in node:
            names.append(production["tokenname"])
        maxlen = max(len(name) for name in names)
        for production in node:
            if production["tokenname"]:
                lastname = production["tokenname"].ljust(maxlen)
                self.body.append(self.starttag(production, "strong", ""))
                self.body.append(lastname + "</strong> ::= ")
            else:
                self.body.append("%s     " % (" " * len(lastname)))
            production.walkabout(self)
            self.body.append("\n")
        self.body.append("</pre>\n")
        raise nodes.SkipNode

    def depart_productionlist(self, node):
        pass

    def visit_production(self, node):
        pass

    def depart_production(self, node):
        pass

    def visit_centered(self, node):
        self.body.append(self.starttag(node, "p", CLASS="centered") + "<strong>")

    def depart_centered(self, node):
        self.body.append("</strong></p>")

    def visit_compact_paragraph(self, node):
        pass

    def depart_compact_paragraph(self, node):
        pass

    def visit_highlightlang(self, node):
        self.highlightlang = node["lang"]
        self.highlightlinenothreshold = node["linenothreshold"]

    def depart_highlightlang(self, node):
        pass

    # overwritten
    def visit_image(self, node):
        olduri = node["uri"]
        # rewrite the URI if the environment knows about it
        if olduri in self.builder.images:
            node["uri"] = posixpath.join(self.builder.imgpath, self.builder.images[olduri])

        if node.has_key("scale"):
            if Image and not (node.has_key("width") and node.has_key("height")):
                try:
                    im = Image.open(os.path.join(self.builder.srcdir, olduri))
                except (
                    IOError,  # Source image can't be found or opened
                    UnicodeError,
                ):  # PIL doesn't like Unicode paths.
                    print olduri
                    pass
                else:
                    if not node.has_key("width"):
                        node["width"] = str(im.size[0])
                    if not node.has_key("height"):
                        node["height"] = str(im.size[1])
                    del im
        BaseTranslator.visit_image(self, node)

    def visit_toctree(self, node):
        # this only happens when formatting a toc from env.tocs -- in this
        # case we don't want to include the subtree
        raise nodes.SkipNode

    def visit_index(self, node):
        raise nodes.SkipNode

    def visit_tabular_col_spec(self, node):
        raise nodes.SkipNode

    def visit_glossary(self, node):
        pass

    def depart_glossary(self, node):
        pass

    def visit_acks(self, node):
        pass

    def depart_acks(self, node):
        pass

    def visit_module(self, node):
        pass

    def depart_module(self, node):
        pass

    def bulk_text_processor(self, text):
        return text

    # overwritten
    def visit_Text(self, node):
        text = node.astext()
        encoded = self.encode(text)
        if self.protect_literal_text:
            # moved here from base class's visit_literal to support
            # more formatting in literal nodes
            for token in self.words_and_spaces.findall(encoded):
                if token.strip():
                    # protect literal text from line wrapping
                    self.body.append('<span class="pre">%s</span>' % token)
                elif token in " \n":
                    # allow breaks at whitespace
                    self.body.append(token)
                else:
                    # protect runs of multiple spaces; the last one can wrap
                    self.body.append("&nbsp;" * (len(token) - 1) + " ")
        else:
            if self.in_mailto and self.settings.cloak_email_addresses:
                encoded = self.cloak_email(encoded)
            else:
                encoded = self.bulk_text_processor(encoded)
            self.body.append(encoded)

    # these are all for docutils 0.5 compatibility

    def visit_note(self, node):
        self.visit_admonition(node, "note")

    def depart_note(self, node):
        self.depart_admonition(node)

    def visit_warning(self, node):
        self.visit_admonition(node, "warning")

    def depart_warning(self, node):
        self.depart_admonition(node)

    def visit_attention(self, node):
        self.visit_admonition(node, "attention")

    def depart_attention(self, node):
        self.depart_admonition()

    def visit_caution(self, node):
        self.visit_admonition(node, "caution")

    def depart_caution(self, node):
        self.depart_admonition()

    def visit_danger(self, node):
        self.visit_admonition(node, "danger")

    def depart_danger(self, node):
        self.depart_admonition()

    def visit_error(self, node):
        self.visit_admonition(node, "error")

    def depart_error(self, node):
        self.depart_admonition()

    def visit_hint(self, node):
        self.visit_admonition(node, "hint")

    def depart_hint(self, node):
        self.depart_admonition()

    def visit_important(self, node):
        self.visit_admonition(node, "important")

    def depart_important(self, node):
        self.depart_admonition()

    def visit_tip(self, node):
        self.visit_admonition(node, "tip")

    def depart_tip(self, node):
        self.depart_admonition()

    # these are only handled specially in the SmartyPantsHTMLTranslator
    def visit_literal_emphasis(self, node):
        return self.visit_emphasis(node)

    def depart_literal_emphasis(self, node):
        return self.depart_emphasis(node)

    def depart_title(self, node):
        close_tag = self.context[-1]
        if (
            self.builder.add_header_links
            and (close_tag.startswith("</h") or close_tag.startswith("</a></h"))
            and node.parent.hasattr("ids")
            and node.parent["ids"]
        ):
            aname = node.parent["ids"][0]
            # add permalink anchor
            self.body.append(
                u'<a class="headerlink" href="#%s" ' % aname
                + u'title="%s">\u00B6</a>' % _("Permalink to this headline")
            )
        BaseTranslator.depart_title(self, node)

    def unknown_visit(self, node):
        raise NotImplementedError("Unknown node: " + node.__class__.__name__)