gh-102130: Support tab completion in cmd for Libedit. (GH-107748)

---

Co-authored-by: Tian Gao <gaogaotiantian@hotmail.com>
This commit is contained in:
Constantin Hong 2023-12-05 16:24:56 +09:00 committed by GitHub
parent dc824c5dc1
commit aa5bee30ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 1 deletions

View file

@ -26,6 +26,13 @@ interface.
key; it defaults to :kbd:`Tab`. If *completekey* is not :const:`None` and key; it defaults to :kbd:`Tab`. If *completekey* is not :const:`None` and
:mod:`readline` is available, command completion is done automatically. :mod:`readline` is available, command completion is done automatically.
The default, ``'tab'``, is treated specially, so that it refers to the
:kbd:`Tab` key on every :data:`readline.backend`.
Specifically, if :data:`readline.backend` is ``editline``,
``Cmd`` will use ``'^I'`` instead of ``'tab'``.
Note that other values are not treated this way, and might only work
with a specific backend.
The optional arguments *stdin* and *stdout* specify the input and output file The optional arguments *stdin* and *stdout* specify the input and output file
objects that the Cmd instance or subclass instance will use for input and objects that the Cmd instance or subclass instance will use for input and
output. If not specified, they will default to :data:`sys.stdin` and output. If not specified, they will default to :data:`sys.stdin` and
@ -35,6 +42,9 @@ interface.
:attr:`use_rawinput` attribute to ``False``, otherwise *stdin* will be :attr:`use_rawinput` attribute to ``False``, otherwise *stdin* will be
ignored. ignored.
.. versionchanged:: 3.13
``completekey='tab'`` is replaced by ``'^I'`` for ``editline``.
.. _cmd-objects: .. _cmd-objects:

View file

@ -108,7 +108,15 @@ class Cmd:
import readline import readline
self.old_completer = readline.get_completer() self.old_completer = readline.get_completer()
readline.set_completer(self.complete) readline.set_completer(self.complete)
readline.parse_and_bind(self.completekey+": complete") if readline.backend == "editline":
if self.completekey == 'tab':
# libedit uses "^I" instead of "tab"
command_string = "bind ^I rl_complete"
else:
command_string = f"bind {self.completekey} rl_complete"
else:
command_string = f"{self.completekey}: complete"
readline.parse_and_bind(command_string)
except ImportError: except ImportError:
pass pass
try: try:

View file

@ -9,7 +9,10 @@ import sys
import doctest import doctest
import unittest import unittest
import io import io
import textwrap
from test import support from test import support
from test.support.import_helper import import_module
from test.support.pty_helper import run_pty
class samplecmdclass(cmd.Cmd): class samplecmdclass(cmd.Cmd):
""" """
@ -259,6 +262,33 @@ class CmdPrintExceptionClass(cmd.Cmd):
def default(self, line): def default(self, line):
print(sys.exc_info()[:2]) print(sys.exc_info()[:2])
@support.requires_subprocess()
class CmdTestReadline(unittest.TestCase):
def setUpClass():
# Ensure that the readline module is loaded
# If this fails, the test is skipped because SkipTest will be raised
readline = import_module('readline')
def test_basic_completion(self):
script = textwrap.dedent("""
import cmd
class simplecmd(cmd.Cmd):
def do_tab_completion_test(self, args):
print('tab completion success')
return True
simplecmd().cmdloop()
""")
# 't' and complete 'ab_completion_test' to 'tab_completion_test'
input = b"t\t\n"
output = run_pty(script, input)
self.assertIn(b'ab_completion_test', output)
self.assertIn(b'tab completion success', output)
def load_tests(loader, tests, pattern): def load_tests(loader, tests, pattern):
tests.addTest(doctest.DocTestSuite()) tests.addTest(doctest.DocTestSuite())
return tests return tests

View file

@ -788,6 +788,7 @@ Thomas Holmes
Craig Holmquist Craig Holmquist
Philip Homburg Philip Homburg
Naofumi Honda Naofumi Honda
Constantin Hong
Weipeng Hong Weipeng Hong
Jeffrey Honig Jeffrey Honig
Rob Hooft Rob Hooft

View file

@ -0,0 +1 @@
Support tab completion in :mod:`cmd` for ``editline``.