summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Galindo Salgado <Pablogsal@gmail.com>2024-05-22 05:28:32 (GMT)
committerGitHub <noreply@github.com>2024-05-22 05:28:32 (GMT)
commite6572e8f98d33994d2d0dd3afa92a2a72ee642a9 (patch)
treea37b8588fde40dbd36c74743de1625cd6c13a467
parentcd516cd1f5e94dba887353f421513fd172efadf3 (diff)
downloadcpython-e6572e8f98d33994d2d0dd3afa92a2a72ee642a9.zip
cpython-e6572e8f98d33994d2d0dd3afa92a2a72ee642a9.tar.gz
cpython-e6572e8f98d33994d2d0dd3afa92a2a72ee642a9.tar.bz2
gh-111201: Speed up paste mode in the REPL (#119341)
Co-authored-by: Ɓukasz Langa <lukasz@langa.pl>
-rw-r--r--Lib/_pyrepl/commands.py5
-rw-r--r--Lib/_pyrepl/reader.py8
-rw-r--r--Lib/_pyrepl/readline.py11
-rw-r--r--Lib/_pyrepl/simple_interact.py3
-rw-r--r--Lib/_pyrepl/utils.py8
-rw-r--r--Lib/test/test_pyrepl/test_pyrepl.py2
6 files changed, 21 insertions, 16 deletions
diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py
index 3d9722d..33c6564 100644
--- a/Lib/_pyrepl/commands.py
+++ b/Lib/_pyrepl/commands.py
@@ -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,10 @@ 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
diff --git a/Lib/_pyrepl/reader.py b/Lib/_pyrepl/reader.py
index 9a207a2..3dbfc34 100644
--- a/Lib/_pyrepl/reader.py
+++ b/Lib/_pyrepl/reader.py
@@ -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)
@@ -448,7 +448,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
@@ -611,7 +611,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()
diff --git a/Lib/_pyrepl/readline.py b/Lib/_pyrepl/readline.py
index 054a39b..796f1ef 100644
--- a/Lib/_pyrepl/readline.py
+++ b/Lib/_pyrepl/readline.py
@@ -328,7 +328,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.
@@ -337,14 +337,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
diff --git a/Lib/_pyrepl/simple_interact.py b/Lib/_pyrepl/simple_interact.py
index d65b6d0..8ab4dab 100644
--- a/Lib/_pyrepl/simple_interact.py
+++ b/Lib/_pyrepl/simple_interact.py
@@ -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
diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py
index cd1df7c..96e917e 100644
--- a/Lib/_pyrepl/utils.py
+++ b/Lib/_pyrepl/utils.py
@@ -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)
diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py
index 930f6759..7b5217e 100644
--- a/Lib/test/test_pyrepl/test_pyrepl.py
+++ b/Lib/test/test_pyrepl/test_pyrepl.py
@@ -578,7 +578,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(), "")