为 python pygments 生成自定义样式

Posted

技术标签:

【中文标题】为 python pygments 生成自定义样式【英文标题】:generating a custom Styling for 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”类?

【问题讨论】:

【参考方案1】:

TL;DR:

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

    定义并创建:扩展Style类✔️ 应用并整合:在 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 个选项之间做出选择:

    通过指定路径导出外部 CSS 文件 嵌入集成的 CSS(默认与您的样式合并)作为 &lt;style&gt; 到 HTML 中 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 样式的不同选项,因此答案冗长而深入。希望它读起来很好,解释了可理解的标签并有所帮助。

以上是关于为 python pygments 生成自定义样式的主要内容,如果未能解决你的问题,请参考以下文章

将 pygments 主题转换为 gvim 颜色方案

如何自定义 Pygments css 类输出

如何在 Pygments 中使用 Dracula 主题作为样式?

未定义的方法`highlight' Python+Pygments

python语法高亮使用Pygments程序

用于 HTML、PHP 和 JavaScript 的 Pygments 样式