撰寫您自己的格式器

除了建立您自己的詞法分析器之外,為 Pygments 撰寫新的格式器也是簡單且直接的。

格式器是一個類別,它使用一些關鍵字參數(格式器選項)初始化,並且必須提供一個 format() 方法。此外,格式器應該提供一個 get_style_defs() 方法,該方法以格式器輸出格式可用的形式,從樣式中返回樣式定義。

快速入門

Pygments 附帶的最基本格式器是 NullFormatter。它只是將 Token 的值發送到輸出流。

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 是一個 Token,而 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