mirror of
https://github.com/python/cpython.git
synced 2025-08-01 07:33:08 +00:00
(cherry picked from commite6572e8f98
) Also includes: * gh-111201: Use calc_complete_screen after bracketed paste in PyREPL (GH-119432) (cherry picked from commit14b063cbf1
) 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>
This commit is contained in:
parent
9fa1b4fc46
commit
58dbb4a4b0
6 changed files with 22 additions and 16 deletions
|
@ -461,8 +461,6 @@ class show_history(Command):
|
||||||
class paste_mode(Command):
|
class paste_mode(Command):
|
||||||
|
|
||||||
def do(self) -> None:
|
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.paste_mode = not self.reader.paste_mode
|
||||||
self.reader.dirty = True
|
self.reader.dirty = True
|
||||||
|
|
||||||
|
@ -470,9 +468,11 @@ class paste_mode(Command):
|
||||||
class enable_bracketed_paste(Command):
|
class enable_bracketed_paste(Command):
|
||||||
def do(self) -> None:
|
def do(self) -> None:
|
||||||
self.reader.paste_mode = True
|
self.reader.paste_mode = True
|
||||||
self.reader.was_paste_mode_activated = True
|
self.reader.in_bracketed_paste = True
|
||||||
|
|
||||||
class disable_bracketed_paste(Command):
|
class disable_bracketed_paste(Command):
|
||||||
def do(self) -> None:
|
def do(self) -> None:
|
||||||
self.reader.paste_mode = False
|
self.reader.paste_mode = False
|
||||||
|
self.reader.in_bracketed_paste = False
|
||||||
self.reader.dirty = True
|
self.reader.dirty = True
|
||||||
|
self.reader.calc_screen = self.reader.calc_complete_screen
|
||||||
|
|
|
@ -54,7 +54,7 @@ def disp_str(buffer: str) -> tuple[str, list[int]]:
|
||||||
b: list[int] = []
|
b: list[int] = []
|
||||||
s: list[str] = []
|
s: list[str] = []
|
||||||
for c in buffer:
|
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)
|
c = r"\u%04x" % ord(c)
|
||||||
s.append(c)
|
s.append(c)
|
||||||
b.append(wlen(c))
|
b.append(wlen(c))
|
||||||
|
@ -225,7 +225,7 @@ class Reader:
|
||||||
dirty: bool = False
|
dirty: bool = False
|
||||||
finished: bool = False
|
finished: bool = False
|
||||||
paste_mode: 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)
|
commands: dict[str, type[Command]] = field(default_factory=make_default_commands)
|
||||||
last_command: type[Command] | None = None
|
last_command: type[Command] | None = None
|
||||||
syntax_table: dict[str, int] = field(default_factory=make_default_syntax_table)
|
syntax_table: dict[str, int] = field(default_factory=make_default_syntax_table)
|
||||||
|
@ -454,7 +454,7 @@ class Reader:
|
||||||
elif "\n" in self.buffer:
|
elif "\n" in self.buffer:
|
||||||
if lineno == 0:
|
if lineno == 0:
|
||||||
prompt = self.ps2
|
prompt = self.ps2
|
||||||
elif lineno == self.buffer.count("\n"):
|
elif self.ps4 and lineno == self.buffer.count("\n"):
|
||||||
prompt = self.ps4
|
prompt = self.ps4
|
||||||
else:
|
else:
|
||||||
prompt = self.ps3
|
prompt = self.ps3
|
||||||
|
@ -617,7 +617,7 @@ class Reader:
|
||||||
|
|
||||||
self.after_command(command)
|
self.after_command(command)
|
||||||
|
|
||||||
if self.dirty:
|
if self.dirty and not self.in_bracketed_paste:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
else:
|
else:
|
||||||
self.update_cursor()
|
self.update_cursor()
|
||||||
|
|
|
@ -341,7 +341,7 @@ class _ReadlineWrapper:
|
||||||
reader.ps1 = str(prompt)
|
reader.ps1 = str(prompt)
|
||||||
return reader.readline(startup_hook=self.startup_hook)
|
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
|
"""Read an input on possibly multiple lines, asking for more
|
||||||
lines as long as 'more_lines(unicodetext)' returns an object whose
|
lines as long as 'more_lines(unicodetext)' returns an object whose
|
||||||
boolean value is true.
|
boolean value is true.
|
||||||
|
@ -350,14 +350,15 @@ class _ReadlineWrapper:
|
||||||
saved = reader.more_lines
|
saved = reader.more_lines
|
||||||
try:
|
try:
|
||||||
reader.more_lines = more_lines
|
reader.more_lines = more_lines
|
||||||
reader.ps1 = reader.ps2 = ps1
|
reader.ps1 = ps1
|
||||||
reader.ps3 = reader.ps4 = ps2
|
reader.ps2 = ps1
|
||||||
|
reader.ps3 = ps2
|
||||||
|
reader.ps4 = ""
|
||||||
with warnings.catch_warnings(action="ignore"):
|
with warnings.catch_warnings(action="ignore"):
|
||||||
return reader.readline(), reader.was_paste_mode_activated
|
return reader.readline()
|
||||||
finally:
|
finally:
|
||||||
reader.more_lines = saved
|
reader.more_lines = saved
|
||||||
reader.paste_mode = False
|
reader.paste_mode = False
|
||||||
reader.was_paste_mode_activated = False
|
|
||||||
|
|
||||||
def parse_and_bind(self, string: str) -> None:
|
def parse_and_bind(self, string: str) -> None:
|
||||||
pass # XXX we don't support parsing GNU-readline-style init files
|
pass # XXX we don't support parsing GNU-readline-style init files
|
||||||
|
|
|
@ -62,6 +62,7 @@ REPL_COMMANDS = {
|
||||||
"quit": _sitebuiltins.Quitter('quit' ,''),
|
"quit": _sitebuiltins.Quitter('quit' ,''),
|
||||||
"copyright": _sitebuiltins._Printer('copyright', sys.copyright),
|
"copyright": _sitebuiltins._Printer('copyright', sys.copyright),
|
||||||
"help": "help",
|
"help": "help",
|
||||||
|
"clear": "clear_screen",
|
||||||
}
|
}
|
||||||
|
|
||||||
class InteractiveColoredConsole(code.InteractiveConsole):
|
class InteractiveColoredConsole(code.InteractiveConsole):
|
||||||
|
@ -163,7 +164,7 @@ def run_multiline_interactive_console(
|
||||||
ps1 = getattr(sys, "ps1", ">>> ")
|
ps1 = getattr(sys, "ps1", ">>> ")
|
||||||
ps2 = getattr(sys, "ps2", "... ")
|
ps2 = getattr(sys, "ps2", "... ")
|
||||||
try:
|
try:
|
||||||
statement, contains_pasted_code = multiline_input(more_lines, ps1, ps2)
|
statement = multiline_input(more_lines, ps1, ps2)
|
||||||
except EOFError:
|
except EOFError:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import re
|
import re
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
import functools
|
||||||
|
|
||||||
ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]")
|
ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]")
|
||||||
|
|
||||||
|
|
||||||
|
@functools.cache
|
||||||
def str_width(c: str) -> int:
|
def str_width(c: str) -> int:
|
||||||
|
if ord(c) < 128:
|
||||||
|
return 1
|
||||||
w = unicodedata.east_asian_width(c)
|
w = unicodedata.east_asian_width(c)
|
||||||
if w in ('N', 'Na', 'H', 'A'):
|
if w in ('N', 'Na', 'H', 'A'):
|
||||||
return 1
|
return 1
|
||||||
|
@ -13,6 +17,6 @@ def str_width(c: str) -> int:
|
||||||
|
|
||||||
def wlen(s: str) -> int:
|
def wlen(s: str) -> int:
|
||||||
length = sum(str_width(i) for i in s)
|
length = sum(str_width(i) for i in s)
|
||||||
|
|
||||||
# remove lengths of any escape sequences
|
# 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)
|
||||||
|
|
|
@ -587,7 +587,7 @@ class TestPyReplCompleter(TestCase):
|
||||||
reader = self.prepare_reader(events, namespace)
|
reader = self.prepare_reader(events, namespace)
|
||||||
mock_get_reader.return_value = reader
|
mock_get_reader.return_value = reader
|
||||||
output = readline_multiline_input(more_lines, ">>>", "...")
|
output = readline_multiline_input(more_lines, ">>>", "...")
|
||||||
self.assertEqual(output[0], "dummy.test_func.__")
|
self.assertEqual(output, "dummy.test_func.__")
|
||||||
self.assertEqual(mock_stderr.getvalue(), "")
|
self.assertEqual(mock_stderr.getvalue(), "")
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue