PageRenderTime 22ms CodeModel.GetById 1ms app.highlight 19ms RepoModel.GetById 0ms app.codeStats 0ms

/console/app/pygments/formatters/terminal256.py

https://bitbucket.org/alex_muscar/myspace-competition-radar
Python | 221 lines | 190 code | 7 blank | 24 comment | 1 complexity | 884f026dfc770060db4fcdf11027beb9 MD5 | raw file
Possible License(s): GPL-3.0
  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: 2007 by Artem Egorkine.
 15    :license: BSD, see LICENSE for more 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
 27from pygments.formatter import Formatter
 28
 29
 30__all__ = ['Terminal256Formatter']
 31
 32
 33class 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
 67class 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        enc = self.encoding
186        # hack: if the output is a terminal and has an encoding set,
187        # use that to avoid unicode encode problems
188        if not enc and hasattr(outfile, "encoding") and \
189           hasattr(outfile, "isatty") and outfile.isatty():
190            enc = outfile.encoding
191
192        for ttype, value in tokensource:
193            if enc:
194                value = value.encode(enc)
195
196            not_found = True
197            while ttype and not_found:
198                try:
199                    #outfile.write( "<" + str(ttype) + ">" )
200                    on, off = self.style_string[str(ttype)]
201
202                    # Like TerminalFormatter, add "reset colors" escape sequence
203                    # on newline.
204                    spl = value.split('\n')
205                    for line in spl[:-1]:
206                        if line:
207                            outfile.write(on + line + off)
208                        outfile.write('\n')
209                    if spl[-1]:
210                        outfile.write(on + spl[-1] + off)
211
212                    not_found = False
213                    #outfile.write( '#' + str(ttype) + '#' )
214
215                except KeyError:
216                    #ottype = ttype
217                    ttype = ttype[:-1]
218                    #outfile.write( '!' + str(ottype) + '->' + str(ttype) + '!' )
219
220            if not_found:
221                outfile.write(value)