Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.13] gh-111201: Use calc_complete_screen after bracketed paste in PyREPL (GH-119432) #119439

Merged
merged 2 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Lib/_pyrepl/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,18 +461,18 @@ 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


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
8 changes: 4 additions & 4 deletions Lib/_pyrepl/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -454,7 +454,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
Expand Down Expand Up @@ -617,7 +617,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()
Expand Down
11 changes: 6 additions & 5 deletions Lib/_pyrepl/readline.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion Lib/_pyrepl/simple_interact.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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

Expand Down
8 changes: 6 additions & 2 deletions Lib/_pyrepl/utils.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)
2 changes: 1 addition & 1 deletion Lib/test/test_pyrepl/test_pyrepl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(), "")


Expand Down
Loading