gh-118878: Pyrepl: show completions menu below the current line (#118939)

Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
This commit is contained in:
Daniel Hollas 2025-01-21 21:06:13 +00:00 committed by GitHub
parent 5a9afe2362
commit 29caec62ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 17 additions and 9 deletions

View file

@ -282,7 +282,7 @@ def do(self) -> None:
x, y = r.pos2xy() x, y = r.pos2xy()
new_y = y + 1 new_y = y + 1
if new_y > r.max_row(): if r.eol() == len(b):
if r.historyi < len(r.history): if r.historyi < len(r.history):
r.select_item(r.historyi + 1) r.select_item(r.historyi + 1)
r.pos = r.eol(0) r.pos = r.eol(0)
@ -309,7 +309,7 @@ def do(self) -> None:
class left(MotionCommand): class left(MotionCommand):
def do(self) -> None: def do(self) -> None:
r = self.reader r = self.reader
for i in range(r.get_arg()): for _ in range(r.get_arg()):
p = r.pos - 1 p = r.pos - 1
if p >= 0: if p >= 0:
r.pos = p r.pos = p
@ -321,7 +321,7 @@ class right(MotionCommand):
def do(self) -> None: def do(self) -> None:
r = self.reader r = self.reader
b = r.buffer b = r.buffer
for i in range(r.get_arg()): for _ in range(r.get_arg()):
p = r.pos + 1 p = r.pos + 1
if p <= len(b): if p <= len(b):
r.pos = p r.pos = p

View file

@ -260,10 +260,15 @@ def after_command(self, cmd: Command) -> None:
def calc_screen(self) -> list[str]: def calc_screen(self) -> list[str]:
screen = super().calc_screen() screen = super().calc_screen()
if self.cmpltn_menu_visible: if self.cmpltn_menu_visible:
ly = self.lxy[1] # We display the completions menu below the current prompt
ly = self.lxy[1] + 1
screen[ly:ly] = self.cmpltn_menu screen[ly:ly] = self.cmpltn_menu
self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu) # If we're not in the middle of multiline edit, don't append to screeninfo
self.cxy = self.cxy[0], self.cxy[1] + len(self.cmpltn_menu) # since that screws up the position calculation in pos2xy function.
# This is a hack to prevent the cursor jumping
# into the completions menu when pressing left or down arrow.
if self.pos != len(self.buffer):
self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu)
return screen return screen
def finish(self) -> None: def finish(self) -> None:

View file

@ -850,7 +850,7 @@ def test_global_namespace_completion(self):
output = multiline_input(reader, namespace) output = multiline_input(reader, namespace)
self.assertEqual(output, "python") self.assertEqual(output, "python")
def test_updown_arrow_with_completion_menu(self): def test_up_down_arrow_with_completion_menu(self):
"""Up arrow in the middle of unfinished tab completion when the menu is displayed """Up arrow in the middle of unfinished tab completion when the menu is displayed
should work and trigger going back in history. Down arrow should subsequently should work and trigger going back in history. Down arrow should subsequently
get us back to the incomplete command.""" get us back to the incomplete command."""
@ -860,6 +860,7 @@ def test_updown_arrow_with_completion_menu(self):
events = itertools.chain( events = itertools.chain(
code_to_events(code), code_to_events(code),
[ [
Event(evt="key", data="down", raw=bytearray(b"\x1bOB")),
Event(evt="key", data="up", raw=bytearray(b"\x1bOA")), Event(evt="key", data="up", raw=bytearray(b"\x1bOA")),
Event(evt="key", data="down", raw=bytearray(b"\x1bOB")), Event(evt="key", data="down", raw=bytearray(b"\x1bOB")),
], ],

View file

@ -295,8 +295,8 @@ def test_completions_updated_on_key_press(self):
actual = reader.screen actual = reader.screen
self.assertEqual(len(actual), 2) self.assertEqual(len(actual), 2)
self.assertEqual(actual[0].rstrip(), "itertools.accumulate(") self.assertEqual(actual[0], f"{code}a")
self.assertEqual(actual[1], f"{code}a") self.assertEqual(actual[1].rstrip(), "itertools.accumulate(")
def test_key_press_on_tab_press_once(self): def test_key_press_on_tab_press_once(self):
namespace = {"itertools": itertools} namespace = {"itertools": itertools}

View file

@ -0,0 +1,2 @@
Show tab completions menu below the current line, which results in less
janky behaviour, and fixes a cursor movement bug. Patch by Daniel Hollas