编写自己的格式化程序

除了创建 自己的词法分析器,为 Pygments 编写新的格式化程序也很容易直观。

格式化程序是一个类,它用一些关键字参数(格式化程序选项)初始化,并且必须提供一个 format() 方法。此外,格式化程序还应该提供一个 get_style_defs() 方法,该方法以格式化程序输出格式可用的形式返回样式中的样式定义。

快速入门

与 Pygments 附带的最基本的格式化程序是 NullFormatter。它只是将令牌的值发送到输出流

from pygments.formatter import Formatter

class NullFormatter(Formatter):
    def format(self, tokensource, outfile):
        for ttype, value in tokensource:
            outfile.write(value)

如您所见,format() 方法传递了两个参数:tokensourceoutfile。第一个是 (token_type, value) 元组的可迭代对象,第二个是具有 write() 方法的文件类对象。

由于格式化程序非常基本,因此它不会覆盖 get_style_defs() 方法。

样式

样式不会被实例化,但它们的元类提供了一些类函数,以便您可以轻松访问样式定义。

样式是可迭代的,并以 (ttype, d) 形式产生元组,其中 ttype 是一个令牌,而 d 是一个具有以下键的字典

'color'

十六进制颜色值(例如:'ff0000' 表示红色)或 None(如果未定义)。

'bold'

True 如果值应为粗体

'italic'

True 如果值应为斜体

'underline'

True 如果值应为下划线

'bgcolor'

背景的十六进制颜色值(例如:'eeeeeee' 表示浅灰色)或 None(如果未定义)。

'border'

边框的十六进制颜色值(例如:'0000aa' 表示深蓝色)或 None 表示无边框。

将来可能会出现其他键,格式化程序应忽略它们不支持的所有键。

HTML 3.2 格式化程序

对于更复杂的示例,让我们实现一个 HTML 3.2 格式化程序。我们不使用 CSS,而是使用内联标记 (<u>, <font> 等)。由于这不是好的风格,因此此格式化程序不在标准库中 ;-)

from pygments.formatter import Formatter

class OldHtmlFormatter(Formatter):

    def __init__(self, **options):
        Formatter.__init__(self, **options)

        # create a dict of (start, end) tuples that wrap the
        # value of a token so that we can use it in the format
        # method later
        self.styles = {}

        # we iterate over the `_styles` attribute of a style item
        # that contains the parsed style values.
        for token, style in self.style:
            start = end = ''
            # a style item is a tuple in the following form:
            # colors are readily specified in hex: 'RRGGBB'
            if style['color']:
                start += '<font color="#%s">' % style['color']
                end = '</font>' + end
            if style['bold']:
                start += '<b>'
                end = '</b>' + end
            if style['italic']:
                start += '<i>'
                end = '</i>' + end
            if style['underline']:
                start += '<u>'
                end = '</u>' + end
            self.styles[token] = (start, end)

    def format(self, tokensource, outfile):
        # lastval is a string we use for caching
        # because it's possible that an lexer yields a number
        # of consecutive tokens with the same token type.
        # to minimize the size of the generated html markup we
        # try to join the values of same-type tokens here
        lastval = ''
        lasttype = None

        # wrap the whole output with <pre>
        outfile.write('<pre>')

        for ttype, value in tokensource:
            # if the token type doesn't exist in the stylemap
            # we try it with the parent of the token type
            # eg: parent of Token.Literal.String.Double is
            # Token.Literal.String
            while ttype not in self.styles:
                ttype = ttype.parent
            if ttype == lasttype:
                # the current token type is the same of the last
                # iteration. cache it
                lastval += value
            else:
                # not the same token as last iteration, but we
                # have some data in the buffer. wrap it with the
                # defined style and write it to the output file
                if lastval:
                    stylebegin, styleend = self.styles[lasttype]
                    outfile.write(stylebegin + lastval + styleend)
                # set lastval/lasttype to current values
                lastval = value
                lasttype = ttype

        # if something is left in the buffer, write it to the
        # output file, then close the opened <pre> tag
        if lastval:
            stylebegin, styleend = self.styles[lasttype]
            outfile.write(stylebegin + lastval + styleend)
        outfile.write('</pre>\n')

注释应对此进行解释。同样,此格式化程序不会覆盖 get_style_defs() 方法。如果我们使用 CSS 类而不是内联 HTML 标记,则需要先生成 CSS。为此目的,存在 get_style_defs() 方法

生成样式定义

一些格式化程序,如 LatexFormatterHtmlFormatter,不输出内联标记,而是引用宏或 css 类。由于这些定义不是输出的一部分,因此存在 get_style_defs() 方法。它传递一个参数(如果使用以及如何使用取决于格式化程序),并且必须返回一个字符串或 None