mirror of
https://github.com/python/cpython.git
synced 2025-11-03 11:23:31 +00:00
gh-112948: Make pdb completion similar to repl completion (#112950)
This commit is contained in:
parent
9db2a8f914
commit
01e7405da4
3 changed files with 80 additions and 15 deletions
43
Lib/pdb.py
43
Lib/pdb.py
|
|
@ -87,6 +87,7 @@ import traceback
|
||||||
import linecache
|
import linecache
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from rlcompleter import Completer
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -573,20 +574,14 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
self.message(repr(obj))
|
self.message(repr(obj))
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def _disable_tab_completion(self):
|
def _disable_command_completion(self):
|
||||||
if self.use_rawinput and self.completekey == 'tab':
|
completenames = self.completenames
|
||||||
try:
|
try:
|
||||||
import readline
|
self.completenames = self.completedefault
|
||||||
except ImportError:
|
|
||||||
yield
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
readline.parse_and_bind('tab: self-insert')
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
readline.parse_and_bind('tab: complete')
|
|
||||||
else:
|
|
||||||
yield
|
yield
|
||||||
|
finally:
|
||||||
|
self.completenames = completenames
|
||||||
|
return
|
||||||
|
|
||||||
def default(self, line):
|
def default(self, line):
|
||||||
if line[:1] == '!': line = line[1:].strip()
|
if line[:1] == '!': line = line[1:].strip()
|
||||||
|
|
@ -595,7 +590,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
try:
|
try:
|
||||||
if (code := codeop.compile_command(line + '\n', '<stdin>', 'single')) is None:
|
if (code := codeop.compile_command(line + '\n', '<stdin>', 'single')) is None:
|
||||||
# Multi-line mode
|
# Multi-line mode
|
||||||
with self._disable_tab_completion():
|
with self._disable_command_completion():
|
||||||
buffer = line
|
buffer = line
|
||||||
continue_prompt = "... "
|
continue_prompt = "... "
|
||||||
while (code := codeop.compile_command(buffer, '<stdin>', 'single')) is None:
|
while (code := codeop.compile_command(buffer, '<stdin>', 'single')) is None:
|
||||||
|
|
@ -771,7 +766,10 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
if commands:
|
if commands:
|
||||||
return commands
|
return commands
|
||||||
else:
|
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):
|
def _complete_location(self, text, line, begidx, endidx):
|
||||||
# Complete a file/module/function location for break/tbreak/clear.
|
# Complete a file/module/function location for break/tbreak/clear.
|
||||||
|
|
@ -828,6 +826,21 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
# Complete a simple name.
|
# Complete a simple name.
|
||||||
return [n for n in ns.keys() if n.startswith(text)]
|
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()
|
# Command definitions, called by cmdloop()
|
||||||
# The argument is the remaining string on the command line
|
# The argument is the remaining string on the command line
|
||||||
# Return true to exit from the command loop
|
# Return true to exit from the command loop
|
||||||
|
|
|
||||||
|
|
@ -3567,6 +3567,57 @@ class PdbTestReadline(unittest.TestCase):
|
||||||
self.assertIn(b'species', output)
|
self.assertIn(b'species', output)
|
||||||
self.assertIn(b'$_frame', output)
|
self.assertIn(b'$_frame', output)
|
||||||
|
|
||||||
|
def test_builtin_completion(self):
|
||||||
|
script = textwrap.dedent("""
|
||||||
|
value = "speci"
|
||||||
|
import pdb; pdb.Pdb().set_trace()
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Complete: print(value + 'al')
|
||||||
|
input = b"pri\tval\t + 'al')\n"
|
||||||
|
|
||||||
|
# Continue
|
||||||
|
input += b"c\n"
|
||||||
|
|
||||||
|
output = run_pty(script, input)
|
||||||
|
|
||||||
|
self.assertIn(b'special', output)
|
||||||
|
|
||||||
|
def test_local_namespace(self):
|
||||||
|
script = textwrap.dedent("""
|
||||||
|
def f():
|
||||||
|
original = "I live Pythin"
|
||||||
|
import pdb; pdb.Pdb().set_trace()
|
||||||
|
f()
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Complete: original.replace('i', 'o')
|
||||||
|
input = b"orig\t.repl\t('i', 'o')\n"
|
||||||
|
|
||||||
|
# Continue
|
||||||
|
input += b"c\n"
|
||||||
|
|
||||||
|
output = run_pty(script, input)
|
||||||
|
|
||||||
|
self.assertIn(b'I love Python', output)
|
||||||
|
|
||||||
|
def test_multiline_completion(self):
|
||||||
|
script = textwrap.dedent("""
|
||||||
|
import pdb; pdb.Pdb().set_trace()
|
||||||
|
""")
|
||||||
|
|
||||||
|
input = b"def func():\n"
|
||||||
|
# Complete: \treturn 40 + 2
|
||||||
|
input += b"\tret\t 40 + 2\n"
|
||||||
|
input += b"\n"
|
||||||
|
# Complete: func()
|
||||||
|
input += b"fun\t()\n"
|
||||||
|
input += b"c\n"
|
||||||
|
|
||||||
|
output = run_pty(script, input)
|
||||||
|
|
||||||
|
self.assertIn(b'42', output)
|
||||||
|
|
||||||
|
|
||||||
def load_tests(loader, tests, pattern):
|
def load_tests(loader, tests, pattern):
|
||||||
from test import test_pdb
|
from test import test_pdb
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Make completion of :mod:`pdb` similar to Python REPL
|
||||||
Loading…
Add table
Add a link
Reference in a new issue