From 074efbe1b193bd09f0a585e4218d9ff6acd76bb1 Mon Sep 17 00:00:00 2001 From: jeff-grimes-pplx <207642104+jeff-grimes-pplx@users.noreply.github.com> Date: Mon, 2 Nov 2026 12:35:20 +0000 Subject: [PATCH] Fix OSC-8 hyperlink regex for BEL terminator and hyphenated params --- tabulate/__init__.py | 8 ++++---- test/test_regression.py | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/tabulate/__init__.py b/tabulate/__init__.py index 12a2950..2f4363b 100644 --- a/tabulate/__init__.py +++ b/tabulate/__init__.py @@ -783,7 +783,7 @@ def escape_empty(val): _esc = r"\x1b" _csi = rf"{_esc}\[" _osc = rf"{_esc}\]" -_st = rf"{_esc}\\" +_st = rf"(?:{_esc}\\|\x07)" _ansi_escape_pat = rf""" ( @@ -795,11 +795,11 @@ def escape_empty(val): | # terminal hyperlinks {_osc}8; # OSC opening - (\w+=\w+:?)* # key=value params list (submatch 2) + ([\w.-]+=[\w.-]+:?)* # key=value params list (submatch 2) ; # delimiter - ([^{_esc}]+) # URI - anything but ESC (submatch 3) + ([^{_esc}\x07]+) # URI - anything but ESC or BEL (submatch 3) {_st} # ST - ([^{_esc}]+) # link text - anything but ESC (submatch 4) + ([^{_esc}\x07]+) # link text - anything but ESC or BEL (submatch 4) {_osc}8;;{_st} # "closing" OSC sequence ) """ diff --git a/test/test_regression.py b/test/test_regression.py index 9555676..db0c528 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -598,3 +598,25 @@ def test_github_escape_pipe_character(): result = tabulate([["foo|bar"]], headers=("spam|eggs",), tablefmt="github") expected = "| spam\\|eggs |\n|:------------|\n| foo\\|bar |" assert_equal(expected, result) + + +def test_alignment_of_bel_and_param_link_cells(): + "Regression: Align OSC-8 links terminated by BEL (0x07) or with hyphenated params." + linktable = [ + ("test", 42, "\x1b]8;;target\x07test\x1b]8;;\x07"), + ("test", 101, "\x1b]8;id=doc-1;target\x1b\\test\x1b]8;;\x1b\\"), + ] + linkheaders = ("test", "\x1b]8;;target\x07test\x1b]8;;\x07", "test") + formatted = tabulate(linktable, linkheaders, "grid") + expected = "\n".join( + [ + "+--------+--------+--------+", + "| test | \x1b]8;;target\x07test\x1b]8;;\x07 | test |", + "+========+========+========+", + "| test | 42 | \x1b]8;;target\x07test\x1b]8;;\x07 |", + "+--------+--------+--------+", + "| test | 101 | \x1b]8;id=doc-1;target\x1b\\test\x1b]8;;\x1b\\ |", + "+--------+--------+--------+", + ] + ) + assert_equal(expected, formatted)