Add --force-colors option

Useful when piping to a pager that supports color.
Improved and cleaned up a bit the ui functions too.

Related #44, #47
main
Fabien Benureau 9 years ago
parent a291114900
commit 2ba435126d

@ -6,7 +6,7 @@ import re
import os import os
def _color_supported(stream): def _color_supported(stream):
"""Returns True is the stream supports colors""" """Return True is the stream supports colors"""
if sys.platform == 'win32' and 'ANSICON' not in os.environ: if sys.platform == 'win32' and 'ANSICON' not in os.environ:
return False return False
if hasattr(stream, 'isatty') and stream.isatty(): # we have a tty if hasattr(stream, 'isatty') and stream.isatty(): # we have a tty
@ -20,7 +20,17 @@ def _color_supported(stream):
COLOR_LIST = [u'black', u'red', u'green', u'yellow', u'blue', u'purple', u'cyan', u'grey'] COLOR_LIST = [u'black', u'red', u'green', u'yellow', u'blue', u'purple', u'cyan', u'grey']
def generate_colors(stream, color=True, bold=True, italic=True): def generate_colors(stream, color=True, bold=True, italic=True, force_colors=False):
"""Generate 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 = {name: u'' for name in COLOR_LIST}
colors.update({u'b' +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'i' +name: u'' for name in COLOR_LIST})
@ -30,7 +40,9 @@ def generate_colors(stream, color=True, bold=True, italic=True):
colors[u'end'] = u'' colors[u'end'] = u''
colors[u''] = u'' colors[u''] = u''
if (color or bold or italic) and _color_supported(stream): color_support = force_colors or _color_supported(stream)
if (color or bold or italic) and color_support:
bold_flag, italic_flag = '', '' bold_flag, italic_flag = '', ''
if bold: if bold:
colors['bold'] = u'\033[1m' colors['bold'] = u'\033[1m'
@ -64,27 +76,32 @@ def generate_colors(stream, color=True, bold=True, italic=True):
COLORS_OUT = generate_colors(sys.stdout, color=False, bold=False, italic=False) COLORS_OUT = generate_colors(sys.stdout, color=False, bold=False, italic=False)
COLORS_ERR = generate_colors(sys.stderr, color=False, bold=False, italic=False) COLORS_ERR = generate_colors(sys.stderr, color=False, bold=False, italic=False)
def dye_out(s, color='end'): def dye_out(s, color='end'):
"""Color a string for output on stdout"""
return u'{}{}{}'.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'):
"""Color a string for output on stderr"""
return u'{}{}{}'.format(COLORS_ERR[color], s, COLORS_OUT['end']) return u'{}{}{}'.format(COLORS_ERR[color], s, COLORS_OUT['end'])
def _nodye(s, *args, **kwargs):
return s
def setup(conf): def setup(conf, force_colors=False):
"""Prepare color for stdout and stderr"""
global COLORS_OUT, COLORS_ERR global COLORS_OUT, COLORS_ERR
COLORS_OUT = generate_colors(sys.stdout, color=conf['formating']['color'], COLORS_OUT = generate_colors(sys.stdout, force_colors=force_colors,
bold=conf['formating']['bold'], color=conf['formating']['color'],
italic=conf['formating']['italics']) bold=conf['formating']['bold'],
COLORS_ERR = generate_colors(sys.stderr, color=conf['formating']['color'], italic=conf['formating']['italics'])
bold=conf['formating']['bold'], COLORS_ERR = generate_colors(sys.stderr, force_colors=force_colors,
italic=conf['formating']['italics']) color=conf['formating']['color'],
bold=conf['formating']['bold'],
italic=conf['formating']['italics'])
for key, value in conf['theme'].items(): for key, value in conf['theme'].items():
COLORS_OUT[key] = COLORS_OUT.get(value, '') COLORS_OUT[key] = COLORS_OUT.get(value, '')
COLORS_ERR[key] = COLORS_ERR.get(value, '') COLORS_ERR[key] = COLORS_ERR.get(value, '')
# undye # undye
undye_re = re.compile('\x1b\[[;\d]*[A-Za-z]') undye_re = re.compile('\x1b\[[;\d]*[A-Za-z]')

@ -35,6 +35,9 @@ def execute(raw_args=sys.argv):
conf_parser = argparse.ArgumentParser(prog="pubs", add_help=False) conf_parser = argparse.ArgumentParser(prog="pubs", add_help=False)
conf_parser.add_argument("-c", "--config", help="path to config file", conf_parser.add_argument("-c", "--config", help="path to config file",
type=str, metavar="FILE") type=str, metavar="FILE")
conf_parser.add_argument('--force-colors', dest='force_colors',
action='store_true', default=False,
help='color are not disabled when piping to a file or other commands')
#conf_parser.add_argument("-u", "--update", help="update config if needed", #conf_parser.add_argument("-u", "--update", help="update config if needed",
# default=False, action='store_true') # default=False, action='store_true')
top_args, remaining_args = conf_parser.parse_known_args(raw_args[1:]) top_args, remaining_args = conf_parser.parse_known_args(raw_args[1:])
@ -59,7 +62,7 @@ def execute(raw_args=sys.argv):
conf = config.load_default_conf() conf = config.load_default_conf()
conf.filename = conf_path conf.filename = conf_path
uis.init_ui(conf) uis.init_ui(conf, force_colors=top_args.force_colors)
ui = uis.get_ui() ui = uis.get_ui()
parser = argparse.ArgumentParser(description="research papers repository", parser = argparse.ArgumentParser(description="research papers repository",

@ -44,19 +44,19 @@ def get_ui():
return _ui return _ui
def init_ui(conf): def init_ui(conf, force_colors=False):
global _ui global _ui
_ui = InputUI(conf) _ui = InputUI(conf, force_colors=force_colors)
class PrintUI(object): class PrintUI(object):
def __init__(self, conf): def __init__(self, conf, force_colors=False):
""" """
:param conf: if None, conservative default values are used. :param conf: if None, conservative default values are used.
Useful to instanciate the UI before parsing the config file. Useful to instanciate the UI before parsing the config file.
""" """
color.setup(conf) color.setup(conf, force_colors=force_colors)
self.encoding = _get_encoding(conf) 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')
@ -87,8 +87,8 @@ class InputUI(PrintUI):
"""UI class. Stores configuration parameters and system information. """UI class. Stores configuration parameters and system information.
""" """
def __init__(self, conf): def __init__(self, conf, force_colors=False):
super(InputUI, self).__init__(conf) super(InputUI, self).__init__(conf, force_colors=force_colors)
self.editor = conf['main']['edit_cmd'] or _get_local_editor() self.editor = conf['main']['edit_cmd'] or _get_local_editor()
def input(self): def input(self):

Loading…
Cancel
Save