]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-110944: Make pdb completion work for alias and convenience vars (GH-110945)
authorTian Gao <gaogaotiantian@hotmail.com>
Tue, 14 Nov 2023 12:22:25 +0000 (04:22 -0800)
committerGitHub <noreply@github.com>
Tue, 14 Nov 2023 12:22:25 +0000 (13:22 +0100)
Lib/pdb.py
Lib/test/test_pdb.py
Misc/NEWS.d/next/Library/2023-10-16-18-41-51.gh-issue-110944.CmUKXo.rst [new file with mode: 0644]

index a4b02e010a6be6a47ef5575848b9c71f51b08e07..ed78d749a47fa8e4b40bd2a9829348c62b10f456 100755 (executable)
@@ -238,7 +238,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
         try:
             import readline
             # remove some common file name delimiters
-            readline.set_completer_delims(' \t\n`@#$%^&*()=+[{]}\\|;:\'",<>?')
+            readline.set_completer_delims(' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?')
         except ImportError:
             pass
         self.allow_kbdint = False
@@ -686,6 +686,18 @@ class Pdb(bdb.Bdb, cmd.Cmd):
     # Generic completion functions.  Individual complete_foo methods can be
     # assigned below to one of these functions.
 
+    def completenames(self, text, line, begidx, endidx):
+        # Overwrite completenames() of cmd so for the command completion,
+        # if no current command matches, check for expressions as well
+        commands = super().completenames(text, line, begidx, endidx)
+        for alias in self.aliases:
+            if alias.startswith(text):
+                commands.append(alias)
+        if commands:
+            return commands
+        else:
+            return self._complete_expression(text, line, begidx, endidx)
+
     def _complete_location(self, text, line, begidx, endidx):
         # Complete a file/module/function location for break/tbreak/clear.
         if line.strip().endswith((':', ',')):
@@ -720,6 +732,10 @@ class Pdb(bdb.Bdb, cmd.Cmd):
         # complete builtins, and they clutter the namespace quite heavily, so we
         # leave them out.
         ns = {**self.curframe.f_globals, **self.curframe_locals}
+        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:])]
         if '.' in text:
             # Walk an attribute chain up to the last part, similar to what
             # rlcompleter does.  This will bail if any of the parts are not
index 2ec4e2ee0e036016b1e7ac54a0c8c4c3b3fa9d12..67a4053a2ac8bcac3c92083f075fff6e4a28b2d5 100644 (file)
@@ -3289,6 +3289,27 @@ class PdbTestReadline(unittest.TestCase):
         self.assertIn(b'continue', output)
         self.assertIn(b'hello!', output)
 
+    def test_expression_completion(self):
+        script = textwrap.dedent("""
+            value = "speci"
+            import pdb; pdb.Pdb().set_trace()
+        """)
+
+        # Complete: value + 'al'
+        input = b"val\t + 'al'\n"
+        # Complete: p value + 'es'
+        input += b"p val\t + 'es'\n"
+        # Complete: $_frame
+        input += b"$_fra\t\n"
+        # Continue
+        input += b"c\n"
+
+        output = run_pty(script, input)
+
+        self.assertIn(b'special', output)
+        self.assertIn(b'species', output)
+        self.assertIn(b'$_frame', output)
+
 
 def load_tests(loader, tests, pattern):
     from test import test_pdb
diff --git a/Misc/NEWS.d/next/Library/2023-10-16-18-41-51.gh-issue-110944.CmUKXo.rst b/Misc/NEWS.d/next/Library/2023-10-16-18-41-51.gh-issue-110944.CmUKXo.rst
new file mode 100644 (file)
index 0000000..ec9ca5a
--- /dev/null
@@ -0,0 +1 @@
+Support alias and convenience vars for :mod:`pdb` completion