mirror of
https://github.com/python/cpython.git
synced 2025-08-02 08:02:56 +00:00
[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:
parent
52ccf264df
commit
5c102a12a1
5 changed files with 17 additions and 9 deletions
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")),
|
||||
],
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue