From c332718c313a741856f2106ea2cf60a98934f7c4 Mon Sep 17 00:00:00 2001 From: Troy Zhong Date: Mon, 29 Sep 2025 14:44:41 -0400 Subject: [PATCH] fix(ReprHighlighter): only match standalone hex literals; support 0X, sign, underscores; add boundary tests --- rich/highlighter.py | 2 +- tests/test_highlighter.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/rich/highlighter.py b/rich/highlighter.py index e4c462e2b6..ebd1982b33 100644 --- a/rich/highlighter.py +++ b/rich/highlighter.py @@ -95,7 +95,7 @@ class ReprHighlighter(RegexHighlighter): r"\b(?PTrue)\b|\b(?PFalse)\b|\b(?PNone)\b", r"(?P\.\.\.)", r"(?P(?(?(?\B(/[-\w._+]+)*\/)(?P[-\w._+]*)?", r"(?b?'''.*?(?(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#~@]*)", diff --git a/tests/test_highlighter.py b/tests/test_highlighter.py index d19928274a..2ee97beab1 100644 --- a/tests/test_highlighter.py +++ b/tests/test_highlighter.py @@ -1,5 +1,7 @@ """Tests for the highlighter classes.""" + import json +import re from typing import List import pytest @@ -12,6 +14,8 @@ ) from rich.text import Span, Text +HEX_LITERAL_RE = re.compile(r"[+-]?0x[0-9a-f](?:_?[0-9a-f])*$", re.IGNORECASE) + def test_wrong_type(): highlighter = NullHighlighter() @@ -167,6 +171,38 @@ def test_highlight_regex(test: str, spans: List[Span]): assert text.spans == spans +@pytest.mark.parametrize( + "literal, should_highlight", + [ + ("0xFF", True), + ("0Xff", True), + ("-0x1A", True), + ("+0x2a", True), + ("0xdead_beef", True), + ("0xDEAD_BEEF", True), + ("(0x2A)", True), + (",0x2A", True), + ("1920x1080", False), + ("abc0x123", False), + ("eth0x1", False), + ("foo0xFFbar", False), + ("0xdead__beef", False), + ("0x_deadbeef", False), + ("0x123_", False), + ], +) +def test_hex_boundaries(literal: str, should_highlight: bool) -> None: + text = Text(literal) + highlighter = ReprHighlighter() + highlighter.highlight(text) + has_hex_highlight = any( + span.style == "repr.number" + and HEX_LITERAL_RE.fullmatch(text.plain[span.start : span.end]) + for span in text.spans + ) + assert has_hex_highlight is should_highlight + + def test_highlight_json_with_indent(): json_string = json.dumps({"name": "apple", "count": 1}, indent=4) text = Text(json_string)