##// END OF EJS Templates
color: update description of the extension...
Jordi Gutiérrez Hermoso -
r22771:d6274291 default
parent child Browse files
Show More
@@ -1,628 +1,628
1 # color.py color output for the status and qseries commands
1 # color.py color output for Mercurial commands
2 2 #
3 3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''colorize output from some commands
9 9
10 This extension modifies the status and resolve commands to add color
11 to their output to reflect file status, the qseries command to add
12 color to reflect patch status (applied, unapplied, missing), and to
13 diff-related commands to highlight additions, removals, diff headers,
14 tabs, and trailing whitespace.
10 The color extension colorizes output from several Mercurial commands.
11 For example, the diff command shows additions in green and deletions
12 in red, while the status command shows modified files in magenta. Many
13 other commands have analogous colors. It is possible to customize
14 these colors.
15 15
16 16 Other effects in addition to color, like bold and underlined text, are
17 17 also available. By default, the terminfo database is used to find the
18 18 terminal codes used to change color and effect. If terminfo is not
19 19 available, then effects are rendered with the ECMA-48 SGR control
20 20 function (aka ANSI escape codes).
21 21
22 22 Text receives color effects depending on the labels that it has. Many
23 23 default Mercurial commands emit labelled text. You can also define
24 24 your own labels in templates using the label function, see :hg:`help
25 25 templates`. A single portion of text may have more than one label. In
26 26 that case, effects given to the last label will override any other
27 27 effects. This includes the special "none" effect, which nullifies
28 28 other effects.
29 29
30 30 Labels are normally invisible. In order to see these labels and their
31 31 position in the text, use the global --color=debug option. The same
32 32 anchor text may be associated to multiple labels, e.g.
33 33
34 34 [log.changeset changeset.secret|changeset: 22611:6f0a53c8f587]
35 35
36 36 The following are the default effects for some default labels. Default
37 37 effects may be overridden from your configuration file::
38 38
39 39 [color]
40 40 status.modified = blue bold underline red_background
41 41 status.added = green bold
42 42 status.removed = red bold blue_background
43 43 status.deleted = cyan bold underline
44 44 status.unknown = magenta bold underline
45 45 status.ignored = black bold
46 46
47 47 # 'none' turns off all effects
48 48 status.clean = none
49 49 status.copied = none
50 50
51 51 qseries.applied = blue bold underline
52 52 qseries.unapplied = black bold
53 53 qseries.missing = red bold
54 54
55 55 diff.diffline = bold
56 56 diff.extended = cyan bold
57 57 diff.file_a = red bold
58 58 diff.file_b = green bold
59 59 diff.hunk = magenta
60 60 diff.deleted = red
61 61 diff.inserted = green
62 62 diff.changed = white
63 63 diff.tab =
64 64 diff.trailingwhitespace = bold red_background
65 65
66 66 # Blank so it inherits the style of the surrounding label
67 67 changeset.public =
68 68 changeset.draft =
69 69 changeset.secret =
70 70
71 71 resolve.unresolved = red bold
72 72 resolve.resolved = green bold
73 73
74 74 bookmarks.current = green
75 75
76 76 branches.active = none
77 77 branches.closed = black bold
78 78 branches.current = green
79 79 branches.inactive = none
80 80
81 81 tags.normal = green
82 82 tags.local = black bold
83 83
84 84 rebase.rebased = blue
85 85 rebase.remaining = red bold
86 86
87 87 shelve.age = cyan
88 88 shelve.newest = green bold
89 89 shelve.name = blue bold
90 90
91 91 histedit.remaining = red bold
92 92
93 93 The available effects in terminfo mode are 'blink', 'bold', 'dim',
94 94 'inverse', 'invisible', 'italic', 'standout', and 'underline'; in
95 95 ECMA-48 mode, the options are 'bold', 'inverse', 'italic', and
96 96 'underline'. How each is rendered depends on the terminal emulator.
97 97 Some may not be available for a given terminal type, and will be
98 98 silently ignored.
99 99
100 100 Note that on some systems, terminfo mode may cause problems when using
101 101 color with the pager extension and less -R. less with the -R option
102 102 will only display ECMA-48 color codes, and terminfo mode may sometimes
103 103 emit codes that less doesn't understand. You can work around this by
104 104 either using ansi mode (or auto mode), or by using less -r (which will
105 105 pass through all terminal control codes, not just color control
106 106 codes).
107 107
108 108 Because there are only eight standard colors, this module allows you
109 109 to define color names for other color slots which might be available
110 110 for your terminal type, assuming terminfo mode. For instance::
111 111
112 112 color.brightblue = 12
113 113 color.pink = 207
114 114 color.orange = 202
115 115
116 116 to set 'brightblue' to color slot 12 (useful for 16 color terminals
117 117 that have brighter colors defined in the upper eight) and, 'pink' and
118 118 'orange' to colors in 256-color xterm's default color cube. These
119 119 defined colors may then be used as any of the pre-defined eight,
120 120 including appending '_background' to set the background to that color.
121 121
122 122 By default, the color extension will use ANSI mode (or win32 mode on
123 123 Windows) if it detects a terminal. To override auto mode (to enable
124 124 terminfo mode, for example), set the following configuration option::
125 125
126 126 [color]
127 127 mode = terminfo
128 128
129 129 Any value other than 'ansi', 'win32', 'terminfo', or 'auto' will
130 130 disable color.
131 131 '''
132 132
133 133 import os
134 134
135 135 from mercurial import cmdutil, commands, dispatch, extensions, ui as uimod, util
136 136 from mercurial import templater, error
137 137 from mercurial.i18n import _
138 138
139 139 cmdtable = {}
140 140 command = cmdutil.command(cmdtable)
141 141 testedwith = 'internal'
142 142
143 143 # start and stop parameters for effects
144 144 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
145 145 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
146 146 'italic': 3, 'underline': 4, 'inverse': 7,
147 147 'black_background': 40, 'red_background': 41,
148 148 'green_background': 42, 'yellow_background': 43,
149 149 'blue_background': 44, 'purple_background': 45,
150 150 'cyan_background': 46, 'white_background': 47}
151 151
152 152 def _terminfosetup(ui, mode):
153 153 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
154 154
155 155 global _terminfo_params
156 156 # If we failed to load curses, we go ahead and return.
157 157 if not _terminfo_params:
158 158 return
159 159 # Otherwise, see what the config file says.
160 160 if mode not in ('auto', 'terminfo'):
161 161 return
162 162
163 163 _terminfo_params.update((key[6:], (False, int(val)))
164 164 for key, val in ui.configitems('color')
165 165 if key.startswith('color.'))
166 166
167 167 try:
168 168 curses.setupterm()
169 169 except curses.error, e:
170 170 _terminfo_params = {}
171 171 return
172 172
173 173 for key, (b, e) in _terminfo_params.items():
174 174 if not b:
175 175 continue
176 176 if not curses.tigetstr(e):
177 177 # Most terminals don't support dim, invis, etc, so don't be
178 178 # noisy and use ui.debug().
179 179 ui.debug("no terminfo entry for %s\n" % e)
180 180 del _terminfo_params[key]
181 181 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
182 182 # Only warn about missing terminfo entries if we explicitly asked for
183 183 # terminfo mode.
184 184 if mode == "terminfo":
185 185 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
186 186 "ECMA-48 color\n"))
187 187 _terminfo_params = {}
188 188
189 189 def _modesetup(ui, coloropt):
190 190 global _terminfo_params
191 191
192 192 if coloropt == 'debug':
193 193 return 'debug'
194 194
195 195 auto = (coloropt == 'auto')
196 196 always = not auto and util.parsebool(coloropt)
197 197 if not always and not auto:
198 198 return None
199 199
200 200 formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
201 201
202 202 mode = ui.config('color', 'mode', 'auto')
203 203 realmode = mode
204 204 if mode == 'auto':
205 205 if os.name == 'nt' and 'TERM' not in os.environ:
206 206 # looks line a cmd.exe console, use win32 API or nothing
207 207 realmode = 'win32'
208 208 else:
209 209 realmode = 'ansi'
210 210
211 211 if realmode == 'win32':
212 212 _terminfo_params = {}
213 213 if not w32effects:
214 214 if mode == 'win32':
215 215 # only warn if color.mode is explicitly set to win32
216 216 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
217 217 return None
218 218 _effects.update(w32effects)
219 219 elif realmode == 'ansi':
220 220 _terminfo_params = {}
221 221 elif realmode == 'terminfo':
222 222 _terminfosetup(ui, mode)
223 223 if not _terminfo_params:
224 224 if mode == 'terminfo':
225 225 ## FIXME Shouldn't we return None in this case too?
226 226 # only warn if color.mode is explicitly set to win32
227 227 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
228 228 realmode = 'ansi'
229 229 else:
230 230 return None
231 231
232 232 if always or (auto and formatted):
233 233 return realmode
234 234 return None
235 235
236 236 try:
237 237 import curses
238 238 # Mapping from effect name to terminfo attribute name or color number.
239 239 # This will also force-load the curses module.
240 240 _terminfo_params = {'none': (True, 'sgr0'),
241 241 'standout': (True, 'smso'),
242 242 'underline': (True, 'smul'),
243 243 'reverse': (True, 'rev'),
244 244 'inverse': (True, 'rev'),
245 245 'blink': (True, 'blink'),
246 246 'dim': (True, 'dim'),
247 247 'bold': (True, 'bold'),
248 248 'invisible': (True, 'invis'),
249 249 'italic': (True, 'sitm'),
250 250 'black': (False, curses.COLOR_BLACK),
251 251 'red': (False, curses.COLOR_RED),
252 252 'green': (False, curses.COLOR_GREEN),
253 253 'yellow': (False, curses.COLOR_YELLOW),
254 254 'blue': (False, curses.COLOR_BLUE),
255 255 'magenta': (False, curses.COLOR_MAGENTA),
256 256 'cyan': (False, curses.COLOR_CYAN),
257 257 'white': (False, curses.COLOR_WHITE)}
258 258 except ImportError:
259 259 _terminfo_params = {}
260 260
261 261 _styles = {'grep.match': 'red bold',
262 262 'grep.linenumber': 'green',
263 263 'grep.rev': 'green',
264 264 'grep.change': 'green',
265 265 'grep.sep': 'cyan',
266 266 'grep.filename': 'magenta',
267 267 'grep.user': 'magenta',
268 268 'grep.date': 'magenta',
269 269 'bookmarks.current': 'green',
270 270 'branches.active': 'none',
271 271 'branches.closed': 'black bold',
272 272 'branches.current': 'green',
273 273 'branches.inactive': 'none',
274 274 'diff.changed': 'white',
275 275 'diff.deleted': 'red',
276 276 'diff.diffline': 'bold',
277 277 'diff.extended': 'cyan bold',
278 278 'diff.file_a': 'red bold',
279 279 'diff.file_b': 'green bold',
280 280 'diff.hunk': 'magenta',
281 281 'diff.inserted': 'green',
282 282 'diff.tab': '',
283 283 'diff.trailingwhitespace': 'bold red_background',
284 284 'changeset.public' : '',
285 285 'changeset.draft' : '',
286 286 'changeset.secret' : '',
287 287 'diffstat.deleted': 'red',
288 288 'diffstat.inserted': 'green',
289 289 'histedit.remaining': 'red bold',
290 290 'ui.prompt': 'yellow',
291 291 'log.changeset': 'yellow',
292 292 'rebase.rebased': 'blue',
293 293 'rebase.remaining': 'red bold',
294 294 'resolve.resolved': 'green bold',
295 295 'resolve.unresolved': 'red bold',
296 296 'shelve.age': 'cyan',
297 297 'shelve.newest': 'green bold',
298 298 'shelve.name': 'blue bold',
299 299 'status.added': 'green bold',
300 300 'status.clean': 'none',
301 301 'status.copied': 'none',
302 302 'status.deleted': 'cyan bold underline',
303 303 'status.ignored': 'black bold',
304 304 'status.modified': 'blue bold',
305 305 'status.removed': 'red bold',
306 306 'status.unknown': 'magenta bold underline',
307 307 'tags.normal': 'green',
308 308 'tags.local': 'black bold'}
309 309
310 310
311 311 def _effect_str(effect):
312 312 '''Helper function for render_effects().'''
313 313
314 314 bg = False
315 315 if effect.endswith('_background'):
316 316 bg = True
317 317 effect = effect[:-11]
318 318 attr, val = _terminfo_params[effect]
319 319 if attr:
320 320 return curses.tigetstr(val)
321 321 elif bg:
322 322 return curses.tparm(curses.tigetstr('setab'), val)
323 323 else:
324 324 return curses.tparm(curses.tigetstr('setaf'), val)
325 325
326 326 def render_effects(text, effects):
327 327 'Wrap text in commands to turn on each effect.'
328 328 if not text:
329 329 return text
330 330 if not _terminfo_params:
331 331 start = [str(_effects[e]) for e in ['none'] + effects.split()]
332 332 start = '\033[' + ';'.join(start) + 'm'
333 333 stop = '\033[' + str(_effects['none']) + 'm'
334 334 else:
335 335 start = ''.join(_effect_str(effect)
336 336 for effect in ['none'] + effects.split())
337 337 stop = _effect_str('none')
338 338 return ''.join([start, text, stop])
339 339
340 340 def extstyles():
341 341 for name, ext in extensions.extensions():
342 342 _styles.update(getattr(ext, 'colortable', {}))
343 343
344 344 def valideffect(effect):
345 345 'Determine if the effect is valid or not.'
346 346 good = False
347 347 if not _terminfo_params and effect in _effects:
348 348 good = True
349 349 elif effect in _terminfo_params or effect[:-11] in _terminfo_params:
350 350 good = True
351 351 return good
352 352
353 353 def configstyles(ui):
354 354 for status, cfgeffects in ui.configitems('color'):
355 355 if '.' not in status or status.startswith('color.'):
356 356 continue
357 357 cfgeffects = ui.configlist('color', status)
358 358 if cfgeffects:
359 359 good = []
360 360 for e in cfgeffects:
361 361 if valideffect(e):
362 362 good.append(e)
363 363 else:
364 364 ui.warn(_("ignoring unknown color/effect %r "
365 365 "(configured in color.%s)\n")
366 366 % (e, status))
367 367 _styles[status] = ' '.join(good)
368 368
369 369 class colorui(uimod.ui):
370 370 def popbuffer(self, labeled=False):
371 371 if self._colormode is None:
372 372 return super(colorui, self).popbuffer(labeled)
373 373
374 374 self._bufferstates.pop()
375 375 if labeled:
376 376 return ''.join(self.label(a, label) for a, label
377 377 in self._buffers.pop())
378 378 return ''.join(a for a, label in self._buffers.pop())
379 379
380 380 _colormode = 'ansi'
381 381 def write(self, *args, **opts):
382 382 if self._colormode is None:
383 383 return super(colorui, self).write(*args, **opts)
384 384
385 385 label = opts.get('label', '')
386 386 if self._buffers:
387 387 self._buffers[-1].extend([(str(a), label) for a in args])
388 388 elif self._colormode == 'win32':
389 389 for a in args:
390 390 win32print(a, super(colorui, self).write, **opts)
391 391 else:
392 392 return super(colorui, self).write(
393 393 *[self.label(str(a), label) for a in args], **opts)
394 394
395 395 def write_err(self, *args, **opts):
396 396 if self._colormode is None:
397 397 return super(colorui, self).write_err(*args, **opts)
398 398
399 399 label = opts.get('label', '')
400 400 if self._bufferstates and self._bufferstates[-1]:
401 401 return self.write(*args, **opts)
402 402 if self._colormode == 'win32':
403 403 for a in args:
404 404 win32print(a, super(colorui, self).write_err, **opts)
405 405 else:
406 406 return super(colorui, self).write_err(
407 407 *[self.label(str(a), label) for a in args], **opts)
408 408
409 409 def showlabel(self, msg, label):
410 410 if label and msg:
411 411 if msg[-1] == '\n':
412 412 return "[%s|%s]\n" % (label, msg[:-1])
413 413 else:
414 414 return "[%s|%s]" % (label, msg)
415 415 else:
416 416 return msg
417 417
418 418 def label(self, msg, label):
419 419 if self._colormode is None:
420 420 return super(colorui, self).label(msg, label)
421 421
422 422 if self._colormode == 'debug':
423 423 return self.showlabel(msg, label)
424 424
425 425 effects = []
426 426 for l in label.split():
427 427 s = _styles.get(l, '')
428 428 if s:
429 429 effects.append(s)
430 430 elif valideffect(l):
431 431 effects.append(l)
432 432 effects = ' '.join(effects)
433 433 if effects:
434 434 return '\n'.join([render_effects(s, effects)
435 435 for s in msg.split('\n')])
436 436 return msg
437 437
438 438 def templatelabel(context, mapping, args):
439 439 if len(args) != 2:
440 440 # i18n: "label" is a keyword
441 441 raise error.ParseError(_("label expects two arguments"))
442 442
443 443 # add known effects to the mapping so symbols like 'red', 'bold',
444 444 # etc. don't need to be quoted
445 445 mapping.update(dict([(k, k) for k in _effects]))
446 446
447 447 thing = templater._evalifliteral(args[1], context, mapping)
448 448
449 449 # apparently, repo could be a string that is the favicon?
450 450 repo = mapping.get('repo', '')
451 451 if isinstance(repo, str):
452 452 return thing
453 453
454 454 label = templater._evalifliteral(args[0], context, mapping)
455 455
456 456 thing = templater.stringify(thing)
457 457 label = templater.stringify(label)
458 458
459 459 return repo.ui.label(thing, label)
460 460
461 461 def uisetup(ui):
462 462 if ui.plain():
463 463 return
464 464 if not isinstance(ui, colorui):
465 465 colorui.__bases__ = (ui.__class__,)
466 466 ui.__class__ = colorui
467 467 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
468 468 mode = _modesetup(ui_, opts['color'])
469 469 colorui._colormode = mode
470 470 if mode and mode != 'debug':
471 471 extstyles()
472 472 configstyles(ui_)
473 473 return orig(ui_, opts, cmd, cmdfunc)
474 474 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
475 475 templater.funcs['label'] = templatelabel
476 476
477 477 def extsetup(ui):
478 478 commands.globalopts.append(
479 479 ('', 'color', 'auto',
480 480 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
481 481 # and should not be translated
482 482 _("when to colorize (boolean, always, auto, never, or debug)"),
483 483 _('TYPE')))
484 484
485 485 @command('debugcolor', [], 'hg debugcolor')
486 486 def debugcolor(ui, repo, **opts):
487 487 global _styles
488 488 _styles = {}
489 489 for effect in _effects.keys():
490 490 _styles[effect] = effect
491 491 ui.write(('color mode: %s\n') % ui._colormode)
492 492 ui.write(_('available colors:\n'))
493 493 for label, colors in _styles.items():
494 494 ui.write(('%s\n') % colors, label=label)
495 495
496 496 if os.name != 'nt':
497 497 w32effects = None
498 498 else:
499 499 import re, ctypes
500 500
501 501 _kernel32 = ctypes.windll.kernel32
502 502
503 503 _WORD = ctypes.c_ushort
504 504
505 505 _INVALID_HANDLE_VALUE = -1
506 506
507 507 class _COORD(ctypes.Structure):
508 508 _fields_ = [('X', ctypes.c_short),
509 509 ('Y', ctypes.c_short)]
510 510
511 511 class _SMALL_RECT(ctypes.Structure):
512 512 _fields_ = [('Left', ctypes.c_short),
513 513 ('Top', ctypes.c_short),
514 514 ('Right', ctypes.c_short),
515 515 ('Bottom', ctypes.c_short)]
516 516
517 517 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
518 518 _fields_ = [('dwSize', _COORD),
519 519 ('dwCursorPosition', _COORD),
520 520 ('wAttributes', _WORD),
521 521 ('srWindow', _SMALL_RECT),
522 522 ('dwMaximumWindowSize', _COORD)]
523 523
524 524 _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
525 525 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
526 526
527 527 _FOREGROUND_BLUE = 0x0001
528 528 _FOREGROUND_GREEN = 0x0002
529 529 _FOREGROUND_RED = 0x0004
530 530 _FOREGROUND_INTENSITY = 0x0008
531 531
532 532 _BACKGROUND_BLUE = 0x0010
533 533 _BACKGROUND_GREEN = 0x0020
534 534 _BACKGROUND_RED = 0x0040
535 535 _BACKGROUND_INTENSITY = 0x0080
536 536
537 537 _COMMON_LVB_REVERSE_VIDEO = 0x4000
538 538 _COMMON_LVB_UNDERSCORE = 0x8000
539 539
540 540 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
541 541 w32effects = {
542 542 'none': -1,
543 543 'black': 0,
544 544 'red': _FOREGROUND_RED,
545 545 'green': _FOREGROUND_GREEN,
546 546 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
547 547 'blue': _FOREGROUND_BLUE,
548 548 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
549 549 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
550 550 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
551 551 'bold': _FOREGROUND_INTENSITY,
552 552 'black_background': 0x100, # unused value > 0x0f
553 553 'red_background': _BACKGROUND_RED,
554 554 'green_background': _BACKGROUND_GREEN,
555 555 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
556 556 'blue_background': _BACKGROUND_BLUE,
557 557 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
558 558 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
559 559 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
560 560 _BACKGROUND_BLUE),
561 561 'bold_background': _BACKGROUND_INTENSITY,
562 562 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
563 563 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
564 564 }
565 565
566 566 passthrough = set([_FOREGROUND_INTENSITY,
567 567 _BACKGROUND_INTENSITY,
568 568 _COMMON_LVB_UNDERSCORE,
569 569 _COMMON_LVB_REVERSE_VIDEO])
570 570
571 571 stdout = _kernel32.GetStdHandle(
572 572 _STD_OUTPUT_HANDLE) # don't close the handle returned
573 573 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
574 574 w32effects = None
575 575 else:
576 576 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
577 577 if not _kernel32.GetConsoleScreenBufferInfo(
578 578 stdout, ctypes.byref(csbi)):
579 579 # stdout may not support GetConsoleScreenBufferInfo()
580 580 # when called from subprocess or redirected
581 581 w32effects = None
582 582 else:
583 583 origattr = csbi.wAttributes
584 584 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
585 585 re.MULTILINE | re.DOTALL)
586 586
587 587 def win32print(text, orig, **opts):
588 588 label = opts.get('label', '')
589 589 attr = origattr
590 590
591 591 def mapcolor(val, attr):
592 592 if val == -1:
593 593 return origattr
594 594 elif val in passthrough:
595 595 return attr | val
596 596 elif val > 0x0f:
597 597 return (val & 0x70) | (attr & 0x8f)
598 598 else:
599 599 return (val & 0x07) | (attr & 0xf8)
600 600
601 601 # determine console attributes based on labels
602 602 for l in label.split():
603 603 style = _styles.get(l, '')
604 604 for effect in style.split():
605 605 try:
606 606 attr = mapcolor(w32effects[effect], attr)
607 607 except KeyError:
608 608 # w32effects could not have certain attributes so we skip
609 609 # them if not found
610 610 pass
611 611 # hack to ensure regexp finds data
612 612 if not text.startswith('\033['):
613 613 text = '\033[m' + text
614 614
615 615 # Look for ANSI-like codes embedded in text
616 616 m = re.match(ansire, text)
617 617
618 618 try:
619 619 while m:
620 620 for sattr in m.group(1).split(';'):
621 621 if sattr:
622 622 attr = mapcolor(int(sattr), attr)
623 623 _kernel32.SetConsoleTextAttribute(stdout, attr)
624 624 orig(m.group(2), **opts)
625 625 m = re.match(ansire, m.group(3))
626 626 finally:
627 627 # Explicitly reset original attributes
628 628 _kernel32.SetConsoleTextAttribute(stdout, origattr)
General Comments 0
You need to be logged in to leave comments. Login now