]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-123177: Fix prompt for wrapped lines in pyrepl (#123324)
authorMatt Wozniski <mwozniski@bloomberg.net>
Sun, 25 Aug 2024 22:54:06 +0000 (18:54 -0400)
committerGitHub <noreply@github.com>
Sun, 25 Aug 2024 22:54:06 +0000 (22:54 +0000)
When display lines above the cursor come from the cache, the first line
to not come from the cache may be a wrapped line, starting half way
through a logical line in the buffer. Detect and handle this case to
avoid accidentally drawing a stray prompt in the middle of a logical
line.

Lib/_pyrepl/reader.py
Lib/test/test_pyrepl/test_reader.py
Misc/NEWS.d/next/Core_and_Builtins/2024-08-25-18-27-49.gh-issue-123177.yLuyqE.rst [new file with mode: 0644]

index 13b1f3eb9d118aabbf6296bcb13de0553e4b9abe..aa3f5fd283eb7df2c3bcc8c612195322866e88c1 100644 (file)
@@ -345,7 +345,10 @@ class Reader:
         pos = self.pos
         pos -= offset
 
+        prompt_from_cache = (offset and self.buffer[offset - 1] != "\n")
+
         lines = "".join(self.buffer[offset:]).split("\n")
+
         cursor_found = False
         lines_beyond_cursor = 0
         for ln, line in enumerate(lines, num_common_lines):
@@ -359,7 +362,12 @@ class Reader:
                     # No need to keep formatting lines.
                     # The console can't show them.
                     break
-            prompt = self.get_prompt(ln, ll >= pos >= 0)
+            if prompt_from_cache:
+                # Only the first line's prompt can come from the cache
+                prompt_from_cache = False
+                prompt = ""
+            else:
+                prompt = self.get_prompt(ln, ll >= pos >= 0)
             while "\n" in prompt:
                 pre_prompt, _, prompt = prompt.partition("\n")
                 last_refresh_line_end_offsets.append(offset)
index e82c3ca0bb5cc27ec9432128b8562ac56cc8afeb..6c72a1d39c55df6f5f38803980ed620bf1b991c4 100644 (file)
@@ -30,6 +30,37 @@ class TestReader(TestCase):
         reader, _ = handle_events_narrow_console(events)
         self.assert_screen_equals(reader, f"{9*"a"}\\\n{9*"a"}\\\naa")
 
+    def test_calc_screen_prompt_handling(self):
+        def prepare_reader_keep_prompts(*args, **kwargs):
+            reader = prepare_reader(*args, **kwargs)
+            del reader.get_prompt
+            reader.ps1 = ">>> "
+            reader.ps2 = ">>> "
+            reader.ps3 = "... "
+            reader.ps4 = ""
+            reader.can_colorize = False
+            reader.paste_mode = False
+            return reader
+
+        events = code_to_events("if some_condition:\nsome_function()")
+        reader, _ = handle_events_narrow_console(
+            events,
+            prepare_reader=prepare_reader_keep_prompts,
+        )
+        # fmt: off
+        self.assert_screen_equals(
+            reader,
+            (
+            ">>> if so\\\n"
+            "me_condit\\\n"
+            "ion:\n"
+            "...     s\\\n"
+            "ome_funct\\\n"
+            "ion()"
+            )
+        )
+        # fmt: on
+
     def test_calc_screen_wrap_three_lines_mixed_character(self):
         # fmt: off
         code = (
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-25-18-27-49.gh-issue-123177.yLuyqE.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-25-18-27-49.gh-issue-123177.yLuyqE.rst
new file mode 100644 (file)
index 0000000..1f1791d
--- /dev/null
@@ -0,0 +1,2 @@
+Fix a bug causing stray prompts to appear in the middle of wrapped lines in
+the new REPL.