color.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #
  2. # Copyright (C) 2008 The Android Open Source Project
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import os
  16. import sys
  17. import pager
  18. COLORS = {None: -1,
  19. 'normal': -1,
  20. 'black': 0,
  21. 'red': 1,
  22. 'green': 2,
  23. 'yellow': 3,
  24. 'blue': 4,
  25. 'magenta': 5,
  26. 'cyan': 6,
  27. 'white': 7}
  28. ATTRS = {None: -1,
  29. 'bold': 1,
  30. 'dim': 2,
  31. 'ul': 4,
  32. 'blink': 5,
  33. 'reverse': 7}
  34. RESET = "\033[m"
  35. def is_color(s):
  36. return s in COLORS
  37. def is_attr(s):
  38. return s in ATTRS
  39. def _Color(fg=None, bg=None, attr=None):
  40. fg = COLORS[fg]
  41. bg = COLORS[bg]
  42. attr = ATTRS[attr]
  43. if attr >= 0 or fg >= 0 or bg >= 0:
  44. need_sep = False
  45. code = "\033["
  46. if attr >= 0:
  47. code += chr(ord('0') + attr)
  48. need_sep = True
  49. if fg >= 0:
  50. if need_sep:
  51. code += ';'
  52. need_sep = True
  53. if fg < 8:
  54. code += '3%c' % (ord('0') + fg)
  55. else:
  56. code += '38;5;%d' % fg
  57. if bg >= 0:
  58. if need_sep:
  59. code += ';'
  60. if bg < 8:
  61. code += '4%c' % (ord('0') + bg)
  62. else:
  63. code += '48;5;%d' % bg
  64. code += 'm'
  65. else:
  66. code = ''
  67. return code
  68. DEFAULT = None
  69. def SetDefaultColoring(state):
  70. """Set coloring behavior to |state|.
  71. This is useful for overriding config options via the command line.
  72. """
  73. if state is None:
  74. # Leave it alone -- return quick!
  75. return
  76. global DEFAULT
  77. state = state.lower()
  78. if state in ('auto',):
  79. DEFAULT = state
  80. elif state in ('always', 'yes', 'true', True):
  81. DEFAULT = 'always'
  82. elif state in ('never', 'no', 'false', False):
  83. DEFAULT = 'never'
  84. class Coloring(object):
  85. def __init__(self, config, section_type):
  86. self._section = 'color.%s' % section_type
  87. self._config = config
  88. self._out = sys.stdout
  89. on = DEFAULT
  90. if on is None:
  91. on = self._config.GetString(self._section)
  92. if on is None:
  93. on = self._config.GetString('color.ui')
  94. if on == 'auto':
  95. if pager.active or os.isatty(1):
  96. self._on = True
  97. else:
  98. self._on = False
  99. elif on in ('true', 'always'):
  100. self._on = True
  101. else:
  102. self._on = False
  103. def redirect(self, out):
  104. self._out = out
  105. @property
  106. def is_on(self):
  107. return self._on
  108. def write(self, fmt, *args):
  109. self._out.write(fmt % args)
  110. def flush(self):
  111. self._out.flush()
  112. def nl(self):
  113. self._out.write('\n')
  114. def printer(self, opt=None, fg=None, bg=None, attr=None):
  115. s = self
  116. c = self.colorer(opt, fg, bg, attr)
  117. def f(fmt, *args):
  118. s._out.write(c(fmt, *args))
  119. return f
  120. def nofmt_printer(self, opt=None, fg=None, bg=None, attr=None):
  121. s = self
  122. c = self.nofmt_colorer(opt, fg, bg, attr)
  123. def f(fmt):
  124. s._out.write(c(fmt))
  125. return f
  126. def colorer(self, opt=None, fg=None, bg=None, attr=None):
  127. if self._on:
  128. c = self._parse(opt, fg, bg, attr)
  129. def f(fmt, *args):
  130. output = fmt % args
  131. return ''.join([c, output, RESET])
  132. return f
  133. else:
  134. def f(fmt, *args):
  135. return fmt % args
  136. return f
  137. def nofmt_colorer(self, opt=None, fg=None, bg=None, attr=None):
  138. if self._on:
  139. c = self._parse(opt, fg, bg, attr)
  140. def f(fmt):
  141. return ''.join([c, fmt, RESET])
  142. return f
  143. else:
  144. def f(fmt):
  145. return fmt
  146. return f
  147. def _parse(self, opt, fg, bg, attr):
  148. if not opt:
  149. return _Color(fg, bg, attr)
  150. v = self._config.GetString('%s.%s' % (self._section, opt))
  151. if v is None:
  152. return _Color(fg, bg, attr)
  153. v = v.strip().lower()
  154. if v == "reset":
  155. return RESET
  156. elif v == '':
  157. return _Color(fg, bg, attr)
  158. have_fg = False
  159. for a in v.split(' '):
  160. if is_color(a):
  161. if have_fg:
  162. bg = a
  163. else:
  164. fg = a
  165. elif is_attr(a):
  166. attr = a
  167. return _Color(fg, bg, attr)