[BUG] Link markups fail when paths contain square brakets.
- [x] I've checked docs and closed issues for possible solutions.
- [x] I can't find my issue in the FAQ.
Describe the bug
It seems like rich.print cannot handle paths that contain square brakets using the [link] directive.
MWE:
import rich
import pathlib
path = pathlib.Path('/data/store/Media/Music/Bon Iver/For Emma, Forever Ago [2007]')
try:
rich.print(rf'[link={path}]{path}[/link]')
except Exception as ex:
print(f'ex={ex!r}')
This causes:
MarkupError: closing tag '[/link]' at position 129 doesn't match any open tag
Furthermore, the standard things that I could think of to escape the square brakets don't seem to work.
candidates = [
r'[link=some_path\[with_brakets]]AnyOtherText[/link]',
r'[link=some_path\\[with_brakets]]AnyOtherText[/link]',
r'[link=some_path\[with_brakets\]]AnyOtherText[/link]',
r'[link=some_path\\[with_brakets\\]]AnyOtherText[/link]',
r'[link=some_path [with_brakets]AnyOtherText[/link]',
r'[link=some_path [[with_brakets]AnyOtherText[/link]',
r'[link="some_path [with_brakets]"]AnyOtherText[/link]',
r'[link="some_path \[with_brakets]"]AnyOtherText[/link]',
# These "work", but the link still doesn't respect the braket
r'[link=some_path with_brakets\\]]AnyOtherText[/link]',
r'[link=some_path with_brakets]AnyOtherText[/link]',
]
for candidate in candidates:
try:
rich.print(candidate)
except Exception as ex:
rich.print(f'[red]FAILED ex={rich.markup.escape(repr(ex))}')
else:
rich.print(f'[green]PASSED: {rich.markup.escape(candidate)}')
Platform
Click to expand
OS: Ubuntu 22.04.3 LTS (x86_64) Python version: 3.11.2 (main, Apr 1 2023, 18:27:37) [GCC 11.3.0] (64-bit runtime) Python platform: Linux-6.2.0-36-generic-x86_64-with-glibc2.35
╭───────────────────────── <class 'rich.console.Console'> ─────────────────────────╮
│ A high level console interface. │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────╮ │
│ │ <console width=180 ColorSystem.TRUECOLOR> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ color_system = 'truecolor' │
│ encoding = 'utf-8' │
│ file = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'> │
│ height = 87 │
│ 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=180, height=87), │
│ legacy_windows=False, │
│ min_width=1, │
│ max_width=180, │
│ is_terminal=True, │
│ encoding='utf-8', │
│ max_height=87, │
│ justify=None, │
│ overflow=None, │
│ no_wrap=False, │
│ highlight=None, │
│ markup=None, │
│ height=None │
│ ) │
│ quiet = False │
│ record = False │
│ safe_box = True │
│ size = ConsoleDimensions(width=180, height=87) │
│ soft_wrap = False │
│ stderr = False │
│ style = None │
│ tab_size = 8 │
│ width = 180 │
╰──────────────────────────────────────────────────────────────────────────────────╯
╭─── <class 'rich._windows.WindowsConsoleFeatures'> ────╮
│ Windows features available. │
│ │
│ ╭───────────────────────────────────────────────────╮ │
│ │ WindowsConsoleFeatures(vt=False, truecolor=False) │ │
│ ╰───────────────────────────────────────────────────╯ │
│ │
│ truecolor = False │
│ vt = False │
╰───────────────────────────────────────────────────────╯
╭────── Environment Variables ───────╮
│ { │
│ 'TERM': 'xterm-256color', │
│ 'COLORTERM': 'truecolor', │
│ '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"
rich==13.7.0
rich_argparse==1.1.0
Is there an escape character specific for link? Or is there a way I can "encode-away" the braket in the path? Or is this just a bug that markup links don't currently support?
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
A funny collary to this issue:
The text:
[blue][link=/data/store/Media/Music/Deep Purple]Deep Purple[/link][/blue]
In the block:
├─╼ [blue][link=/data/store/Media/Music/Jethro Tull]Jethro Tull[/link][/blue]
├─╼ [blue][link=/data/store/Media/Music/Bread]Bread[/link][/blue]
├─╼ [blue][link=/data/store/Media/Music/Deep Purple]Deep Purple[/link][/blue]
├─╼ [blue][link=/data/store/Media/Music/Tenacious D]Tenacious D[/link][/blue]
├─╼ [blue][link=/data/store/Media/Music/The Shins]The Shins[/link][/blue]
├─╼ [blue][link=/data/store/Media/Music/Dragonforce]Dragonforce[/link][/blue]
├─╼ [blue][link=/data/store/Media/Music/Red Hot Chili Peppers]Red Hot Chili Peppers[/link][/blue]
Renders like this:
However:
rich.print('[blue][link=file:///data/store/Media/Music/Deep%20Purple]Deep Purple[/link][/blue]')
does work.
I was able to solve this by replaceing the brakets with "%5B" and "%5D":
import rich
import pathlib
import os
path = pathlib.Path('/data/store/Media/Music/Bon Iver/For Emma, Forever Ago [2007]')
try:
encoded_path = 'file://' + os.fspath(path).replace(' ', '%20').replace('[', '%5B').replace(']', '%5D')
escaped_path = rich.markup.escape(os.fspath(path))
rich.print(rf'[blue][link={encoded_path}]{escaped_path}[/link][/blue]')
except Exception as ex:
print(f'ex={ex!r}')
It might be nice to mention URL encoding in the links docs and refer to urllib.parse (e.g. 'file://' + urllib.parse.quote(os.fspath(path)))
I found that when the brackets are surrounded by blanks, the MarkupError will not occur.