Skip to content

Commit

Permalink
pdb.py/pythongh-102130: Support a tab completion for Libedit in cmd a…
Browse files Browse the repository at this point in the history
…nd pdb.
  • Loading branch information
Constantin1489 committed Aug 7, 2023
1 parent 16c9415 commit b4f28d4
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 12 deletions.
4 changes: 2 additions & 2 deletions Doc/library/cmd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ command interpreters. These are often useful for test harnesses, administrative
tools, and prototypes that will later be wrapped in a more sophisticated
interface.

.. class:: Cmd(completekey='tab', stdin=None, stdout=None)
.. class:: Cmd(completekey=r'"\t"', stdin=None, stdout=None)

A :class:`Cmd` instance or subclass instance is a line-oriented interpreter
framework. There is no good reason to instantiate :class:`Cmd` itself; rather,
it's useful as a superclass of an interpreter class you define yourself in order
to inherit :class:`Cmd`'s methods and encapsulate action methods.

The optional argument *completekey* is the :mod:`readline` name of a completion
key; it defaults to :kbd:`Tab`. If *completekey* is not :const:`None` and
key; it defaults to "\\t"(:kbd:`tab`). If *completekey* is not :const:`None` and
:mod:`readline` is available, command completion is done automatically.

The optional arguments *stdin* and *stdout* specify the input and output file
Expand Down
2 changes: 1 addition & 1 deletion Doc/library/pdb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ The ``run*`` functions and :func:`set_trace` are aliases for instantiating the
:class:`Pdb` class and calling the method of the same name. If you want to
access further features, you have to do this yourself:

.. class:: Pdb(completekey='tab', stdin=None, stdout=None, skip=None, \
.. class:: Pdb(completekey=r'"\t"', stdin=None, stdout=None, skip=None, \
nosigint=False, readrc=True)

:class:`Pdb` is the debugger class.
Expand Down
36 changes: 33 additions & 3 deletions Doc/library/readline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ made using this module affect the behaviour of both the interpreter's
interactive prompt and the prompts offered by the built-in :func:`input`
function.

Compatible keybindings
----------------------

To support compatible keybindings between GNU readline and Libedit, use the
following backslashed escape sequences or octal escape sequences in quotes. ::

\a bell
\b backspace
\f form feed
\n newline
\r carriage return
\t horizontal tab
\v vertical tab
\nnn octal escape sequences

Readline keybindings may be configured via an initialization file, typically
``.inputrc`` in your home directory. See `Readline Init File
<https://tiswww.cwru.edu/php/chet/readline/rluserman.html#Readline-Init-File>`_
Expand All @@ -39,10 +54,10 @@ Readline library in general.
If you use *editline*/``libedit`` readline emulation on macOS, the
initialization file located in your home directory is named
``.editrc``. For example, the following content in ``~/.editrc`` will
turn ON *vi* keybindings and TAB completion::
turn ON *vi* keybindings and "\\t"(:kbd:`tab`) completion::

python:bind -v
python:bind ^I rl_complete
python:bind "\t" rl_complete


Init file
Expand All @@ -56,6 +71,16 @@ The following functions relate to the init file and user configuration:
Execute the init line provided in the *string* argument. This calls
:c:func:`rl_parse_and_bind` in the underlying library.

.. note::
The syntax and command of *string* argument may be different depends on the readline library.

For GNU readline::

readline.parse_and_bind(r'"\t": complete')

For Libedit::

readline.parse_and_bind(r'bind "\t" rl_complete')

.. function:: read_init_file([filename])

Expand Down Expand Up @@ -348,7 +373,12 @@ support history save/restore. ::
self.init_history(histfile)

def init_history(self, histfile):
readline.parse_and_bind("tab: complete")

readline_doc = getattr(readline, '__doc__', '')
if readline_doc is not None and 'libedit' in readline_doc:
readline.parse_and_bind(r'bind "\t" rl_complete')
else:
readline.parse_and_bind(r'"\t": complete')
if hasattr(readline, "read_history_file"):
try:
readline.read_history_file(histfile)
Expand Down
2 changes: 1 addition & 1 deletion Doc/library/rlcompleter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Example::

>>> import rlcompleter
>>> import readline
>>> readline.parse_and_bind("tab: complete")
>>> readline.parse_and_bind(r'"\t": complete')
>>> readline. <TAB PRESSED>
readline.__doc__ readline.get_line_buffer( readline.read_init_file(
readline.__file__ readline.insert_text( readline.set_completer(
Expand Down
8 changes: 6 additions & 2 deletions Lib/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class Cmd:
nohelp = "*** No help on %s"
use_rawinput = 1

def __init__(self, completekey='tab', stdin=None, stdout=None):
def __init__(self, completekey='"\t"', stdin=None, stdout=None):
"""Instantiate a line-oriented interpreter framework.
The optional argument 'completekey' is the readline name of a
Expand Down Expand Up @@ -108,7 +108,11 @@ def cmdloop(self, intro=None):
import readline
self.old_completer = readline.get_completer()
readline.set_completer(self.complete)
readline.parse_and_bind(self.completekey+": complete")
readline_doc = getattr(readline, '__doc__', '')
if readline_doc is not None and 'libedit' in readline_doc:
readline.parse_and_bind("bind "+self.completekey+" rl_complete")
else:
readline.parse_and_bind(self.completekey+": complete")
except ImportError:
pass
try:
Expand Down
2 changes: 1 addition & 1 deletion Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):

_previous_sigint_handler = None

def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
def __init__(self, completekey=r'"\t"', stdin=None, stdout=None, skip=None,
nosigint=False, readrc=True):
bdb.Bdb.__init__(self, skip=skip)
cmd.Cmd.__init__(self, completekey, stdin, stdout)
Expand Down
4 changes: 2 additions & 2 deletions Lib/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,9 @@ def register_readline():
# completion key, so we set one first and then read the file.
readline_doc = getattr(readline, '__doc__', '')
if readline_doc is not None and 'libedit' in readline_doc:
readline.parse_and_bind('bind ^I rl_complete')
readline.parse_and_bind(r'bind "\t" rl_complete')
else:
readline.parse_and_bind('tab: complete')
readline.parse_and_bind(r'"\t": complete')

try:
readline.read_init_file()
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ Thomas Holmes
Craig Holmquist
Philip Homburg
Naofumi Honda
Constantin Hong
Weipeng Hong
Jeffrey Honig
Rob Hooft
Expand Down

0 comments on commit b4f28d4

Please sign in to comment.