Merge pull request #459 from Textualize/expanded-css-hex-support

Support 3 and 4 character hex strings for colours
This commit is contained in:
Darren Burns
2022-05-04 10:23:54 +01:00
committed by GitHub
5 changed files with 29 additions and 8 deletions

View File

@@ -7,5 +7,6 @@
.list-item {
height: 8;
background: darkblue;
color: #12a0;
background: #ffffff00;
}

View File

@@ -1,7 +1,7 @@
"""
Manages Color in Textual.
All instances where the developer is presented with a color should use this class. The only
All instances where the developer is presented with a color should use this class. The only
exception should be when passing things to a Rich renderable, which will need to use the
`rich_color` attribute to perform a conversion.
@@ -54,6 +54,8 @@ class Lab(NamedTuple):
RE_COLOR = re.compile(
r"""^
\#([0-9a-fA-F]{3})$|
\#([0-9a-fA-F]{4})$|
\#([0-9a-fA-F]{6})$|
\#([0-9a-fA-F]{8})$|
rgb\((\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*)\)$|
@@ -62,7 +64,7 @@ rgba\((\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*)\)$
re.VERBOSE,
)
# Fast way to split a string of 8 characters in to 3 pairs of 2 characters
# Fast way to split a string of 6 characters in to 3 pairs of 2 characters
split_pairs3: Callable[[str], tuple[str, str, str]] = itemgetter(
slice(0, 2), slice(2, 4), slice(4, 6)
)
@@ -264,9 +266,27 @@ class Color(NamedTuple):
color_match = RE_COLOR.match(color_text)
if color_match is None:
raise ColorParseError(f"failed to parse {color_text!r} as a color")
rgb_hex, rgba_hex, rgb, rgba = color_match.groups()
(
rgb_hex_triple,
rgb_hex_quad,
rgb_hex,
rgba_hex,
rgb,
rgba,
) = color_match.groups()
if rgb_hex is not None:
if rgb_hex_triple is not None:
r, g, b = rgb_hex_triple
color = cls(int(f"{r}{r}", 16), int(f"{g}{g}", 16), int(f"{b}{b}", 16))
elif rgb_hex_quad is not None:
r, g, b, a = rgb_hex_quad
color = cls(
int(f"{r}{r}", 16),
int(f"{g}{g}", 16),
int(f"{b}{b}", 16),
int(f"{a}{a}", 16) / 255.0,
)
elif rgb_hex is not None:
r, g, b = [int(pair, 16) for pair in split_pairs3(rgb_hex)]
color = cls(r, g, b, 1.0)
elif rgba_hex is not None:

View File

@@ -9,7 +9,7 @@ COMMENT_START = r"\/\*"
SCALAR = r"\-?\d+\.?\d*(?:fr|%|w|h|vw|vh)"
DURATION = r"\d+\.?\d*(?:ms|s)"
NUMBER = r"\-?\d+\.?\d*"
COLOR = r"\#[0-9a-fA-F]{8}|\#[0-9a-fA-F]{6}|rgb\(\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*\)|rgba\(\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*\)"
COLOR = r"\#[0-9a-fA-F]{8}|\#[0-9a-fA-F]{6}|\#[0-9a-fA-F]{4}|\#[0-9a-fA-F]{3}|rgb\(\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*\)|rgba\(\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*,\-?\d+\.?\d*\)"
KEY_VALUE = r"[a-zA-Z_-][a-zA-Z0-9_-]*=[0-9a-zA-Z_\-\/]+"
TOKEN = "[a-zA-Z][a-zA-Z0-9_-]*"
STRING = r"\".*?\""

View File

@@ -32,8 +32,6 @@ from textual.css.tokenizer import TokenizeError
["red 4", pytest.raises(StylesheetParseError), None], # space in it
["1", pytest.raises(StylesheetParseError), None], # invalid value
["()", pytest.raises(TokenizeError), None], # invalid tokens
# TODO: implement hex colors with 3 chars? @link https://devdocs.io/css/color_value
["#09f", pytest.raises(TokenizeError), None],
# TODO: allow spaces in rgb/rgba expressions?
["rgb(200, 90, 30)", pytest.raises(TokenizeError), None],
["rgba(200,90,30, 0.4)", pytest.raises(TokenizeError), None],

View File

@@ -93,6 +93,8 @@ def test_color_blend():
("#000000", Color(0, 0, 0, 1.0)),
("#ffffff", Color(255, 255, 255, 1.0)),
("#FFFFFF", Color(255, 255, 255, 1.0)),
("#fab", Color(255, 170, 187, 1.0)), # #ffaabb
("#fab0", Color(255, 170, 187, .0)), # #ffaabb00
("#020304ff", Color(2, 3, 4, 1.0)),
("#02030400", Color(2, 3, 4, 0.0)),
("#0203040f", Color(2, 3, 4, 0.058823529411764705)),