comparison hgext/color.py @ 30968:0d2a58a04080

color: move '_terminfo_params' into the core 'color' module On step closer to have color in core.
author Pierre-Yves David <pierre-yves.david@ens-lyon.org>
date Thu, 22 Dec 2016 02:23:23 +0100
parents 20990991d384
children ddc80d1777a6
comparison
equal deleted inserted replaced
30967:20990991d384 30968:0d2a58a04080
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
167 try:
168 import curses
169 curses.COLOR_BLACK # force import
170 except ImportError:
171 curses = None
166 172
167 from mercurial.i18n import _ 173 from mercurial.i18n import _
168 from mercurial import ( 174 from mercurial import (
169 cmdutil, 175 cmdutil,
170 color, 176 color,
188 194
189 def _terminfosetup(ui, mode): 195 def _terminfosetup(ui, mode):
190 '''Initialize terminfo data and the terminal if we're in terminfo mode.''' 196 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
191 197
192 # If we failed to load curses, we go ahead and return. 198 # If we failed to load curses, we go ahead and return.
193 if not _terminfo_params: 199 if not color._terminfo_params:
194 return 200 return
195 # Otherwise, see what the config file says. 201 # Otherwise, see what the config file says.
196 if mode not in ('auto', 'terminfo'): 202 if mode not in ('auto', 'terminfo'):
197 return 203 return
198 204
199 _terminfo_params.update((key[6:], (False, int(val), '')) 205 color._terminfo_params.update((key[6:], (False, int(val), ''))
200 for key, val in ui.configitems('color') 206 for key, val in ui.configitems('color')
201 if key.startswith('color.')) 207 if key.startswith('color.'))
202 _terminfo_params.update((key[9:], (True, '', val.replace('\\E', '\x1b'))) 208 color._terminfo_params.update((key[9:],
209 (True, '', val.replace('\\E', '\x1b')))
203 for key, val in ui.configitems('color') 210 for key, val in ui.configitems('color')
204 if key.startswith('terminfo.')) 211 if key.startswith('terminfo.'))
205 212
206 try: 213 try:
207 curses.setupterm() 214 curses.setupterm()
208 except curses.error as e: 215 except curses.error as e:
209 _terminfo_params.clear() 216 color._terminfo_params.clear()
210 return 217 return
211 218
212 for key, (b, e, c) in _terminfo_params.items(): 219 for key, (b, e, c) in color._terminfo_params.items():
213 if not b: 220 if not b:
214 continue 221 continue
215 if not c and not curses.tigetstr(e): 222 if not c and not curses.tigetstr(e):
216 # Most terminals don't support dim, invis, etc, so don't be 223 # Most terminals don't support dim, invis, etc, so don't be
217 # noisy and use ui.debug(). 224 # noisy and use ui.debug().
218 ui.debug("no terminfo entry for %s\n" % e) 225 ui.debug("no terminfo entry for %s\n" % e)
219 del _terminfo_params[key] 226 del color._terminfo_params[key]
220 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'): 227 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
221 # Only warn about missing terminfo entries if we explicitly asked for 228 # Only warn about missing terminfo entries if we explicitly asked for
222 # terminfo mode. 229 # terminfo mode.
223 if mode == "terminfo": 230 if mode == "terminfo":
224 ui.warn(_("no terminfo entry for setab/setaf: reverting to " 231 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
225 "ECMA-48 color\n")) 232 "ECMA-48 color\n"))
226 _terminfo_params.clear() 233 color._terminfo_params.clear()
227 234
228 def _modesetup(ui, coloropt): 235 def _modesetup(ui, coloropt):
229 if coloropt == 'debug': 236 if coloropt == 'debug':
230 return 'debug' 237 return 'debug'
231 238
268 # a formatted terminal 275 # a formatted terminal
269 if mode == realmode and ui.formatted(): 276 if mode == realmode and ui.formatted():
270 ui.warn(_('warning: failed to set color mode to %s\n') % mode) 277 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
271 278
272 if realmode == 'win32': 279 if realmode == 'win32':
273 _terminfo_params.clear() 280 color._terminfo_params.clear()
274 if not w32effects: 281 if not w32effects:
275 modewarn() 282 modewarn()
276 return None 283 return None
277 color._effects.update(w32effects) 284 color._effects.update(w32effects)
278 elif realmode == 'ansi': 285 elif realmode == 'ansi':
279 _terminfo_params.clear() 286 color._terminfo_params.clear()
280 elif realmode == 'terminfo': 287 elif realmode == 'terminfo':
281 _terminfosetup(ui, mode) 288 _terminfosetup(ui, mode)
282 if not _terminfo_params: 289 if not color._terminfo_params:
283 ## FIXME Shouldn't we return None in this case too? 290 ## FIXME Shouldn't we return None in this case too?
284 modewarn() 291 modewarn()
285 realmode = 'ansi' 292 realmode = 'ansi'
286 else: 293 else:
287 return None 294 return None
288 295
289 if always or (auto and formatted): 296 if always or (auto and formatted):
290 return realmode 297 return realmode
291 return None 298 return None
292 299
293 try:
294 import curses
295 # Mapping from effect name to terminfo attribute name (or raw code) or
296 # color number. This will also force-load the curses module.
297 _terminfo_params = {'none': (True, 'sgr0', ''),
298 'standout': (True, 'smso', ''),
299 'underline': (True, 'smul', ''),
300 'reverse': (True, 'rev', ''),
301 'inverse': (True, 'rev', ''),
302 'blink': (True, 'blink', ''),
303 'dim': (True, 'dim', ''),
304 'bold': (True, 'bold', ''),
305 'invisible': (True, 'invis', ''),
306 'italic': (True, 'sitm', ''),
307 'black': (False, curses.COLOR_BLACK, ''),
308 'red': (False, curses.COLOR_RED, ''),
309 'green': (False, curses.COLOR_GREEN, ''),
310 'yellow': (False, curses.COLOR_YELLOW, ''),
311 'blue': (False, curses.COLOR_BLUE, ''),
312 'magenta': (False, curses.COLOR_MAGENTA, ''),
313 'cyan': (False, curses.COLOR_CYAN, ''),
314 'white': (False, curses.COLOR_WHITE, '')}
315 except ImportError:
316 _terminfo_params = {}
317
318 def _effect_str(effect): 300 def _effect_str(effect):
319 '''Helper function for render_effects().''' 301 '''Helper function for render_effects().'''
320 302
321 bg = False 303 bg = False
322 if effect.endswith('_background'): 304 if effect.endswith('_background'):
323 bg = True 305 bg = True
324 effect = effect[:-11] 306 effect = effect[:-11]
325 try: 307 try:
326 attr, val, termcode = _terminfo_params[effect] 308 attr, val, termcode = color._terminfo_params[effect]
327 except KeyError: 309 except KeyError:
328 return '' 310 return ''
329 if attr: 311 if attr:
330 if termcode: 312 if termcode:
331 return termcode 313 return termcode
338 320
339 def render_effects(text, effects): 321 def render_effects(text, effects):
340 'Wrap text in commands to turn on each effect.' 322 'Wrap text in commands to turn on each effect.'
341 if not text: 323 if not text:
342 return text 324 return text
343 if not _terminfo_params: 325 if not color._terminfo_params:
344 start = [str(color._effects[e]) for e in ['none'] + effects.split()] 326 start = [str(color._effects[e]) for e in ['none'] + effects.split()]
345 start = '\033[' + ';'.join(start) + 'm' 327 start = '\033[' + ';'.join(start) + 'm'
346 stop = '\033[' + str(color._effects['none']) + 'm' 328 stop = '\033[' + str(color._effects['none']) + 'm'
347 else: 329 else:
348 start = ''.join(_effect_str(effect) 330 start = ''.join(_effect_str(effect)
351 return ''.join([start, text, stop]) 333 return ''.join([start, text, stop])
352 334
353 def valideffect(effect): 335 def valideffect(effect):
354 'Determine if the effect is valid or not.' 336 'Determine if the effect is valid or not.'
355 good = False 337 good = False
356 if not _terminfo_params and effect in color._effects: 338 if not color._terminfo_params and effect in color._effects:
357 good = True 339 good = True
358 elif effect in _terminfo_params or effect[:-11] in _terminfo_params: 340 elif (effect in color._terminfo_params
341 or effect[:-11] in color._terminfo_params):
359 good = True 342 good = True
360 return good 343 return good
361 344
362 def configstyles(ui): 345 def configstyles(ui):
363 for status, cfgeffects in ui.configitems('color'): 346 for status, cfgeffects in ui.configitems('color'):
481 oldstyle = color._styles.copy() 464 oldstyle = color._styles.copy()
482 try: 465 try:
483 color._styles.clear() 466 color._styles.clear()
484 for effect in color._effects.keys(): 467 for effect in color._effects.keys():
485 color._styles[effect] = effect 468 color._styles[effect] = effect
486 if _terminfo_params: 469 if color._terminfo_params:
487 for k, v in ui.configitems('color'): 470 for k, v in ui.configitems('color'):
488 if k.startswith('color.'): 471 if k.startswith('color.'):
489 color._styles[k] = k[6:] 472 color._styles[k] = k[6:]
490 elif k.startswith('terminfo.'): 473 elif k.startswith('terminfo.'):
491 color._styles[k] = k[9:] 474 color._styles[k] = k[9:]