color.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. from git_config import GitConfig
  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): return s in COLORS
  37. def is_attr(s): return s in ATTRS
  38. def _Color(fg = None, bg = None, attr = None):
  39. fg = COLORS[fg]
  40. bg = COLORS[bg]
  41. attr = ATTRS[attr]
  42. if attr >= 0 or fg >= 0 or bg >= 0:
  43. need_sep = False
  44. code = "\033["
  45. if attr >= 0:
  46. code += chr(ord('0') + attr)
  47. need_sep = True
  48. if fg >= 0:
  49. if need_sep:
  50. code += ';'
  51. need_sep = True
  52. if fg < 8:
  53. code += '3%c' % (ord('0') + fg)
  54. else:
  55. code += '38;5;%d' % fg
  56. if bg >= 0:
  57. if need_sep:
  58. code += ';'
  59. need_sep = True
  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. class Coloring(object):
  69. def __init__(self, config, type):
  70. self._section = 'color.%s' % type
  71. self._config = config
  72. self._out = sys.stdout
  73. on = self._config.GetString(self._section)
  74. if on is None:
  75. on = self._config.GetString('color.ui')
  76. if on == 'auto':
  77. if pager.active or os.isatty(1):
  78. self._on = True
  79. else:
  80. self._on = False
  81. elif on in ('true', 'always'):
  82. self._on = True
  83. else:
  84. self._on = False
  85. @property
  86. def is_on(self):
  87. return self._on
  88. def write(self, fmt, *args):
  89. self._out.write(fmt % args)
  90. def nl(self):
  91. self._out.write('\n')
  92. def printer(self, opt=None, fg=None, bg=None, attr=None):
  93. s = self
  94. c = self.colorer(opt, fg, bg, attr)
  95. def f(fmt, *args):
  96. s._out.write(c(fmt, *args))
  97. return f
  98. def colorer(self, opt=None, fg=None, bg=None, attr=None):
  99. if self._on:
  100. c = self._parse(opt, fg, bg, attr)
  101. def f(fmt, *args):
  102. str = fmt % args
  103. return ''.join([c, str, RESET])
  104. return f
  105. else:
  106. def f(fmt, *args):
  107. return fmt % args
  108. return f
  109. def _parse(self, opt, fg, bg, attr):
  110. if not opt:
  111. return _Color(fg, bg, attr)
  112. v = self._config.GetString('%s.%s' % (self._section, opt))
  113. if v is None:
  114. return _Color(fg, bg, attr)
  115. v = v.strip().lower()
  116. if v == "reset":
  117. return RESET
  118. elif v == '':
  119. return _Color(fg, bg, attr)
  120. have_fg = False
  121. for a in v.split(' '):
  122. if is_color(a):
  123. if have_fg: bg = a
  124. else: fg = a
  125. elif is_attr(a):
  126. attr = a
  127. return _Color(fg, bg, attr)