mirror of
https://github.com/python/cpython.git
synced 2026-11-08 22:00:54 +00:00
gh-157928: Have PyREPL detect OSC sequences (GH-157932)
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Brett Cannon <[email protected]>
This commit is contained in:
co-authored by
blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Brett Cannon
parent
7515b64aa7
commit
ef1fce0a69
+15
-1
@@ -19,7 +19,21 @@ from .types import CharBuffer, CharWidths
|
||||
from .trace import trace
|
||||
|
||||
|
||||
ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]")
|
||||
ANSI_ESCAPE_SEQUENCE = re.compile(
|
||||
r"""
|
||||
\x1b
|
||||
(?:
|
||||
# CSI: ESC [ followed by parameter/intermediate bytes and a final byte.
|
||||
# For example, ESC [ 31 m ("\x1b[31m") selects red foreground text.
|
||||
\[ [ -@]* [A-~]
|
||||
|
|
||||
# OSC: ESC ] followed by a payload terminated by BEL or ST (ESC \).
|
||||
# For example, ESC ] 0 ; title BEL ("\x1b]0;title\x07") sets the title.
|
||||
\] [^\x1b\x07]* (?: \x07 | \x1b\\ )
|
||||
)
|
||||
""",
|
||||
re.X,
|
||||
)
|
||||
ZERO_WIDTH_BRACKET = re.compile(r"\x01.*?\x02")
|
||||
ZERO_WIDTH_TRANS = str.maketrans({"\x01": "", "\x02": ""})
|
||||
IDENTIFIERS_AFTER = frozenset({"def", "class"})
|
||||
|
||||
@@ -55,6 +55,15 @@ class TestRenderLine(TestCase):
|
||||
self.assertEqual(line.text, "")
|
||||
self.assertEqual(line.width, 0)
|
||||
|
||||
def test_from_rendered_text_with_osc_control(self):
|
||||
osc = "\x1b]633;A\x1b\\"
|
||||
prompt = ">>> "
|
||||
line = RenderLine.from_rendered_text(osc + prompt)
|
||||
|
||||
self.assertEqual(line.width, len(prompt))
|
||||
self.assertEqual(line.cells[0].controls, (osc,))
|
||||
self.assertEqual(line.cells[0].text, "")
|
||||
|
||||
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")
|
||||
|
||||
@@ -47,6 +47,14 @@ class TestUtils(TestCase):
|
||||
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):
|
||||
prompt = ">>> "
|
||||
self.assertEqual(wlen("\x1b]633;A\x07" + prompt), len(prompt))
|
||||
|
||||
def test_wlen_with_unterminated_osc_sequence_as_individual_characters(self):
|
||||
# \x1b is treated as a single character (ESC)
|
||||
self.assertEqual(wlen("\x1b]633;A"), len("\x1b]633;A"))
|
||||
|
||||
def test_prev_next_window(self):
|
||||
def gen_normal():
|
||||
yield 1
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Correctly detect and handle OSC sequences in PyREPL.
|
||||
Reference in New Issue
Block a user