From 78c562d640ed4b5c3da4d7b9c1ec9b9ebe746aed Mon Sep 17 00:00:00 2001 From: Fabien Benureau Date: Mon, 28 Dec 2015 21:28:32 +0100 Subject: [PATCH] 256 colors support + The colors name's are the number 0 through 255. + Old names still work. + Add `magenta` color, wrongly named `purple` before. + Adds `white`, `darkgrey`. + grey/gray spelling Also removed italics as a default option for publisher. Related: #44 --- pubs/color.py | 104 +++++++++++++++++++++++++++++++------------- pubs/config/spec.py | 2 +- 2 files changed, 74 insertions(+), 32 deletions(-) diff --git a/pubs/color.py b/pubs/color.py index 45ef268..9706a6f 100644 --- a/pubs/color.py +++ b/pubs/color.py @@ -1,46 +1,87 @@ """ -Small code to handle colored text +Code to handle colored text """ + +""" +Here is a little explanation about bash color code, useful to understand +the code below. See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html +for a complete referece. + +# 8 colors +The code `\033[{c}m` generate a color, with 30 <= c < 38. The order is: +'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'grey'. + +Additionaly, adding `1;` and `3;` will generate bold and italic text, +respectively, so `\033[1;3;31m` would be bold italic red. Bold and italic +can also be used independently, so `\033[1m` would create bold text without +changing the current color. + +Bold and italic will only be displayed if the terminal allows it *and* the +font supports it (thus, no italic with Monaco). Sometimes, bold is replaced +by the bright version of the font; some terminals allow the user to decide that. + +# 256 colors +256 colors work the same. The code `\033[38;5;{c}` with 0 <= c < 256 will +display colors, with 0 <= c < 8 corresponding to the 8 above colors, and +8 <= c < 16 their bright version. +""" + import sys import re import os - -def _color_supported(stream): - """Return True is the stream supports colors""" +import subprocess + + +COLOR_LIST = {u'black': '0', u'red': '1', u'green': '2', u'yellow': '3', u'blue': '4', + u'magenta': '5', u'cyan': '6', u'grey': '7', + u'brightblack': '8', u'brightred': '9', u'brightgreen': '10', + u'brightyellow': '11', u'brightblue': '12', u'brightmagenta': '13', + u'brightcyan': '14', u'brightgrey': '15', + u'darkgrey': '8', # == brightblack + u'gray': '7', u'darkgray': '8', u'brightgray': '15', # gray/grey spelling + u'purple': '5', # for compatibility reasons + u'white': '15' # == brightgrey + } +for c in range(256): + COLOR_LIST[str(c)] = str(c) + + +def _color_supported(stream, force=False): + """Return the number of supported colors""" + min_colors = 8 if force else 0 if sys.platform == 'win32' and 'ANSICON' not in os.environ: - return False + return min_colors + if hasattr(stream, 'isatty') and stream.isatty(): # we have a tty try: import curses curses.setupterm() - return curses.tigetnum('colors') >= 8 + return max(min_colors, curses.tigetnum('colors')) except Exception: # not picky. - return False - return False + pass -COLOR_LIST = [u'black', u'red', u'green', u'yellow', u'blue', u'purple', u'cyan', u'grey'] + if force: + p = subprocess.Popen(['tput', 'colors'], stdout=subprocess.PIPE) + return max(min_colors, int(p.communicate()[0])) + return 0 def generate_colors(stream, color=True, bold=True, italic=True, force_colors=False): - """Generate colors, based on configuration and detected support + """Generate 256 colors, based on configuration and detected support :param color: generate colors. If False, bold and italic will not change the current color. :param bold: generate bold colors, if False, bold color are the same as normal colors. :param italic: generate italic colors - :param force_colors: generate colors whether support is detected or not. Will not - overrride the `color` parameter. """ - colors = {name: u'' for name in COLOR_LIST} - colors.update({u'b' +name: u'' for name in COLOR_LIST}) - colors.update({u'i' +name: u'' for name in COLOR_LIST}) - colors.update({u'bi'+name: u'' for name in COLOR_LIST}) - colors[u'bold'] = u'' - colors[u'italic'] = u'' - colors[u'end'] = u'' - colors[u''] = u'' + colors = {u'bold': u'', u'italic': u'', u'end': u'', u'': u''} + for name, code in COLOR_LIST.items(): + colors[name] = u'' + colors[u'b' +name] = u'' + colors[u'i' +name] = u'' + colors[u'bi'+name] = u'' - color_support = force_colors or _color_supported(stream) + color_support = _color_supported(stream, force=force_colors) >= 8 if (color or bold or italic) and color_support: bold_flag, italic_flag = '', '' @@ -53,12 +94,13 @@ def generate_colors(stream, color=True, bold=True, italic=True, force_colors=Fal if bold and italic: colors['bolditalic'] = u'\033[1;3m' - for i, name in enumerate(COLOR_LIST): + for name, code in COLOR_LIST.items(): if color: - colors[name] = u'\x1b[3{}m'.format(i) - colors.update({u'b'+name: u'\033[{}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'bi'+name: u'\033[{}{}3{}m'.format(bold_flag, italic_flag, i) for i, name in enumerate(COLOR_LIST)}) + colors[name] = u'\033[38;5;{}m'.format(code) + colors[u'b'+name] = u'\033[{}38;5;{}m'.format(bold_flag, code) + colors[u'i'+name] = u'\033[{}38;5;{}m'.format(italic_flag, code) + colors[u'bi'+name] = u'\033[{}38;5;{}m'.format(bold_flag, italic_flag, code) + else: if bold: colors.update({u'b'+name: u'\033[1m' for i, name in enumerate(COLOR_LIST)}) @@ -68,7 +110,7 @@ def generate_colors(stream, color=True, bold=True, italic=True, force_colors=Fal 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: - colors['end'] = u'\033[0m' + colors[u'end'] = u'\033[0m' return colors @@ -90,12 +132,12 @@ def setup(conf, force_colors=False): """Prepare color for stdout and stderr""" global COLORS_OUT, COLORS_ERR COLORS_OUT = generate_colors(sys.stdout, force_colors=force_colors, - color=conf['formating']['color'], - bold=conf['formating']['bold'], + color =conf['formating']['color'], + bold =conf['formating']['bold'], italic=conf['formating']['italics']) COLORS_ERR = generate_colors(sys.stderr, force_colors=force_colors, - color=conf['formating']['color'], - bold=conf['formating']['bold'], + color =conf['formating']['color'], + bold =conf['formating']['bold'], italic=conf['formating']['italics']) for key, value in conf['theme'].items(): COLORS_OUT[key] = COLORS_OUT.get(value, '') diff --git a/pubs/config/spec.py b/pubs/config/spec.py index 50d2693..6324750 100644 --- a/pubs/config/spec.py +++ b/pubs/config/spec.py @@ -61,7 +61,7 @@ tag = string(default='cyan') # bibliographic fields author = string(default='bold') title = string(default='') -publisher = string(default='italic') +publisher = string(default='') year = string(default='bold') volume = string(default='bold') pages = string(default='')