Paul D. Eden
Paul D. Eden

Reputation: 20559

Howto do python command-line autocompletion but NOT only at the beginning of a string

Python, through it's readline bindings allows for great command-line autocompletion (as described in here).

But, the completion only seems to work at the beginning of strings. If you want to match the middle or end of a string readline doesn't work.

I would like to autocomplete strings, in a command-line python program by matching what I type with any of the strings in a list of available strings.

Using terminal emulators like curses would be fine. It only has to run on linux, not Mac or Windows.

Here is an example: Say I have the following three strings in a list

['Paul Eden <[email protected]>', 
'Eden Jones <[email protected]>', 
'Somebody Else <[email protected]>']

I would like some code that will autocomplete the first two items in the list after I type 'Eden' and then allow me to pick one of them (all through the command-line using the keyboard).

Upvotes: 7

Views: 8344

Answers (1)

Kirk Strauser
Kirk Strauser

Reputation: 30933

I'm not sure I understand the problem. You could use readline.clear_history and readline.add_history to set up the completable strings you want, then control-r to search backword in the history (just as if you were at a shell prompt). For example:

#!/usr/bin/env python

import readline

readline.clear_history()
readline.add_history('foo')
readline.add_history('bar')

while 1:
    print raw_input('> ')

Alternatively, you could write your own completer version and bind the appropriate key to it. This version uses caching in case your match list is huge:

#!/usr/bin/env python

import readline

values = ['Paul Eden <[email protected]>', 
          'Eden Jones <[email protected]>', 
          'Somebody Else <[email protected]>']
completions = {}

def completer(text, state):
    try:
        matches = completions[text]
    except KeyError:
        matches = [value for value in values
                   if text.upper() in value.upper()]
        completions[text] = matches
    try:
        return matches[state]
    except IndexError:
        return None

readline.set_completer(completer)
readline.parse_and_bind('tab: menu-complete')

while 1:
    a = raw_input('> ')
    print 'said:', a

Upvotes: 10

Related Questions