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