libcopp  1.1.0
print_color.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 
4 import sys
5 import os, ctypes, platform
6 import cgi
7 
8 console_encoding = sys.getfilesystemencoding()
9 
11  version = '1.0.2.0'
12  engine = None
13  theme = None
14 
15  FC_BLACK = 0
16  FC_BLUE = 1
17  FC_GREEN = 2
18  FC_CYAN = 3
19  FC_RED = 4
20  FC_MAGENTA = 5
21  FC_YELLOW = 6
22  FC_WHITE = 7
23 
24  BC_BLACK = 8
25  BC_BLUE = 9
26  BC_GREEN = 10
27  BC_CYAN = 11
28  BC_RED = 12
29  BC_MAGENTA = 13
30  BC_YELLOW = 14
31  BC_WHITE = 15
32 
33  FW_BOLD = 16
34 
35  def __contains__(self, value):
36  return False
37 
38 ''''' See https://msdn.microsoft.com/zh-cn/windows/apps/ms682088%28v=vs.100%29#_win32_character_attributes
39  for color codes
40 '''
41 
43  name = 'windows console'
44  STD_INPUT_HANDLE = -10
45  STD_OUTPUT_HANDLE = -11
46  STD_ERROR_HANDLE = -12
47 
48  FOREGROUND_BLACK = 0x0
49  FOREGROUND_BLUE = 0x01 # text color contains blue.
50  FOREGROUND_GREEN = 0x02 # text color contains green.
51  FOREGROUND_RED = 0x04 # text color contains red.
52  FOREGROUND_INTENSITY = 0x08 # text color is intensified.
53 
54  BACKGROUND_BLUE = 0x10 # background color contains blue.
55  BACKGROUND_GREEN = 0x20 # background color contains green.
56  BACKGROUND_RED = 0x40 # background color contains red.
57  BACKGROUND_INTENSITY = 0x80 # background color is intensified.
58 
59  COLOR_MAP = {
60  print_style.FC_BLACK: FOREGROUND_BLACK,
61  print_style.FC_BLUE: FOREGROUND_BLUE | FOREGROUND_INTENSITY,
62  print_style.FC_GREEN: FOREGROUND_GREEN | FOREGROUND_INTENSITY,
63  print_style.FC_CYAN: FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
64  print_style.FC_RED: FOREGROUND_RED | FOREGROUND_INTENSITY,
65  print_style.FC_MAGENTA: FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
66  print_style.FC_YELLOW: FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
67  print_style.FC_WHITE: FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED,
68 
69  print_style.BC_BLACK: FOREGROUND_BLACK,
70  print_style.BC_BLUE: BACKGROUND_BLUE,
71  print_style.BC_GREEN: BACKGROUND_GREEN,
72  print_style.BC_CYAN: BACKGROUND_BLUE | BACKGROUND_GREEN,
73  print_style.BC_RED: BACKGROUND_RED,
74  print_style.BC_MAGENTA: BACKGROUND_RED | BACKGROUND_BLUE,
75  print_style.BC_YELLOW: BACKGROUND_RED | BACKGROUND_GREEN,
76  print_style.BC_WHITE: BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
77 
78  print_style.FW_BOLD: BACKGROUND_INTENSITY
79  }
80 
81  std_out_handle = None
82  std_err_handle = None
83 
84  def get_cmd_color(self, handle=std_out_handle):
85  return Win32ConsoleColor.FOREGROUND_RED | Win32ConsoleColor.FOREGROUND_GREEN | Win32ConsoleColor.FOREGROUND_BLUE
86 
87  def set_cmd_color(self, color, handle=std_out_handle):
88  """(color) -> bit
89  Example: set_cmd_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)
90  """
91  bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
92  return bool
93 
94  def stdout_with_color(self, options, text):
95  style = Win32ConsoleColor.FOREGROUND_BLACK
96  for opt in options:
97  style = style | Win32ConsoleColor.COLOR_MAP[opt]
98  if style == Win32ConsoleColor.FOREGROUND_BLACK:
99  sys.stdout.write(text)
100  else:
101  old_style = self.get_cmd_color()
102  self.set_cmd_color(style, self.std_out_handle)
103  sys.stdout.write(text)
104  self.set_cmd_color(old_style, self.std_out_handle)
105 
106  def stderr_with_color(self, options, text):
107  style = Win32ConsoleColor.FOREGROUND_BLACK
108  for opt in options:
109  style = style | Win32ConsoleColor.COLOR_MAP[opt]
110  if style == Win32ConsoleColor.FOREGROUND_BLACK:
111  sys.stderr.write(text)
112  else:
113  old_style = self.get_cmd_color()
114  self.set_cmd_color(style, self.std_err_handle)
115  sys.stderr.write(text)
116  self.set_cmd_color(old_style, self.std_err_handle)
117 
118 class TermColor:
119  name = 'terminal'
120  COLOR_MAP = {
121  print_style.FC_BLACK: '30',
122  print_style.FC_BLUE: '34',
123  print_style.FC_GREEN: '32',
124  print_style.FC_CYAN: '36',
125  print_style.FC_RED: '31',
126  print_style.FC_MAGENTA: '35',
127  print_style.FC_YELLOW: '33',
128  print_style.FC_WHITE: '37',
129 
130  print_style.BC_BLACK: '40',
131  print_style.BC_BLUE: '44',
132  print_style.BC_GREEN: '42',
133  print_style.BC_CYAN: '46',
134  print_style.BC_RED: '41',
135  print_style.BC_MAGENTA: '45',
136  print_style.BC_YELLOW: '43',
137  print_style.BC_WHITE: '47',
138 
139  print_style.FW_BOLD: '1'
140  }
141 
142  def stdout_with_color(self, options, text):
143  style = []
144  for opt in options:
145  style.append(TermColor.COLOR_MAP[opt])
146 
147  if len(style) > 0:
148  sys.stdout.write('\033[' + ';'.join(style) + 'm' + text + '\033[0m')
149  else:
150  sys.stdout.write(text)
151 
152  def stderr_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.stderr.write('\033[' + ';'.join(style) + 'm' + text + '\033[0m')
159  else:
160  sys.stderr.write(text)
161 
162 class HtmlColor:
163  name = 'html css'
164  COLOR_MAP = {
165  print_style.FC_BLACK: 'color: {0}Black;',
166  print_style.FC_BLUE: 'color: {0}Blue;',
167  print_style.FC_GREEN: 'color: {0}Green;',
168  print_style.FC_CYAN: 'color: {0}Cyan;',
169  print_style.FC_RED: 'color: {0}Red;',
170  print_style.FC_MAGENTA: 'color: {0}Magenta;',
171  print_style.FC_YELLOW: 'color: {0}Yellow;',
172  print_style.FC_WHITE: 'color: {0}White;',
173 
174  print_style.BC_BLACK: 'background-color: {0}Black;',
175  print_style.BC_BLUE: 'background-color: {0}Blue;',
176  print_style.BC_GREEN: 'background-color: {0}Green;',
177  print_style.BC_CYAN: 'background-color: {0}Cyan;',
178  print_style.BC_RED: 'background-color: {0}Red;',
179  print_style.BC_MAGENTA: 'background-color: {0}Magenta;',
180  print_style.BC_YELLOW: 'background-color: {0}Yellow;',
181  print_style.BC_WHITE: 'background-color: {0}White;',
182 
183  print_style.FW_BOLD: 'font-weight: bold;'
184  }
185 
186  def stdout_with_color(self, options, text):
187  style = []
188  for opt in options:
189  if print_style.theme:
190  style.append(HtmlColor.COLOR_MAP[opt].format(print_style.theme))
191  else:
192  style.append(HtmlColor.COLOR_MAP[opt].format(''))
193 
194  if len(style) > 0:
195  sys.stdout.write('<span style="' + ' '.join(style) + '">' + cgi.escape(text) + '</span>')
196  else:
197  sys.stdout.write(cgi.escape(text))
198 
199  def stderr_with_color(self, options, text):
200  style = []
201  for opt in options:
202  if print_style.theme:
203  style.append(HtmlColor.COLOR_MAP[opt].format(print_style.theme))
204  else:
205  style.append(HtmlColor.COLOR_MAP[opt].format(''))
206 
207  if len(style) > 0:
208  sys.stderr.write('<span style="' + ' '.join(style) + '">' + cgi.escape(text) + '</span>')
209  else:
210  sys.stderr.write(cgi.escape(text))
211 
212 class NoneColor:
213  name = 'none'
214  def stdout_with_color(self, options, text):
215  sys.stdout.write(text)
216 
217  def stderr_with_color(self, options, text):
218  sys.stderr.write(text)
219 
220 
221 def cprintf_set_mode(mode_name='auto'):
222  mode_name = mode_name.lower()
223  if not mode_name or mode_name == 'auto':
224  # set by environment variable
225  if os.getenv('CPRINTF_MODE'):
226  cprintf_set_mode(os.getenv('CPRINTF_MODE'))
227  elif 'windows' == platform.system().lower():
228  ostype_name = os.getenv('OSTYPE')
229  if ostype_name:
230  ostype_name = ostype_name.lower()
231  if 'msys' == ostype_name or 'cygwin' == ostype_name:
232  cprintf_set_mode('term')
233  return
234  term_name = os.getenv('TERM')
235  if term_name:
236  term_name = term_name.lower()
237  if 'xterm' == term_name[0:5] or 'vt' == term_name[0:2]:
238  cprintf_set_mode('term')
239  return
240  cprintf_set_mode('win32_console')
241  elif os.getenv('ANSI_COLORS_DISABLED') is None:
242  cprintf_set_mode('term')
243  else:
244  cprintf_set_mode('none')
245 
246  elif mode_name == 'none':
247  print_style.engine = NoneColor
248 
249  elif mode_name == 'term':
250  print_style.engine = TermColor
251 
252  elif mode_name == 'win32_console':
253  ''''' See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winprog/winprog/windows_api_reference.asp
254  for information on Windows APIs.'''
255  Win32ConsoleColor.std_out_handle = ctypes.windll.kernel32.GetStdHandle(Win32ConsoleColor.STD_OUTPUT_HANDLE)
256  Win32ConsoleColor.std_err_handle = ctypes.windll.kernel32.GetStdHandle(Win32ConsoleColor.STD_ERROR_HANDLE)
257 
258  print_style.engine = Win32ConsoleColor
259 
260  elif mode_name == 'html':
261  print_style.engine = HtmlColor
262 
263  else:
264  print_style.engine = NoneColor
265 
266 def cprintf_set_theme(theme_name=None):
267  if theme_name is None:
268  if not os.getenv('CPRINTF_THEME') is None:
269  cprintf_set_theme(os.getenv('CPRINTF_THEME'))
270  else:
271  print_style.theme = theme_name
272 
273 def cprintf_unpack_text(fmt, text):
274  if len(text) > 0:
275  try:
276  ret = fmt.format(*text)
277  return ret
278  except Exception:
279  ret = fmt.decode('utf-8').encode(console_encoding).format(*text)
280  return ret
281  else:
282  return fmt
283 
284 def cprintf_stdout(options, fmt, *text):
285  cp = print_style.engine()
286  cp.stdout_with_color(options, cprintf_unpack_text(fmt, text))
287  sys.stdout.flush()
288 
289 def cprintf_stderr(options, fmt, *text):
290  cp = print_style.engine()
291  cp.stderr_with_color(options, cprintf_unpack_text(fmt, text))
292  sys.stderr.flush()
293 
294 cprintf_set_mode('auto')
295 
296 """ run as a executable """
297 if __name__ == "__main__":
298  from optparse import OptionParser
299  usage = "usage: %prog [options...] <format message> [format parameters...]"
300  parser = OptionParser(usage)
301  parser.disable_interspersed_args()
302 
303  parser.add_option("-v", "--version", action="store_true", help="show version and exit", dest="version")
304  parser.add_option("-c", "--color", action="append", help="set font color.(any of: black, blue, green, cyan, red, magenta, yellow, white)", metavar="<color>", dest="color")
305  parser.add_option("-b", "--background-color", action="append", help="set background color.(any of: black, blue, green, cyan, red, magenta, yellow, white)", metavar="<background color>", dest="background_color")
306  parser.add_option("-B", "--bold", action="append_const", help="set font weight to bold", const=print_style.FW_BOLD, dest="style")
307  parser.add_option("-m", "--mode", action="store", help="set mode.(any of: auto, term, win32_console, none, html)", metavar="<output mode>", dest="mode")
308  parser.add_option("-s", "--output-stream", action="store", help="set output stream.(any of: stdout, stderr)", metavar="<ostream>", dest="ostream", default="stdout")
309  parser.add_option("-e", action="store_true", help="enable interpretation of backslash escapes(just like echo command in unix like system)", dest="interp_bse", default=False)
310  parser.add_option("-E", action="store_false", help="disable interpretation of backslash escapes(just like echo command in unix like system)", dest="interp_bse")
311  parser.add_option("-t", "--theme", action="store", help="set theme in html mode(light or dark)", metavar="<theme>", dest="theme", default=None)
312 
313  (options, left_args) = parser.parse_args()
314 
315  print_stream = 'stdout'
316  print_options = []
317 
318  fc_list = ['FC_' + x.upper() for x in options.color or [] ]
319  bk_list = ['BC_' + y.upper() for y in options.background_color or [] ]
320  for style_list in [ fc_list, bk_list ]:
321  for style_name in style_list:
322  if style_name in print_style.__dict__ :
323  print_options.append(print_style.__dict__[style_name])
324 
325  for style_code in options.style or []:
326  print_options.append(style_code)
327 
328  if options.mode:
329  cprintf_set_mode(options.mode)
330 
331  if options.theme:
332  cprintf_set_theme(options.theme)
333  else:
334  cprintf_set_theme(None)
335 
336  if options.version:
337  print(print_style.version)
338  print('Color Engine: ' + print_style.engine.name)
339  exit(0)
340 
341  if len(left_args) > 0:
342  if options.interp_bse:
343  for i in range(0, len(left_args)):
344  left_args[i] = eval(repr(left_args[i]).replace("\\\\", "\\"))
345  if 'stdout' == options.ostream:
346  cprintf_stdout(print_options, *left_args)
347  else:
348  cprintf_stderr(print_options, *left_args)
def cprintf_stdout(options, fmt, text)
Definition: print_color.py:284
def stderr_with_color(self, options, text)
Definition: print_color.py:217
def stdout_with_color(self, options, text)
Definition: print_color.py:214
def stdout_with_color(self, options, text)
Definition: print_color.py:186
def cprintf_unpack_text(fmt, text)
Definition: print_color.py:273
def stdout_with_color(self, options, text)
Definition: print_color.py:94
def set_cmd_color(self, color, handle=std_out_handle)
Definition: print_color.py:87
def __contains__(self, value)
Definition: print_color.py:35
def cprintf_set_mode(mode_name='auto')
Definition: print_color.py:221
def stderr_with_color(self, options, text)
Definition: print_color.py:106
def stderr_with_color(self, options, text)
Definition: print_color.py:152
def stdout_with_color(self, options, text)
Definition: print_color.py:142
def cprintf_stderr(options, fmt, text)
Definition: print_color.py:289
def cprintf_set_theme(theme_name=None)
Definition: print_color.py:266
def get_cmd_color(self, handle=std_out_handle)
Definition: print_color.py:84
def stderr_with_color(self, options, text)
Definition: print_color.py:199