summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLysandros Nikolaou <lisandrosnik@gmail.com>2024-05-22 02:35:44 (GMT)
committerGitHub <noreply@github.com>2024-05-22 02:35:44 (GMT)
commitc886bece3b3a49f8a0f188aecfc1d6ff89d281e6 (patch)
tree43956c1fc6a1df7b0c124fb0c9845ad364f5239a
parentd065edfb66470bbf06367b3570661d0346aa6707 (diff)
downloadcpython-c886bece3b3a49f8a0f188aecfc1d6ff89d281e6.zip
cpython-c886bece3b3a49f8a0f188aecfc1d6ff89d281e6.tar.gz
cpython-c886bece3b3a49f8a0f188aecfc1d6ff89d281e6.tar.bz2
gh-111201: Add append to screen method to avoid recalculation (#119274)
Co-authored-by: Ɓukasz Langa <lukasz@langa.pl>
-rw-r--r--Lib/_pyrepl/commands.py5
-rw-r--r--Lib/_pyrepl/completing_reader.py16
-rw-r--r--Lib/_pyrepl/reader.py34
-rw-r--r--Lib/_pyrepl/unix_console.py2
4 files changed, 43 insertions, 14 deletions
diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py
index 51c7afe..3d9722d 100644
--- a/Lib/_pyrepl/commands.py
+++ b/Lib/_pyrepl/commands.py
@@ -358,7 +358,10 @@ class backward_word(MotionCommand):
class self_insert(EditCommand):
def do(self) -> None:
r = self.reader
- r.insert(self.event * r.get_arg())
+ text = self.event * r.get_arg()
+ r.insert(text)
+ if len(text) == 1 and r.pos == len(r.buffer):
+ r.calc_screen = r.append_to_screen
class insert_nl(EditCommand):
diff --git a/Lib/_pyrepl/completing_reader.py b/Lib/_pyrepl/completing_reader.py
index 19fc06f..3f8506b 100644
--- a/Lib/_pyrepl/completing_reader.py
+++ b/Lib/_pyrepl/completing_reader.py
@@ -187,8 +187,8 @@ class complete(commands.Command):
if p:
r.insert(p)
if last_is_completer:
- if not r.cmpltn_menu_vis:
- r.cmpltn_menu_vis = 1
+ if not r.cmpltn_menu_visible:
+ r.cmpltn_menu_visible = True
r.cmpltn_menu, r.cmpltn_menu_end = build_menu(
r.console, completions, r.cmpltn_menu_end,
r.use_brackets, r.sort_in_column)
@@ -208,7 +208,7 @@ class self_insert(commands.self_insert):
commands.self_insert.do(self)
- if r.cmpltn_menu_vis:
+ if r.cmpltn_menu_visible:
stem = r.get_stem()
if len(stem) < 1:
r.cmpltn_reset()
@@ -235,7 +235,7 @@ class CompletingReader(Reader):
### Instance variables
cmpltn_menu: list[str] = field(init=False)
- cmpltn_menu_vis: int = field(init=False)
+ cmpltn_menu_visible: bool = field(init=False)
cmpltn_menu_end: int = field(init=False)
cmpltn_menu_choices: list[str] = field(init=False)
@@ -255,9 +255,9 @@ class CompletingReader(Reader):
if not isinstance(cmd, (complete, self_insert)):
self.cmpltn_reset()
- def calc_screen(self) -> list[str]:
- screen = super().calc_screen()
- if self.cmpltn_menu_vis:
+ def calc_complete_screen(self) -> list[str]:
+ screen = super().calc_complete_screen()
+ if self.cmpltn_menu_visible:
ly = self.lxy[1]
screen[ly:ly] = self.cmpltn_menu
self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu)
@@ -270,7 +270,7 @@ class CompletingReader(Reader):
def cmpltn_reset(self) -> None:
self.cmpltn_menu = []
- self.cmpltn_menu_vis = 0
+ self.cmpltn_menu_visible = False
self.cmpltn_menu_end = 0
self.cmpltn_menu_choices = []
diff --git a/Lib/_pyrepl/reader.py b/Lib/_pyrepl/reader.py
index 2c8c9e7..9a207a2 100644
--- a/Lib/_pyrepl/reader.py
+++ b/Lib/_pyrepl/reader.py
@@ -35,7 +35,9 @@ from .trace import trace
# types
Command = commands.Command
if False:
+ from typing import Callable
from .types import Callback, SimpleContextManager, KeySpec, CommandName
+ CalcScreen = Callable[[], list[str]]
def disp_str(buffer: str) -> tuple[str, list[int]]:
@@ -231,9 +233,11 @@ class Reader:
keymap: tuple[tuple[str, str], ...] = ()
input_trans: input.KeymapTranslator = field(init=False)
input_trans_stack: list[input.KeymapTranslator] = field(default_factory=list)
+ screen: list[str] = field(default_factory=list)
screeninfo: list[tuple[int, list[int]]] = field(init=False)
cxy: tuple[int, int] = field(init=False)
lxy: tuple[int, int] = field(init=False)
+ calc_screen: CalcScreen = field(init=False)
def __post_init__(self) -> None:
# Enable the use of `insert` without a `prepare` call - necessary to
@@ -243,14 +247,36 @@ class Reader:
self.input_trans = input.KeymapTranslator(
self.keymap, invalid_cls="invalid-key", character_cls="self-insert"
)
- self.screeninfo = [(0, [0])]
+ self.screeninfo = [(0, [])]
self.cxy = self.pos2xy()
self.lxy = (self.pos, 0)
+ self.calc_screen = self.calc_complete_screen
def collect_keymap(self) -> tuple[tuple[KeySpec, CommandName], ...]:
return default_keymap
- def calc_screen(self) -> list[str]:
+ def append_to_screen(self) -> list[str]:
+ new_screen = self.screen.copy() or ['']
+
+ new_character = self.buffer[-1]
+ new_character_len = wlen(new_character)
+
+ last_line_len = wlen(new_screen[-1])
+ if last_line_len + new_character_len >= self.console.width: # We need to wrap here
+ new_screen[-1] += '\\'
+ self.screeninfo[-1][1].append(1)
+ new_screen.append(self.buffer[-1])
+ self.screeninfo.append((0, [new_character_len]))
+ else:
+ new_screen[-1] += self.buffer[-1]
+ self.screeninfo[-1][1].append(new_character_len)
+ self.cxy = self.pos2xy()
+
+ # Reset the function that is used for completing the screen
+ self.calc_screen = self.calc_complete_screen
+ return new_screen
+
+ def calc_complete_screen(self) -> list[str]:
"""The purpose of this method is to translate changes in
self.buffer into changes in self.screen. Currently it rips
everything down and starts from scratch, which whilst not
@@ -563,8 +589,8 @@ class Reader:
def refresh(self) -> None:
"""Recalculate and refresh the screen."""
# this call sets up self.cxy, so call it first.
- screen = self.calc_screen()
- self.console.refresh(screen, self.cxy)
+ self.screen = self.calc_screen()
+ self.console.refresh(self.screen, self.cxy)
self.dirty = False
def do_cmd(self, cmd: tuple[str, list[str]]) -> None:
diff --git a/Lib/_pyrepl/unix_console.py b/Lib/_pyrepl/unix_console.py
index 7c59f48..ec7d063 100644
--- a/Lib/_pyrepl/unix_console.py
+++ b/Lib/_pyrepl/unix_console.py
@@ -293,7 +293,7 @@ class UnixConsole(Console):
self.__show_cursor()
- self.screen = screen
+ self.screen = screen.copy()
self.move_cursor(cx, cy)
self.flushoutput()