[3.13] gh-118878: Pyrepl: show completions menu below the current line (GH-118939) (#129161)

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

(cherry picked from commit 29caec62ee)

Co-authored-by: Daniel Hollas <daniel.hollas@bristol.ac.uk>
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
This commit is contained in:
Miss Islington (bot) 2025-01-23 22:15:27 +01:00 committed by GitHub
parent 52ccf264df
commit 5c102a12a1
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 @@ class down(MotionCommand):
x, y = r.pos2xy()
new_y = y + 1
if new_y > r.max_row():
if r.eol() == len(b):
if r.historyi < len(r.history):
r.select_item(r.historyi + 1)
r.pos = r.eol(0)
@ -309,7 +309,7 @@ class down(MotionCommand):
class left(MotionCommand):
def do(self) -> None:
r = self.reader
for i in range(r.get_arg()):
for _ in range(r.get_arg()):
p = r.pos - 1
if p >= 0:
r.pos = p
@ -321,7 +321,7 @@ class right(MotionCommand):
def do(self) -> None:
r = self.reader
b = r.buffer
for i in range(r.get_arg()):
for _ in range(r.get_arg()):
p = r.pos + 1
if p <= len(b):
r.pos = p

View file

@ -260,10 +260,15 @@ class CompletingReader(Reader):
def calc_screen(self) -> list[str]:
screen = super().calc_screen()
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
self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu)
self.cxy = self.cxy[0], self.cxy[1] + len(self.cmpltn_menu)
# If we're not in the middle of multiline edit, don't append to screeninfo
# 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
def finish(self) -> None:

View file

@ -850,7 +850,7 @@ class TestPyReplCompleter(TestCase):
output = multiline_input(reader, namespace)
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
should work and trigger going back in history. Down arrow should subsequently
get us back to the incomplete command."""
@ -860,6 +860,7 @@ class TestPyReplCompleter(TestCase):
events = itertools.chain(
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="down", raw=bytearray(b"\x1bOB")),
],

View file

@ -296,8 +296,8 @@ class TestReader(TestCase):
actual = reader.screen
self.assertEqual(len(actual), 2)
self.assertEqual(actual[0].rstrip(), "itertools.accumulate(")
self.assertEqual(actual[1], f"{code}a")
self.assertEqual(actual[0], f"{code}a")
self.assertEqual(actual[1].rstrip(), "itertools.accumulate(")
def test_key_press_on_tab_press_once(self):
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