Sphinx内联代码高亮

21

我使用Sphinx制作包含代码示例的网站。 我成功地使用.. code-block 指令来获得语法高亮。 但是,我无法使用以下代码实现内联语法高亮:

.. role:: bash(code)
   :language: bash

Test inline: :bash:`export FOO="bar"`.

.. code-block:: bash

    export FOO="bar"

这会产生如下输出,即内联代码未被突出显示,而代码块被突出显示:

result

对我来说,问题在于生成的内联代码的 HTML 包含了很长的类名,而代码块则没有。以下是输出的 HTML(为了可读性进行了缩进):

<p>Test inline:
    <tt class="code bash docutils literal">
        <span class="name builtin">
            <span class="pre">export</span>
        </span>
        <span class="name variable">
            <span class="pre">FOO</span>
        </span>
        <span class="operator">
            <span class="pre">=</span>
        </span>
        <span class="literal string double">
            <span class="pre">&quot;bar&quot;</span>
        </span>
    </tt>.
</p>


<p>Test code-block:</p>
<div class="highlight-bash">
    <div class="highlight">
        <pre>
            <span class="nb">export </span>
            <span class="nv">FOO</span>
            <span class="o">=</span>
            <span class="s2">&quot;bar&quot;</span>
        </pre>
    </div>
</div>
任何帮助将不胜感激。

1
如果我是你,我也会添加 [tag:pygments] 标签。 - Adobe
6个回答

19

syntax_highlight是docutils的一个普通设置,可以在docutils.conf中进行设置。如果将此文件放置在Sphinx的配置目录(即conf.py所在的位置),Sphinx也会尊重该文件。

[restructuredtext parser]
syntax_highlight = short

这比修补docutilssphinx代码或创建一个很长的命名CSS文件要好得多。


这应该是被接受的答案,迄今为止最干净的解决方案。 - Brian
1
这解决了类名的问题,但是高亮效果只有在我在 .. role 指令上也加上 :class: highlight 选项时才能生效,就像 Adobe 的回答中所示。 - goodmami

5

我找到了一个更好的(仅适用于sphinx)解决方案:在sphinx/builders/html.py中找到一行代码。

from docutils.core import Publisher

并将其更改为:

from docutils.core import Publisher
def process_programmatic_settings(self, settings_spec,
                                  settings_overrides,
                                  config_section):
    if self.settings is None:
        defaults = (settings_overrides or {}).copy()
        # Propagate exceptions by default when used programmatically:
        defaults.setdefault('traceback', True)
        defaults.setdefault('syntax_highlight', 'short') # ADDED THIS LINE
        self.get_settings(settings_spec=settings_spec,
                          config_section=config_section,
                          **defaults)
Publisher.process_programmatic_settings = process_programmatic_settings

这个解决方案比之前的更好:它不会使CSS规则数量增加一倍,也不会修改文档工具。但是,理想的解决方案应该只改变conf.py。因此,还有很大的改进空间。

docutils的解决方案很好,文档也相当完善。但据我所知,它不能轻松地应用于sphinx。因此,如果我理解正确的话,与sphinx兼容的解决方案仍将意味着双倍数量的css。 - user378147
@binoua:您是什么意思?我发布的三个答案都可以解决Sphinx的问题。其中一个通过提供“pygments.css”来解决,另一个修改了docutils的默认选项,最后一个修改了Sphinx。 - Adobe
感谢您的回答。 pygments.css 方法基本上是我想到的解决方案,即提供一个包含短名称和长名称的 CSS。如果我错了,请纠正我,但另外两个解决方案都意味着直接修改软件包(在一个案例中是 docutils,在另一个案例中是 sphinx),这也是一种解决方案,但是,无意冒犯,这并不是很令人满意,因为这个补丁应该在每次软件包更新后应用,而不是由 docutils/sphinx 开发团队直接修复。 - user378147
@binoua:据我所知,您每次编译Sphinx时都会生成pygments.css。对于我的第一个答案来说,这没有问题,我只是想指出您可以将文件添加到主题中。您的解决方案会使需要着色代码的CSS规则数量翻倍,这将导致渲染速度变慢。如果这对您来说没问题-那就没问题了。两种需要修改的解决方案都很小而且容易:Sphinx或docutils的代码并没有什么宗教意义-人们可以进行微调,并在每次更新后再次微调。最后-人们可以将Sphinx解决方案实现为扩展(自定义HTML构建器)。 - Adobe
你说得完全正确:自定义HTML构建器绝对可以成为Sphinx扩展(我没有想到过这一点)。在我看来,这将是适当的解决方案。至于归档,我实际上是通过上面的脚本生成pygment.css的。 - user378147

