ThirdParty/Pygments/pygments/formatters/terminal256.py

changeset 0
de9c2efb9d02
child 684
2f29a0b6e1c7
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2 """
3 pygments.formatters.terminal256
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Formatter for 256-color terminal output with ANSI sequences.
7
8 RGB-to-XTERM color conversion routines adapted from xterm256-conv
9 tool (http://frexx.de/xterm-256-notes/data/xterm256-conv2.tar.bz2)
10 by Wolfgang Frisch.
11
12 Formatter version 1.
13
14 :copyright: Copyright 2006-2009 by the Pygments team, see AUTHORS.
15 :license: BSD, see LICENSE for details.
16 """
17
18 # TODO:
19 # - Options to map style's bold/underline/italic/border attributes
20 # to some ANSI attrbutes (something like 'italic=underline')
21 # - An option to output "style RGB to xterm RGB/index" conversion table
22 # - An option to indicate that we are running in "reverse background"
23 # xterm. This means that default colors are white-on-black, not
24 # black-on-while, so colors like "white background" need to be converted
25 # to "white background, black foreground", etc...
26
27 from pygments.formatter import Formatter
28
29
30 __all__ = ['Terminal256Formatter']
31
32
33 class EscapeSequence:
34 def __init__(self, fg=None, bg=None, bold=False, underline=False):
35 self.fg = fg
36 self.bg = bg
37 self.bold = bold
38 self.underline = underline
39
40 def escape(self, attrs):
41 if len(attrs):
42 return "\x1b[" + ";".join(attrs) + "m"
43 return ""
44
45 def color_string(self):
46 attrs = []
47 if self.fg is not None:
48 attrs.extend(("38", "5", "%i" % self.fg))
49 if self.bg is not None:
50 attrs.extend(("48", "5", "%i" % self.bg))
51 if self.bold:
52 attrs.append("01")
53 if self.underline:
54 attrs.append("04")
55 return self.escape(attrs)
56
57 def reset_string(self):
58 attrs = []
59 if self.fg is not None:
60 attrs.append("39")
61 if self.bg is not None:
62 attrs.append("49")
63 if self.bold or self.underline:
64 attrs.append("00")
65 return self.escape(attrs)
66
67 class Terminal256Formatter(Formatter):
68 r"""
69 Format tokens with ANSI color sequences, for output in a 256-color
70 terminal or console. Like in `TerminalFormatter` color sequences
71 are terminated at newlines, so that paging the output works correctly.
72
73 The formatter takes colors from a style defined by the `style` option
74 and converts them to nearest ANSI 256-color escape sequences. Bold and
75 underline attributes from the style are preserved (and displayed).
76
77 *New in Pygments 0.9.*
78
79 Options accepted:
80
81 `style`
82 The style to use, can be a string or a Style subclass (default:
83 ``'default'``).
84 """
85 name = 'Terminal256'
86 aliases = ['terminal256', 'console256', '256']
87 filenames = []
88
89 def __init__(self, **options):
90 Formatter.__init__(self, **options)
91
92 self.xterm_colors = []
93 self.best_match = {}
94 self.style_string = {}
95
96 self.usebold = 'nobold' not in options
97 self.useunderline = 'nounderline' not in options
98
99 self._build_color_table() # build an RGB-to-256 color conversion table
100 self._setup_styles() # convert selected style's colors to term. colors
101
102 def _build_color_table(self):
103 # colors 0..15: 16 basic colors
104
105 self.xterm_colors.append((0x00, 0x00, 0x00)) # 0
106 self.xterm_colors.append((0xcd, 0x00, 0x00)) # 1
107 self.xterm_colors.append((0x00, 0xcd, 0x00)) # 2
108 self.xterm_colors.append((0xcd, 0xcd, 0x00)) # 3
109 self.xterm_colors.append((0x00, 0x00, 0xee)) # 4
110 self.xterm_colors.append((0xcd, 0x00, 0xcd)) # 5
111 self.xterm_colors.append((0x00, 0xcd, 0xcd)) # 6
112 self.xterm_colors.append((0xe5, 0xe5, 0xe5)) # 7
113 self.xterm_colors.append((0x7f, 0x7f, 0x7f)) # 8
114 self.xterm_colors.append((0xff, 0x00, 0x00)) # 9
115 self.xterm_colors.append((0x00, 0xff, 0x00)) # 10
116 self.xterm_colors.append((0xff, 0xff, 0x00)) # 11
117 self.xterm_colors.append((0x5c, 0x5c, 0xff)) # 12
118 self.xterm_colors.append((0xff, 0x00, 0xff)) # 13
119 self.xterm_colors.append((0x00, 0xff, 0xff)) # 14
120 self.xterm_colors.append((0xff, 0xff, 0xff)) # 15
121
122 # colors 16..232: the 6x6x6 color cube
123
124 valuerange = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff)
125
126 for i in range(217):
127 r = valuerange[(i // 36) % 6]
128 g = valuerange[(i // 6) % 6]
129 b = valuerange[i % 6]
130 self.xterm_colors.append((r, g, b))
131
132 # colors 233..253: grayscale
133
134 for i in range(1, 22):
135 v = 8 + i * 10
136 self.xterm_colors.append((v, v, v))
137
138 def _closest_color(self, r, g, b):
139 distance = 257*257*3 # "infinity" (>distance from #000000 to #ffffff)
140 match = 0
141
142 for i in range(0, 254):
143 values = self.xterm_colors[i]
144
145 rd = r - values[0]
146 gd = g - values[1]
147 bd = b - values[2]
148 d = rd*rd + gd*gd + bd*bd
149
150 if d < distance:
151 match = i
152 distance = d
153 return match
154
155 def _color_index(self, color):
156 index = self.best_match.get(color, None)
157 if index is None:
158 try:
159 rgb = int(str(color), 16)
160 except ValueError:
161 rgb = 0
162
163 r = (rgb >> 16) & 0xff
164 g = (rgb >> 8) & 0xff
165 b = rgb & 0xff
166 index = self._closest_color(r, g, b)
167 self.best_match[color] = index
168 return index
169
170 def _setup_styles(self):
171 for ttype, ndef in self.style:
172 escape = EscapeSequence()
173 if ndef['color']:
174 escape.fg = self._color_index(ndef['color'])
175 if ndef['bgcolor']:
176 escape.bg = self._color_index(ndef['bgcolor'])
177 if self.usebold and ndef['bold']:
178 escape.bold = True
179 if self.useunderline and ndef['underline']:
180 escape.underline = True
181 self.style_string[str(ttype)] = (escape.color_string(),
182 escape.reset_string())
183
184 def format(self, tokensource, outfile):
185 # hack: if the output is a terminal and has an encoding set,
186 # use that to avoid unicode encode problems
187 if not self.encoding and hasattr(outfile, "encoding") and \
188 hasattr(outfile, "isatty") and outfile.isatty():
189 self.encoding = outfile.encoding
190 return Formatter.format(self, tokensource, outfile)
191
192 def format_unencoded(self, tokensource, outfile):
193 for ttype, value in tokensource:
194 not_found = True
195 while ttype and not_found:
196 try:
197 #outfile.write( "<" + str(ttype) + ">" )
198 on, off = self.style_string[str(ttype)]
199
200 # Like TerminalFormatter, add "reset colors" escape sequence
201 # on newline.
202 spl = value.split('\n')
203 for line in spl[:-1]:
204 if line:
205 outfile.write(on + line + off)
206 outfile.write('\n')
207 if spl[-1]:
208 outfile.write(on + spl[-1] + off)
209
210 not_found = False
211 #outfile.write( '#' + str(ttype) + '#' )
212
213 except KeyError:
214 #ottype = ttype
215 ttype = ttype[:-1]
216 #outfile.write( '!' + str(ottype) + '->' + str(ttype) + '!' )
217
218 if not_found:
219 outfile.write(value)

eric ide

mercurial