]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-111201: Speed up paste mode in the REPL (#119341) (GH-119432) (#119439)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 23 May 2024 04:23:40 +0000 (06:23 +0200)
committerGitHub <noreply@github.com>
Thu, 23 May 2024 04:23:40 +0000 (04:23 +0000)
(cherry picked from commit e6572e8f98d33994d2d0dd3afa92a2a72ee642a9)

Also includes:

* gh-111201: Use calc_complete_screen after bracketed paste in PyREPL (GH-119432)
(cherry picked from commit 14b063cbf1bb11a489d04a31f277edba0fc8893c)

Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
Co-authored-by: Ɓukasz Langa <lukasz@langa.pl>
Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
Lib/_pyrepl/commands.py
Lib/_pyrepl/reader.py
Lib/_pyrepl/readline.py
Lib/_pyrepl/simple_interact.py
Lib/_pyrepl/utils.py
Lib/test/test_pyrepl/test_pyrepl.py

index 3d9722d1586c2a24dd58b2f95d766914db182518..ed977f84baac4e19bc61779a49a53125674d196c 100644 (file)
@@ -461,8 +461,6 @@ class show_history(Command):
 class paste_mode(Command):
 
     def do(self) -> None:
-        if not self.reader.paste_mode:
-            self.reader.was_paste_mode_activated = True
         self.reader.paste_mode = not self.reader.paste_mode
         self.reader.dirty = True
 
@@ -470,9 +468,11 @@ class paste_mode(Command):
 class enable_bracketed_paste(Command):
     def do(self) -> None:
         self.reader.paste_mode = True
-        self.reader.was_paste_mode_activated = True
+        self.reader.in_bracketed_paste = True
 
 class disable_bracketed_paste(Command):
     def do(self) -> None:
         self.reader.paste_mode = False
+        self.reader.in_bracketed_paste = False
         self.reader.dirty = True
+        self.reader.calc_screen = self.reader.calc_complete_screen
index 40cbe422fabdbec0500c50a0d0bef027069f3d31..0f0ef15f9eb2eab6ef62c50e52dec6cc763d1643 100644 (file)
@@ -54,7 +54,7 @@ def disp_str(buffer: str) -> tuple[str, list[int]]:
     b: list[int] = []
     s: list[str] = []
     for c in buffer:
-        if unicodedata.category(c).startswith("C"):
+        if ord(c) > 128 and unicodedata.category(c).startswith("C"):
             c = r"\u%04x" % ord(c)
         s.append(c)
         b.append(wlen(c))
@@ -225,7 +225,7 @@ class Reader:
     dirty: bool = False
     finished: bool = False
     paste_mode: bool = False
-    was_paste_mode_activated: bool = False
+    in_bracketed_paste: bool = False
     commands: dict[str, type[Command]] = field(default_factory=make_default_commands)
     last_command: type[Command] | None = None
     syntax_table: dict[str, int] = field(default_factory=make_default_syntax_table)
@@ -454,7 +454,7 @@ class Reader:
         elif "\n" in self.buffer:
             if lineno == 0:
                 prompt = self.ps2
-            elif lineno == self.buffer.count("\n"):
+            elif self.ps4 and lineno == self.buffer.count("\n"):
                 prompt = self.ps4
             else:
                 prompt = self.ps3
@@ -617,7 +617,7 @@ class Reader:
 
         self.after_command(command)
 
-        if self.dirty:
+        if self.dirty and not self.in_bracketed_paste:
             self.refresh()
         else:
             self.update_cursor()
index 57e00a66295b7b4f6dba17aa18b11d176e766578..ffa14a9ce31a8f3510822db57def47d473edf921 100644 (file)
@@ -341,7 +341,7 @@ class _ReadlineWrapper:
         reader.ps1 = str(prompt)
         return reader.readline(startup_hook=self.startup_hook)
 
-    def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) -> tuple[str, bool]:
+    def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) -> str:
         """Read an input on possibly multiple lines, asking for more
         lines as long as 'more_lines(unicodetext)' returns an object whose
         boolean value is true.
@@ -350,14 +350,15 @@ class _ReadlineWrapper:
         saved = reader.more_lines
         try:
             reader.more_lines = more_lines
-            reader.ps1 = reader.ps2 = ps1
-            reader.ps3 = reader.ps4 = ps2
+            reader.ps1 = ps1
+            reader.ps2 = ps1
+            reader.ps3 = ps2
+            reader.ps4 = ""
             with warnings.catch_warnings(action="ignore"):
-                return reader.readline(), reader.was_paste_mode_activated
+                return reader.readline()
         finally:
             reader.more_lines = saved
             reader.paste_mode = False
-            reader.was_paste_mode_activated = False
 
     def parse_and_bind(self, string: str) -> None:
         pass  # XXX we don't support parsing GNU-readline-style init files
index d65b6d0d62790acf8e10b1c0635752bf21c1c8b7..8ab4dab757685ee6e85aa265eb1da422b17b797d 100644 (file)
@@ -62,6 +62,7 @@ REPL_COMMANDS = {
     "quit": _sitebuiltins.Quitter('quit' ,''),
     "copyright": _sitebuiltins._Printer('copyright', sys.copyright),
     "help": "help",
+    "clear": "clear_screen",
 }
 
 class InteractiveColoredConsole(code.InteractiveConsole):
@@ -163,7 +164,7 @@ def run_multiline_interactive_console(
             ps1 = getattr(sys, "ps1", ">>> ")
             ps2 = getattr(sys, "ps2", "... ")
             try:
-                statement, contains_pasted_code = multiline_input(more_lines, ps1, ps2)
+                statement = multiline_input(more_lines, ps1, ps2)
             except EOFError:
                 break
 
index cd1df7c49a216ddc323f081fe20213e2385ce37e..96e917e487d91a8019f110d4e2b0f8103d4507ca 100644 (file)
@@ -1,10 +1,14 @@
 import re
 import unicodedata
+import functools
 
 ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]")
 
 
+@functools.cache
 def str_width(c: str) -> int:
+    if ord(c) < 128:
+        return 1
     w = unicodedata.east_asian_width(c)
     if w in ('N', 'Na', 'H', 'A'):
         return 1
@@ -13,6 +17,6 @@ def str_width(c: str) -> int:
 
 def wlen(s: str) -> int:
     length = sum(str_width(i) for i in s)
-
     # remove lengths of any escape sequences
-    return length - sum(len(i) for i in ANSI_ESCAPE_SEQUENCE.findall(s))
+    sequence = ANSI_ESCAPE_SEQUENCE.findall(s)
+    return length - sum(len(i) for i in sequence)
index 7dff2888da3a58a2f7865c4fd811f85eaab7ab03..bdcabf9be05b9eda4839ff888f0aa0e8e250e74d 100644 (file)
@@ -587,7 +587,7 @@ class TestPyReplCompleter(TestCase):
         reader = self.prepare_reader(events, namespace)
         mock_get_reader.return_value = reader
         output = readline_multiline_input(more_lines, ">>>", "...")
-        self.assertEqual(output[0], "dummy.test_func.__")
+        self.assertEqual(output, "dummy.test_func.__")
         self.assertEqual(mock_stderr.getvalue(), "")