Fix color support

Fix bugs and regression on color support introduced by previous commits
main
Fabien Benureau 9 years ago
parent 05ec6d274b
commit b8bcd6cc11

@ -31,49 +31,48 @@ def generate_colors(stream, color=True, bold=True, italic=True):
if (color or bold or italic) and _color_supported(stream): if (color or bold or italic) and _color_supported(stream):
bold_flag, italic_flag = '', '' bold_flag, italic_flag = '', ''
if bold: if bold:
colors['bold'] = u'\x1b[1m' colors['bold'] = u'\033[1m'
bold_flag = '1;' bold_flag = '1;'
if italic: if italic:
colors['italic'] = u'\x1b[3m' colors['italic'] = u'\033[3m'
italic_flag = '3;' italic_flag = '3;'
for i, name in enumerate(COLOR_LIST): for i, name in enumerate(COLOR_LIST):
if color: if color:
color_flag = '3{}'.format(name) colors[name] = u'\x1b[3{}m'.format(i)
colors[name] = u'\x1b[{}m'.format(color_flag) colors.update({u'b'+name: u'\033[{}3{}m'.format(bold_flag, i) for i, name in enumerate(COLOR_LIST)})
colors.update({u'b'+name: u'\x1b[{}3{}m'.format(bold_flag, i) for i, name in enumerate(COLOR_LIST)}) colors.update({u'i'+name: u'\033[{}3{}m'.format(italic_flag, i) for i, name in enumerate(COLOR_LIST)})
colors.update({u'i'+name: u'\x1b[{}3{}m'.format(italic_flag, i) for i, name in enumerate(COLOR_LIST)}) colors.update({u'bi'+name: u'\033[{}{}3{}m'.format(bold_flag, italic_flag, i) for i, name in enumerate(COLOR_LIST)})
colors.update({u'bi'+name: u'\x1b[{}3{}m'.format(bold_flag, italic_flag, i) for i, name in enumerate(COLOR_LIST)})
else: else:
if bold: if bold:
colors.update({u'b'+name: u'\x1b[{}m'.format(bold_flag, i) for i, name in enumerate(COLOR_LIST)}) colors.update({u'b'+name: u'\033[1m' for i, name in enumerate(COLOR_LIST)})
if italic: if italic:
colors.update({u'i'+name: u'\x1b[{}m'.format(italic_flag, i) for i, name in enumerate(COLOR_LIST)}) colors.update({u'i'+name: u'\033[3m' for i, name in enumerate(COLOR_LIST)})
if bold or italic: if bold or italic:
colors.update({u'bi'+name: u'\x1b[{}m'.format(bold_flag, italic_flag, i) for i, name in enumerate(COLOR_LIST)}) colors.update({u'bi'+name: u'\033[{}{}m'.format(bold_flag, italic_flag) for i, name in enumerate(COLOR_LIST)})
if color or bold or italic: if color or bold or italic:
colors[u'end'] = u'\x1b[0m' colors['end'] = u'\033[0m'
return colors return colors
COLORS_OUT = generate_colors(sys.stdout, color=True, bold=True, italic=True) COLORS_OUT = generate_colors(sys.stdout, color=False, bold=False, italic=False)
COLORS_ERR = generate_colors(sys.stderr, color=True, bold=True, italic=True) COLORS_ERR = generate_colors(sys.stderr, color=False, bold=False, italic=False)
def dye_out(s, color='end'): def dye_out(s, color='end'):
return '{}{}{}'.format(COLORS_OUT[color], s, COLORS_OUT['end']) return u'{}{}{}'.format(COLORS_OUT[color], s, COLORS_OUT['end'])
def dye_err(s, color='end'): def dye_err(s, color='end'):
return '{}{}{}'.format(COLORS_ERR[color], s, COLORS_OUT['end']) return u'{}{}{}'.format(COLORS_ERR[color], s, COLORS_OUT['end'])
def _nodye(s, *args, **kwargs): def _nodye(s, *args, **kwargs):
return s return s
def setup(color=True, bold=True, italic=True): def setup(color=False, bold=False, italic=False):
global COLORS_OUT, COLORS_ERR global COLORS_OUT, COLORS_ERR
COLORS_OUT = generate_colors(sys.stdout, color=color, bold=color, italic=color) COLORS_OUT = generate_colors(sys.stdout, color=color, bold=bold, italic=italic)
COLORS_ERR = generate_colors(sys.stderr, color=color, bold=color, italic=color) COLORS_ERR = generate_colors(sys.stderr, color=color, bold=bold, italic=italic)
# undye # undye
undye_re = re.compile('\x1b\[[;\d]*[A-Za-z]') undye_re = re.compile('\x1b\[[;\d]*[A-Za-z]')

