From d3fce35481f09f28561dc2438baa7ec5245b7870 Mon Sep 17 00:00:00 2001 From: Tom Jaspers Date: Mon, 26 Jan 2015 17:24:32 +0100 Subject: [PATCH 1/5] Colors are user configurable - Colors are mapped on to a dictionary using abstract names (e.g., text_success) - Add `colors` option under `ui` to allow users to choose their own color scheme - Move configuration option `color` from top-level to `ui` - Show deprecation warning if top-level `color` configuration is used (but respect it) Fix #1238 --- beets/config_default.yaml | 10 +++++++++- beets/ui/__init__.py | 35 +++++++++++++++++++++++++++-------- beets/ui/commands.py | 30 +++++++++++++++++------------- beetsplug/fetchart.py | 6 ++++-- beetsplug/play.py | 5 +++-- 5 files changed, 60 insertions(+), 26 deletions(-) diff --git a/beets/config_default.yaml b/beets/config_default.yaml index 1d3c4ad7a..c448585d9 100644 --- a/beets/config_default.yaml +++ b/beets/config_default.yaml @@ -41,7 +41,6 @@ max_filename_length: 0 plugins: [] pluginpath: [] threaded: yes -color: yes timeout: 5.0 per_disc_numbering: no verbose: no @@ -52,6 +51,15 @@ id3v23: no ui: terminal_width: 80 length_diff_thresh: 10.0 + color: yes + colors: + text_success: green + text_warning: yellow + text_error: red + text_highlight: red + text_highlight_minor: lightgray + action_default: turquoise + action: blue list_format_item: $artist - $album - $title list_format_album: $albumartist - $album diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index c541ba2de..633a2c3e6 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -191,7 +191,9 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None, is_default = False # Colorize the letter shortcut. - show_letter = colorize('turquoise' if is_default else 'blue', + show_letter = colorize(COLORS['action_default'] + if is_default + else COLORS['action'], show_letter) # Insert the highlighted letter back into the word. @@ -218,7 +220,7 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None, if numrange: if isinstance(default, int): default_name = str(default) - default_name = colorize('turquoise', default_name) + default_name = colorize(COLORS['action_default'], default_name) tmpl = '# selection (default %s)' prompt_parts.append(tmpl % default_name) prompt_part_lengths.append(len(tmpl % str(default))) @@ -357,6 +359,13 @@ LIGHT_COLORS = ["darkgray", "red", "green", "yellow", "blue", "fuchsia", "turquoise", "white"] RESET_COLOR = COLOR_ESCAPE + "39;49;00m" +# Map the color names to the configured colors in a dict +COLOR_NAMES = ['text_success', 'text_warning', 'text_error', 'text_highlight', + 'text_highlight_minor', 'action_default', 'action'] +COLORS = dict(zip(COLOR_NAMES, + map(lambda x: config['ui']['colors'][x].get(str), + COLOR_NAMES))) + def _colorize(color, text): """Returns a string that prints the given text in the given color @@ -376,13 +385,14 @@ def colorize(color, text): """Colorize text if colored output is enabled. (Like _colorize but conditional.) """ - if config['color']: + if config['ui']['color']: return _colorize(color, text) else: return text -def _colordiff(a, b, highlight='red', minor_highlight='lightgray'): +def _colordiff(a, b, highlight=COLORS['text_highlight'], + minor_highlight=COLORS['text_highlight_minor']): """Given two values, return the same pair of strings except with their differences highlighted in the specified color. Strings are highlighted intelligently to show differences; other values are @@ -432,11 +442,11 @@ def _colordiff(a, b, highlight='red', minor_highlight='lightgray'): return u''.join(a_out), u''.join(b_out) -def colordiff(a, b, highlight='red'): +def colordiff(a, b, highlight=COLORS['text_highlight']): """Colorize differences between two values if color is enabled. (Like _colordiff but conditional.) """ - if config['color']: + if config['ui']['color']: return _colordiff(a, b, highlight) else: return unicode(a), unicode(b) @@ -546,7 +556,8 @@ def _field_diff(field, old, new): if isinstance(oldval, basestring): oldstr, newstr = colordiff(oldval, newstr) else: - oldstr, newstr = colorize('red', oldstr), colorize('red', newstr) + oldstr = colorize(COLORS['text_error'], oldstr) + newstr = colorize(COLORS['text_error'], newstr) return u'{0} -> {1}'.format(oldstr, newstr) @@ -582,7 +593,7 @@ def show_model_changes(new, old=None, fields=None, always=False): changes.append(u' {0}: {1}'.format( field, - colorize('red', new.formatted()[field]) + colorize(COLORS['text_highlight'], new.formatted()[field]) )) # Print changes. @@ -865,6 +876,14 @@ def _configure(options): else: log.setLevel(logging.INFO) + # Ensure compatibility with old (top-level) color configuration. + # Deprecation msg to motivate user to switch to config['ui']['color]. + if config['color'].exists(): + log.warning(u'Warning: top-level configuration of `color` ' + u'is deprecated. Configure color use under `ui`. ' + u'See documentation for more info.') + config['ui']['color'].set(config['color'].get(bool)) + config_path = config.user_config_path() if os.path.isfile(config_path): log.debug(u'user configuration: {0}', diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 839263fc5..89eff2d49 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -175,11 +175,11 @@ def dist_string(dist): """ out = '%.1f%%' % ((1 - dist) * 100) if dist <= config['match']['strong_rec_thresh'].as_number(): - out = ui.colorize('green', out) + out = ui.colorize(ui.COLORS['text_success'], out) elif dist <= config['match']['medium_rec_thresh'].as_number(): - out = ui.colorize('yellow', out) + out = ui.colorize(ui.COLORS['text_warning'], out) else: - out = ui.colorize('red', out) + out = ui.colorize(ui.COLORS['text_error'], out) return out @@ -196,7 +196,8 @@ def penalty_string(distance, limit=None): if penalties: if limit and len(penalties) > limit: penalties = penalties[:limit] + ['...'] - return ui.colorize('yellow', '(%s)' % ', '.join(penalties)) + return ui.colorize(ui.COLORS['text_warning'], + '(%s)' % ', '.join(penalties)) def show_change(cur_artist, cur_album, match): @@ -269,7 +270,8 @@ def show_change(cur_artist, cur_album, match): # Disambiguation. disambig = disambig_string(match.info) if disambig: - info.append(ui.colorize('lightgray', '(%s)' % disambig)) + info.append(ui.colorize(ui.COLORS['text_highlight_minor'], + '(%s)' % disambig)) print_(' '.join(info)) # Tracks. @@ -314,9 +316,9 @@ def show_change(cur_artist, cur_album, match): cur_track, new_track = format_index(item), format_index(track_info) if cur_track != new_track: if item.track in (track_info.index, track_info.medium_index): - color = 'lightgray' + color = ui.COLORS['text_highlight_minor'] else: - color = 'red' + color = ui.COLORS['text_highlight'] templ = ui.colorize(color, u' (#{0})') lhs += templ.format(cur_track) rhs += templ.format(new_track) @@ -328,7 +330,7 @@ def show_change(cur_artist, cur_album, match): config['ui']['length_diff_thresh'].as_number(): cur_length = ui.human_seconds_short(item.length) new_length = ui.human_seconds_short(track_info.length) - templ = ui.colorize('red', u' ({0})') + templ = ui.colorize(ui.COLORS['text_highlight'], u' ({0})') lhs += templ.format(cur_length) rhs += templ.format(new_length) lhs_width += len(cur_length) + 3 @@ -363,14 +365,14 @@ def show_change(cur_artist, cur_album, match): line = ' ! %s (#%s)' % (track_info.title, format_index(track_info)) if track_info.length: line += ' (%s)' % ui.human_seconds_short(track_info.length) - print_(ui.colorize('yellow', line)) + print_(ui.colorize(ui.COLORS['text_warning'], line)) if match.extra_items: print_('Unmatched tracks:') for item in match.extra_items: line = ' ! %s (#%s)' % (item.title, format_index(item)) if item.length: line += ' (%s)' % ui.human_seconds_short(item.length) - print_(ui.colorize('yellow', line)) + print_(ui.colorize(ui.COLORS['text_warning'], line)) def show_item_change(item, match): @@ -407,7 +409,8 @@ def show_item_change(item, match): # Disambiguation. disambig = disambig_string(match.info) if disambig: - info.append(ui.colorize('lightgray', '(%s)' % disambig)) + info.append(ui.colorize(ui.COLORS['text_highlight_minor'], + '(%s)' % disambig)) print_(' '.join(info)) @@ -566,7 +569,8 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None, # Disambiguation disambig = disambig_string(match.info) if disambig: - line.append(ui.colorize('lightgray', '(%s)' % disambig)) + line.append(ui.colorize(ui.COLORS['text_highlight_minor'], + '(%s)' % disambig)) print_(' '.join(line)) @@ -1000,7 +1004,7 @@ def update_items(lib, query, album, move, pretend): # Item deleted? if not os.path.exists(syspath(item.path)): ui.print_obj(item, lib) - ui.print_(ui.colorize('red', u' deleted')) + ui.print_(ui.colorize(ui.COLORS['text_error'], u' deleted')) if not pretend: item.remove(True) affected_albums.add(item.album_id) diff --git a/beetsplug/fetchart.py b/beetsplug/fetchart.py index 196be4b2d..ce3e3360d 100644 --- a/beetsplug/fetchart.py +++ b/beetsplug/fetchart.py @@ -444,9 +444,11 @@ class FetchArtPlugin(plugins.BeetsPlugin): if path: album.set_art(path, False) album.store() - message = ui.colorize('green', 'found album art') + message = ui.colorize(ui.COLORS['text_success'], + 'found album art') else: - message = ui.colorize('red', 'no art found') + message = ui.colorize(ui.COLORS['text_error'], + 'no art found') self._log.info(u'{0.albumartist} - {0.album}: {1}', album, message) diff --git a/beetsplug/play.py b/beetsplug/play.py index 5072234ca..7d0c0a531 100644 --- a/beetsplug/play.py +++ b/beetsplug/play.py @@ -73,13 +73,14 @@ def play_music(lib, opts, args, log): item_type += 's' if len(selection) > 1 else '' if not selection: - ui.print_(ui.colorize('yellow', 'No {0} to play.'.format(item_type))) + ui.print_(ui.colorize(ui.COLORS['text_warning'], + 'No {0} to play.'.format(item_type))) return # Warn user before playing any huge playlists. if len(selection) > 100: ui.print_(ui.colorize( - 'yellow', + ui.COLORS['text_warning'], 'You are about to queue {0} {1}.'.format(len(selection), item_type) )) From e7378c77a73b5a7ef27b9d153004f01feb490343 Mon Sep 17 00:00:00 2001 From: Tom Jaspers Date: Thu, 29 Jan 2015 14:04:37 +0100 Subject: [PATCH 2/5] Fix tests to use config['ui']['color'] instead of top-level color --- test/helper.py | 2 +- test/test_ui.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/helper.py b/test/helper.py index a1faf2a63..2f0889bc0 100644 --- a/test/helper.py +++ b/test/helper.py @@ -165,7 +165,7 @@ class TestHelper(object): self.config['plugins'] = [] self.config['verbose'] = True - self.config['color'] = False + self.config['ui']['color'] = False self.config['threaded'] = False self.libdir = os.path.join(self.temp_dir, 'libdir') diff --git a/test/test_ui.py b/test/test_ui.py index e32f9ed83..05e3b53c2 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -888,7 +888,7 @@ class ShowChangeTest(_common.TestCase): items = items or self.items info = info or self.info mapping = dict(zip(items, info.tracks)) - config['color'] = False + config['ui']['color'] = False album_dist = distance(items, info, mapping) album_dist._penalties = {'album': [dist]} commands.show_change( From ea687baebdd173490af60d5a7e7d65ff591ee257 Mon Sep 17 00:00:00 2001 From: Tom Jaspers Date: Thu, 29 Jan 2015 14:05:00 +0100 Subject: [PATCH 3/5] Configurable colors: update documentation and changelog --- docs/changelog.rst | 4 ++++ docs/reference/config.rst | 50 +++++++++++++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index c10a64981..0cfc279ce 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,10 @@ Changelog Features: +* The colors used are now configurable via the new config option ``colors``, + nested under the option ``ui``. The `color` config option has been moved + from top-level to under ``ui``. Beets will respect the old color setting, + but will warn the user with a deprecation message. :bug:`1238` * A new :doc:`/plugins/filefilter` lets you write regular expressions to automatically avoid importing certain files. Thanks to :user:`mried`. :bug:`1186` diff --git a/docs/reference/config.rst b/docs/reference/config.rst index 7782e4ad8..a64e73749 100644 --- a/docs/reference/config.rst +++ b/docs/reference/config.rst @@ -162,13 +162,6 @@ Either ``yes`` or ``no``, indicating whether the autotagger should use multiple threads. This makes things faster but may behave strangely. Defaults to ``yes``. -color -~~~~~ - -Either ``yes`` or ``no``; whether to use color in console output (currently -only in the ``import`` command). Turn this off if your terminal doesn't -support ANSI colors. - .. _list_format_item: list_format_item @@ -277,6 +270,49 @@ version of ID3. Enable this option to instead use the older ID3v2.3 standard, which is preferred by certain older software such as Windows Media Player. +UI Options +---------- + +The options that allow for customization of the visual appearance +of the console interface. + +These options are available in this section: + +color +~~~~~ + +Either ``yes`` or ``no``; whether to use color in console output (currently +only in the ``import`` command). Turn this off if your terminal doesn't +support ANSI colors. + +.. note:: + + The `color` option was previously a top-level configuration. This is + still respected, but a deprecation message will be shown until your + top-level `color` configuration has been nested under `ui`. + +colors +~~~~~~ + +The colors that are used throughout the user interface. These are only used if +the ``color`` option is set to ``yes``. For example, you might have a section +in your configuration file that looks like this:: + + ui: + color: yes + colors: + text_success: green + text_warning: yellow + text_error: red + text_highlight: red + text_highlight_minor: lightgray + action_default: turquoise + action: blue + +Available colors: black, darkred, darkgreen, brown, darkblue, purple, teal, +lightgray, darkgray, red, green, yellow, blue, fuchsia, turquoise, white + + Importer Options ---------------- From f483012183b1f56456c2c7005a5fbf5244f63b5e Mon Sep 17 00:00:00 2001 From: Tom Jaspers Date: Thu, 29 Jan 2015 14:33:57 +0100 Subject: [PATCH 4/5] Colorize is now to be called with the abstract color_name instead of the color. E.g., `colorize('text_success', 'hello world')` To ensure compatibility with 3rd party plugins, a valid color ('red') can still be passed, but it will be logged. --- beets/ui/__init__.py | 26 +++++++++++++++----------- beets/ui/commands.py | 29 +++++++++++++---------------- beetsplug/fetchart.py | 6 ++---- beetsplug/play.py | 4 ++-- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index 633a2c3e6..9efd0c706 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -191,9 +191,7 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None, is_default = False # Colorize the letter shortcut. - show_letter = colorize(COLORS['action_default'] - if is_default - else COLORS['action'], + show_letter = colorize('action_default' if is_default else 'action', show_letter) # Insert the highlighted letter back into the word. @@ -220,7 +218,7 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None, if numrange: if isinstance(default, int): default_name = str(default) - default_name = colorize(COLORS['action_default'], default_name) + default_name = colorize('action_default', default_name) tmpl = '# selection (default %s)' prompt_parts.append(tmpl % default_name) prompt_part_lengths.append(len(tmpl % str(default))) @@ -381,18 +379,24 @@ def _colorize(color, text): return escape + text + RESET_COLOR -def colorize(color, text): +def colorize(color_name, text): """Colorize text if colored output is enabled. (Like _colorize but conditional.) """ if config['ui']['color']: + # In case a 3rd party plugin is still passing the actual color ('red') + # instead of the abstract color name ('text_error') + color = COLORS.get(color_name) + if not color: + log.debug(u'Invalid color_name: {0}', color_name) + color = color_name return _colorize(color, text) else: return text -def _colordiff(a, b, highlight=COLORS['text_highlight'], - minor_highlight=COLORS['text_highlight_minor']): +def _colordiff(a, b, highlight='text_highlight', + minor_highlight='text_highlight_minor'): """Given two values, return the same pair of strings except with their differences highlighted in the specified color. Strings are highlighted intelligently to show differences; other values are @@ -442,7 +446,7 @@ def _colordiff(a, b, highlight=COLORS['text_highlight'], return u''.join(a_out), u''.join(b_out) -def colordiff(a, b, highlight=COLORS['text_highlight']): +def colordiff(a, b, highlight='text_highlight'): """Colorize differences between two values if color is enabled. (Like _colordiff but conditional.) """ @@ -556,8 +560,8 @@ def _field_diff(field, old, new): if isinstance(oldval, basestring): oldstr, newstr = colordiff(oldval, newstr) else: - oldstr = colorize(COLORS['text_error'], oldstr) - newstr = colorize(COLORS['text_error'], newstr) + oldstr = colorize('text_error', oldstr) + newstr = colorize('text_error', newstr) return u'{0} -> {1}'.format(oldstr, newstr) @@ -593,7 +597,7 @@ def show_model_changes(new, old=None, fields=None, always=False): changes.append(u' {0}: {1}'.format( field, - colorize(COLORS['text_highlight'], new.formatted()[field]) + colorize('text_highlight', new.formatted()[field]) )) # Print changes. diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 89eff2d49..710e7bd4d 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -175,11 +175,11 @@ def dist_string(dist): """ out = '%.1f%%' % ((1 - dist) * 100) if dist <= config['match']['strong_rec_thresh'].as_number(): - out = ui.colorize(ui.COLORS['text_success'], out) + out = ui.colorize('text_success', out) elif dist <= config['match']['medium_rec_thresh'].as_number(): - out = ui.colorize(ui.COLORS['text_warning'], out) + out = ui.colorize('text_warning', out) else: - out = ui.colorize(ui.COLORS['text_error'], out) + out = ui.colorize('text_error', out) return out @@ -196,8 +196,7 @@ def penalty_string(distance, limit=None): if penalties: if limit and len(penalties) > limit: penalties = penalties[:limit] + ['...'] - return ui.colorize(ui.COLORS['text_warning'], - '(%s)' % ', '.join(penalties)) + return ui.colorize('text_warning', '(%s)' % ', '.join(penalties)) def show_change(cur_artist, cur_album, match): @@ -270,8 +269,7 @@ def show_change(cur_artist, cur_album, match): # Disambiguation. disambig = disambig_string(match.info) if disambig: - info.append(ui.colorize(ui.COLORS['text_highlight_minor'], - '(%s)' % disambig)) + info.append(ui.colorize('text_highlight_minor', '(%s)' % disambig)) print_(' '.join(info)) # Tracks. @@ -316,9 +314,9 @@ def show_change(cur_artist, cur_album, match): cur_track, new_track = format_index(item), format_index(track_info) if cur_track != new_track: if item.track in (track_info.index, track_info.medium_index): - color = ui.COLORS['text_highlight_minor'] + color = 'text_highlight_minor' else: - color = ui.COLORS['text_highlight'] + color = 'text_highlight' templ = ui.colorize(color, u' (#{0})') lhs += templ.format(cur_track) rhs += templ.format(new_track) @@ -330,7 +328,7 @@ def show_change(cur_artist, cur_album, match): config['ui']['length_diff_thresh'].as_number(): cur_length = ui.human_seconds_short(item.length) new_length = ui.human_seconds_short(track_info.length) - templ = ui.colorize(ui.COLORS['text_highlight'], u' ({0})') + templ = ui.colorize('text_highlight', u' ({0})') lhs += templ.format(cur_length) rhs += templ.format(new_length) lhs_width += len(cur_length) + 3 @@ -365,14 +363,14 @@ def show_change(cur_artist, cur_album, match): line = ' ! %s (#%s)' % (track_info.title, format_index(track_info)) if track_info.length: line += ' (%s)' % ui.human_seconds_short(track_info.length) - print_(ui.colorize(ui.COLORS['text_warning'], line)) + print_(ui.colorize('text_warning', line)) if match.extra_items: print_('Unmatched tracks:') for item in match.extra_items: line = ' ! %s (#%s)' % (item.title, format_index(item)) if item.length: line += ' (%s)' % ui.human_seconds_short(item.length) - print_(ui.colorize(ui.COLORS['text_warning'], line)) + print_(ui.colorize('text_warning', line)) def show_item_change(item, match): @@ -409,8 +407,7 @@ def show_item_change(item, match): # Disambiguation. disambig = disambig_string(match.info) if disambig: - info.append(ui.colorize(ui.COLORS['text_highlight_minor'], - '(%s)' % disambig)) + info.append(ui.colorize('text_highlight_minor', '(%s)' % disambig)) print_(' '.join(info)) @@ -569,7 +566,7 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None, # Disambiguation disambig = disambig_string(match.info) if disambig: - line.append(ui.colorize(ui.COLORS['text_highlight_minor'], + line.append(ui.colorize('text_highlight_minor', '(%s)' % disambig)) print_(' '.join(line)) @@ -1004,7 +1001,7 @@ def update_items(lib, query, album, move, pretend): # Item deleted? if not os.path.exists(syspath(item.path)): ui.print_obj(item, lib) - ui.print_(ui.colorize(ui.COLORS['text_error'], u' deleted')) + ui.print_(ui.colorize('text_error', u' deleted')) if not pretend: item.remove(True) affected_albums.add(item.album_id) diff --git a/beetsplug/fetchart.py b/beetsplug/fetchart.py index ce3e3360d..5af21d23a 100644 --- a/beetsplug/fetchart.py +++ b/beetsplug/fetchart.py @@ -444,11 +444,9 @@ class FetchArtPlugin(plugins.BeetsPlugin): if path: album.set_art(path, False) album.store() - message = ui.colorize(ui.COLORS['text_success'], - 'found album art') + message = ui.colorize('text_success', 'found album art') else: - message = ui.colorize(ui.COLORS['text_error'], - 'no art found') + message = ui.colorize('text_error', 'no art found') self._log.info(u'{0.albumartist} - {0.album}: {1}', album, message) diff --git a/beetsplug/play.py b/beetsplug/play.py index 7d0c0a531..6707c8411 100644 --- a/beetsplug/play.py +++ b/beetsplug/play.py @@ -73,14 +73,14 @@ def play_music(lib, opts, args, log): item_type += 's' if len(selection) > 1 else '' if not selection: - ui.print_(ui.colorize(ui.COLORS['text_warning'], + ui.print_(ui.colorize('text_warning', 'No {0} to play.'.format(item_type))) return # Warn user before playing any huge playlists. if len(selection) > 100: ui.print_(ui.colorize( - ui.COLORS['text_warning'], + 'text_warning', 'You are about to queue {0} {1}.'.format(len(selection), item_type) )) From 0947b8f286764e5a13c4ce0ce504dd8e7e38ea8a Mon Sep 17 00:00:00 2001 From: Tom Jaspers Date: Fri, 30 Jan 2015 12:13:07 +0100 Subject: [PATCH 5/5] Move color-lookup from config in to the `colorize` function The mapping occurs lazily (and only once); now in a more pythonic style --- beets/ui/__init__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index 9efd0c706..9b71de0ae 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -357,12 +357,11 @@ LIGHT_COLORS = ["darkgray", "red", "green", "yellow", "blue", "fuchsia", "turquoise", "white"] RESET_COLOR = COLOR_ESCAPE + "39;49;00m" -# Map the color names to the configured colors in a dict +# These abstract COLOR_NAMES are lazily mapped on to the actual color in COLORS +# as they are defined in the configuration files, see function: colorize COLOR_NAMES = ['text_success', 'text_warning', 'text_error', 'text_highlight', 'text_highlight_minor', 'action_default', 'action'] -COLORS = dict(zip(COLOR_NAMES, - map(lambda x: config['ui']['colors'][x].get(str), - COLOR_NAMES))) +COLORS = None def _colorize(color, text): @@ -384,6 +383,10 @@ def colorize(color_name, text): conditional.) """ if config['ui']['color']: + global COLORS + if not COLORS: + COLORS = dict((name, config['ui']['colors'][name].get(unicode)) + for name in COLOR_NAMES) # In case a 3rd party plugin is still passing the actual color ('red') # instead of the abstract color name ('text_error') color = COLORS.get(color_name)