【问题标题】:generating a custom Styling for python pygments为 python pygments 生成自定义样式
【发布时间】:2021-08-03 10:42:01
【问题描述】:

我目前正在为我的网站使用 python pygments 来突出显示一些代码,并想调整一些使用的颜色。到目前为止,我已经尝试了以下方法:

from pygments.token import Keyword, Name, Comment, String, Error, \
     Number, Operator, Generic
from pygments.formatters import HtmlFormatter

class MyStyle(Style):
    styles = {
        Comment:                '#f00000',
        Keyword:                '#f00000',
        Name:                   '#f00000',
        Name.Function:          '#f00000',
        Name.Class:             '#f00000',
        String:                 '#f00000'
    }


code = 'print("Hello World")'
result = highlight(code, Python3Lexer(), HtmlFormatter(style=MyStyle))
print(result)

打印出来

<div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Hello World&quot;</span><span class="p">)</span>
</pre></div>

旁边生成的pygments.css如下:

.highlight .hll { background-color: #ffffcc }
.highlight { background: #f8f8f8; }
.highlight .c { color: #8f5902; font-style: italic } /* Comment */
.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */
.highlight .g { color: #000000 } /* Generic */
.highlight .k { color: #204a87; font-weight: bold } /* Keyword */
.highlight .l { color: #000000 } /* Literal */
.highlight .n { color: #000000 } /* Name */
.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */
.highlight .x { color: #000000 } /* Other */
.highlight .p { color: #000000; font-weight: bold } /* Punctuation */
.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */
.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */
.highlight .gd { color: #a40000 } /* Generic.Deleted */
.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
.highlight .gr { color: #ef2929 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #000000; font-style: italic } /* Generic.Output */
.highlight .gp { color: #8f5902 } /* Generic.Prompt */
.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */
.highlight .ld { color: #000000 } /* Literal.Date */
.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */
.highlight .s { color: #4e9a06 } /* Literal.String */
.highlight .na { color: #c4a000 } /* Name.Attribute */
.highlight .nb { color: #204a87 } /* Name.Builtin */
.highlight .nc { color: #000000 } /* Name.Class */
.highlight .no { color: #000000 } /* Name.Constant */
.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #ce5c00 } /* Name.Entity */
.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #000000 } /* Name.Function */
.highlight .nl { color: #f57900 } /* Name.Label */
.highlight .nn { color: #000000 } /* Name.Namespace */
.highlight .nx { color: #000000 } /* Name.Other */
.highlight .py { color: #000000 } /* Name.Property */
.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #000000 } /* Name.Variable */
.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */
.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */
.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */
.highlight .sc { color: #4e9a06 } /* Literal.String.Char */
.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */
.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */
.highlight .se { color: #4e9a06 } /* Literal.String.Escape */
.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */
.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */
.highlight .sx { color: #4e9a06 } /* Literal.String.Other */
.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */
.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */
.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */
.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #000000 } /* Name.Function.Magic */
.highlight .vc { color: #000000 } /* Name.Variable.Class */
.highlight .vg { color: #000000 } /* Name.Variable.Global */
.highlight .vi { color: #000000 } /* Name.Variable.Instance */
.highlight .vm { color: #000000 } /* Name.Variable.Magic */
.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */

不幸的是,没有一个样式元素是这样调整的。有没有更简单的方法来改变一些使用的颜色,例如对于“nb”类?

【问题讨论】:

    标签: python pygments


    【解决方案1】:

    TL;DR:

    您需要 2 个步骤来使用您的自定义样式:

    1. 定义并创建:扩展Style类✔️
    2. 应用并整合:在 3 个HTMLFormatter 选项之间做出选择❌️

    你错过了最后一个。


    首先,到reproduce your code,需要添加以下导入:

    from pygments import highlight
    from pygments.style import Style
    from pygments.lexers import Python3Lexer
    

    定义自定义样式

    您自己的样式已正确创建并遵循官方教程"Creating Own Styles"。您的 MyStyle 类(继承自基类 Style)将 red color 分配给多个语言元素。

    应用自定义样式

    要使用您将其作为参数 style = MyStyle() 传递给格式化程序构造函数的自定义样式:HtmlFormatter(style=MyStyle())

    很遗憾,这不适用于样式。它必须以某种方式与 pygments 使用的现有 默认样式 集成。

    见: How can I customize the output from pygments?

    要集成和应用自定义样式,您基本上可以在 3 个选项之间做出选择:

    1. 通过指定路径导出外部 CSS 文件
    2. 嵌入集成的 CSS(默认与您的样式合并)作为 &lt;style&gt; 到 HTML 中
    3. inline 将您的样式直接添加到渲染/突出显示的代码的 HTML 元素中,例如 &lt;span style="color: #f00000"&gt;print&lt;/span&gt;

    pygments API reference for HTMLFormatter 比较其中两个:

    使用 full 选项,输出一个完整的 HTML 4 文档,包括标签内的样式定义,或者如果给出 cssfile 选项,则在单独的文件中。

    这 3 个选项将在以下部分进行说明。

    导出一个单独的 CSS 文件

    formatter = HtmlFormatter(style=MyStyle, full=True, cssfile=`my_pygments.css`)
    

    将完整的 CSS 样式表写入指定文件。来自文档:

    如果 full 选项为 true 并且给出了此选项,则它必须是外部文件的名称。如果文件名不包含绝对路径,则假定文件路径相对于主输出文件的路径(如果可以找到后者)。然后将样式表写入此文件而不是 HTML 文件。 Pygments 0.6 中的新功能。

    将 CSS 嵌入 HTML

    formatter = HtmlFormatter(style=MyStyle(), full=True)
    

    来自文档:

    告诉格式化程序输出“完整”文档,即完整的自包含文档(默认值:False)。 上面我用粗体强调了使用生成的 HTML 隔离的好处,作为单个文件,没有任何依赖项,如 CSS 文件:“自包含”

    将样式内联到每个代码的 HTML 元素

    formatter = HtmlFormatter(style=MyStyle())
    formatter.noclasses = True
    

    这里不涉及 pygment 使用的现有 CSS 类(如 nb)。 相反,您定义的自定义样式直接应用于 HTML 元素,例如 style="color: #f00000"

    所以,您给定的 HTML 输出(带有样式类 nbps2):

    <div class="highlight">
      <pre>
        <span></span><span class="nb">print</span>
        <span class="p">(</span><span class="s2">&quot;Hello World&quot;</span><span class="p">)</span>
      </pre>
    </div>
    

    会变成这样(没有样式类):

    <div class="highlight" style="background: #ffffff">
      <pre style="line-height: 125%">
        <span></span><span style="color: #f00000">print</span>
        (<span style="color: #f00000">&quot;Hello World&quot;</span>)
      </pre>
    </div>
    

    解决方案

    我添加了缺少的导入,提取了formatter 变量并通过传递选项full = True 启用了自包含HTML,因此您可以按预期测试CSS。

    from pygments import highlight
    from pygments.style import Style
    from pygments.lexers import Python3Lexer
    from pygments.token import Keyword, Name, Comment, String, Error, \
         Number, Operator, Generic
    from pygments.formatters import HtmlFormatter
    
    # step 1: define custom style
    class MyStyle(Style):
        styles = {
            Comment:                '#f00000',
            Keyword:                '#f00000',
            Name:                   '#f00000',
            Name.Function:          '#f00000',
            Name.Class:             '#f00000',
            String:                 '#f00000'
        }
    
    # step 2: apply custom style
    formatter = HtmlFormatter(style=MyStyle, full=True)  # embed Style inside HTML (self-contained, no external CSS-file
    # formatter.noclasses = True  # inline style to each element directly
    
    
    code = 'print("Hello World")'
    result = highlight(code, Python3Lexer(), formatter)
    print(result)
    

    将打印以下 HTML(包括 &lt;style&gt; 嵌入的 CSS):

    <!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>
      <meta http-equiv="content-type" content="text/html; charset=None">
      <style type="text/css">
    /*
    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%; }
    body .hll { background-color: #ffffcc }
    body  { background: #ffffff; }
    body .c { color: #f00000 } /* Comment */
    body .k { color: #f00000 } /* Keyword */
    body .n { color: #f00000 } /* Name */
    body .ch { color: #f00000 } /* Comment.Hashbang */
    body .cm { color: #f00000 } /* Comment.Multiline */
    body .cp { color: #f00000 } /* Comment.Preproc */
    body .cpf { color: #f00000 } /* Comment.PreprocFile */
    body .c1 { color: #f00000 } /* Comment.Single */
    body .cs { color: #f00000 } /* Comment.Special */
    body .kc { color: #f00000 } /* Keyword.Constant */
    body .kd { color: #f00000 } /* Keyword.Declaration */
    body .kn { color: #f00000 } /* Keyword.Namespace */
    body .kp { color: #f00000 } /* Keyword.Pseudo */
    body .kr { color: #f00000 } /* Keyword.Reserved */
    body .kt { color: #f00000 } /* Keyword.Type */
    body .s { color: #f00000 } /* Literal.String */
    body .na { color: #f00000 } /* Name.Attribute */
    body .nb { color: #f00000 } /* Name.Builtin */
    body .nc { color: #f00000 } /* Name.Class */
    body .no { color: #f00000 } /* Name.Constant */
    body .nd { color: #f00000 } /* Name.Decorator */
    body .ni { color: #f00000 } /* Name.Entity */
    body .ne { color: #f00000 } /* Name.Exception */
    body .nf { color: #f00000 } /* Name.Function */
    body .nl { color: #f00000 } /* Name.Label */
    body .nn { color: #f00000 } /* Name.Namespace */
    body .nx { color: #f00000 } /* Name.Other */
    body .py { color: #f00000 } /* Name.Property */
    body .nt { color: #f00000 } /* Name.Tag */
    body .nv { color: #f00000 } /* Name.Variable */
    body .sa { color: #f00000 } /* Literal.String.Affix */
    body .sb { color: #f00000 } /* Literal.String.Backtick */
    body .sc { color: #f00000 } /* Literal.String.Char */
    body .dl { color: #f00000 } /* Literal.String.Delimiter */
    body .sd { color: #f00000 } /* Literal.String.Doc */
    body .s2 { color: #f00000 } /* Literal.String.Double */
    body .se { color: #f00000 } /* Literal.String.Escape */
    body .sh { color: #f00000 } /* Literal.String.Heredoc */
    body .si { color: #f00000 } /* Literal.String.Interpol */
    body .sx { color: #f00000 } /* Literal.String.Other */
    body .sr { color: #f00000 } /* Literal.String.Regex */
    body .s1 { color: #f00000 } /* Literal.String.Single */
    body .ss { color: #f00000 } /* Literal.String.Symbol */
    body .bp { color: #f00000 } /* Name.Builtin.Pseudo */
    body .fm { color: #f00000 } /* Name.Function.Magic */
    body .vc { color: #f00000 } /* Name.Variable.Class */
    body .vg { color: #f00000 } /* Name.Variable.Global */
    body .vi { color: #f00000 } /* Name.Variable.Instance */
    body .vm { color: #f00000 } /* Name.Variable.Magic */
    
      </style>
    </head>
    <body>
    <h2></h2>
    
    <div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Hello World&quot;</span><span class="p">)</span>
    </pre></div>
    </body>
    </html>
    

    【讨论】:

    • 抱歉,我想解释一下应用自定义 CSS 样式的不同选项,因此答案冗长而深入。希望它读起来很好,解释了可理解的标签并有所帮助。
    猜你喜欢
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-14
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 2011-08-24
    相关资源
    最近更新 更多