diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py index e77001f6a1d10b..fd63fadb6072bd 100644 --- a/Lib/_pyrepl/utils.py +++ b/Lib/_pyrepl/utils.py @@ -19,7 +19,9 @@ from .trace import trace -ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]") +ANSI_ESCAPE_SEQUENCE = re.compile( + r"\x1b(?:\[[ -@]*[A-~]|\][^\x1b\x07]*(?:\x07|\x1b\\))" +) ZERO_WIDTH_BRACKET = re.compile(r"\x01.*?\x02") ZERO_WIDTH_TRANS = str.maketrans({"\x01": "", "\x02": ""}) IDENTIFIERS_AFTER = frozenset({"def", "class"}) diff --git a/Lib/test/test_pyrepl/test_render.py b/Lib/test/test_pyrepl/test_render.py index 5479f2eb4bae39..10a119150376a0 100644 --- a/Lib/test/test_pyrepl/test_render.py +++ b/Lib/test/test_pyrepl/test_render.py @@ -55,6 +55,15 @@ def test_from_rendered_text_empty_string(self): self.assertEqual(line.text, "") self.assertEqual(line.width, 0) + def test_from_rendered_text_with_osc_control(self): + osc = "\x1b]633;A\x1b\\" + line = RenderLine.from_rendered_text(f"{osc}>>> ") + + self.assertEqual(line.width, 4) + self.assertEqual(line.cells[0].controls, (osc,)) + self.assertEqual(line.cells[0].text, "") + self.assertEqual(line.text, f"{osc}>>> ") + def test_from_rendered_text_with_non_sgr_controls(self): # \x1b[H is a cursor-home control (not SGR since it doesn't end with 'm') line = RenderLine.from_rendered_text("\x1b[Hx") diff --git a/Lib/test/test_pyrepl/test_utils.py b/Lib/test/test_pyrepl/test_utils.py index e87d14304c8225..13483937831b25 100644 --- a/Lib/test/test_pyrepl/test_utils.py +++ b/Lib/test/test_pyrepl/test_utils.py @@ -47,6 +47,12 @@ def test_wlen(self): self.assertEqual(wlen('e\N{COMBINING ACUTE ACCENT}'), 1) self.assertEqual(wlen('a\N{ZERO WIDTH JOINER}b'), 2) + def test_wlen_with_osc_sequence(self): + self.assertEqual(wlen("\x1b]633;A\x07>>> "), 4) + + def test_wlen_with_unterminated_osc_sequence(self): + self.assertEqual(wlen("\x1b]633;A"), 7) + def test_prev_next_window(self): def gen_normal(): yield 1 diff --git a/Misc/NEWS.d/next/Library/2026-09-21-21-07-12.gh-issue-157928.ZPlNYC.rst b/Misc/NEWS.d/next/Library/2026-09-21-21-07-12.gh-issue-157928.ZPlNYC.rst new file mode 100644 index 00000000000000..2fa00484bf8986 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-21-21-07-12.gh-issue-157928.ZPlNYC.rst @@ -0,0 +1 @@ +Correctly detect and handle OSC sequences in PyREPL