Textualize / rich

Rich is a Python library for rich text and beautiful formatting in the terminal.
https://rich.readthedocs.io/en/latest/
MIT License
49.56k stars 1.73k forks source link

[BUG] Minor ReprHighlighter "repr.ipv6" Visual Defect fix #3246

Open bionicles opened 10 months ago

bionicles commented 10 months ago

found https://github.com/Textualize/rich/issues/1259 and ridiculous regex is something i'm happy to work on, i may have found a fix!

Describe the bug

Double colon separators sometimes highlight in green due to false positive ipv6 ReprHighlighter regex match image

Provide a minimal code example that demonstrates the issue if you can. If the issue is visual in nature, consider posting a screenshot.

remember -s flag to see the colors in pytest pytest tests/test_highlighter.py -s -k "double_colon"

Candidate add to test_highlighter.py:

from rich.console import Console
from rich.theme import Theme

def test_highlight_ipv6_double_colon_visual_defect():
    "Tests for a visual defect with double colon due to ipv6 regex"
    console = Console(markup=False, theme=Theme({"repr.ipv6": "bold green blink"}))
    highlighter = ReprHighlighter()
    test_str_1 = """// Simple global function
void printMessage(const std::string &message) {
    std::cout << message << std::endl;
}"""
    test_str_2 = "┃   ┣━━ -Arustdoc::broken_intra_doc_links"
    ipv6_long_str = "2001:0db8:0000:0000:0000:8a2e:0370:7334"
    ipv6_short_str = "2001:db8::8a2e:370:7334"
    # visualizing the issue if pytest -s flag is true
    print("\n>>>HIGHLIGHT ON:")
    console.print("str_1  if highlighted:", test_str_1, highlight=True)
    console.print("str_2  if highlighted:", test_str_2, highlight=True)
    console.print("ipv6_long_str  if highlighted:", ipv6_long_str, highlight=True)
    console.print("ipv6_short_str  if highlighted:", ipv6_short_str, highlight=True)
    print(">>>HIGHLIGHT OFF:")
    console.print("str_1 not highlighted:", test_str_1, highlight=False)
    console.print("str_2 not highlighted:", test_str_2, highlight=False)
    console.print("ipv6_long_str not highlighted:", ipv6_long_str, highlight=False)
    console.print("ipv6_short_str not highlighted:", ipv6_short_str, highlight=False)
    console_theme_hack = Console(markup=False, theme=Theme({"repr.ipv6": "default"}))
    print(">>>THEME WORKAROUND")
    console_theme_hack.print(
        "str_1  if 'repr.ipv6': 'default':", test_str_1, highlight=True
    )
    console_theme_hack.print(
        "str_2  if 'repr.ipv6': 'default':", test_str_2, highlight=True
    )
    # catching the issue programmatically
    test_text_1 = Text(test_str_1)
    highlighter.highlight(test_text_1)
    print("test_text_1.spans")
    print(test_text_1.spans)
    test_text_2 = Text(test_str_1)
    highlighter.highlight(test_text_2)
    print("test_text_2.spans")
    print(test_text_2.spans)
    incorrect_spans = []
    all_spans = test_text_1.spans + test_text_2.spans
    for span in all_spans:
        _start, _stop, kind = span
        if kind == "repr.ipv6":
            incorrect_spans.append(span)
    if incorrect_spans:
        print("incorrect_spans:")
        print(incorrect_spans)
        assert len(incorrect_spans) == 0

Candidate Fix: rich/highlighter.py::ReprHighlighter (Around Line 90)

-            r"(?P<ipv6>([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})", 
+           r"(?P<ipv6>([A-Fa-f0-9]{1,4}:){1,7}[A-Fa-f0-9]{1,4})",

maybe that screws up ipv6 edge cases, however it un-screws-up the C code examples:

image

Here's the difference in test outcome:

Before: image

After: image

Then, of course, I found the answer was already in the closed issues:

image

        console_theme_hack = Console(markup=False, theme=Theme({"repr.ipv6": "default"}))
        print(">>>THEME WORKAROUND")
        console_theme_hack.print(
            "str_1  if 'repr.ipv6': 'default':", test_str_1, highlight=True
        )
        console_theme_hack.print(
            "str_2  if 'repr.ipv6': 'default':", test_str_2, highlight=True
        )

TL;DR: It's an annoying visual bug which makes stuff look dumb, users can totally fix it themselves if they know they can re-theme a particular regex pattern in the ReprHighlighter, I personally didn't really know any of this stuff existed. Might be good to just remove the :? so people don't have to deal with that.

