59 |
59 |
60 resolve.unresolved = red bold |
60 resolve.unresolved = red bold |
61 resolve.resolved = green bold |
61 resolve.resolved = green bold |
62 |
62 |
63 bookmarks.current = green |
63 bookmarks.current = green |
|
64 |
|
65 The color extension will try to detect whether to use ANSI codes or |
|
66 Win32 console APIs, unless it is made explicit:: |
|
67 |
|
68 [color] |
|
69 mode = ansi |
|
70 |
|
71 Any value other than 'ansi', 'win32', or 'auto' will disable color. |
|
72 |
64 ''' |
73 ''' |
65 |
74 |
66 import os, sys |
75 import os, sys |
67 |
76 |
68 from mercurial import commands, dispatch, extensions |
77 from mercurial import commands, dispatch, extensions |
148 global _buffers |
157 global _buffers |
149 if labeled: |
158 if labeled: |
150 return ''.join(style(a, label) for a, label in _buffers.pop()) |
159 return ''.join(style(a, label) for a, label in _buffers.pop()) |
151 return ''.join(a for a, label in _buffers.pop()) |
160 return ''.join(a for a, label in _buffers.pop()) |
152 |
161 |
|
162 mode = 'ansi' |
153 def write(orig, *args, **opts): |
163 def write(orig, *args, **opts): |
154 label = opts.get('label', '') |
164 label = opts.get('label', '') |
155 global _buffers |
165 global _buffers |
156 if _buffers: |
166 if _buffers: |
157 _buffers[-1].extend([(str(a), label) for a in args]) |
167 _buffers[-1].extend([(str(a), label) for a in args]) |
|
168 elif mode == 'win32': |
|
169 for a in args: |
|
170 win32print(a, orig, **opts) |
158 else: |
171 else: |
159 return orig(*[style(str(a), label) for a in args], **opts) |
172 return orig(*[style(str(a), label) for a in args], **opts) |
160 |
173 |
161 def write_err(orig, *args, **opts): |
174 def write_err(orig, *args, **opts): |
162 label = opts.get('label', '') |
175 label = opts.get('label', '') |
163 return orig(*[style(str(a), label) for a in args], **opts) |
176 if mode == 'win32': |
|
177 for a in args: |
|
178 win32print(a, orig, **opts) |
|
179 else: |
|
180 return orig(*[style(str(a), label) for a in args], **opts) |
164 |
181 |
165 def uisetup(ui): |
182 def uisetup(ui): |
|
183 global mode |
|
184 mode = ui.config('color', 'mode', 'auto') |
|
185 if mode == 'auto': |
|
186 if os.name == 'nt' and 'TERM' not in os.environ: |
|
187 # looks line a cmd.exe console, use win32 API or nothing |
|
188 mode = w32effects and 'win32' or 'none' |
|
189 else: |
|
190 mode = 'ansi' |
|
191 if mode == 'win32': |
|
192 if w32effects is None: |
|
193 # only warn if color.mode is explicitly set to win32 |
|
194 ui.warn(_('win32console not found, please install pywin32\n')) |
|
195 return |
|
196 _effects.update(w32effects) |
|
197 elif mode != 'ansi': |
|
198 return |
166 def colorcmd(orig, ui_, opts, cmd, cmdfunc): |
199 def colorcmd(orig, ui_, opts, cmd, cmdfunc): |
167 if (opts['color'] == 'always' or |
200 if (opts['color'] == 'always' or |
168 (opts['color'] == 'auto' and (os.environ.get('TERM') != 'dumb' |
201 (opts['color'] == 'auto' and (os.environ.get('TERM') != 'dumb' |
169 and sys.__stdout__.isatty()))): |
202 and sys.__stdout__.isatty()))): |
170 global _buffers |
203 global _buffers |
178 return orig(ui_, opts, cmd, cmdfunc) |
211 return orig(ui_, opts, cmd, cmdfunc) |
179 extensions.wrapfunction(dispatch, '_runcommand', colorcmd) |
212 extensions.wrapfunction(dispatch, '_runcommand', colorcmd) |
180 |
213 |
181 commands.globalopts.append(('', 'color', 'auto', |
214 commands.globalopts.append(('', 'color', 'auto', |
182 _("when to colorize (always, auto, or never)"))) |
215 _("when to colorize (always, auto, or never)"))) |
|
216 |
|
217 try: |
|
218 import re |
|
219 from win32console import * |
|
220 |
|
221 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx |
|
222 w32effects = { |
|
223 'none': 0, |
|
224 'black': 0, |
|
225 'red': FOREGROUND_RED, |
|
226 'green': FOREGROUND_GREEN, |
|
227 'yellow': FOREGROUND_RED | FOREGROUND_GREEN, |
|
228 'blue': FOREGROUND_BLUE, |
|
229 'magenta': FOREGROUND_BLUE | FOREGROUND_RED, |
|
230 'cyan': FOREGROUND_BLUE | FOREGROUND_GREEN, |
|
231 'white': FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, |
|
232 'bold': FOREGROUND_INTENSITY, |
|
233 'black_background': 0, |
|
234 'red_background': BACKGROUND_RED, |
|
235 'green_background': BACKGROUND_GREEN, |
|
236 'blue_background': BACKGROUND_BLUE, |
|
237 'cyan_background': BACKGROUND_BLUE | BACKGROUND_GREEN, |
|
238 'bold_background': FOREGROUND_INTENSITY, |
|
239 'underline': COMMON_LVB_UNDERSCORE, # double-byte charsets only |
|
240 'inverse': COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only |
|
241 } |
|
242 |
|
243 stdout = GetStdHandle(STD_OUTPUT_HANDLE) |
|
244 origattr = stdout.GetConsoleScreenBufferInfo()['Attributes'] |
|
245 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL) |
|
246 |
|
247 def win32print(text, orig, **opts): |
|
248 label = opts.get('label', '') |
|
249 attr = 0 |
|
250 |
|
251 # determine console attributes based on labels |
|
252 for l in label.split(): |
|
253 style = _styles.get(l, '') |
|
254 for effect in style.split(): |
|
255 attr |= w32effects[effect] |
|
256 |
|
257 # hack to ensure regexp finds data |
|
258 if not text.startswith('\033['): |
|
259 text = '\033[m' + text |
|
260 |
|
261 # Look for ANSI-like codes embedded in text |
|
262 m = re.match(ansire, text) |
|
263 while m: |
|
264 for sattr in m.group(1).split(';'): |
|
265 if sattr: |
|
266 val = int(sattr) |
|
267 attr = val and attr|val or 0 |
|
268 stdout.SetConsoleTextAttribute(attr or origattr) |
|
269 orig(m.group(2), **opts) |
|
270 m = re.match(ansire, m.group(3)) |
|
271 |
|
272 # Explicity reset original attributes |
|
273 stdout.SetConsoleTextAttribute(origattr) |
|
274 |
|
275 except ImportError: |
|
276 w32effects = None |