GH-130328: Speedup pasting in legacy console on Windows (gh-133728)

This commit is contained in:
Chris Eibl 2025-05-25 15:17:43 +02:00 committed by GitHub
parent 2fd09b0110
commit 91b48868a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 26 additions and 12 deletions

View file

@ -370,6 +370,13 @@ class self_insert(EditCommand):
r = self.reader
text = self.event * r.get_arg()
r.insert(text)
if r.paste_mode:
data = ""
ev = r.console.getpending()
data += ev.data
if data:
r.insert(data)
r.last_refresh_cache.invalidated = True
class insert_nl(EditCommand):
@ -484,7 +491,6 @@ class perform_bracketed_paste(Command):
data = ""
start = time.time()
while done not in data:
self.reader.console.wait(100)
ev = self.reader.console.getpending()
data += ev.data
trace(

View file

@ -419,10 +419,7 @@ class WindowsConsole(Console):
return info.srWindow.Bottom # type: ignore[no-any-return]
def _read_input(self, block: bool = True) -> INPUT_RECORD | None:
if not block and not self.wait(timeout=0):
return None
def _read_input(self) -> INPUT_RECORD | None:
rec = INPUT_RECORD()
read = DWORD()
if not ReadConsoleInput(InHandle, rec, 1, read):
@ -431,14 +428,10 @@ class WindowsConsole(Console):
return rec
def _read_input_bulk(
self, block: bool, n: int
self, n: int
) -> tuple[ctypes.Array[INPUT_RECORD], int]:
rec = (n * INPUT_RECORD)()
read = DWORD()
if not block and not self.wait(timeout=0):
return rec, 0
if not ReadConsoleInput(InHandle, rec, n, read):
raise WinError(GetLastError())
@ -449,8 +442,11 @@ class WindowsConsole(Console):
and there is no event pending, otherwise waits for the
completion of an event."""
if not block and not self.wait(timeout=0):
return None
while self.event_queue.empty():
rec = self._read_input(block)
rec = self._read_input()
if rec is None:
return None
@ -551,12 +547,20 @@ class WindowsConsole(Console):
if e2:
e.data += e2.data
recs, rec_count = self._read_input_bulk(False, 1024)
recs, rec_count = self._read_input_bulk(1024)
for i in range(rec_count):
rec = recs[i]
# In case of a legacy console, we do not only receive a keydown
# event, but also a keyup event - and for uppercase letters
# an additional SHIFT_PRESSED event.
if rec and rec.EventType == KEY_EVENT:
key_event = rec.Event.KeyEvent
if not key_event.bKeyDown:
continue
ch = key_event.uChar.UnicodeChar
if ch == "\x00":
# ignore SHIFT_PRESSED and special keys
continue
if ch == "\r":
ch += "\n"
e.data += ch

View file

@ -20,6 +20,7 @@ except ImportError:
def unix_console(events, **kwargs):
console = UnixConsole()
console.get_event = MagicMock(side_effect=events)
console.getpending = MagicMock(return_value=Event("key", ""))
height = kwargs.get("height", 25)
width = kwargs.get("width", 80)

View file

@ -35,6 +35,7 @@ class WindowsConsoleTests(TestCase):
def console(self, events, **kwargs) -> Console:
console = WindowsConsole()
console.get_event = MagicMock(side_effect=events)
console.getpending = MagicMock(return_value=Event("key", ""))
console.wait = MagicMock()
console._scroll = MagicMock()
console._hide_cursor = MagicMock()

View file

@ -0,0 +1,2 @@
Speedup pasting in ``PyREPL`` on Windows in a legacy console. Patch by Chris
Eibl.