Your test suite still passes with the new regex, but might be good to verify this doesn't cause issues image

Alright, being a completionist and not wanting anyone else to need to context switch on this:

image the new regex still works on the example long and short ipv6 from wikipedia https://en.wikipedia.org/wiki/IPv6

it just doesn't highlight the double colons in green, whatever, that's less annoying than a billion edge cases like this imho

image image image

Platform

Ubuntu 22.04.3 LTS? What terminal software are you using?

I may ask you to copy and paste the output of the following commands. It may save some time if you do it now.

If you're using Rich in a terminal:

python -m rich.diagnose
pip freeze | grep rich
(py310) [2024-01-03T15:36:35-0500]
~/hax/externals/rich (master) $
> python -m rich.diagnose
╭───────────────────────── <class 'rich.console.Console'> ─────────────────────────╮
│ A high level console interface.                                                  │
│                                                                                  │
│ ╭──────────────────────────────────────────────────────────────────────────────╮ │
│ │ <console width=94 ColorSystem.EIGHT_BIT>                                     │ │
│ ╰──────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                  │
│     color_system = '256'                                                         │
│         encoding = 'utf-8'                                                       │
│             file = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'> │
│           height = 111                                                           │
│    is_alt_screen = False                                                         │
│ is_dumb_terminal = False                                                         │
│   is_interactive = True                                                          │
│       is_jupyter = False                                                         │
│      is_terminal = True                                                          │
│   legacy_windows = False                                                         │
│         no_color = False                                                         │
│          options = ConsoleOptions(                                               │
│                        size=ConsoleDimensions(width=94, height=111),             │
│                        legacy_windows=False,                                     │
│                        min_width=1,                                              │
│                        max_width=94,                                             │
│                        is_terminal=True,                                         │
│                        encoding='utf-8',                                         │
│                        max_height=111,                                           │
│                        justify=None,                                             │
│                        overflow=None,                                            │
│                        no_wrap=False,                                            │
│                        highlight=None,                                           │
│                        markup=None,                                              │
│                        height=None                                               │
│                    )                                                             │
│            quiet = False                                                         │
│           record = False                                                         │
│         safe_box = True                                                          │
│             size = ConsoleDimensions(width=94, height=111)                       │
│        soft_wrap = False                                                         │
│           stderr = False                                                         │
│            style = None                                                          │
│         tab_size = 8                                                             │
│            width = 94                                                            │
╰──────────────────────────────────────────────────────────────────────────────────╯
╭─── <class 'rich._windows.WindowsConsoleFeatures'> ────╮
│ Windows features available.                           │
│                                                       │
│ ╭───────────────────────────────────────────────────╮ │
│ │ WindowsConsoleFeatures(vt=False, truecolor=False) │ │
│ ╰───────────────────────────────────────────────────╯ │
│                                                       │
│ truecolor = False                                     │
│        vt = False                                     │
╰───────────────────────────────────────────────────────╯
╭────── Environment Variables ───────╮
│ {                                  │
│     'TERM': 'xterm-256color',      │
│     'COLORTERM': None,             │
│     'CLICOLOR': None,              │
│     'NO_COLOR': None,              │
│     'TERM_PROGRAM': None,          │
│     'COLUMNS': None,               │
│     'LINES': None,                 │
│     'JUPYTER_COLUMNS': None,       │
│     'JUPYTER_LINES': None,         │
│     'JPY_PARENT_PID': None,        │
│     'VSCODE_VERBOSE_LOGGING': None │
│ }                                  │
╰────────────────────────────────────╯
platform="Linux"
(py310) [2024-01-03T15:36:39-0500]
~/hax/externals/rich (master) $
> pip freeze | grep rich
-e git+https://github.com/Textualize/rich.git@fd981823644ccf50d685ac9c0cfe8e1e56c9dd35#egg=rich
rich-cli==1.8.0
rich-rst==1.1.7
github-actions[bot] commented 10 months ago

Thank you for your issue. Give us a little time to review it.

PS. You might want to check the FAQ if you haven't done so already.

This is an automated reply, generated by FAQtory

cmclaughlin commented 7 months ago

I think I hit the same bug

Screen Shot 2024-03-20 at 8 40 36 PM
bionicles commented 7 months ago

For a TLDR workaround, this fixed it for me, you have to create a Console to use a Theme, and in the theme set this key to this value:

"repr.ipv6": "default"
cmclaughlin commented 7 months ago

@bionicles thanks for the info! I can confirm that workaround fixes it for me too.