diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f24a4ea7..5ac3df672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed extraction of recursive exceptions https://github.com/Textualize/rich/pull/3772 - Fixed padding applied to Syntax https://github.com/Textualize/rich/pull/3782 - Fixed `Panel` title missing the panel background style https://github.com/Textualize/rich/issues/3569 +- Fixed parsing of SGR color codes using colons https://github.com/Textualize/rich/pull/3789 ### Added diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4b04786b9..6341d5a50 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -11,6 +11,7 @@ The following people have contributed to the development of Rich: - [Robin Bowes](https://github.com/yo61) - [Dennis Brakhane](https://github.com/brakhane) - [Darren Burns](https://github.com/darrenburns) +- [Alex Carney](https://github.com/alcarney) - [Ceyda Cinarel](https://github.com/cceyda) - [Jim Crist-Harif](https://github.com/jcrist) - [Ed Davis](https://github.com/davised) diff --git a/rich/ansi.py b/rich/ansi.py index 7de86ce50..bd59b7594 100644 --- a/rich/ansi.py +++ b/rich/ansi.py @@ -144,6 +144,7 @@ def decode_line(self, line: str) -> Text: Returns: Text: A Text instance marked up according to ansi codes. """ + from_ansi = Color.from_ansi from_rgb = Color.from_rgb _Style = Style @@ -163,7 +164,7 @@ def decode_line(self, line: str) -> Text: # Ignore invalid codes, because we want to be lenient codes = [ min(255, int(_code) if _code else 0) - for _code in sgr.split(";") + for _code in sgr.replace("::", ";").replace(":", ";").split(";") if _code.isdigit() or _code == "" ] iter_codes = iter(codes) diff --git a/tests/test_ansi.py b/tests/test_ansi.py index d81f6459f..f88d43ad9 100644 --- a/tests/test_ansi.py +++ b/tests/test_ansi.py @@ -1,5 +1,4 @@ import pytest - from rich.ansi import AnsiDecoder from rich.console import Console from rich.style import Style @@ -70,6 +69,23 @@ def test_decode_issue_2688(ansi_bytes, expected_text): assert str(text) == expected_text +@pytest.mark.parametrize( + "text,expected", + [ + ( + "\x1b[38;2;255;0;0mred\x1b[0m text", + Text("red text", spans=[Span(0, 3, Style.parse("#ff0000"))]), + ), + ( + "\x1b[38:2::255:0:0mred\x1b[0m text", + Text("red text", spans=[Span(0, 3, Style.parse("#ff0000"))]), + ), + ], +) +def test_decode_sgr_rgb(text, expected): + assert Text.from_ansi(text) == expected + + @pytest.mark.parametrize("code", [*"0123456789:;<=>?"]) def test_strip_private_escape_sequences(code): text = Text.from_ansi(f"\x1b{code}x")