# # Copyright (C) 2008 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys import pager COLORS = {None :-1, 'normal' :-1, 'black' : 0, 'red' : 1, 'green' : 2, 'yellow' : 3, 'blue' : 4, 'magenta': 5, 'cyan' : 6, 'white' : 7} ATTRS = {None :-1, 'bold' : 1, 'dim' : 2, 'ul' : 4, 'blink' : 5, 'reverse': 7} RESET = "\033[m" # pylint: disable=W1401 # backslash is not anomalous def is_color(s): return s in COLORS def is_attr(s): return s in ATTRS def _Color(fg = None, bg = None, attr = None): fg = COLORS[fg] bg = COLORS[bg] attr = ATTRS[attr] if attr >= 0 or fg >= 0 or bg >= 0: need_sep = False code = "\033[" #pylint: disable=W1401 if attr >= 0: code += chr(ord('0') + attr) need_sep = True if fg >= 0: if need_sep: code += ';' need_sep = True if fg < 8: code += '3%c' % (ord('0') + fg) else: code += '38;5;%d' % fg if bg >= 0: if need_sep: code += ';' need_sep = True if bg < 8: code += '4%c' % (ord('0') + bg) else: code += '48;5;%d' % bg code += 'm' else: code = '' return code class Coloring(object): def __init__(self, config, section_type): self._section = 'color.%s' % section_type self._config = config self._out = sys.stdout on = self._config.GetString(self._section) if on is None: on = self._config.GetString('color.ui') if on == 'auto': if pager.active or os.isatty(1): self._on = True else: self._on = False elif on in ('true', 'always'): self._on = True else: self._on = False def redirect(self, out): self._out = out @property def is_on(self): return self._on def write(self, fmt, *args): self._out.write(fmt % args) def flush(self): self._out.flush() def nl(self): self._out.write('\n') def printer(self, opt=None, fg=None, bg=None, attr=None): s = self c = self.colorer(opt, fg, bg, attr) def f(fmt, *args): s._out.write(c(fmt, *args)) return f def nofmt_printer(self, opt=None, fg=None, bg=None, attr=None): s = self c = self.nofmt_colorer(opt, fg, bg, attr) def f(fmt): s._out.write(c(fmt)) return f def colorer(self, opt=None, fg=None, bg=None, attr=None): if self._on: c = self._parse(opt, fg, bg, attr) def f(fmt, *args): output = fmt % args return ''.join([c, output, RESET]) return f else: def f(fmt, *args): return fmt % args return f def nofmt_colorer(self, opt=None, fg=None, bg=None, attr=None): if self._on: c = self._parse(opt, fg, bg, attr) def f(fmt): return ''.join([c, fmt, RESET]) return f else: def f(fmt): return fmt return f def _parse(self, opt, fg, bg, attr): if not opt: return _Color(fg, bg, attr) v = self._config.GetString('%s.%s' % (self._section, opt)) if v is None: return _Color(fg, bg, attr) v = v.strip().lower() if v == "reset": return RESET elif v == '': return _Color(fg, bg, attr) have_fg = False for a in v.split(' '): if is_color(a): if have_fg: bg = a else: fg = a elif is_attr(a): attr = a return _Color(fg, bg, attr)