Skip to content

Commit 58dbb4a

Browse files
miss-islingtonpablogsalambvlysnikolaou
authored
[3.13] gh-111201: Speed up paste mode in the REPL (#119341) (GH-119432) (#119439)
(cherry picked from commit e6572e8) Also includes: * gh-111201: Use calc_complete_screen after bracketed paste in PyREPL (GH-119432) (cherry picked from commit 14b063c) 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>
1 parent 9fa1b4f commit 58dbb4a

File tree

6 files changed

+22
-16
lines changed

6 files changed

+22
-16
lines changed

Diff for: Lib/_pyrepl/commands.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -461,18 +461,18 @@ def do(self) -> None:
461461
class paste_mode(Command):
462462

463463
def do(self) -> None:
464-
if not self.reader.paste_mode:
465-
self.reader.was_paste_mode_activated = True
466464
self.reader.paste_mode = not self.reader.paste_mode
467465
self.reader.dirty = True
468466

469467

470468
class enable_bracketed_paste(Command):
471469
def do(self) -> None:
472470
self.reader.paste_mode = True
473-
self.reader.was_paste_mode_activated = True
471+
self.reader.in_bracketed_paste = True
474472

475473
class disable_bracketed_paste(Command):
476474
def do(self) -> None:
477475
self.reader.paste_mode = False
476+
self.reader.in_bracketed_paste = False
478477
self.reader.dirty = True
478+
self.reader.calc_screen = self.reader.calc_complete_screen

Diff for: Lib/_pyrepl/reader.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def disp_str(buffer: str) -> tuple[str, list[int]]:
5454
b: list[int] = []
5555
s: list[str] = []
5656
for c in buffer:
57-
if unicodedata.category(c).startswith("C"):
57+
if ord(c) > 128 and unicodedata.category(c).startswith("C"):
5858
c = r"\u%04x" % ord(c)
5959
s.append(c)
6060
b.append(wlen(c))
@@ -225,7 +225,7 @@ class Reader:
225225
dirty: bool = False
226226
finished: bool = False
227227
paste_mode: bool = False
228-
was_paste_mode_activated: bool = False
228+
in_bracketed_paste: bool = False
229229
commands: dict[str, type[Command]] = field(default_factory=make_default_commands)
230230
last_command: type[Command] | None = None
231231
syntax_table: dict[str, int] = field(default_factory=make_default_syntax_table)
@@ -454,7 +454,7 @@ def get_prompt(self, lineno: int, cursor_on_line: bool) -> str:
454454
elif "\n" in self.buffer:
455455
if lineno == 0:
456456
prompt = self.ps2
457-
elif lineno == self.buffer.count("\n"):
457+
elif self.ps4 and lineno == self.buffer.count("\n"):
458458
prompt = self.ps4
459459
else:
460460
prompt = self.ps3
@@ -617,7 +617,7 @@ def do_cmd(self, cmd: tuple[str, list[str]]) -> None:
617617

618618
self.after_command(command)
619619

620-
if self.dirty:
620+
if self.dirty and not self.in_bracketed_paste:
621621
self.refresh()
622622
else:
623623
self.update_cursor()

Diff for: Lib/_pyrepl/readline.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ def input(self, prompt: object = "") -> str:
341341
reader.ps1 = str(prompt)
342342
return reader.readline(startup_hook=self.startup_hook)
343343

344-
def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) -> tuple[str, bool]:
344+
def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) -> str:
345345
"""Read an input on possibly multiple lines, asking for more
346346
lines as long as 'more_lines(unicodetext)' returns an object whose
347347
boolean value is true.
@@ -350,14 +350,15 @@ def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) ->
350350
saved = reader.more_lines
351351
try:
352352
reader.more_lines = more_lines
353-
reader.ps1 = reader.ps2 = ps1
354-
reader.ps3 = reader.ps4 = ps2
353+
reader.ps1 = ps1
354+
reader.ps2 = ps1
355+
reader.ps3 = ps2
356+
reader.ps4 = ""
355357
with warnings.catch_warnings(action="ignore"):
356-
return reader.readline(), reader.was_paste_mode_activated
358+
return reader.readline()
357359
finally:
358360
reader.more_lines = saved
359361
reader.paste_mode = False
360-
reader.was_paste_mode_activated = False
361362

362363
def parse_and_bind(self, string: str) -> None:
363364
pass # XXX we don't support parsing GNU-readline-style init files

Diff for: Lib/_pyrepl/simple_interact.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def _strip_final_indent(text: str) -> str:
6262
"quit": _sitebuiltins.Quitter('quit' ,''),
6363
"copyright": _sitebuiltins._Printer('copyright', sys.copyright),
6464
"help": "help",
65+
"clear": "clear_screen",
6566
}
6667

6768
class InteractiveColoredConsole(code.InteractiveConsole):
@@ -163,7 +164,7 @@ def more_lines(unicodetext: str) -> bool:
163164
ps1 = getattr(sys, "ps1", ">>> ")
164165
ps2 = getattr(sys, "ps2", "... ")
165166
try:
166-
statement, contains_pasted_code = multiline_input(more_lines, ps1, ps2)
167+
statement = multiline_input(more_lines, ps1, ps2)
167168
except EOFError:
168169
break
169170

Diff for: Lib/_pyrepl/utils.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import re
22
import unicodedata
3+
import functools
34

45
ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]")
56

67

8+
@functools.cache
79
def str_width(c: str) -> int:
10+
if ord(c) < 128:
11+
return 1
812
w = unicodedata.east_asian_width(c)
913
if w in ('N', 'Na', 'H', 'A'):
1014
return 1
@@ -13,6 +17,6 @@ def str_width(c: str) -> int:
1317

1418
def wlen(s: str) -> int:
1519
length = sum(str_width(i) for i in s)
16-
1720
# remove lengths of any escape sequences
18-
return length - sum(len(i) for i in ANSI_ESCAPE_SEQUENCE.findall(s))
21+
sequence = ANSI_ESCAPE_SEQUENCE.findall(s)
22+
return length - sum(len(i) for i in sequence)

Diff for: Lib/test/test_pyrepl/test_pyrepl.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ def test_func(self):
587587
reader = self.prepare_reader(events, namespace)
588588
mock_get_reader.return_value = reader
589589
output = readline_multiline_input(more_lines, ">>>", "...")
590-
self.assertEqual(output[0], "dummy.test_func.__")
590+
self.assertEqual(output, "dummy.test_func.__")
591591
self.assertEqual(mock_stderr.getvalue(), "")
592592

593593

0 commit comments

Comments
 (0)