Skip to content

Commit 27c6780

Browse files
committed
Handle the confirmation prompt issued by 'clear'
1 parent 72830e2 commit 27c6780

File tree

1 file changed

+67
-8
lines changed

1 file changed

+67
-8
lines changed

Lib/pdb.py

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
import tempfile
9090
import textwrap
9191
import tokenize
92+
import functools
9293
import itertools
9394
import traceback
9495
import linecache
@@ -1466,6 +1467,13 @@ def do_ignore(self, arg):
14661467

14671468
complete_ignore = _complete_bpnumber
14681469

1470+
def _prompt_for_confirmation(self, prompt, choices, default):
1471+
try:
1472+
reply = input(prompt)
1473+
except EOFError:
1474+
reply = default
1475+
return reply.strip().lower()
1476+
14691477
def do_clear(self, arg):
14701478
"""cl(ear) [filename:lineno | bpnumber ...]
14711479
@@ -1475,11 +1483,11 @@ def do_clear(self, arg):
14751483
clear all breaks at that line in that file.
14761484
"""
14771485
if not arg:
1478-
try:
1479-
reply = input('Clear all breaks? ')
1480-
except EOFError:
1481-
reply = 'no'
1482-
reply = reply.strip().lower()
1486+
reply = self._prompt_for_confirmation(
1487+
'Clear all breaks? ',
1488+
choices=('y', 'yes', 'n', 'no'),
1489+
default='no',
1490+
)
14831491
if reply in ('y', 'yes'):
14841492
bplist = [bp for bp in bdb.Breakpoint.bpbynumber if bp]
14851493
self.clear_all_breaks()
@@ -2725,6 +2733,26 @@ def do_commands(self, arg):
27252733
def _create_recursive_debugger(self):
27262734
return _RemotePdb(self._sockfile, owns_sockfile=False)
27272735

2736+
@typing.override
2737+
def _prompt_for_confirmation(self, prompt, choices, default):
2738+
self._send(
2739+
confirm={"prompt": prompt, "choices": choices, "default": default}
2740+
)
2741+
payload = self._sockfile.readline()
2742+
2743+
if not payload:
2744+
return default
2745+
2746+
try:
2747+
match json.loads(payload):
2748+
case {"confirmation_reply": str(reply)}:
2749+
return reply
2750+
except json.JSONDecodeError:
2751+
pass
2752+
2753+
self.error(f"Ignoring unexpected remote message: {payload}")
2754+
return default
2755+
27282756
def do_run(self, arg):
27292757
self.error("remote PDB cannot restart the program")
27302758

@@ -2807,7 +2835,7 @@ def read_command(self, prompt):
28072835
return prefix + buffer
28082836

28092837
@contextmanager
2810-
def readline_completion(self):
2838+
def readline_completion(self, completer):
28112839
try:
28122840
import readline
28132841
except ImportError:
@@ -2816,7 +2844,7 @@ def readline_completion(self):
28162844

28172845
old_completer = readline.get_completer()
28182846
try:
2819-
readline.set_completer(self.complete)
2847+
readline.set_completer(completer)
28202848
if readline.backend == "editline":
28212849
# libedit uses "^I" instead of "tab"
28222850
command_string = "bind ^I rl_complete"
@@ -2828,7 +2856,7 @@ def readline_completion(self):
28282856
readline.set_completer(old_completer)
28292857

28302858
def cmdloop(self):
2831-
with self.readline_completion():
2859+
with self.readline_completion(self.complete):
28322860
while True:
28332861
try:
28342862
if not (payload_bytes := self.sockfile.readline()):
@@ -2876,6 +2904,14 @@ def process_payload(self, payload):
28762904
self.prompt_for_breakpoint_command_list("(com) ")
28772905
else:
28782906
self.prompt_for_repl_command(prompt)
2907+
case {
2908+
"confirm": {
2909+
"prompt": str(prompt),
2910+
"choices": list(choices),
2911+
"default": str(default),
2912+
}
2913+
} if all(isinstance(c, str) for c in choices):
2914+
self.prompt_for_confirmation(prompt, choices, default)
28792915
case {
28802916
"commands_entry": {
28812917
"bpnum": int(bpnum),
@@ -2930,6 +2966,20 @@ def prompt_for_repl_command(self, prompt):
29302966
self.sockfile.flush()
29312967
return
29322968

2969+
def prompt_for_confirmation(self, prompt, choices, default):
2970+
try:
2971+
with self.readline_completion(
2972+
functools.partial(self.complete_choices, choices=choices)
2973+
):
2974+
reply = input(prompt).strip()
2975+
except (KeyboardInterrupt, EOFError):
2976+
print(flush=True)
2977+
reply = default
2978+
2979+
payload = {"confirmation_reply": reply}
2980+
self.sockfile.write((json.dumps(payload) + "\n").encode())
2981+
self.sockfile.flush()
2982+
29332983
def complete(self, text, state):
29342984
import readline
29352985

@@ -2964,6 +3014,15 @@ def complete(self, text, state):
29643014
except IndexError:
29653015
return None
29663016

3017+
def complete_choices(self, text, state, choices):
3018+
if state == 0:
3019+
self.completion_matches = [c for c in choices if c.startswith(text)]
3020+
3021+
try:
3022+
return choices[state]
3023+
except IndexError:
3024+
return None
3025+
29673026

29683027
def _connect(host, port, frame):
29693028
with closing(socket.create_connection((host, port))) as conn:

0 commit comments

Comments
 (0)