gh-112948: Make pdb completion similar to repl completion (#112950)

This commit is contained in:
Tian Gao 2024-03-25 08:18:09 -07:00 committed by GitHub
parent 9db2a8f914
commit 01e7405da4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 15 deletions

View file

@ -87,6 +87,7 @@ import traceback
import linecache
from contextlib import contextmanager
from rlcompleter import Completer
from typing import Union
@ -573,20 +574,14 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self.message(repr(obj))
@contextmanager
def _disable_tab_completion(self):
if self.use_rawinput and self.completekey == 'tab':
try:
import readline
except ImportError:
yield
return
try:
readline.parse_and_bind('tab: self-insert')
yield
finally:
readline.parse_and_bind('tab: complete')
else:
def _disable_command_completion(self):
completenames = self.completenames
try:
self.completenames = self.completedefault
yield
finally:
self.completenames = completenames
return
def default(self, line):
if line[:1] == '!': line = line[1:].strip()
@ -595,7 +590,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
try:
if (code := codeop.compile_command(line + '\n', '<stdin>', 'single')) is None:
# Multi-line mode
with self._disable_tab_completion():
with self._disable_command_completion():
buffer = line
continue_prompt = "... "
while (code := codeop.compile_command(buffer, '<stdin>', 'single')) is None:
@ -771,7 +766,10 @@ class Pdb(bdb.Bdb, cmd.Cmd):
if commands:
return commands
else:
return self._complete_expression(text, line, begidx, endidx)
expressions = self._complete_expression(text, line, begidx, endidx)
if expressions:
return expressions
return self.completedefault(text, line, begidx, endidx)
def _complete_location(self, text, line, begidx, endidx):
# Complete a file/module/function location for break/tbreak/clear.
@ -828,6 +826,21 @@ class Pdb(bdb.Bdb, cmd.Cmd):
# Complete a simple name.
return [n for n in ns.keys() if n.startswith(text)]
def completedefault(self, text, line, begidx, endidx):
if text.startswith("$"):
# Complete convenience variables
conv_vars = self.curframe.f_globals.get('__pdb_convenience_variables', {})
return [f"${name}" for name in conv_vars if name.startswith(text[1:])]
# Use rlcompleter to do the completion
state = 0
matches = []
completer = Completer(self.curframe.f_globals | self.curframe_locals)
while (match := completer.complete(text, state)) is not None:
matches.append(match)
state += 1
return matches
# Command definitions, called by cmdloop()
# The argument is the remaining string on the command line
# Return true to exit from the command loop