Skip to content

Commit aefe2e6

Browse files
miss-islingtonlysnikolaouambv
authored
[3.13] gh-111201: Add append to screen method to avoid recalculation (GH-119274) (#119405)
(cherry picked from commit c886bec) Co-authored-by: Lysandros Nikolaou <[email protected]> Co-authored-by: Łukasz Langa <[email protected]>
1 parent ac91636 commit aefe2e6

File tree

4 files changed

+43
-14
lines changed

4 files changed

+43
-14
lines changed

Lib/_pyrepl/commands.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,10 @@ def do(self) -> None:
358358
class self_insert(EditCommand):
359359
def do(self) -> None:
360360
r = self.reader
361-
r.insert(self.event * r.get_arg())
361+
text = self.event * r.get_arg()
362+
r.insert(text)
363+
if len(text) == 1 and r.pos == len(r.buffer):
364+
r.calc_screen = r.append_to_screen
362365

363366

364367
class insert_nl(EditCommand):

Lib/_pyrepl/completing_reader.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ def do(self) -> None:
187187
if p:
188188
r.insert(p)
189189
if last_is_completer:
190-
if not r.cmpltn_menu_vis:
191-
r.cmpltn_menu_vis = 1
190+
if not r.cmpltn_menu_visible:
191+
r.cmpltn_menu_visible = True
192192
r.cmpltn_menu, r.cmpltn_menu_end = build_menu(
193193
r.console, completions, r.cmpltn_menu_end,
194194
r.use_brackets, r.sort_in_column)
@@ -208,7 +208,7 @@ def do(self) -> None:
208208

209209
commands.self_insert.do(self)
210210

211-
if r.cmpltn_menu_vis:
211+
if r.cmpltn_menu_visible:
212212
stem = r.get_stem()
213213
if len(stem) < 1:
214214
r.cmpltn_reset()
@@ -235,7 +235,7 @@ class CompletingReader(Reader):
235235

236236
### Instance variables
237237
cmpltn_menu: list[str] = field(init=False)
238-
cmpltn_menu_vis: int = field(init=False)
238+
cmpltn_menu_visible: bool = field(init=False)
239239
cmpltn_menu_end: int = field(init=False)
240240
cmpltn_menu_choices: list[str] = field(init=False)
241241

@@ -255,9 +255,9 @@ def after_command(self, cmd: Command) -> None:
255255
if not isinstance(cmd, (complete, self_insert)):
256256
self.cmpltn_reset()
257257

258-
def calc_screen(self) -> list[str]:
259-
screen = super().calc_screen()
260-
if self.cmpltn_menu_vis:
258+
def calc_complete_screen(self) -> list[str]:
259+
screen = super().calc_complete_screen()
260+
if self.cmpltn_menu_visible:
261261
ly = self.lxy[1]
262262
screen[ly:ly] = self.cmpltn_menu
263263
self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu)
@@ -270,7 +270,7 @@ def finish(self) -> None:
270270

271271
def cmpltn_reset(self) -> None:
272272
self.cmpltn_menu = []
273-
self.cmpltn_menu_vis = 0
273+
self.cmpltn_menu_visible = False
274274
self.cmpltn_menu_end = 0
275275
self.cmpltn_menu_choices = []
276276

Lib/_pyrepl/reader.py

+30-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
# types
3636
Command = commands.Command
3737
if False:
38+
from typing import Callable
3839
from .types import Callback, SimpleContextManager, KeySpec, CommandName
40+
CalcScreen = Callable[[], list[str]]
3941

4042

4143
def disp_str(buffer: str) -> tuple[str, list[int]]:
@@ -231,9 +233,11 @@ class Reader:
231233
keymap: tuple[tuple[str, str], ...] = ()
232234
input_trans: input.KeymapTranslator = field(init=False)
233235
input_trans_stack: list[input.KeymapTranslator] = field(default_factory=list)
236+
screen: list[str] = field(default_factory=list)
234237
screeninfo: list[tuple[int, list[int]]] = field(init=False)
235238
cxy: tuple[int, int] = field(init=False)
236239
lxy: tuple[int, int] = field(init=False)
240+
calc_screen: CalcScreen = field(init=False)
237241

238242
def __post_init__(self) -> None:
239243
# Enable the use of `insert` without a `prepare` call - necessary to
@@ -243,14 +247,36 @@ def __post_init__(self) -> None:
243247
self.input_trans = input.KeymapTranslator(
244248
self.keymap, invalid_cls="invalid-key", character_cls="self-insert"
245249
)
246-
self.screeninfo = [(0, [0])]
250+
self.screeninfo = [(0, [])]
247251
self.cxy = self.pos2xy()
248252
self.lxy = (self.pos, 0)
253+
self.calc_screen = self.calc_complete_screen
249254

250255
def collect_keymap(self) -> tuple[tuple[KeySpec, CommandName], ...]:
251256
return default_keymap
252257

253-
def calc_screen(self) -> list[str]:
258+
def append_to_screen(self) -> list[str]:
259+
new_screen = self.screen.copy() or ['']
260+
261+
new_character = self.buffer[-1]
262+
new_character_len = wlen(new_character)
263+
264+
last_line_len = wlen(new_screen[-1])
265+
if last_line_len + new_character_len >= self.console.width: # We need to wrap here
266+
new_screen[-1] += '\\'
267+
self.screeninfo[-1][1].append(1)
268+
new_screen.append(self.buffer[-1])
269+
self.screeninfo.append((0, [new_character_len]))
270+
else:
271+
new_screen[-1] += self.buffer[-1]
272+
self.screeninfo[-1][1].append(new_character_len)
273+
self.cxy = self.pos2xy()
274+
275+
# Reset the function that is used for completing the screen
276+
self.calc_screen = self.calc_complete_screen
277+
return new_screen
278+
279+
def calc_complete_screen(self) -> list[str]:
254280
"""The purpose of this method is to translate changes in
255281
self.buffer into changes in self.screen. Currently it rips
256282
everything down and starts from scratch, which whilst not
@@ -563,8 +589,8 @@ def update_screen(self) -> None:
563589
def refresh(self) -> None:
564590
"""Recalculate and refresh the screen."""
565591
# this call sets up self.cxy, so call it first.
566-
screen = self.calc_screen()
567-
self.console.refresh(screen, self.cxy)
592+
self.screen = self.calc_screen()
593+
self.console.refresh(self.screen, self.cxy)
568594
self.dirty = False
569595

570596
def do_cmd(self, cmd: tuple[str, list[str]]) -> None:

Lib/_pyrepl/unix_console.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ def refresh(self, screen, c_xy):
283283

284284
self.__show_cursor()
285285

286-
self.screen = screen
286+
self.screen = screen.copy()
287287
self.move_cursor(cx, cy)
288288
self.flushoutput()
289289

0 commit comments

Comments
 (0)