2006-05-02 09:31:56 +08:00
|
|
|
"""
|
|
|
|
termcolors.py
|
|
|
|
"""
|
|
|
|
|
2012-07-21 03:14:27 +08:00
|
|
|
from django.utils import six
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
|
2014-12-07 05:00:09 +08:00
|
|
|
foreground = {color_names[x]: '3%s' % x for x in range(8)}
|
|
|
|
background = {color_names[x]: '4%s' % x for x in range(8)}
|
2006-05-02 09:31:56 +08:00
|
|
|
|
|
|
|
RESET = '0'
|
|
|
|
opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
|
|
|
|
|
2013-11-03 03:37:48 +08:00
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
def colorize(text='', opts=(), **kwargs):
|
|
|
|
"""
|
|
|
|
Returns your text, enclosed in ANSI graphics codes.
|
|
|
|
|
|
|
|
Depends on the keyword arguments 'fg' and 'bg', and the contents of
|
|
|
|
the opts tuple/list.
|
|
|
|
|
|
|
|
Returns the RESET code if no parameters are given.
|
|
|
|
|
|
|
|
Valid colors:
|
|
|
|
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
|
|
|
|
|
|
|
|
Valid options:
|
|
|
|
'bold'
|
|
|
|
'underscore'
|
|
|
|
'blink'
|
|
|
|
'reverse'
|
|
|
|
'conceal'
|
|
|
|
'noreset' - string will not be auto-terminated with the RESET code
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
colorize('hello', fg='red', bg='blue', opts=('blink',))
|
|
|
|
colorize()
|
|
|
|
colorize('goodbye', opts=('underscore',))
|
2012-04-29 00:02:01 +08:00
|
|
|
print(colorize('first line', fg='red', opts=('noreset',)))
|
|
|
|
print('this should be red too')
|
|
|
|
print(colorize('and so should this'))
|
|
|
|
print('this should not be red')
|
2006-05-02 09:31:56 +08:00
|
|
|
"""
|
|
|
|
code_list = []
|
|
|
|
if text == '' and len(opts) == 1 and opts[0] == 'reset':
|
|
|
|
return '\x1b[%sm' % RESET
|
2012-07-21 03:14:27 +08:00
|
|
|
for k, v in six.iteritems(kwargs):
|
2006-05-02 09:31:56 +08:00
|
|
|
if k == 'fg':
|
|
|
|
code_list.append(foreground[v])
|
|
|
|
elif k == 'bg':
|
|
|
|
code_list.append(background[v])
|
|
|
|
for o in opts:
|
|
|
|
if o in opt_dict:
|
|
|
|
code_list.append(opt_dict[o])
|
|
|
|
if 'noreset' not in opts:
|
2013-02-02 05:51:08 +08:00
|
|
|
text = '%s\x1b[%sm' % (text or '', RESET)
|
|
|
|
return '%s%s' % (('\x1b[%sm' % ';'.join(code_list)), text or '')
|
2006-05-02 09:31:56 +08:00
|
|
|
|
2013-11-03 03:37:48 +08:00
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
def make_style(opts=(), **kwargs):
|
|
|
|
"""
|
|
|
|
Returns a function with default parameters for colorize()
|
|
|
|
|
|
|
|
Example:
|
|
|
|
bold_red = make_style(opts=('bold',), fg='red')
|
2012-04-29 00:02:01 +08:00
|
|
|
print(bold_red('hello'))
|
2006-05-02 09:31:56 +08:00
|
|
|
KEYWORD = make_style(fg='yellow')
|
|
|
|
COMMENT = make_style(fg='blue', opts=('bold',))
|
|
|
|
"""
|
|
|
|
return lambda text: colorize(text, opts, **kwargs)
|
2009-12-28 14:48:47 +08:00
|
|
|
|
2016-11-13 01:11:23 +08:00
|
|
|
|
2009-12-28 14:48:47 +08:00
|
|
|
NOCOLOR_PALETTE = 'nocolor'
|
|
|
|
DARK_PALETTE = 'dark'
|
|
|
|
LIGHT_PALETTE = 'light'
|
|
|
|
|
|
|
|
PALETTES = {
|
|
|
|
NOCOLOR_PALETTE: {
|
2013-11-03 03:37:48 +08:00
|
|
|
'ERROR': {},
|
2015-09-22 04:47:48 +08:00
|
|
|
'SUCCESS': {},
|
2014-01-20 10:45:21 +08:00
|
|
|
'WARNING': {},
|
2013-11-03 03:37:48 +08:00
|
|
|
'NOTICE': {},
|
|
|
|
'SQL_FIELD': {},
|
|
|
|
'SQL_COLTYPE': {},
|
|
|
|
'SQL_KEYWORD': {},
|
|
|
|
'SQL_TABLE': {},
|
|
|
|
'HTTP_INFO': {},
|
|
|
|
'HTTP_SUCCESS': {},
|
|
|
|
'HTTP_REDIRECT': {},
|
2010-01-24 01:26:56 +08:00
|
|
|
'HTTP_NOT_MODIFIED': {},
|
2013-11-03 03:37:48 +08:00
|
|
|
'HTTP_BAD_REQUEST': {},
|
|
|
|
'HTTP_NOT_FOUND': {},
|
2010-01-04 20:16:09 +08:00
|
|
|
'HTTP_SERVER_ERROR': {},
|
2013-11-03 03:37:48 +08:00
|
|
|
'MIGRATE_HEADING': {},
|
|
|
|
'MIGRATE_LABEL': {},
|
2009-12-28 14:48:47 +08:00
|
|
|
},
|
|
|
|
DARK_PALETTE: {
|
2013-11-03 03:37:48 +08:00
|
|
|
'ERROR': {'fg': 'red', 'opts': ('bold',)},
|
2015-09-22 04:47:48 +08:00
|
|
|
'SUCCESS': {'fg': 'green', 'opts': ('bold',)},
|
2014-01-20 10:45:21 +08:00
|
|
|
'WARNING': {'fg': 'yellow', 'opts': ('bold',)},
|
2013-11-03 03:37:48 +08:00
|
|
|
'NOTICE': {'fg': 'red'},
|
|
|
|
'SQL_FIELD': {'fg': 'green', 'opts': ('bold',)},
|
|
|
|
'SQL_COLTYPE': {'fg': 'green'},
|
|
|
|
'SQL_KEYWORD': {'fg': 'yellow'},
|
|
|
|
'SQL_TABLE': {'opts': ('bold',)},
|
|
|
|
'HTTP_INFO': {'opts': ('bold',)},
|
|
|
|
'HTTP_SUCCESS': {},
|
|
|
|
'HTTP_REDIRECT': {'fg': 'green'},
|
2013-10-15 03:13:14 +08:00
|
|
|
'HTTP_NOT_MODIFIED': {'fg': 'cyan'},
|
2013-11-03 03:37:48 +08:00
|
|
|
'HTTP_BAD_REQUEST': {'fg': 'red', 'opts': ('bold',)},
|
|
|
|
'HTTP_NOT_FOUND': {'fg': 'yellow'},
|
2013-10-15 03:13:14 +08:00
|
|
|
'HTTP_SERVER_ERROR': {'fg': 'magenta', 'opts': ('bold',)},
|
2013-11-03 03:37:48 +08:00
|
|
|
'MIGRATE_HEADING': {'fg': 'cyan', 'opts': ('bold',)},
|
|
|
|
'MIGRATE_LABEL': {'opts': ('bold',)},
|
2009-12-28 14:48:47 +08:00
|
|
|
},
|
|
|
|
LIGHT_PALETTE: {
|
2013-11-03 03:37:48 +08:00
|
|
|
'ERROR': {'fg': 'red', 'opts': ('bold',)},
|
2015-09-22 04:47:48 +08:00
|
|
|
'SUCCESS': {'fg': 'green', 'opts': ('bold',)},
|
2014-01-20 10:45:21 +08:00
|
|
|
'WARNING': {'fg': 'yellow', 'opts': ('bold',)},
|
2013-11-03 03:37:48 +08:00
|
|
|
'NOTICE': {'fg': 'red'},
|
|
|
|
'SQL_FIELD': {'fg': 'green', 'opts': ('bold',)},
|
|
|
|
'SQL_COLTYPE': {'fg': 'green'},
|
|
|
|
'SQL_KEYWORD': {'fg': 'blue'},
|
|
|
|
'SQL_TABLE': {'opts': ('bold',)},
|
|
|
|
'HTTP_INFO': {'opts': ('bold',)},
|
|
|
|
'HTTP_SUCCESS': {},
|
|
|
|
'HTTP_REDIRECT': {'fg': 'green', 'opts': ('bold',)},
|
2013-10-15 03:13:14 +08:00
|
|
|
'HTTP_NOT_MODIFIED': {'fg': 'green'},
|
2013-11-03 03:37:48 +08:00
|
|
|
'HTTP_BAD_REQUEST': {'fg': 'red', 'opts': ('bold',)},
|
|
|
|
'HTTP_NOT_FOUND': {'fg': 'red'},
|
2013-10-15 03:13:14 +08:00
|
|
|
'HTTP_SERVER_ERROR': {'fg': 'magenta', 'opts': ('bold',)},
|
2013-11-03 03:37:48 +08:00
|
|
|
'MIGRATE_HEADING': {'fg': 'cyan', 'opts': ('bold',)},
|
|
|
|
'MIGRATE_LABEL': {'opts': ('bold',)},
|
2009-12-28 14:48:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
DEFAULT_PALETTE = DARK_PALETTE
|
|
|
|
|
2013-11-03 03:37:48 +08:00
|
|
|
|
2009-12-28 14:48:47 +08:00
|
|
|
def parse_color_setting(config_string):
|
|
|
|
"""Parse a DJANGO_COLORS environment variable to produce the system palette
|
|
|
|
|
2015-11-03 17:55:10 +08:00
|
|
|
The general form of a palette definition is:
|
2009-12-28 14:48:47 +08:00
|
|
|
|
|
|
|
"palette;role=fg;role=fg/bg;role=fg,option,option;role=fg/bg,option,option"
|
|
|
|
|
|
|
|
where:
|
|
|
|
palette is a named palette; one of 'light', 'dark', or 'nocolor'.
|
|
|
|
role is a named style used by Django
|
|
|
|
fg is a background color.
|
|
|
|
bg is a background color.
|
|
|
|
option is a display options.
|
|
|
|
|
|
|
|
Specifying a named palette is the same as manually specifying the individual
|
2015-11-03 17:55:10 +08:00
|
|
|
definitions for each role. Any individual definitions following the palette
|
2009-12-28 14:48:47 +08:00
|
|
|
definition will augment the base palette definition.
|
|
|
|
|
|
|
|
Valid roles:
|
2016-10-06 21:27:33 +08:00
|
|
|
'error', 'success', 'warning', 'notice', 'sql_field', 'sql_coltype',
|
|
|
|
'sql_keyword', 'sql_table', 'http_info', 'http_success',
|
|
|
|
'http_redirect', 'http_not_modified', 'http_bad_request',
|
|
|
|
'http_not_found', 'http_server_error', 'migrate_heading',
|
|
|
|
'migrate_label'
|
2009-12-28 14:48:47 +08:00
|
|
|
|
|
|
|
Valid colors:
|
|
|
|
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
|
|
|
|
|
|
|
|
Valid options:
|
2016-10-06 21:27:33 +08:00
|
|
|
'bold', 'underscore', 'blink', 'reverse', 'conceal', 'noreset'
|
2009-12-28 14:48:47 +08:00
|
|
|
"""
|
|
|
|
if not config_string:
|
|
|
|
return PALETTES[DEFAULT_PALETTE]
|
|
|
|
|
|
|
|
# Split the color configuration into parts
|
|
|
|
parts = config_string.lower().split(';')
|
|
|
|
palette = PALETTES[NOCOLOR_PALETTE].copy()
|
|
|
|
for part in parts:
|
|
|
|
if part in PALETTES:
|
|
|
|
# A default palette has been specified
|
|
|
|
palette.update(PALETTES[part])
|
|
|
|
elif '=' in part:
|
|
|
|
# Process a palette defining string
|
|
|
|
definition = {}
|
|
|
|
|
|
|
|
# Break the definition into the role,
|
|
|
|
# plus the list of specific instructions.
|
|
|
|
# The role must be in upper case
|
|
|
|
role, instructions = part.split('=')
|
|
|
|
role = role.upper()
|
|
|
|
|
|
|
|
styles = instructions.split(',')
|
|
|
|
styles.reverse()
|
|
|
|
|
|
|
|
# The first instruction can contain a slash
|
|
|
|
# to break apart fg/bg.
|
|
|
|
colors = styles.pop().split('/')
|
|
|
|
colors.reverse()
|
|
|
|
fg = colors.pop()
|
|
|
|
if fg in color_names:
|
|
|
|
definition['fg'] = fg
|
|
|
|
if colors and colors[-1] in color_names:
|
|
|
|
definition['bg'] = colors[-1]
|
|
|
|
|
|
|
|
# All remaining instructions are options
|
|
|
|
opts = tuple(s for s in styles if s in opt_dict.keys())
|
|
|
|
if opts:
|
|
|
|
definition['opts'] = opts
|
|
|
|
|
|
|
|
# The nocolor palette has all available roles.
|
|
|
|
# Use that palette as the basis for determining
|
|
|
|
# if the role is valid.
|
|
|
|
if role in PALETTES[NOCOLOR_PALETTE] and definition:
|
|
|
|
palette[role] = definition
|
|
|
|
|
|
|
|
# If there are no colors specified, return the empty palette.
|
|
|
|
if palette == PALETTES[NOCOLOR_PALETTE]:
|
|
|
|
return None
|
|
|
|
return palette
|