blob: 7df202235566523887325dc6419dbf7864819acb [file] [log] [blame]
Mike Frysingerf6013762019-06-13 02:30:51 -04001# -*- coding:utf-8 -*-
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07002#
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
17import os
18import sys
19
20import pager
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070021
Anthony Kingbdf7ed22015-03-28 21:10:17 +000022COLORS = {None: -1,
23 'normal': -1,
24 'black': 0,
25 'red': 1,
26 'green': 2,
27 'yellow': 3,
28 'blue': 4,
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070029 'magenta': 5,
Anthony Kingbdf7ed22015-03-28 21:10:17 +000030 'cyan': 6,
31 'white': 7}
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070032
Anthony Kingbdf7ed22015-03-28 21:10:17 +000033ATTRS = {None: -1,
34 'bold': 1,
35 'dim': 2,
36 'ul': 4,
37 'blink': 5,
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070038 'reverse': 7}
39
Anthony Kingbdf7ed22015-03-28 21:10:17 +000040RESET = "\033[m"
41
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070042
David Pursehouse8a68ff92012-09-24 12:15:13 +090043def is_color(s):
David Pursehousec1b86a22012-11-14 11:36:51 +090044 return s in COLORS
David Pursehouse8a68ff92012-09-24 12:15:13 +090045
Anthony Kingbdf7ed22015-03-28 21:10:17 +000046
David Pursehouse8a68ff92012-09-24 12:15:13 +090047def is_attr(s):
David Pursehousec1b86a22012-11-14 11:36:51 +090048 return s in ATTRS
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070049
Anthony Kingbdf7ed22015-03-28 21:10:17 +000050
51def _Color(fg=None, bg=None, attr=None):
David Pursehousec1b86a22012-11-14 11:36:51 +090052 fg = COLORS[fg]
53 bg = COLORS[bg]
54 attr = ATTRS[attr]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070055
David Pursehousec1b86a22012-11-14 11:36:51 +090056 if attr >= 0 or fg >= 0 or bg >= 0:
57 need_sep = False
Anthony Kingbdf7ed22015-03-28 21:10:17 +000058 code = "\033["
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070059
David Pursehousec1b86a22012-11-14 11:36:51 +090060 if attr >= 0:
61 code += chr(ord('0') + attr)
62 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070063
David Pursehousec1b86a22012-11-14 11:36:51 +090064 if fg >= 0:
65 if need_sep:
66 code += ';'
67 need_sep = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070068
David Pursehousec1b86a22012-11-14 11:36:51 +090069 if fg < 8:
70 code += '3%c' % (ord('0') + fg)
71 else:
72 code += '38;5;%d' % fg
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070073
David Pursehousec1b86a22012-11-14 11:36:51 +090074 if bg >= 0:
75 if need_sep:
76 code += ';'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070077
David Pursehousec1b86a22012-11-14 11:36:51 +090078 if bg < 8:
79 code += '4%c' % (ord('0') + bg)
80 else:
81 code += '48;5;%d' % bg
82 code += 'm'
83 else:
84 code = ''
85 return code
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070086
David Pursehouse819827a2020-02-12 15:20:19 +090087
Mike Frysinger902665b2014-12-22 15:17:59 -050088DEFAULT = None
89
Anthony Kingbdf7ed22015-03-28 21:10:17 +000090
Mike Frysinger902665b2014-12-22 15:17:59 -050091def SetDefaultColoring(state):
92 """Set coloring behavior to |state|.
93
94 This is useful for overriding config options via the command line.
95 """
96 if state is None:
97 # Leave it alone -- return quick!
98 return
99
100 global DEFAULT
101 state = state.lower()
102 if state in ('auto',):
103 DEFAULT = state
104 elif state in ('always', 'yes', 'true', True):
105 DEFAULT = 'always'
106 elif state in ('never', 'no', 'false', False):
107 DEFAULT = 'never'
108
109
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700110class Coloring(object):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900111 def __init__(self, config, section_type):
112 self._section = 'color.%s' % section_type
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700113 self._config = config
114 self._out = sys.stdout
115
Mike Frysinger902665b2014-12-22 15:17:59 -0500116 on = DEFAULT
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700117 if on is None:
Mike Frysinger902665b2014-12-22 15:17:59 -0500118 on = self._config.GetString(self._section)
119 if on is None:
120 on = self._config.GetString('color.ui')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700121
122 if on == 'auto':
123 if pager.active or os.isatty(1):
124 self._on = True
125 else:
126 self._on = False
127 elif on in ('true', 'always'):
128 self._on = True
129 else:
130 self._on = False
131
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700132 def redirect(self, out):
133 self._out = out
134
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700135 @property
136 def is_on(self):
137 return self._on
138
139 def write(self, fmt, *args):
140 self._out.write(fmt % args)
141
Shawn O. Pearcedb45da12009-04-18 13:49:13 -0700142 def flush(self):
143 self._out.flush()
144
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700145 def nl(self):
146 self._out.write('\n')
147
148 def printer(self, opt=None, fg=None, bg=None, attr=None):
149 s = self
150 c = self.colorer(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000151
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700152 def f(fmt, *args):
153 s._out.write(c(fmt, *args))
154 return f
155
Olof Johanssonb7541502013-02-26 07:36:03 +0100156 def nofmt_printer(self, opt=None, fg=None, bg=None, attr=None):
157 s = self
158 c = self.nofmt_colorer(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000159
Olof Johanssonb7541502013-02-26 07:36:03 +0100160 def f(fmt):
161 s._out.write(c(fmt))
162 return f
163
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700164 def colorer(self, opt=None, fg=None, bg=None, attr=None):
165 if self._on:
166 c = self._parse(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000167
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700168 def f(fmt, *args):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900169 output = fmt % args
170 return ''.join([c, output, RESET])
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700171 return f
172 else:
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000173
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700174 def f(fmt, *args):
175 return fmt % args
176 return f
177
Olof Johanssonb7541502013-02-26 07:36:03 +0100178 def nofmt_colorer(self, opt=None, fg=None, bg=None, attr=None):
179 if self._on:
180 c = self._parse(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000181
Olof Johanssonb7541502013-02-26 07:36:03 +0100182 def f(fmt):
183 return ''.join([c, fmt, RESET])
184 return f
185 else:
186 def f(fmt):
187 return fmt
188 return f
189
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700190 def _parse(self, opt, fg, bg, attr):
191 if not opt:
192 return _Color(fg, bg, attr)
193
194 v = self._config.GetString('%s.%s' % (self._section, opt))
195 if v is None:
196 return _Color(fg, bg, attr)
197
Shawn O. Pearcea8e98a62009-02-02 16:17:02 -0800198 v = v.strip().lower()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700199 if v == "reset":
200 return RESET
201 elif v == '':
202 return _Color(fg, bg, attr)
203
204 have_fg = False
205 for a in v.split(' '):
206 if is_color(a):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900207 if have_fg:
208 bg = a
209 else:
210 fg = a
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700211 elif is_attr(a):
212 attr = a
213
214 return _Color(fg, bg, attr)