1"""
2 pygments.formatters.other
3 ~~~~~~~~~~~~~~~~~~~~~~~~~
4
5 Other formatters: NullFormatter, RawTokenFormatter.
6
7 :copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
9"""
10
11from pygments.formatter import Formatter
12from pygments.util import get_choice_opt
13from pygments.token import Token
14from pygments.console import colorize
15
16__all__ = ['NullFormatter', 'RawTokenFormatter', 'TestcaseFormatter']
17
18
19class NullFormatter(Formatter):
20 """
21 Output the text unchanged without any formatting.
22 """
23 name = 'Text only'
24 aliases = ['text', 'null']
25 filenames = ['*.txt']
26
27 def format(self, tokensource, outfile):
28 enc = self.encoding
29 for ttype, value in tokensource:
30 if enc:
31 outfile.write(value.encode(enc))
32 else:
33 outfile.write(value)
34
35
36class RawTokenFormatter(Formatter):
37 r"""
38 Format tokens as a raw representation for storing token streams.
39
40 The format is ``tokentype<TAB>repr(tokenstring)\n``. The output can later
41 be converted to a token stream with the `RawTokenLexer`, described in the
42 :doc:`lexer list <lexers>`.
43
44 Only two options are accepted:
45
46 `compress`
47 If set to ``'gz'`` or ``'bz2'``, compress the output with the given
48 compression algorithm after encoding (default: ``''``).
49 `error_color`
50 If set to a color name, highlight error tokens using that color. If
51 set but with no value, defaults to ``'red'``.
52
53 .. versionadded:: 0.11
54
55 """
56 name = 'Raw tokens'
57 aliases = ['raw', 'tokens']
58 filenames = ['*.raw']
59
60 unicodeoutput = False
61
62 def __init__(self, **options):
63 Formatter.__init__(self, **options)
64 # We ignore self.encoding if it is set, since it gets set for lexer
65 # and formatter if given with -Oencoding on the command line.
66 # The RawTokenFormatter outputs only ASCII. Override here.
67 self.encoding = 'ascii' # let pygments.format() do the right thing
68 self.compress = get_choice_opt(options, 'compress',
69 ['', 'none', 'gz', 'bz2'], '')
70 self.error_color = options.get('error_color', None)
71 if self.error_color is True:
72 self.error_color = 'red'
73 if self.error_color is not None:
74 try:
75 colorize(self.error_color, '')
76 except KeyError:
77 raise ValueError(f"Invalid color {self.error_color!r} specified")
78
79 def format(self, tokensource, outfile):
80 try:
81 outfile.write(b'')
82 except TypeError:
83 raise TypeError('The raw tokens formatter needs a binary '
84 'output file')
85 if self.compress == 'gz':
86 import gzip
87 outfile = gzip.GzipFile('', 'wb', 9, outfile)
88
89 write = outfile.write
90 flush = outfile.close
91 elif self.compress == 'bz2':
92 import bz2
93 compressor = bz2.BZ2Compressor(9)
94
95 def write(text):
96 outfile.write(compressor.compress(text))
97
98 def flush():
99 outfile.write(compressor.flush())
100 outfile.flush()
101 else:
102 write = outfile.write
103 flush = outfile.flush
104
105 if self.error_color:
106 for ttype, value in tokensource:
107 line = b"%r\t%r\n" % (ttype, value)
108 if ttype is Token.Error:
109 write(colorize(self.error_color, line.decode()).encode())
110 else:
111 write(line)
112 else:
113 for ttype, value in tokensource:
114 write(b"%r\t%r\n" % (ttype, value))
115 flush()
116
117
118TESTCASE_BEFORE = '''\
119 def testNeedsName(lexer):
120 fragment = %r
121 tokens = [
122'''
123TESTCASE_AFTER = '''\
124 ]
125 assert list(lexer.get_tokens(fragment)) == tokens
126'''
127
128
129class TestcaseFormatter(Formatter):
130 """
131 Format tokens as appropriate for a new testcase.
132
133 .. versionadded:: 2.0
134 """
135 name = 'Testcase'
136 aliases = ['testcase']
137
138 def __init__(self, **options):
139 Formatter.__init__(self, **options)
140 if self.encoding is not None and self.encoding != 'utf-8':
141 raise ValueError("Only None and utf-8 are allowed encodings.")
142
143 def format(self, tokensource, outfile):
144 indentation = ' ' * 12
145 rawbuf = []
146 outbuf = []
147 for ttype, value in tokensource:
148 rawbuf.append(value)
149 outbuf.append(f'{indentation}({ttype}, {value!r}),\n')
150
151 before = TESTCASE_BEFORE % (''.join(rawbuf),)
152 during = ''.join(outbuf)
153 after = TESTCASE_AFTER
154 if self.encoding is None:
155 outfile.write(before + during + after)
156 else:
157 outfile.write(before.encode('utf-8'))
158 outfile.write(during.encode('utf-8'))
159 outfile.write(after.encode('utf-8'))
160 outfile.flush()