libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
print_color.py
Go to the documentation of this file.
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import sys
5import os
6import ctypes
7import platform
8import re
9
10console_encoding = sys.getfilesystemencoding()
11
12
14 version = "1.0.2.0"
15 engine = None
16 theme = None
17
18 FC_BLACK = 0
19 FC_BLUE = 1
20 FC_GREEN = 2
21 FC_CYAN = 3
22 FC_RED = 4
23 FC_MAGENTA = 5
24 FC_YELLOW = 6
25 FC_WHITE = 7
26
27 BC_BLACK = 8
28 BC_BLUE = 9
29 BC_GREEN = 10
30 BC_CYAN = 11
31 BC_RED = 12
32 BC_MAGENTA = 13
33 BC_YELLOW = 14
34 BC_WHITE = 15
35
36 FW_BOLD = 16
37
38 def __contains__(self, value):
39 return False
40
41
42"""
43See https://msdn.microsoft.com/zh-cn/windows/apps/ms682088%28v=vs.100%29#_win32_character_attributes
44 for color codes
45"""
46
47
49 name = "windows console"
50 STD_INPUT_HANDLE = -10
51 STD_OUTPUT_HANDLE = -11
52 STD_ERROR_HANDLE = -12
53
54 FOREGROUND_BLACK = 0x0
55 FOREGROUND_BLUE = 0x01 # text color contains blue.
56 FOREGROUND_GREEN = 0x02 # text color contains green.
57 FOREGROUND_RED = 0x04 # text color contains red.
58 FOREGROUND_INTENSITY = 0x08 # text color is intensified.
59
60 BACKGROUND_BLUE = 0x10 # background color contains blue.
61 BACKGROUND_GREEN = 0x20 # background color contains green.
62 BACKGROUND_RED = 0x40 # background color contains red.
63 BACKGROUND_INTENSITY = 0x80 # background color is intensified.
64
65 COLOR_MAP = {
66 print_style.FC_BLACK: FOREGROUND_BLACK,
67 print_style.FC_BLUE: FOREGROUND_BLUE | FOREGROUND_INTENSITY,
68 print_style.FC_GREEN: FOREGROUND_GREEN | FOREGROUND_INTENSITY,
69 print_style.FC_CYAN:
70 FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
71 print_style.FC_RED: FOREGROUND_RED | FOREGROUND_INTENSITY,
72 print_style.FC_MAGENTA:
73 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
74 print_style.FC_YELLOW:
75 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
76 print_style.FC_WHITE:
77 FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED,
78 print_style.BC_BLACK: FOREGROUND_BLACK,
79 print_style.BC_BLUE: BACKGROUND_BLUE,
80 print_style.BC_GREEN: BACKGROUND_GREEN,
81 print_style.BC_CYAN: BACKGROUND_BLUE | BACKGROUND_GREEN,
82 print_style.BC_RED: BACKGROUND_RED,
83 print_style.BC_MAGENTA: BACKGROUND_RED | BACKGROUND_BLUE,
84 print_style.BC_YELLOW: BACKGROUND_RED | BACKGROUND_GREEN,
85 print_style.BC_WHITE:
86 BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
87 print_style.FW_BOLD: BACKGROUND_INTENSITY,
88 }
89
90 std_out_handle = None
91 std_err_handle = None
92
93 def get_cmd_color(self, handle=std_out_handle):
94 return (Win32ConsoleColor.FOREGROUND_RED
95 | Win32ConsoleColor.FOREGROUND_GREEN
96 | Win32ConsoleColor.FOREGROUND_BLUE)
97
98 def set_cmd_color(self, color, handle=std_out_handle):
99 """(color) -> bit
100 Example: set_cmd_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)
101 """
102 bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
103 return bool
104
105 def stdout_with_color(self, options, text):
106 style = Win32ConsoleColor.FOREGROUND_BLACK
107 for opt in options:
108 style = style | Win32ConsoleColor.COLOR_MAP[opt]
109 if style == Win32ConsoleColor.FOREGROUND_BLACK:
110 sys.stdout.write(text)
111 else:
112 old_style = self.get_cmd_color()
113 self.set_cmd_color(style, self.std_out_handle)
114 sys.stdout.write(text)
115 self.set_cmd_color(old_style, self.std_out_handle)
116
117 def stderr_with_color(self, options, text):
118 style = Win32ConsoleColor.FOREGROUND_BLACK
119 for opt in options:
120 style = style | Win32ConsoleColor.COLOR_MAP[opt]
121 if style == Win32ConsoleColor.FOREGROUND_BLACK:
122 sys.stderr.write(text)
123 else:
124 old_style = self.get_cmd_color()
125 self.set_cmd_color(style, self.std_err_handle)
126 sys.stderr.write(text)
127 self.set_cmd_color(old_style, self.std_err_handle)
128
129
131 name = "terminal"
132 COLOR_MAP = {
133 print_style.FC_BLACK: "30",
134 print_style.FC_BLUE: "34",
135 print_style.FC_GREEN: "32",
136 print_style.FC_CYAN: "36",
137 print_style.FC_RED: "31",
138 print_style.FC_MAGENTA: "35",
139 print_style.FC_YELLOW: "33",
140 print_style.FC_WHITE: "37",
141 print_style.BC_BLACK: "40",
142 print_style.BC_BLUE: "44",
143 print_style.BC_GREEN: "42",
144 print_style.BC_CYAN: "46",
145 print_style.BC_RED: "41",
146 print_style.BC_MAGENTA: "45",
147 print_style.BC_YELLOW: "43",
148 print_style.BC_WHITE: "47",
149 print_style.FW_BOLD: "1",
150 }
151
152 def stdout_with_color(self, options, text):
153 style = []
154 for opt in options:
155 style.append(TermColor.COLOR_MAP[opt])
156
157 if len(style) > 0:
158 sys.stdout.write("\033[" + ";".join(style) + "m" + text +
159 "\033[0m")
160 else:
161 sys.stdout.write(text)
162
163 def stderr_with_color(self, options, text):
164 style = []
165 for opt in options:
166 style.append(TermColor.COLOR_MAP[opt])
167
168 if len(style) > 0:
169 sys.stderr.write("\033[" + ";".join(style) + "m" + text +
170 "\033[0m")
171 else:
172 sys.stderr.write(text)
173
174
176 name = "html css"
177 COLOR_MAP = {
178 print_style.FC_BLACK: "color: {0}Black;",
179 print_style.FC_BLUE: "color: {0}Blue;",
180 print_style.FC_GREEN: "color: {0}Green;",
181 print_style.FC_CYAN: "color: {0}Cyan;",
182 print_style.FC_RED: "color: {0}Red;",
183 print_style.FC_MAGENTA: "color: {0}Magenta;",
184 print_style.FC_YELLOW: "color: {0}Yellow;",
185 print_style.FC_WHITE: "color: {0}White;",
186 print_style.BC_BLACK: "background-color: {0}Black;",
187 print_style.BC_BLUE: "background-color: {0}Blue;",
188 print_style.BC_GREEN: "background-color: {0}Green;",
189 print_style.BC_CYAN: "background-color: {0}Cyan;",
190 print_style.BC_RED: "background-color: {0}Red;",
191 print_style.BC_MAGENTA: "background-color: {0}Magenta;",
192 print_style.BC_YELLOW: "background-color: {0}Yellow;",
193 print_style.BC_WHITE: "background-color: {0}White;",
194 print_style.FW_BOLD: "font-weight: bold;",
195 }
196
197 def stdout_with_color(self, options, text):
198 style = []
199 for opt in options:
200 if print_style.theme:
201 style.append(
202 HtmlColor.COLOR_MAP[opt].format(print_style.theme + "-"))
203 else:
204 style.append(HtmlColor.COLOR_MAP[opt].format(""))
205
206 if len(style) > 0:
207 sys.stdout.write('<span style="' + " ".join(style) + '">' +
208 text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;') + "</span>")
209 else:
210 sys.stdout.write(text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;'))
211
212 def stderr_with_color(self, options, text):
213 style = []
214 for opt in options:
215 if print_style.theme:
216 style.append(
217 HtmlColor.COLOR_MAP[opt].format(print_style.theme + "-"))
218 else:
219 style.append(HtmlColor.COLOR_MAP[opt].format(""))
220
221 if len(style) > 0:
222 sys.stderr.write('<span style="' + " ".join(style) + '">' +
223 text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;') + "</span>")
224 else:
225 sys.stderr.write(text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;'))
226
227
229 name = "none"
230
231 def stdout_with_color(self, options, text):
232 sys.stdout.write(text)
233
234 def stderr_with_color(self, options, text):
235 sys.stderr.write(text)
236
237
239 # set by environment variable
240 if os.getenv("CPRINTF_MODE"):
241 return os.getenv("CPRINTF_MODE")
242 term_name = os.getenv("TERM")
243 if not term_name:
244 term_name = ""
245 if "dump" == term_name:
246 return "none"
247 if re.search('-256(color)?$', term_name, re.IGNORECASE):
248 return "term"
249 if re.search('^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux',
250 term_name, re.IGNORECASE):
251 return "term"
252 if os.getenv("COLORTERM"):
253 return "term"
254 if os.getenv("TF_BUILD") and os.getenv("AGENT_NAME"):
255 return "term"
256 if os.getenv("CI"):
257 for known_ci in [
258 'TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI',
259 'GITHUB_ACTIONS', 'BUILDKITE', 'DRONE'
260 ]:
261 if os.getenv(known_ci):
262 return "term"
263 ci_name = os.getenv("CI_NAME")
264 if ci_name and ci_name.lower() == "codeship":
265 return "term"
266 return "none"
267 if os.getenv("TEAMCITY_VERSION"):
268 return "term"
269 if os.getenv("TERM_PROGRAM"):
270 if re.search('(iTerm.app|Apple_Terminal)', os.getenv("TERM_PROGRAM"),
271 re.IGNORECASE):
272 return "term"
273
274 if "windows" == platform.system().lower():
275 ostype_name = os.getenv("OSTYPE")
276 if ostype_name:
277 ostype_name = ostype_name.lower()
278 if "msys" == ostype_name or "cygwin" == ostype_name:
279 return "none"
280 return "win32_console"
281 return "none"
282
283
284def cprintf_set_mode(mode_name="auto"):
285 mode_name = mode_name.lower()
286 if not mode_name or mode_name == "auto":
288
289 elif mode_name == "none":
290 print_style.engine = NoneColor
291
292 elif mode_name == "term":
293 print_style.engine = TermColor
294
295 elif mode_name == "win32_console":
296 """
297 See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winprog/winprog/windows_api_reference.asp
298 for information on Windows APIs.
299 """
300 Win32ConsoleColor.std_out_handle = ctypes.windll.kernel32.GetStdHandle(
301 Win32ConsoleColor.STD_OUTPUT_HANDLE)
302 Win32ConsoleColor.std_err_handle = ctypes.windll.kernel32.GetStdHandle(
303 Win32ConsoleColor.STD_ERROR_HANDLE)
304
305 print_style.engine = Win32ConsoleColor
306
307 elif mode_name == "html":
308 print_style.engine = HtmlColor
309
310 else:
311 print_style.engine = NoneColor
312
313
314def cprintf_set_theme(theme_name=None):
315 if theme_name is None:
316 if not os.getenv("CPRINTF_THEME") is None:
317 cprintf_set_theme(os.getenv("CPRINTF_THEME"))
318 else:
319 print_style.theme = theme_name
320
321
322def cprintf_unpack_text(fmt, text):
323 if len(text) > 0:
324 try:
325 ret = fmt.format(*text)
326 return ret
327 except TypeError:
328 ret = fmt.decode("utf-8").encode(console_encoding).format(*text)
329 return ret
330 except EnvironmentError:
331 ret = fmt.decode("utf-8").encode(console_encoding).format(*text)
332 return ret
333 else:
334 return fmt
335
336
337def cprintf_stdout(options, fmt, *text):
338 cp = print_style.engine()
339 cp.stdout_with_color(options, cprintf_unpack_text(fmt, text))
340 sys.stdout.flush()
341
342
343def cprintf_stderr(options, fmt, *text):
344 cp = print_style.engine()
345 cp.stderr_with_color(options, cprintf_unpack_text(fmt, text))
346 sys.stderr.flush()
347
348
349cprintf_set_mode("auto")
350""" run as a executable """
351if __name__ == "__main__":
352 from optparse import OptionParser
353
354 usage = "usage: %prog [options...] <format message> [format parameters...]"
355 parser = OptionParser(usage)
356 parser.disable_interspersed_args()
357
358 parser.add_option(
359 "-v",
360 "--version",
361 action="store_true",
362 help="show version and exit",
363 dest="version",
364 )
365 parser.add_option(
366 "-c",
367 "--color",
368 action="append",
369 help=
370 "set font color.(any of: black, blue, green, cyan, red, magenta, yellow, white)",
371 metavar="<color>",
372 dest="color",
373 )
374 parser.add_option(
375 "-b",
376 "--background-color",
377 action="append",
378 help=
379 "set background color.(any of: black, blue, green, cyan, red, magenta, yellow, white)",
380 metavar="<background color>",
381 dest="background_color",
382 )
383 parser.add_option(
384 "-B",
385 "--bold",
386 action="append_const",
387 help="set font weight to bold",
388 const=print_style.FW_BOLD,
389 dest="style",
390 )
391 parser.add_option(
392 "-m",
393 "--mode",
394 action="store",
395 help="set mode.(any of: auto, term, win32_console, none, html)",
396 metavar="<output mode>",
397 dest="mode",
398 )
399 parser.add_option(
400 "-s",
401 "--output-stream",
402 action="store",
403 help="set output stream.(any of: stdout, stderr)",
404 metavar="<ostream>",
405 dest="ostream",
406 default="stdout",
407 )
408 parser.add_option(
409 "-e",
410 action="store_true",
411 help=
412 "enable interpretation of backslash escapes(just like echo command in unix like system)",
413 dest="interp_bse",
414 default=False,
415 )
416 parser.add_option(
417 "-E",
418 action="store_false",
419 help=
420 "disable interpretation of backslash escapes(just like echo command in unix like system)",
421 dest="interp_bse",
422 )
423 parser.add_option(
424 "-t",
425 "--theme",
426 action="store",
427 help="set theme in html mode(light or dark)",
428 metavar="<theme>",
429 dest="theme",
430 default=None,
431 )
432
433 (options, left_args) = parser.parse_args()
434
435 print_stream = "stdout"
436 print_options = []
437
438 fc_list = ["FC_" + x.upper() for x in options.color or []]
439 bk_list = ["BC_" + y.upper() for y in options.background_color or []]
440 for style_list in [fc_list, bk_list]:
441 for style_name in style_list:
442 if style_name in print_style.__dict__:
443 print_options.append(print_style.__dict__[style_name])
444
445 for style_code in options.style or []:
446 print_options.append(style_code)
447
448 if options.mode:
449 cprintf_set_mode(options.mode)
450
451 if options.theme:
452 cprintf_set_theme(options.theme)
453 else:
455
456 if options.version:
457 print(print_style.version)
458 print("Color Engine: " + print_style.engine.name)
459 exit(0)
460
461 if len(left_args) > 0:
462 if options.interp_bse:
463 for i in range(0, len(left_args)):
464 left_args[i] = eval(repr(left_args[i]).replace("\\\\", "\\"))
465 if "stdout" == options.ostream:
466 cprintf_stdout(print_options, *left_args)
467 else:
468 cprintf_stderr(print_options, *left_args)
stdout_with_color(self, options, text)
stderr_with_color(self, options, text)
stdout_with_color(self, options, text)
stderr_with_color(self, options, text)
stderr_with_color(self, options, text)
stdout_with_color(self, options, text)
stderr_with_color(self, options, text)
stdout_with_color(self, options, text)
get_cmd_color(self, handle=std_out_handle)
set_cmd_color(self, color, handle=std_out_handle)
__contains__(self, value)
cprintf_resolve_auto_mode()
cprintf_set_theme(theme_name=None)
cprintf_stdout(options, fmt, *text)
cprintf_unpack_text(fmt, text)
cprintf_stderr(options, fmt, *text)
cprintf_set_mode(mode_name="auto")