mirror of https://github.com/python/cpython.git
gh-111201: Speed up paste mode in the REPL (#119341)
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
parent
cd516cd1f5
commit
e6572e8f98
|
@ -461,8 +461,6 @@ def do(self) -> None:
|
|||
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 @@ def do(self) -> None:
|
|||
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
|
||||
|
|
|
@ -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 @@ def get_prompt(self, lineno: int, cursor_on_line: bool) -> str:
|
|||
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 @@ def do_cmd(self, cmd: tuple[str, list[str]]) -> None:
|
|||
|
||||
self.after_command(command)
|
||||
|
||||
if self.dirty:
|
||||
if self.dirty and not self.in_bracketed_paste:
|
||||
self.refresh()
|
||||
else:
|
||||
self.update_cursor()
|
||||
|
|
|
@ -328,7 +328,7 @@ def input(self, prompt: object = "") -> str:
|
|||
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 @@ def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) ->
|
|||
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
|
||||
|
|
|
@ -62,6 +62,7 @@ def _strip_final_indent(text: str) -> str:
|
|||
"quit": _sitebuiltins.Quitter('quit' ,''),
|
||||
"copyright": _sitebuiltins._Printer('copyright', sys.copyright),
|
||||
"help": "help",
|
||||
"clear": "clear_screen",
|
||||
}
|
||||
|
||||
class InteractiveColoredConsole(code.InteractiveConsole):
|
||||
|
@ -163,7 +164,7 @@ def more_lines(unicodetext: str) -> bool:
|
|||
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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -578,7 +578,7 @@ def test_func(self):
|
|||
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(), "")
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue