From 73b501c9610142a3c8d69e6d3d720a90d3ea0b06 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 1 Dec 2017 20:02:47 +0530 Subject: [PATCH] Make color parsing a little more robust Add a few tests for it --- kitty/rgb.py | 47 +++++++++++++++++++++++++--------------- kitty_tests/datatypes.py | 16 ++++++++++++++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/kitty/rgb.py b/kitty/rgb.py index c34bb465a..69587bcec 100644 --- a/kitty/rgb.py +++ b/kitty/rgb.py @@ -7,32 +7,43 @@ from collections import namedtuple Color = namedtuple('Color', 'red green blue') -color_pat = re.compile(r'^#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})$') -color_pat2 = re.compile( - r'rgb:([a-f0-9]{2})/([a-f0-9]{2})/([a-f0-9]{2})$', re.IGNORECASE -) + +def parse_single_color(c): + if len(c) == 1: + c += c + return int(c[:2], 16) + + +def parse_sharp(spec): + if len(spec) in (3, 6, 9, 12): + part_len = len(spec) // 3 + colors = re.findall(r'[a-fA-F0-9]{%d}' % part_len, spec) + return Color(*map(parse_single_color, colors)) + + +def parse_rgb(spec): + colors = spec.split('/') + if len(colors) == 3: + return Color(*map(parse_single_color, colors)) def to_color(raw, validate=False): + # See man XParseColor x = raw.strip().lower() ans = color_names.get(x) if ans is not None: return ans - m = color_pat.match(x) val = None - if m is not None: - val = m.group(1) - if len(val) == 3: - val = ''.join(2 * s for s in val) - else: - m = color_pat2.match(x) - if m is not None: - val = m.group(1) + m.group(2) + m.group(3) - if val is None: - if validate: - raise ValueError('Invalid color name: {}'.format(raw)) - return - return Color(int(val[:2], 16), int(val[2:4], 16), int(val[4:], 16)) + try: + if raw.startswith('#'): + val = parse_sharp(raw[1:]) + elif raw.startswith('rgb:'): + val = parse_rgb(raw[4:]) + except Exception: + pass + if val is None and validate: + raise ValueError('Invalid color name: {}'.format(raw)) + return val # BEGIN_DATA_SECTION {{{ diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py index 0dc77d688..aaa563350 100644 --- a/kitty_tests/datatypes.py +++ b/kitty_tests/datatypes.py @@ -10,6 +10,7 @@ from kitty.fast_data_types import ( REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf ) from kitty.utils import sanitize_title, wcwidth +from kitty.rgb import to_color from . import BaseTest, filled_cursor, filled_history_buf, filled_line_buf @@ -27,6 +28,21 @@ def create_lbuf(*lines): class TestDataTypes(BaseTest): + def test_to_color(self): + for x in 'xxx #12 #1234 rgb:a/b'.split(): + self.assertIsNone(to_color(x)) + + def c(spec, r=0, g=0, b=0): + self.ae(tuple(to_color(spec)), (r, g, b)) + + c('#eee', 0xee, 0xee, 0xee) + c('#234567', 0x23, 0x45, 0x67) + c('#abcabcdef', 0xab, 0xab, 0xde) + c('rgb:e/e/e', 0xee, 0xee, 0xee) + c('rgb:23/45/67', 0x23, 0x45, 0x67) + c('rgb:abc/abc/def', 0xab, 0xab, 0xde) + c('red', 0xff) + def test_linebuf(self): old = filled_line_buf(2, 3, filled_cursor()) new = LineBuf(1, 3)