gh-111201: Add append to screen method to avoid recalculation (#119274)

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
Lysandros Nikolaou 2024-05-21 22:35:44 -04:00 committed by GitHub
parent d065edfb66
commit c886bece3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 43 additions and 14 deletions

View file

@ -358,7 +358,10 @@ def do(self) -> None:
class self_insert(EditCommand): class self_insert(EditCommand):
def do(self) -> None: def do(self) -> None:
r = self.reader 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): class insert_nl(EditCommand):

View file

@ -187,8 +187,8 @@ def do(self) -> None:
if p: if p:
r.insert(p) r.insert(p)
if last_is_completer: if last_is_completer:
if not r.cmpltn_menu_vis: if not r.cmpltn_menu_visible:
r.cmpltn_menu_vis = 1 r.cmpltn_menu_visible = True
r.cmpltn_menu, r.cmpltn_menu_end = build_menu( r.cmpltn_menu, r.cmpltn_menu_end = build_menu(
r.console, completions, r.cmpltn_menu_end, r.console, completions, r.cmpltn_menu_end,
r.use_brackets, r.sort_in_column) r.use_brackets, r.sort_in_column)
@ -208,7 +208,7 @@ def do(self) -> None:
commands.self_insert.do(self) commands.self_insert.do(self)
if r.cmpltn_menu_vis: if r.cmpltn_menu_visible:
stem = r.get_stem() stem = r.get_stem()
if len(stem) < 1: if len(stem) < 1:
r.cmpltn_reset() r.cmpltn_reset()
@ -235,7 +235,7 @@ class CompletingReader(Reader):
### Instance variables ### Instance variables
cmpltn_menu: list[str] = field(init=False) 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_end: int = field(init=False)
cmpltn_menu_choices: list[str] = field(init=False) cmpltn_menu_choices: list[str] = field(init=False)
@ -255,9 +255,9 @@ def after_command(self, cmd: Command) -> None:
if not isinstance(cmd, (complete, self_insert)): if not isinstance(cmd, (complete, self_insert)):
self.cmpltn_reset() self.cmpltn_reset()
def calc_screen(self) -> list[str]: def calc_complete_screen(self) -> list[str]:
screen = super().calc_screen() screen = super().calc_complete_screen()
if self.cmpltn_menu_vis: if self.cmpltn_menu_visible:
ly = self.lxy[1] ly = self.lxy[1]
screen[ly:ly] = self.cmpltn_menu screen[ly:ly] = self.cmpltn_menu
self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu) self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu)
@ -270,7 +270,7 @@ def finish(self) -> None:
def cmpltn_reset(self) -> None: def cmpltn_reset(self) -> None:
self.cmpltn_menu = [] self.cmpltn_menu = []
self.cmpltn_menu_vis = 0 self.cmpltn_menu_visible = False
self.cmpltn_menu_end = 0 self.cmpltn_menu_end = 0
self.cmpltn_menu_choices = [] self.cmpltn_menu_choices = []

View file

@ -35,7 +35,9 @@
# types # types
Command = commands.Command Command = commands.Command
if False: if False:
from typing import Callable
from .types import Callback, SimpleContextManager, KeySpec, CommandName from .types import Callback, SimpleContextManager, KeySpec, CommandName
CalcScreen = Callable[[], list[str]]
def disp_str(buffer: str) -> tuple[str, list[int]]: def disp_str(buffer: str) -> tuple[str, list[int]]:
@ -231,9 +233,11 @@ class Reader:
keymap: tuple[tuple[str, str], ...] = () keymap: tuple[tuple[str, str], ...] = ()
input_trans: input.KeymapTranslator = field(init=False) input_trans: input.KeymapTranslator = field(init=False)
input_trans_stack: list[input.KeymapTranslator] = field(default_factory=list) 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) screeninfo: list[tuple[int, list[int]]] = field(init=False)
cxy: tuple[int, int] = field(init=False) cxy: tuple[int, int] = field(init=False)
lxy: tuple[int, int] = field(init=False) lxy: tuple[int, int] = field(init=False)
calc_screen: CalcScreen = field(init=False)
def __post_init__(self) -> None: def __post_init__(self) -> None:
# Enable the use of `insert` without a `prepare` call - necessary to # Enable the use of `insert` without a `prepare` call - necessary to
@ -243,14 +247,36 @@ def __post_init__(self) -> None:
self.input_trans = input.KeymapTranslator( self.input_trans = input.KeymapTranslator(
self.keymap, invalid_cls="invalid-key", character_cls="self-insert" self.keymap, invalid_cls="invalid-key", character_cls="self-insert"
) )
self.screeninfo = [(0, [0])] self.screeninfo = [(0, [])]
self.cxy = self.pos2xy() self.cxy = self.pos2xy()
self.lxy = (self.pos, 0) self.lxy = (self.pos, 0)
self.calc_screen = self.calc_complete_screen
def collect_keymap(self) -> tuple[tuple[KeySpec, CommandName], ...]: def collect_keymap(self) -> tuple[tuple[KeySpec, CommandName], ...]:
return default_keymap 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 """The purpose of this method is to translate changes in
self.buffer into changes in self.screen. Currently it rips self.buffer into changes in self.screen. Currently it rips
everything down and starts from scratch, which whilst not everything down and starts from scratch, which whilst not
@ -563,8 +589,8 @@ def update_screen(self) -> None:
def refresh(self) -> None: def refresh(self) -> None:
"""Recalculate and refresh the screen.""" """Recalculate and refresh the screen."""
# this call sets up self.cxy, so call it first. # this call sets up self.cxy, so call it first.
screen = self.calc_screen() self.screen = self.calc_screen()
self.console.refresh(screen, self.cxy) self.console.refresh(self.screen, self.cxy)
self.dirty = False self.dirty = False
def do_cmd(self, cmd: tuple[str, list[str]]) -> None: def do_cmd(self, cmd: tuple[str, list[str]]) -> None:

View file

@ -293,7 +293,7 @@ def refresh(self, screen, c_xy):
self.__show_cursor() self.__show_cursor()
self.screen = screen self.screen = screen.copy()
self.move_cursor(cx, cy) self.move_cursor(cx, cy)
self.flushoutput() self.flushoutput()