独自のフォーマッターを書く

独自のレクサーを作成することに加え、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() メソッドには 2 つのパラメーターが渡されます: tokensourceoutfile です。前者は (token_type, value) タプルの反復可能であり、後者は write() メソッドを持つ file のようなオブジェクトです。

フォーマッターは非常に基本的なため、get_style_defs() メソッドをオーバーライドしません。

スタイル

スタイルはインスタンス化されませんが、そのメタクラスは、スタイル定義に簡単にアクセスできるようにいくつかのクラス関数を提供します。

スタイルは反復可能で、ttype はトークンであり、d は次のキーを持つ辞書の形であるタプルを生成します。

'color'

16 進数のカラー値(例: 赤の 'ff0000')または未定義の場合は None

'bold'

True の場合、値は太字にする必要があります

'italic'

True の場合、値は斜体にする必要があります

'underline'

True の場合、値は下線付きにする必要があります

'bgcolor'

背景用の 16 進数のカラー値(例: 薄いグレーの 'eeeeeee')または未定義の場合は None

'border'

境界用の 16 進数のカラー値(例: 濃い青色の '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() メソッドをオーバーライドしません。インライン HTML マークアップの代わりに CSS クラスを使用していた場合、最初に CSS を生成する必要があります。その目的のために get_style_defs() メソッドがあります

スタイル定義の生成

LatexFormatter や HtmlFormatter といった書式設定には、インラインのマークアップが出力されず、マクロや CSS クラスを参照するものがあります。これらの定義は出力に含まれないため、get_style_defs() メソッドを使用してください。このメソッドには 1 つのパラメーターが渡され (使用方法や渡され方は書式設定によって異なります)、文字列または None を返す必要があります。