https://github.com/python/cpython/commit/8fc7653766b106bdbc4ff6154e0020aea4ab15e6
commit: 8fc7653766b106bdbc4ff6154e0020aea4ab15e6
branch: main
author: Lysandros Nikolaou <lisandros...@gmail.com>
committer: ambv <luk...@langa.pl>
date: 2024-06-04T18:09:31+02:00
summary:

gh-120041: Do not use append_to_screen when completions are visible (GH-120042)

files:
M Lib/_pyrepl/commands.py
M Lib/_pyrepl/completing_reader.py
M Lib/test/test_pyrepl/support.py
M Lib/test/test_pyrepl/test_reader.py

diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py
index 2ef5dada9d9e58..b967f5206614f8 100644
--- a/Lib/_pyrepl/commands.py
+++ b/Lib/_pyrepl/commands.py
@@ -365,7 +365,12 @@ def do(self) -> None:
         r = self.reader
         text = self.event * r.get_arg()
         r.insert(text)
-        if len(text) == 1 and r.pos == len(r.buffer):
+        if (
+            len(text) == 1 and
+            r.pos == len(r.buffer) and
+            not r.cmpltn_menu_visible and  # type: ignore[attr-defined]
+            not r.cmpltn_message_visible  # type: ignore[attr-defined]
+        ):
             r.calc_screen = r.append_to_screen
 
 
diff --git a/Lib/_pyrepl/completing_reader.py b/Lib/_pyrepl/completing_reader.py
index c11d2dabdd2792..215ad8753c9f8b 100644
--- a/Lib/_pyrepl/completing_reader.py
+++ b/Lib/_pyrepl/completing_reader.py
@@ -187,18 +187,20 @@ def do(self) -> None:
             if p:
                 r.insert(p)
             if last_is_completer:
-                if not r.cmpltn_menu_visible:
-                    r.cmpltn_menu_visible = True
+                r.cmpltn_menu_visible = True
+                r.cmpltn_message_visible = False
                 r.cmpltn_menu, r.cmpltn_menu_end = build_menu(
                     r.console, completions, r.cmpltn_menu_end,
                     r.use_brackets, r.sort_in_column)
                 r.dirty = True
-            elif stem + p in completions:
-                r.msg = "[ complete but not unique ]"
-                r.dirty = True
-            else:
-                r.msg = "[ not unique ]"
-                r.dirty = True
+            elif not r.cmpltn_menu_visible:
+                r.cmpltn_message_visible = True
+                if stem + p in completions:
+                    r.msg = "[ complete but not unique ]"
+                    r.dirty = True
+                else:
+                    r.msg = "[ not unique ]"
+                    r.dirty = True
 
 
 class self_insert(commands.self_insert):
@@ -236,6 +238,7 @@ class CompletingReader(Reader):
     ### Instance variables
     cmpltn_menu: list[str] = field(init=False)
     cmpltn_menu_visible: bool = field(init=False)
+    cmpltn_message_visible: bool = field(init=False)
     cmpltn_menu_end: int = field(init=False)
     cmpltn_menu_choices: list[str] = field(init=False)
 
@@ -271,6 +274,7 @@ def finish(self) -> None:
     def cmpltn_reset(self) -> None:
         self.cmpltn_menu = []
         self.cmpltn_menu_visible = False
+        self.cmpltn_message_visible = False
         self.cmpltn_menu_end = 0
         self.cmpltn_menu_choices = []
 
diff --git a/Lib/test/test_pyrepl/support.py b/Lib/test/test_pyrepl/support.py
index d2f5429aea7a11..e807b5f3404550 100644
--- a/Lib/test/test_pyrepl/support.py
+++ b/Lib/test/test_pyrepl/support.py
@@ -39,7 +39,7 @@ def code_to_events(code: str):
 
 
 def prepare_reader(console: Console, **kwargs):
-    config = ReadlineConfig(readline_completer=None)
+    config = 
ReadlineConfig(readline_completer=kwargs.pop("readline_completer", None))
     reader = ReadlineAlikeReader(console=console, config=config)
     reader.more_lines = partial(more_lines, namespace=None)
     reader.paste_mode = True  # Avoid extra indents
diff --git a/Lib/test/test_pyrepl/test_reader.py 
b/Lib/test/test_pyrepl/test_reader.py
index 9fb956b655594f..d02815bfa11d74 100644
--- a/Lib/test/test_pyrepl/test_reader.py
+++ b/Lib/test/test_pyrepl/test_reader.py
@@ -1,5 +1,6 @@
 import itertools
 import functools
+import rlcompleter
 from unittest import TestCase
 
 from .support import handle_all_events, handle_events_narrow_console, 
code_to_events, prepare_reader
@@ -9,7 +10,7 @@
 
 class TestReader(TestCase):
     def assert_screen_equals(self, reader, expected):
-        actual = reader.calc_screen()
+        actual = reader.screen
         expected = expected.split("\n")
         self.assertListEqual(actual, expected)
 
@@ -208,3 +209,37 @@ def test_prompt_length(self):
         prompt, l = Reader.process_prompt(ps1)
         self.assertEqual(prompt, "\033[0;32m樂>\033[0m> ")
         self.assertEqual(l, 5)
+
+    def test_completions_updated_on_key_press(self):
+        namespace = {"itertools": itertools}
+        code = "itertools."
+        events = itertools.chain(code_to_events(code), [
+            Event(evt='key', data='\t', raw=bytearray(b'\t')),  # Two tabs for 
completion
+            Event(evt='key', data='\t', raw=bytearray(b'\t')),
+        ], code_to_events("a"))
+
+        completing_reader = functools.partial(
+            prepare_reader,
+            readline_completer=rlcompleter.Completer(namespace).complete
+        )
+        reader, _ = handle_all_events(events, prepare_reader=completing_reader)
+
+        actual = reader.screen
+        self.assertEqual(len(actual), 2)
+        self.assertEqual(actual[0].rstrip(), "itertools.accumulate(")
+        self.assertEqual(actual[1], f"{code}a")
+
+    def test_key_press_on_tab_press_once(self):
+        namespace = {"itertools": itertools}
+        code = "itertools."
+        events = itertools.chain(code_to_events(code), [
+            Event(evt='key', data='\t', raw=bytearray(b'\t')),
+        ], code_to_events("a"))
+
+        completing_reader = functools.partial(
+            prepare_reader,
+            readline_completer=rlcompleter.Completer(namespace).complete
+        )
+        reader, _ = handle_all_events(events, prepare_reader=completing_reader)
+
+        self.assert_screen_equals(reader, f"{code}a")

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to