Tab Completion in Python Command Line Interface - how to catch Tab events
-
20-09-2019 - |
Question
I'm writing a little CLI in Python (as an extension to Mercurial) and would like to support tab-completion. Specifically, I would like catch tabs in the prompt and show a list of matching options (just like bash).
Example: Enter section name:
ext*TAB*
extensions
extras
The problem is I'm not sure how to catch the Tab events. I'm using the ui.prompt()
API of Mercurial, which is just calling raw_input()
under the hood.
As far as I know, raw_input()
only returns on 'enter' and if a user enters a tab, the string returned simply includes a "\t"
.
Solution
For that you use the readline
module.
Simplest code I can think:
import readline
COMMANDS = ['extra', 'extension', 'stuff', 'errors',
'email', 'foobar', 'foo']
def complete(text, state):
for cmd in COMMANDS:
if cmd.startswith(text):
if not state:
return cmd
else:
state -= 1
readline.parse_and_bind("tab: complete")
readline.set_completer(complete)
raw_input('Enter section name: ')
Example usage:
Enter section name: <tab>
email errors extension extra foo foobar stuff
Enter section name: e<tab>
email errors extension extra
Enter section name: ext<tab>
extension extra
Besides completion, readline
provides you with:
- Line editing
- Keybinding configuration (emacs and vi modes included)
- History (up arrow to recall previous values)
- History searching, saving and loading
OTHER TIPS
An excellent example of how to do tab-completion in cooperation with readline is supplied in the standard library as the rlcompleter module — you can't use it as-is (it completes based on names currently defined in the Python's main and builtin), but it shows how to do the general task and how to hook it up to readline
.
You should almost certainly be using the cmd module, which already implements tab completion and so on, and probably other parts of what you're trying to do, using the readline module and so on. There's no point reinventing the wheel.