Xqt has submitted this change and it was merged.
Change subject: Add background colors and a script to show color combinations (colors.py) ......................................................................
Add background colors and a script to show color combinations (colors.py)
Modify background colors support introduced in: 59e9544e68bc77ee9545d317bac4bc94f813259b No backward compatibility considered, as unlikely someone as used it yet.
Modify tool._ColorFormatter to support background colors.
Add utility to show possible background/foreground combinations, in preparation for possibility for user to select default use.
Bug: T135984 Change-Id: Iecb648176b41c9ea3a2cc4ce879526f20d75bfde --- M pywikibot/diff.py M pywikibot/tools/formatter.py M pywikibot/userinterfaces/terminal_interface_base.py M pywikibot/userinterfaces/terminal_interface_unix.py M pywikibot/userinterfaces/terminal_interface_win32.py A scripts/maintenance/colors.py M tests/tools_formatter_tests.py M tests/ui_tests.py 8 files changed, 95 insertions(+), 15 deletions(-)
Approvals: Xqt: Looks good to me, approved Merlijn van Deen: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/diff.py b/pywikibot/diff.py index 6ea3acd..4a1872c 100644 --- a/pywikibot/diff.py +++ b/pywikibot/diff.py @@ -59,8 +59,8 @@ '-': 'lightred', } self.bg_colors = { - '+': 'Blightgreen', - '-': 'Blightred', + '+': 'lightgreen', + '-': 'lightred', }
self.diff = list(self.create_diff()) @@ -187,7 +187,7 @@ if char != ' ': apply_color = self.colors[color] else: - apply_color = self.bg_colors[color] + apply_color = 'default;' + self.bg_colors[color] char_tagged = color_format('{color}{0}', char, color=apply_color) color_closed = False diff --git a/pywikibot/tools/formatter.py b/pywikibot/tools/formatter.py index a571ee4..c53d80a 100644 --- a/pywikibot/tools/formatter.py +++ b/pywikibot/tools/formatter.py @@ -68,6 +68,9 @@ """Special string formatter which skips colors."""
colors = set(colors) + # Dot.product of colors to create all possible combinations of foreground + # and background colors. + colors |= set(['%s;%s' % (c1, c2) for c1 in colors for c2 in colors])
def __init__(self): """Create new instance and store the stack depth.""" diff --git a/pywikibot/userinterfaces/terminal_interface_base.py b/pywikibot/userinterfaces/terminal_interface_base.py index 3cda2cf..bb30c1c 100755 --- a/pywikibot/userinterfaces/terminal_interface_base.py +++ b/pywikibot/userinterfaces/terminal_interface_base.py @@ -47,11 +47,10 @@ 'lightpurple', 'lightyellow', 'white', - 'Blightgreen', - 'Blightred', ]
-colorTagR = re.compile('\03{(?P<name>%s|previous)}' % '|'.join(colors)) +_color_pat = '%s|previous' % '|'.join(colors) +colorTagR = re.compile('\03{((:?%s);?(:?%s)?)}' % (_color_pat, _color_pat))
if __debug__ and not PY2: raw_input = NotImplemented # pyflakes workaround @@ -60,6 +59,8 @@ class UI(object):
"""Base for terminal user interfaces.""" + + split_col_pat = re.compile('(\w+);?(\w+)?')
def __init__(self): """ @@ -127,6 +128,17 @@ raise NotImplementedError('The {0} class does not support ' 'colors.'.format(self.__class__.__name__))
+ @classmethod + def divide_color(cls, color): + """ + Split color label in a tuple. + + Received color is a string like 'fg_color;bg_color' or 'fg_color'. + Returned values are (fg_color, bg_color) or (fg_color, None). + + """ + return cls.split_col_pat.search(color).groups() + def _write(self, text, target_stream): """Optionally encode and write the text to the target stream.""" if PY2: @@ -145,8 +157,11 @@ # Therefore we need this stack. color_stack = ['default'] text_parts = colorTagR.split(text) + ['default'] - for index, (text, next_color) in enumerate(zip(text_parts[::2], - text_parts[1::2])): + # match.split() includes every regex group; for each matched color + # fg_col:b_col, fg_col and bg_col are added to the resulting list. + len_text_parts = len(text_parts[::4]) + for index, (text, next_color) in enumerate(zip(text_parts[::4], + text_parts[1::4])): current_color = color_stack[-1] if next_color == 'previous': if len(color_stack) > 1: # keep the last element in the stack @@ -161,7 +176,7 @@ if '\n' in text: # Normal end of line text = text.replace('\n', ' ***\n', 1) colored_line = False - elif index == len(text_parts) // 2 - 1: # Or end of text + elif index == len_text_parts - 1: # Or end of text text += ' ***' colored_line = False
diff --git a/pywikibot/userinterfaces/terminal_interface_unix.py b/pywikibot/userinterfaces/terminal_interface_unix.py index 9f37d58..789f319 100755 --- a/pywikibot/userinterfaces/terminal_interface_unix.py +++ b/pywikibot/userinterfaces/terminal_interface_unix.py @@ -9,6 +9,7 @@
__version__ = '$Id$'
+import re import sys
from pywikibot.userinterfaces import terminal_interface_base @@ -31,8 +32,6 @@ 'lightpurple': chr(27) + '[95m', # Light Purple tag (Magenta) 'lightaqua': chr(27) + '[96m', # Light Aqua tag (Cyan) 'white': chr(27) + '[97m', # White start tag (Bright White) - 'Blightgreen': chr(27) + '[102m', # Background Light Red tag - 'Blightred': chr(27) + '[101m', # Background Light Green tag }
@@ -44,9 +43,19 @@ """Return that the target stream supports colors.""" return True
+ def make_unix_bg_color(self, color): + """Obtain background color from foreground color.""" + code = re.search('(?<=[)\d+', color).group() + return chr(27) + '[' + str(int(code) + 10) + 'm' + def encounter_color(self, color, target_stream): """Write the unix color directly to the stream.""" - self._write(unixColors[color], target_stream) + fg, bg = self.divide_color(color) + fg = unixColors[fg] + self._write(fg, target_stream) + if bg is not None: + bg = unixColors[bg] + self._write(self.make_unix_bg_color(bg), target_stream)
def _write(self, text, target_stream): """Optionally encode and write the text to the target stream.""" diff --git a/pywikibot/userinterfaces/terminal_interface_win32.py b/pywikibot/userinterfaces/terminal_interface_win32.py index 7c3ed10..c2b0299 100755 --- a/pywikibot/userinterfaces/terminal_interface_win32.py +++ b/pywikibot/userinterfaces/terminal_interface_win32.py @@ -38,8 +38,6 @@ 'lightpurple': 13, 'lightyellow': 14, 'white': 15, - 'Blightgreen': 32, # background color green. - 'Blightred': 64, # background color red. }
@@ -74,8 +72,13 @@
def encounter_color(self, color, target_stream): """Set the new color.""" + fg, bg = self.divide_color(color) + windows_color = windowsColors[fg] + # Merge foreground/backgroung color if needed. + if bg is not None: + windows_color = windowsColors[bg] << 4 | windows_color ctypes.windll.kernel32.SetConsoleTextAttribute( - target_stream._hConsole, windowsColors[color]) + target_stream._hConsole, windows_color)
def _raw_input(self): data = self.stdin.readline() diff --git a/scripts/maintenance/colors.py b/scripts/maintenance/colors.py new file mode 100644 index 0000000..b388e75 --- /dev/null +++ b/scripts/maintenance/colors.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""Utility to show pywikibot colors.""" +# +# (C) Pywikibot team, 2016 +# +# Distributed under the terms of the MIT license. +# +from __future__ import absolute_import, unicode_literals + +import pywikibot + +from pywikibot.tools.formatter import color_format +from pywikibot.tools import itergroup +from pywikibot.userinterfaces.terminal_interface_base import colors as colors + + +def main(): + """Main function.""" + fg_colors = [col for col in colors if col != 'default'] + bg_colors = fg_colors[:] + n_fg_colors = len(fg_colors) + fg_colors.insert(3 * int(n_fg_colors / 4), 'default') + fg_colors.insert(2 * int(n_fg_colors / 4), 'default') + fg_colors.insert(int(n_fg_colors / 4), 'default') + fg_colors.insert(0, 'default') + + # Max len of color names for padding. + max_len_fg_colors = len(max(fg_colors, key=len)) + max_len_bc_color = len(max(bg_colors, key=len)) + + for bg_col in bg_colors: + # Three lines per each backgoung color. + for fg_col_group in itergroup(fg_colors, n_fg_colors / 4 + 1): + line = '' + for fg_col in fg_col_group: + line += ' ' + line += color_format('{color}{0}{default}', + fg_col.ljust(max_len_fg_colors), + color='%s;%s' % (fg_col, bg_col)) + + line = '{0} {1}'.format(bg_col.ljust(max_len_bc_color), line) + pywikibot.output(line) + + pywikibot.output('') + +if __name__ == '__main__': + main() diff --git a/tests/tools_formatter_tests.py b/tests/tools_formatter_tests.py index 73a377b..21de181 100644 --- a/tests/tools_formatter_tests.py +++ b/tests/tools_formatter_tests.py @@ -32,6 +32,7 @@ self.assertEqual(outputter.format_list(), '\nfoo\nbar\n')
+# TODO: add tests for background colors. class TestColorFormat(TestCase):
"""Test color_format function in bot module.""" diff --git a/tests/ui_tests.py b/tests/ui_tests.py index 7dbf363..bbb9de7 100644 --- a/tests/ui_tests.py +++ b/tests/ui_tests.py @@ -689,6 +689,7 @@ self.assertEqual(lines, [u'Alpha', u'Bετα', u'Гамма', u'دلتا', u''])
+# TODO: add tests for background colors. class FakeUITest(TestCase):
"""Test case to allow doing uncolorized general UI tests."""