3

好的,我用了这个解决方法:我生成了一个包含短名称和长名称的css文件。我仍然对“好”的答案感兴趣。

#!/usr/bin/env python

"""Generate a css file thanks to pygments that will contain both short
and long class names."""


import subprocess
import sys


PYGMENTIZE = 'pygmentize'


def parse_command_line():
    import argparse
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('-s', '--style', default='colorful')
    parser.add_argument('-p', '--prefix', default='.highlight')
    return parser.parse_args()


def pygmentize(style, prefix='.highlight'):
    cmd = '{0} -f html -S {1} -a {2}'.format(PYGMENTIZE, style, prefix)
    # This will fail if pygmentize does not exist.
    try:
        p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
    except OSError:
        print >> sys.stderr, '{0}: command not found'.format(PYGMENTIZE)
        exit(1)

    out, err = p.communicate()
    if p.returncode != 0:
        exit(p.returncode)
    return out


def main():
    args = parse_command_line()
    style = args.style
    prefix = args.prefix

    # Print new css header.
    header = """\
/* 
 * This is pygment css style {0} generated with
 *     {1}
 */""".format(style, ' '.join(sys.argv))
    print header

    # Parse pygmentize output.
    # Find long names based on comments.
    content = pygmentize(style, prefix)
    s = content.splitlines()
    out = ''
    for line in s:
        start = line.find("/* ") + 3
        end = line.find(" */")
        # if line has a comment
        if start != 2:
            comment = line[start:end]
            name = '.' + comment.lower()
            arg = line[line.find('{ '): start - 4]
            out += '%(prefix)s %(name)s %(arg)s\n' % vars()

    print content
    print out


if __name__ == '__main__':
    main()

2
这个问题可以通过在conf.py中添加'sphinxcontrib.inlinesyntaxhighlight'扩展来解决:
extensions = [ 'sphinxcontrib.inlinesyntaxhighlight' ]

# use language set by highlight directive if no language is set by role
inline_highlight_respect_highlight = False

# use language set by highlight directive if no role is set
inline_highlight_literals = False

扩展文档

该扩展可在此处PyPi上获取。


