Make color parsing a little more robust
Add a few tests for it
This commit is contained in:
parent
08079ad889
commit
73b501c961
45
kitty/rgb.py
generated
45
kitty/rgb.py
generated
@ -7,32 +7,43 @@ from collections import namedtuple
|
|||||||
|
|
||||||
Color = namedtuple('Color', 'red green blue')
|
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(
|
def parse_single_color(c):
|
||||||
r'rgb:([a-f0-9]{2})/([a-f0-9]{2})/([a-f0-9]{2})$', re.IGNORECASE
|
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):
|
def to_color(raw, validate=False):
|
||||||
|
# See man XParseColor
|
||||||
x = raw.strip().lower()
|
x = raw.strip().lower()
|
||||||
ans = color_names.get(x)
|
ans = color_names.get(x)
|
||||||
if ans is not None:
|
if ans is not None:
|
||||||
return ans
|
return ans
|
||||||
m = color_pat.match(x)
|
|
||||||
val = None
|
val = None
|
||||||
if m is not None:
|
try:
|
||||||
val = m.group(1)
|
if raw.startswith('#'):
|
||||||
if len(val) == 3:
|
val = parse_sharp(raw[1:])
|
||||||
val = ''.join(2 * s for s in val)
|
elif raw.startswith('rgb:'):
|
||||||
else:
|
val = parse_rgb(raw[4:])
|
||||||
m = color_pat2.match(x)
|
except Exception:
|
||||||
if m is not None:
|
pass
|
||||||
val = m.group(1) + m.group(2) + m.group(3)
|
if val is None and validate:
|
||||||
if val is None:
|
|
||||||
if validate:
|
|
||||||
raise ValueError('Invalid color name: {}'.format(raw))
|
raise ValueError('Invalid color name: {}'.format(raw))
|
||||||
return
|
return val
|
||||||
return Color(int(val[:2], 16), int(val[2:4], 16), int(val[4:], 16))
|
|
||||||
|
|
||||||
|
|
||||||
# BEGIN_DATA_SECTION {{{
|
# BEGIN_DATA_SECTION {{{
|
||||||
|
|||||||
@ -10,6 +10,7 @@ from kitty.fast_data_types import (
|
|||||||
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf
|
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf
|
||||||
)
|
)
|
||||||
from kitty.utils import sanitize_title, wcwidth
|
from kitty.utils import sanitize_title, wcwidth
|
||||||
|
from kitty.rgb import to_color
|
||||||
|
|
||||||
from . import BaseTest, filled_cursor, filled_history_buf, filled_line_buf
|
from . import BaseTest, filled_cursor, filled_history_buf, filled_line_buf
|
||||||
|
|
||||||
@ -27,6 +28,21 @@ def create_lbuf(*lines):
|
|||||||
|
|
||||||
class TestDataTypes(BaseTest):
|
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):
|
def test_linebuf(self):
|
||||||
old = filled_line_buf(2, 3, filled_cursor())
|
old = filled_line_buf(2, 3, filled_cursor())
|
||||||
new = LineBuf(1, 3)
|
new = LineBuf(1, 3)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user