@ -16,32 +16,40 @@ from .p3 import _get_raw_stdout, _get_raw_stderr, input
_ui = None _ui = None
def _get_encoding(config): def _get_encoding(conf):
"""Get local terminal encoding or user preference in config.""" """Get local terminal encoding or user preference in config."""
enc = None enc = 'utf-8'
try: try:
enc = locale.getdefaultlocale()[1] enc = locale.getdefaultlocale()[1]
except ValueError: except ValueError:
pass # Keep default pass # Keep default
return config.get('terminal-encoding', enc or 'utf-8') if conf is None:
return enc or 'utf-8'
return conf.get('terminal-encoding', enc or 'utf-8')
def get_ui(): def get_ui():
if _ui is None: if _ui is None:
raise ValueError('ui not instanciated yet') return PrintUI() # no editor support. (#FIXME?)
return _ui return _ui
def init_ui(conf):
def init_ui(config):
global _ui global _ui
_ui = InputUI(config) _ui = InputUI(conf)
class PrintUI(object): class PrintUI(object):
def __init__(self, config): def __init__(self, conf=None):
color.setup(config.color) """
self.encoding = _get_encoding(config) :param conf: if None, conservative default values are used.
Useful to instanciate the UI before parsing the config file.
"""
if conf is None:
color.setup()
else:
color.setup(color=True, bold=True, italic=True)
# color.setup(color=conf.color, bold=conf.bold, italic=conf.italic)
self.encoding = _get_encoding(conf)
self._stdout = codecs.getwriter(self.encoding)(_get_raw_stdout(), self._stdout = codecs.getwriter(self.encoding)(_get_raw_stdout(),
errors='replace') errors='replace')
self._stderr = codecs.getwriter(self.encoding)(_get_raw_stderr(), self._stderr = codecs.getwriter(self.encoding)(_get_raw_stderr(),
@ -61,25 +69,23 @@ class PrintUI(object):
""" """
print(' '.join(strings), file=self._stderr, **kwargs) print(' '.join(strings), file=self._stderr, **kwargs)
def error(self, message):
self.print_err('{}: {}'.format(color.dye_err('error', 'red'), message))
def warning(self, message): def warning(self, message):
self.print_err("%s: %s" % (color.dye_err('warning', 'yellow'), message)) self.print_err("%s: %s" % (color.dye_err('warning', 'yellow'), message))
def error(self, message):
self.print_err('{}: {}'.format(color.dye_err('error', 'red'), message))
def exit(self, error_code=1):
sys.exit(error_code)
class InputUI(PrintUI): class InputUI(PrintUI):
"""UI class. Stores configuration parameters and system information. """UI class. Stores configuration parameters and system information.
""" """
def __init__(self, config): def __init__(self, conf):
super(InputUI, self).__init__(config) super(InputUI, self).__init__(conf)
self.editor = config.edit_cmd self.editor = conf.edit_cmd
def exit(self, error_code=1):
sys.exit(error_code)
def input(self): def input(self):
try: try:

@ -9,13 +9,13 @@ def resolve_citekey(repo, citekey, ui=None, exit_on_fail=True):
citekeys = repo.citekeys_from_prefix(citekey) citekeys = repo.citekeys_from_prefix(citekey)
if len(citekeys) == 0: if len(citekeys) == 0:
if ui is not None: if ui is not None:
ui.error("no citekey named or beginning with '{}'".format(color.dye(citekey, color.citekey))) ui.error("no citekey named or beginning with '{}'".format(color.dye_out(citekey, color.citekey)))
if exit_on_fail: if exit_on_fail:
ui.exit() ui.exit()
elif len(citekeys) == 1: elif len(citekeys) == 1:
if citekeys[0] != citekey: if citekeys[0] != citekey:
if ui is not None: if ui is not None:
ui.warning("provided citekey '{}' has been autocompleted into '{}'".format(color.dye(citekey, color.citekey), color.dye(citekeys[0], color.citekey))) ui.warning("provided citekey '{}' has been autocompleted into '{}'".format(color.dye_out(citekey, color.citekey), color.dye_out(citekeys[0], color.citekey)))
citekey = citekeys[0] citekey = citekeys[0]
elif citekey not in citekeys: elif citekey not in citekeys:
if ui is not None: if ui is not None:

Loading…
Cancel
Save