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".

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top