# 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" 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[" 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 += ';' if bg < 8: code += '4%c' % (ord('0') + bg) else: code += '48;5;%d' % bg code += 'm' else: code = '' return code DEFAULT = None def SetDefaultColoring(state): """Set coloring behavior to |state|. This is useful for overriding config options via the command line. """ if state is None: # Leave it alone -- return quick! return global DEFAULT state = state.lower() if state in ('auto',): DEFAULT = state elif state in ('always', 'yes', 'true', True): DEFAULT = 'always' elif state in ('never', 'no', 'false', False): DEFAULT = 'never' class Coloring(object): def __init__(self, config, section_type): self._section = 'color.%s' % section_type self._config = config self._out = sys.stdout on = DEFAULT if on is None: 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)