blob: 5b3a282da02118645d6d3f7f165637bc110b71b3 [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
Mike Frysinger902665b2014-12-22 15:17:59 -050087DEFAULT = None
88
Anthony Kingbdf7ed22015-03-28 21:10:17 +000089
Mike Frysinger902665b2014-12-22 15:17:59 -050090def SetDefaultColoring(state):
91 """Set coloring behavior to |state|.
92
93 This is useful for overriding config options via the command line.
94 """
95 if state is None:
96 # Leave it alone -- return quick!
97 return
98
99 global DEFAULT
100 state = state.lower()
101 if state in ('auto',):
102 DEFAULT = state
103 elif state in ('always', 'yes', 'true', True):
104 DEFAULT = 'always'
105 elif state in ('never', 'no', 'false', False):
106 DEFAULT = 'never'
107
108
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700109class Coloring(object):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900110 def __init__(self, config, section_type):
111 self._section = 'color.%s' % section_type
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700112 self._config = config
113 self._out = sys.stdout
114
Mike Frysinger902665b2014-12-22 15:17:59 -0500115 on = DEFAULT
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700116 if on is None:
Mike Frysinger902665b2014-12-22 15:17:59 -0500117 on = self._config.GetString(self._section)
118 if on is None:
119 on = self._config.GetString('color.ui')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700120
121 if on == 'auto':
122 if pager.active or os.isatty(1):
123 self._on = True
124 else:
125 self._on = False
126 elif on in ('true', 'always'):
127 self._on = True
128 else:
129 self._on = False
130
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700131 def redirect(self, out):
132 self._out = out
133
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700134 @property
135 def is_on(self):
136 return self._on
137
138 def write(self, fmt, *args):
139 self._out.write(fmt % args)
140
Shawn O. Pearcedb45da12009-04-18 13:49:13 -0700141 def flush(self):
142 self._out.flush()
143
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700144 def nl(self):
145 self._out.write('\n')
146
147 def printer(self, opt=None, fg=None, bg=None, attr=None):
148 s = self
149 c = self.colorer(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000150
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700151 def f(fmt, *args):
152 s._out.write(c(fmt, *args))
153 return f
154
Olof Johanssonb7541502013-02-26 07:36:03 +0100155 def nofmt_printer(self, opt=None, fg=None, bg=None, attr=None):
156 s = self
157 c = self.nofmt_colorer(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000158
Olof Johanssonb7541502013-02-26 07:36:03 +0100159 def f(fmt):
160 s._out.write(c(fmt))
161 return f
162
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700163 def colorer(self, opt=None, fg=None, bg=None, attr=None):
164 if self._on:
165 c = self._parse(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000166
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700167 def f(fmt, *args):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900168 output = fmt % args
169 return ''.join([c, output, RESET])
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700170 return f
171 else:
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000172
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700173 def f(fmt, *args):
174 return fmt % args
175 return f
176
Olof Johanssonb7541502013-02-26 07:36:03 +0100177 def nofmt_colorer(self, opt=None, fg=None, bg=None, attr=None):
178 if self._on:
179 c = self._parse(opt, fg, bg, attr)
Anthony Kingbdf7ed22015-03-28 21:10:17 +0000180
Olof Johanssonb7541502013-02-26 07:36:03 +0100181 def f(fmt):
182 return ''.join([c, fmt, RESET])
183 return f
184 else:
185 def f(fmt):
186 return fmt
187 return f
188
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700189 def _parse(self, opt, fg, bg, attr):
190 if not opt:
191 return _Color(fg, bg, attr)
192
193 v = self._config.GetString('%s.%s' % (self._section, opt))
194 if v is None:
195 return _Color(fg, bg, attr)
196
Shawn O. Pearcea8e98a62009-02-02 16:17:02 -0800197 v = v.strip().lower()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700198 if v == "reset":
199 return RESET
200 elif v == '':
201 return _Color(fg, bg, attr)
202
203 have_fg = False
204 for a in v.split(' '):
205 if is_color(a):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900206 if have_fg:
207 bg = a
208 else:
209 fg = a
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700210 elif is_attr(a):
211 attr = a
212
213 return _Color(fg, bg, attr)