2
当Sphinx主题有static/pygments.css时,该文件不会被覆盖。因此,我只保留包含短名称和长名称的文件(我使用Emacs中的正则表达式获得这些名称)。
.highlight .hll { background-color: #ffffcc }
/* .highlight  { background: #eeffcc; } */
.highlight .c { color: #408090; font-style: italic } /* comment */
.highlight .comment { color: #408090; font-style: italic }
.highlight .err { border: 1px solid #ff0000 } /* error */
.highlight .error { border: 1px solid #ff0000 }
.highlight .k { color: #007020; font-weight: bold } /* keyword */
.highlight .keyword { color: #007020; font-weight: bold }
.highlight .o { color: #666666 } /* operator */
.highlight .operator { color: #666666 }
.highlight .cm { color: #408090; font-style: italic } /* comment.multiline */
.highlight .comment.multiline { color: #408090; font-style: italic }
.highlight .cp { color: #007020 } /* comment.preproc */
.highlight .comment.preproc { color: #007020 }
.highlight .c1 { color: #408090; font-style: italic } /* comment.single */
.highlight .comment.single { color: #408090; font-style: italic }
.highlight .cs { color: #408090; background-color: #fff0f0 } /* comment.special */
.highlight .comment.special { color: #408090; background-color: #fff0f0 }
.highlight .gd { color: #a00000 } /* generic.deleted */
.highlight .generic.deleted { color: #a00000 }
.highlight .ge { font-style: italic } /* generic.emph */
.highlight .generic.emph { font-style: italic }
.highlight .gr { color: #ff0000 } /* generic.error */
.highlight .generic.error { color: #ff0000 }
.highlight .gh { color: #000080; font-weight: bold } /* generic.heading */
.highlight .generic.heading { color: #000080; font-weight: bold }
.highlight .gi { color: #00a000 } /* generic.inserted */
.highlight .generic.inserted { color: #00a000 }
.highlight .go { color: #333333 } /* generic.output */
.highlight .generic.output { color: #333333 }
.highlight .gp { color: #c65d09; font-weight: bold } /* generic.prompt */
.highlight .generic.prompt { color: #c65d09; font-weight: bold }
.highlight .gs { font-weight: bold } /* generic.strong */
.highlight .generic.strong { font-weight: bold }
.highlight .gu { color: #800080; font-weight: bold } /* generic.subheading */
.highlight .generic.subheading { color: #800080; font-weight: bold }
.highlight .gt { color: #0044dd } /* generic.traceback */
.highlight .generic.traceback { color: #0044dd }
.highlight .kc { color: #007020; font-weight: bold } /* keyword.constant */
.highlight .keyword.constant { color: #007020; font-weight: bold }
.highlight .kd { color: #007020; font-weight: bold } /* keyword.declaration */
.highlight .keyword.declaration { color: #007020; font-weight: bold }
.highlight .kn { color: #007020; font-weight: bold } /* keyword.namespace */
.highlight .keyword.namespace { color: #007020; font-weight: bold }
.highlight .kp { color: #007020 } /* keyword.pseudo */
.highlight .keyword.pseudo { color: #007020 }
.highlight .kr { color: #007020; font-weight: bold } /* keyword.reserved */
.highlight .keyword.reserved { color: #007020; font-weight: bold }
.highlight .kt { color: #902000 } /* keyword.type */
.highlight .keyword.type { color: #902000 }
.highlight .m { color: #208050 } /* literal.number */
.highlight .literal.number { color: #208050 }
.highlight .s { color: #4070a0 } /* literal.string */
.highlight .literal.string { color: #4070a0 }
.highlight .na { color: #4070a0 } /* name.attribute */
.highlight .name.attribute { color: #4070a0 }
.highlight .nb { color: #007020 } /* name.builtin */
.highlight .name.builtin { color: #007020 }
.highlight .nc { color: #0e84b5; font-weight: bold } /* name.class */
.highlight .name.class { color: #0e84b5; font-weight: bold }
.highlight .no { color: #60add5 } /* name.constant */
.highlight .name.constant { color: #60add5 }
.highlight .nd { color: #555555; font-weight: bold } /* name.decorator */
.highlight .name.decorator { color: #555555; font-weight: bold }
.highlight .ni { color: #d55537; font-weight: bold } /* name.entity */
.highlight .name.entity { color: #d55537; font-weight: bold }
.highlight .ne { color: #007020 } /* name.exception */
.highlight .name.exception { color: #007020 }
.highlight .nf { color: #06287e } /* name.function */
.highlight .name.function { color: #06287e }
.highlight .nl { color: #002070; font-weight: bold } /* name.label */
.highlight .name.label { color: #002070; font-weight: bold }
.highlight .nn { color: #0e84b5; font-weight: bold } /* name.namespace */
.highlight .name.namespace { color: #0e84b5; font-weight: bold }
.highlight .nt { color: #062873; font-weight: bold } /* name.tag */
.highlight .name.tag { color: #062873; font-weight: bold }
.highlight .nv { color: #bb60d5 } /* name.variable */
.highlight .name.variable { color: #bb60d5 }
.highlight .ow { color: #007020; font-weight: bold } /* operator.word */
.highlight .operator.word { color: #007020; font-weight: bold }
.highlight .w { color: #bbbbbb } /* text.whitespace */
.highlight .text.whitespace { color: #bbbbbb }
.highlight .mf { color: #208050 } /* literal.number.float */
.highlight .literal.number.float { color: #208050 }
.highlight .mh { color: #208050 } /* literal.number.hex */
.highlight .literal.number.hex { color: #208050 }
.highlight .mi { color: #208050 } /* literal.number.integer */
.highlight .literal.number.integer { color: #208050 }
.highlight .mo { color: #208050 } /* literal.number.oct */
.highlight .literal.number.oct { color: #208050 }
.highlight .sb { color: #4070a0 } /* literal.string.backtick */
.highlight .literal.string.backtick { color: #4070a0 }
.highlight .sc { color: #4070a0 } /* literal.string.char */
.highlight .literal.string.char { color: #4070a0 }
.highlight .sd { color: #4070a0; font-style: italic } /* literal.string.doc */
.highlight .literal.string.doc { color: #4070a0; font-style: italic }
.highlight .s2 { color: #4070a0 } /* literal.string.double */
.highlight .literal.string.double { color: #4070a0 }
.highlight .se { color: #4070a0; font-weight: bold } /* literal.string.escape */
.highlight .literal.string.escape { color: #4070a0; font-weight: bold }
.highlight .sh { color: #4070a0 } /* literal.string.heredoc */
.highlight .literal.string.heredoc { color: #4070a0 }
.highlight .si { color: #70a0d0; font-style: italic } /* literal.string.interpol */
.highlight .literal.string.interpol { color: #70a0d0; font-style: italic }
.highlight .sx { color: #c65d09 } /* literal.string.other */
.highlight .literal.string.other { color: #c65d09 }
.highlight .sr { color: #235388 } /* literal.string.regex */
.highlight .literal.string.regex { color: #235388 }
.highlight .s1 { color: #4070a0 } /* literal.string.single */
.highlight .literal.string.single { color: #4070a0 }
.highlight .ss { color: #517918 } /* literal.string.symbol */
.highlight .literal.string.symbol { color: #517918 }
.highlight .bp { color: #007020 } /* name.builtin.pseudo */
.highlight .name.builtin.pseudo { color: #007020 }
.highlight .vc { color: #bb60d5 } /* name.variable.class */
.highlight .name.variable.class { color: #bb60d5 }
.highlight .vg { color: #bb60d5 } /* name.variable.global */
.highlight .name.variable.global { color: #bb60d5 }
.highlight .vi { color: #bb60d5 } /* name.variable.instance */
.highlight .name.variable.instance { color: #bb60d5 }
.highlight .il { color: #208050 } /* literal.number.integer.long */
.highlight .literal.number.integer.long { color: #208050 }

我遇到了另一个问题——我正在使用 Bootstrap 主题,它也定义了 label 标签...


2

这里提供一个比之前更好的解决方法:

修改docutils的默认--syntax-highlight选项。在

docutils/parsers/rst/__init__.py

查找

         ('Token name set for parsing code with Pygments: one of '
          '"long", "short", or "none (no parsing)". Default is "short".',
          ['--syntax-highlight'],
          {'choices': ['long', 'short', 'none'],
           'default': 'long', 'metavar': '<format>'}),

并将默认值更改为short

           'default': 'short', 'metavar': '<format>'}),

在Sphinx中突出显示行内代码的方法是注册一个新角色:
.. role:: py(code)
   :language: py
   :class: highlight

这个结构来自于docutils,而不是sphinx。因此,可以更改docutils的默认设置,以获得所需的输出(短类名)。更好的解决方案是在sphinx类的init期间设置值。但是,在哪里发生可能不容易找到。

之前的解决方案相比,这个解决方案要好得多,因为它不会使匹配颜色代码的css规则数量增加一倍。


docutils的解决方案很好,文档也相当完善。但据我所知,它不能轻松地应用于sphinx。因此,如果我理解正确的话,与sphinx兼容的解决方案仍将意味着双倍数量的css。 - user378147

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接