color.py 4.4 KB

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