diff --git a/Lib/pdb.py b/Lib/pdb.py index 343cf4404d7f8c..2aa60c75396085 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -2933,6 +2933,7 @@ def __init__(self, pid, sockfile, interrupt_script): self.completion_matches = [] self.state = "dumb" self.write_failed = False + self.multiline_block = False def _ensure_valid_message(self, msg): # Ensure the message conforms to our protocol. @@ -2979,6 +2980,7 @@ def _send(self, **kwargs): self.write_failed = True def read_command(self, prompt): + self.multiline_block = False reply = input(prompt) if self.state == "dumb": @@ -3003,6 +3005,7 @@ def read_command(self, prompt): return prefix + reply # Otherwise, valid first line of a multi-line statement + self.multiline_block = True continue_prompt = "...".ljust(len(prompt)) while codeop.compile_command(reply, "", "single") is None: reply += "\n" + input(continue_prompt) @@ -3105,9 +3108,13 @@ def complete(self, text, state): origline = readline.get_line_buffer() line = origline.lstrip() - stripped = len(origline) - len(line) - begidx = readline.get_begidx() - stripped - endidx = readline.get_endidx() - stripped + if self.multiline_block: + # We're completing a line contained in a multi-line block. + # Force the remote to treat it as a Python expression. + line = "! " + line + offset = len(origline) - len(line) + begidx = readline.get_begidx() - offset + endidx = readline.get_endidx() - offset msg = { "complete": { diff --git a/Lib/test/test_remote_pdb.py b/Lib/test/test_remote_pdb.py index e4c44c78d4a537..9fbe94fcdd6da7 100644 --- a/Lib/test/test_remote_pdb.py +++ b/Lib/test/test_remote_pdb.py @@ -531,6 +531,44 @@ def test_completion_in_pdb_state(self): expected_state={"state": "pdb"}, ) + def test_multiline_completion_in_pdb_state(self): + """Test requesting tab completions at a (Pdb) continuation prompt.""" + # GIVEN + incoming = [ + ("server", {"prompt": "(Pdb) ", "state": "pdb"}), + ("user", {"prompt": "(Pdb) ", "input": "if True:"}), + ( + "user", + { + "prompt": "... ", + "completion_request": { + "line": " b", + "begidx": 4, + "endidx": 5, + }, + "input": " bool()", + }, + ), + ("server", {"completions": ["bin", "bool", "bytes"]}), + ("user", {"prompt": "... ", "input": ""}), + ] + self.do_test( + incoming=incoming, + expected_outgoing=[ + { + "complete": { + "text": "b", + "line": "! b", + "begidx": 2, + "endidx": 3, + } + }, + {"reply": "if True:\n bool()\n"}, + ], + expected_completions=["bin", "bool", "bytes"], + expected_state={"state": "pdb"}, + ) + def test_completion_in_interact_state(self): """Test requesting tab completions at a >>> prompt.""" incoming = [ diff --git a/Misc/NEWS.d/next/Library/2025-05-04-13-46-20.gh-issue-133351.YsZls1.rst b/Misc/NEWS.d/next/Library/2025-05-04-13-46-20.gh-issue-133351.YsZls1.rst new file mode 100644 index 00000000000000..c843f3e6888e52 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-04-13-46-20.gh-issue-133351.YsZls1.rst @@ -0,0 +1,3 @@ +Fix remote PDB to correctly request tab completions for Python expressions +from the server when completing a continuation line of a multi-line Python +block.