views:

504

answers:

3

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

Could anyone help me with a solution to this?

Thank you.

+8  A: 

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
nosklo
Thank you, this is exactly what I was hoping for! There's only one issue - I can't get it to work on my main system. I'm on OSX 10.6 with Python 2.6 and it just inserts a '\t' as normal. So I booted up Ubuntu and it works perfectly there - do you know if there's a library to this is a more platform-independent way?
Paulitex
The Apple-supplied Pythons don't use the GNU readline library; they use the BSD-derived editline library instead. The Python installers for OS X from python.org do use GNU readline, as do recent Pythons installed with MacPorts.
Ned Deily
+1  A: 

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.

Alex Martelli
+1  A: 

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.

Devin Jeanpierre