blob: 7970198a50fe0e4affc1c995d0ae02a0b921b095 [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001#
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
16import os
17import sys
18
19import pager
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070020
21COLORS = {None :-1,
22 'normal' :-1,
23 'black' : 0,
24 'red' : 1,
25 'green' : 2,
26 'yellow' : 3,
27 'blue' : 4,
28 'magenta': 5,
29 'cyan' : 6,
30 'white' : 7}
31
32ATTRS = {None :-1,
33 'bold' : 1,
34 'dim' : 2,
35 'ul' : 4,
36 'blink' : 5,
37 'reverse': 7}
38
David Pursehouse1d947b32012-10-25 12:23:11 +090039RESET = "\033[m" # pylint: disable=W1401
40 # backslash is not anomalous
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070041
David Pursehouse8a68ff92012-09-24 12:15:13 +090042def is_color(s):
David Pursehousec1b86a22012-11-14 11:36:51 +090043 return s in COLORS
David Pursehouse8a68ff92012-09-24 12:15:13 +090044
45def is_attr(s):
David Pursehousec1b86a22012-11-14 11:36:51 +090046 return s in ATTRS
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070047
48def _Color(fg = None, bg = None, attr = None):
David Pursehousec1b86a22012-11-14 11:36:51 +090049 fg = COLORS[fg]
50 bg = COLORS[bg]
51 attr = ATTRS[attr]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070052
David Pursehousec1b86a22012-11-14 11:36:51 +090053 if attr >= 0 or fg >= 0 or bg >= 0:
54 need_sep = False
55 code = "\033[" #pylint: disable=W1401
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070056
David Pursehousec1b86a22012-11-14 11:36:51 +090057 if attr >= 0:
58 code += chr(ord('0') + attr)
59 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070060
David Pursehousec1b86a22012-11-14 11:36:51 +090061 if fg >= 0:
62 if need_sep:
63 code += ';'
64 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070065
David Pursehousec1b86a22012-11-14 11:36:51 +090066 if fg < 8:
67 code += '3%c' % (ord('0') + fg)
68 else:
69 code += '38;5;%d' % fg
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070070
David Pursehousec1b86a22012-11-14 11:36:51 +090071 if bg >= 0:
72 if need_sep:
73 code += ';'
74 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070075
David Pursehousec1b86a22012-11-14 11:36:51 +090076 if bg < 8:
77 code += '4%c' % (ord('0') + bg)
78 else:
79 code += '48;5;%d' % bg
80 code += 'm'
81 else:
82 code = ''
83 return code
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070084
85
86class Coloring(object):
David Pursehouse8a68ff92012-09-24 12:15:13 +090087 def __init__(self, config, section_type):
88 self._section = 'color.%s' % section_type
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070089 self._config = config
90 self._out = sys.stdout
91
92 on = self._config.GetString(self._section)
93 if on is None:
94 on = self._config.GetString('color.ui')
95
96 if on == 'auto':
97 if pager.active or os.isatty(1):
98 self._on = True
99 else:
100 self._on = False
101 elif on in ('true', 'always'):
102 self._on = True
103 else:
104 self._on = False
105
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700106 def redirect(self, out):
107 self._out = out
108
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700109 @property
110 def is_on(self):
111 return self._on
112
113 def write(self, fmt, *args):
114 self._out.write(fmt % args)
115
Shawn O. Pearcedb45da12009-04-18 13:49:13 -0700116 def flush(self):
117 self._out.flush()
118
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700119 def nl(self):
120 self._out.write('\n')
121
122 def printer(self, opt=None, fg=None, bg=None, attr=None):
123 s = self
124 c = self.colorer(opt, fg, bg, attr)
125 def f(fmt, *args):
126 s._out.write(c(fmt, *args))
127 return f
128
Olof Johanssonb7541502013-02-26 07:36:03 +0100129 def nofmt_printer(self, opt=None, fg=None, bg=None, attr=None):
130 s = self
131 c = self.nofmt_colorer(opt, fg, bg, attr)
132 def f(fmt):
133 s._out.write(c(fmt))
134 return f
135
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700136 def colorer(self, opt=None, fg=None, bg=None, attr=None):
137 if self._on:
138 c = self._parse(opt, fg, bg, attr)
139 def f(fmt, *args):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900140 output = fmt % args
141 return ''.join([c, output, RESET])
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700142 return f
143 else:
144 def f(fmt, *args):
145 return fmt % args
146 return f
147
Olof Johanssonb7541502013-02-26 07:36:03 +0100148 def nofmt_colorer(self, opt=None, fg=None, bg=None, attr=None):
149 if self._on:
150 c = self._parse(opt, fg, bg, attr)
151 def f(fmt):
152 return ''.join([c, fmt, RESET])
153 return f
154 else:
155 def f(fmt):
156 return fmt
157 return f
158
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700159 def _parse(self, opt, fg, bg, attr):
160 if not opt:
161 return _Color(fg, bg, attr)
162
163 v = self._config.GetString('%s.%s' % (self._section, opt))
164 if v is None:
165 return _Color(fg, bg, attr)
166
Shawn O. Pearcea8e98a62009-02-02 16:17:02 -0800167 v = v.strip().lower()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700168 if v == "reset":
169 return RESET
170 elif v == '':
171 return _Color(fg, bg, attr)
172
173 have_fg = False
174 for a in v.split(' '):
175 if is_color(a):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900176 if have_fg:
177 bg = a
178 else:
179 fg = a
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700180 elif is_attr(a):
181 attr = a
182
183 return _Color(fg, bg, attr)