blob: 8f29b59f6a3768dcea0b7475ab6eadd7fe0f2cb4 [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
Gavin Makea2e3302023-03-11 06:46:20 +000020COLORS = {
21 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}
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070032
Gavin Makea2e3302023-03-11 06:46:20 +000033ATTRS = {None: -1, "bold": 1, "dim": 2, "ul": 4, "blink": 5, "reverse": 7}
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070034
Anthony Kingbdf7ed22015-03-28 21:10:17 +000035RESET = "\033[m"
36
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070037
David Pursehouse8a68ff92012-09-24 12:15:13 +090038def is_color(s):
Gavin Makea2e3302023-03-11 06:46:20 +000039 return s in COLORS
David Pursehouse8a68ff92012-09-24 12:15:13 +090040
Anthony Kingbdf7ed22015-03-28 21:10:17 +000041
David Pursehouse8a68ff92012-09-24 12:15:13 +090042def is_attr(s):
Gavin Makea2e3302023-03-11 06:46:20 +000043 return s in ATTRS
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070044
Anthony Kingbdf7ed22015-03-28 21:10:17 +000045
46def _Color(fg=None, bg=None, attr=None):
Gavin Makea2e3302023-03-11 06:46:20 +000047 fg = COLORS[fg]
48 bg = COLORS[bg]
49 attr = ATTRS[attr]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070050
Gavin Makea2e3302023-03-11 06:46:20 +000051 if attr >= 0 or fg >= 0 or bg >= 0:
52 need_sep = False
53 code = "\033["
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070054
Gavin Makea2e3302023-03-11 06:46:20 +000055 if attr >= 0:
56 code += chr(ord("0") + attr)
57 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070058
Gavin Makea2e3302023-03-11 06:46:20 +000059 if fg >= 0:
60 if need_sep:
61 code += ";"
62 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070063
Gavin Makea2e3302023-03-11 06:46:20 +000064 if fg < 8:
65 code += "3%c" % (ord("0") + fg)
66 else:
67 code += "38;5;%d" % fg
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070068
Gavin Makea2e3302023-03-11 06:46:20 +000069 if bg >= 0:
70 if need_sep:
71 code += ";"
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070072
Gavin Makea2e3302023-03-11 06:46:20 +000073 if bg < 8:
74 code += "4%c" % (ord("0") + bg)
75 else:
76 code += "48;5;%d" % bg
77 code += "m"
78 else:
79 code = ""
80 return code
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070081
David Pursehouse819827a2020-02-12 15:20:19 +090082
Mike Frysinger902665b2014-12-22 15:17:59 -050083DEFAULT = None
84
Anthony Kingbdf7ed22015-03-28 21:10:17 +000085
Mike Frysinger902665b2014-12-22 15:17:59 -050086def SetDefaultColoring(state):
Gavin Makea2e3302023-03-11 06:46:20 +000087 """Set coloring behavior to |state|.
Mike Frysinger902665b2014-12-22 15:17:59 -050088
Gavin Makea2e3302023-03-11 06:46:20 +000089 This is useful for overriding config options via the command line.
90 """
91 if state is None:
92 # Leave it alone -- return quick!
93 return
Mike Frysinger902665b2014-12-22 15:17:59 -050094
Gavin Makea2e3302023-03-11 06:46:20 +000095 global DEFAULT
96 state = state.lower()
97 if state in ("auto",):
98 DEFAULT = state
99 elif state in ("always", "yes", "true", True):
100 DEFAULT = "always"
101 elif state in ("never", "no", "false", False):
102 DEFAULT = "never"
Mike Frysinger902665b2014-12-22 15:17:59 -0500103
104
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700105class Coloring(object):
Gavin Makea2e3302023-03-11 06:46:20 +0000106 def __init__(self, config, section_type):
107 self._section = "color.%s" % section_type
108 self._config = config
109 self._out = sys.stdout
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700110
Gavin Makea2e3302023-03-11 06:46:20 +0000111 on = DEFAULT
112 if on is None:
113 on = self._config.GetString(self._section)
114 if on is None:
115 on = self._config.GetString("color.ui")
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700116
Gavin Makea2e3302023-03-11 06:46:20 +0000117 if on == "auto":
118 if pager.active or os.isatty(1):
119 self._on = True
120 else:
121 self._on = False
122 elif on in ("true", "always"):
123 self._on = True
David Pursehouse8a68ff92012-09-24 12:15:13 +0900124 else:
Gavin Makea2e3302023-03-11 06:46:20 +0000125 self._on = False
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700126
Gavin Makea2e3302023-03-11 06:46:20 +0000127 def redirect(self, out):
128 self._out = out
129
130 @property
131 def is_on(self):
132 return self._on
133
134 def write(self, fmt, *args):
135 self._out.write(fmt % args)
136
137 def flush(self):
138 self._out.flush()
139
140 def nl(self):
141 self._out.write("\n")
142
143 def printer(self, opt=None, fg=None, bg=None, attr=None):
144 s = self
145 c = self.colorer(opt, fg, bg, attr)
146
147 def f(fmt, *args):
148 s._out.write(c(fmt, *args))
149
150 return f
151
152 def nofmt_printer(self, opt=None, fg=None, bg=None, attr=None):
153 s = self
154 c = self.nofmt_colorer(opt, fg, bg, attr)
155
156 def f(fmt):
157 s._out.write(c(fmt))
158
159 return f
160
161 def colorer(self, opt=None, fg=None, bg=None, attr=None):
162 if self._on:
163 c = self._parse(opt, fg, bg, attr)
164
165 def f(fmt, *args):
166 output = fmt % args
167 return "".join([c, output, RESET])
168
169 return f
170 else:
171
172 def f(fmt, *args):
173 return fmt % args
174
175 return f
176
177 def nofmt_colorer(self, opt=None, fg=None, bg=None, attr=None):
178 if self._on:
179 c = self._parse(opt, fg, bg, attr)
180
181 def f(fmt):
182 return "".join([c, fmt, RESET])
183
184 return f
185 else:
186
187 def f(fmt):
188 return fmt
189
190 return f
191
192 def _parse(self, opt, fg, bg, attr):
193 if not opt:
194 return _Color(fg, bg, attr)
195
196 v = self._config.GetString("%s.%s" % (self._section, opt))
197 if v is None:
198 return _Color(fg, bg, attr)
199
200 v = v.strip().lower()
201 if v == "reset":
202 return RESET
203 elif v == "":
204 return _Color(fg, bg, attr)
205
206 have_fg = False
207 for a in v.split(" "):
208 if is_color(a):
209 if have_fg:
210 bg = a
211 else:
212 fg = a
213 elif is_attr(a):
214 attr = a
215
216 return _Color(fg, bg, attr)