blob: fdd7253422b12d9b35c83de1a47fe22e116d5d26 [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001# Copyright (C) 2008 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import os
16import sys
17
18import pager
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070019
Anthony Kingbdf7ed22015-03-28 21:10:17 +000020COLORS = {None: -1,
21 'normal': -1,
22 'black': 0,
23 'red': 1,
24 'green': 2,
25 'yellow': 3,
26 'blue': 4,
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070027 'magenta': 5,
Anthony Kingbdf7ed22015-03-28 21:10:17 +000028 'cyan': 6,
29 'white': 7}
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070030
Anthony Kingbdf7ed22015-03-28 21:10:17 +000031ATTRS = {None: -1,
32 'bold': 1,
33 'dim': 2,
34 'ul': 4,
35 'blink': 5,
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070036 'reverse': 7}
37
Anthony Kingbdf7ed22015-03-28 21:10:17 +000038RESET = "\033[m"
39
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070040
David Pursehouse8a68ff92012-09-24 12:15:13 +090041def is_color(s):
David Pursehousec1b86a22012-11-14 11:36:51 +090042 return s in COLORS
David Pursehouse8a68ff92012-09-24 12:15:13 +090043
Anthony Kingbdf7ed22015-03-28 21:10:17 +000044
David Pursehouse8a68ff92012-09-24 12:15:13 +090045def 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
Anthony Kingbdf7ed22015-03-28 21:10:17 +000048
49def _Color(fg=None, bg=None, attr=None):
David Pursehousec1b86a22012-11-14 11:36:51 +090050 fg = COLORS[fg]
51 bg = COLORS[bg]
52 attr = ATTRS[attr]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070053
David Pursehousec1b86a22012-11-14 11:36:51 +090054 if attr >= 0 or fg >= 0 or bg >= 0:
55 need_sep = False
Anthony Kingbdf7ed22015-03-28 21:10:17 +000056 code = "\033["
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070057
David Pursehousec1b86a22012-11-14 11:36:51 +090058 if attr >= 0:
59 code += chr(ord('0') + attr)
60 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070061
David Pursehousec1b86a22012-11-14 11:36:51 +090062 if fg >= 0:
63 if need_sep:
64 code += ';'
65 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070066
David Pursehousec1b86a22012-11-14 11:36:51 +090067 if fg < 8:
68 code += '3%c' % (ord('0') + fg)
69 else:
70 code += '38;5;%d' % fg
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070071
David Pursehousec1b86a22012-11-14 11:36:51 +090072 if bg >= 0:
73 if need_sep:
74 code += ';'
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
David Pursehouse819827a2020-02-12 15:20:19 +090085
Mike Frysinger902665b2014-12-22 15:17:59 -050086DEFAULT = None
87
Anthony Kingbdf7ed22015-03-28 21:10:17 +000088
Mike Frysinger902665b2014-12-22 15:17:59 -050089def SetDefaultColoring(state):
90 """Set coloring behavior to |state|.
91
92 This is useful for overriding config options via the command line.
93 """
94 if state is None:
95 # Leave it alone -- return quick!
96 return
97
98 global DEFAULT
99 state = state.lower()
100 if state in ('auto',):
101 DEFAULT = state
102 elif state in ('always', 'yes', 'true', True):
103 DEFAULT = 'always'
104 elif state in ('never', 'no', 'false', False):
105 DEFAULT = 'never'
106
107
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700108class Coloring(object):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900109 def __init__(self, config, section_type):
110 self._section = 'color.%s' % section_type
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700111 self._config = config
112 self._out = sys.stdout
113
Mike Frysinger902665b2014-12-22 15:17:59 -0500114 on = DEFAULT
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700115 if on is None:
Mike Frysinger902665b2014-12-22 15:17:59 -0500116 on = self._config.GetString(self._section)
117 if on is None:
118 on = self._config.GetString('color.ui')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700119
120 if on == 'auto':
121 if pager.active or os.isatty(1):
122 self._on = True
123 else:
124 self._on = False
125 elif on in ('true', 'always'):
126 self._on = True
127 else:
128 self._on = False
129
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700130 def redirect(self, out):
131 self._out = out
132
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700133 @property
134 def is_on(self):
135 return self._on
136
137 def write(self, fmt, *args):
138 self._out.write(fmt % args)
139
Shawn O. Pearcedb45da12009-04-18 13:49:13 -0700140 def flush(self):
141 self._out.flush()
142
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700143 def nl(self):
144 self._out.write('\n')
145
146 def printer(self, opt=None, fg=None, bg=None, attr=None):
147 s = self
148 c = self.colorer(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000149
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700150 def f(fmt, *args):
151 s._out.write(c(fmt, *args))
152 return f
153
Olof Johanssonb7541502013-02-26 07:36:03 +0100154 def nofmt_printer(self, opt=None, fg=None, bg=None, attr=None):
155 s = self
156 c = self.nofmt_colorer(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000157
Olof Johanssonb7541502013-02-26 07:36:03 +0100158 def f(fmt):
159 s._out.write(c(fmt))
160 return f
161
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700162 def colorer(self, opt=None, fg=None, bg=None, attr=None):
163 if self._on:
164 c = self._parse(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000165
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700166 def f(fmt, *args):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900167 output = fmt % args
168 return ''.join([c, output, RESET])
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700169 return f
170 else:
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000171
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700172 def f(fmt, *args):
173 return fmt % args
174 return f
175
Olof Johanssonb7541502013-02-26 07:36:03 +0100176 def nofmt_colorer(self, opt=None, fg=None, bg=None, attr=None):
177 if self._on:
178 c = self._parse(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000179
Olof Johanssonb7541502013-02-26 07:36:03 +0100180 def f(fmt):
181 return ''.join([c, fmt, RESET])
182 return f
183 else:
184 def f(fmt):
185 return fmt
186 return f
187
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700188 def _parse(self, opt, fg, bg, attr):
189 if not opt:
190 return _Color(fg, bg, attr)
191
192 v = self._config.GetString('%s.%s' % (self._section, opt))
193 if v is None:
194 return _Color(fg, bg, attr)
195
Shawn O. Pearcea8e98a62009-02-02 16:17:02 -0800196 v = v.strip().lower()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700197 if v == "reset":
198 return RESET
199 elif v == '':
200 return _Color(fg, bg, attr)
201
202 have_fg = False
203 for a in v.split(' '):
204 if is_color(a):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900205 if have_fg:
206 bg = a
207 else:
208 fg = a
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700209 elif is_attr(a):
210 attr = a
211
212 return _Color(fg, bg, attr)