Trcx
Trcx

Reputation: 4434

Python: Homemade Tab Completion Help

I need some help. I am completely stumped. I'm trying to write my own tab completion module for a custom shell style program (also completing arguments) I can tab complete the commands, but the arguments are giving me trouble. Can some one write a sample tab completing module for me to look at?
Available Commands: ['show','exit','clear', 'ship'] for command show, first arg: ['ip','mac','options'] and for sub arg IP: ['external,'internal','local']

In the end I want to be able to go:

My Prompt > sh<tab>
show ship
My Prompt > sho<tab>
My Prompt > show <tab>
ip mac options
My Prompt > show ip <tab>
external local internal
My Prompt > show ip e<tab>
My Prompt > show ip external

and so on an so forth. If I just had one good working example I think I could figure this out. I've completely rewritten my tab completion code 5 times, but still I can't get it. Could some one please help?

Upvotes: 1

Views: 910

Answers (3)

Trcx
Trcx

Reputation: 4434

In the end I figured it out after the 7th rewrite. A little messier than I would like, but workable, likely I will clean this up later. Anyways, here's the code:

"""defined earlier in the script:"""
COMMANDS=['show', 'exit', 'ship']
def complete(text, state, list = COMMANDS):
    for option in list:
        if option.startswith(text):
            if not state:
                return option
            else:
                state -= 1
def precomplete(text, state):
    BUFFER=readline.get_line_buffer()
    args=[None,None,None,None,None,None,None,None,None,None]
    argtemp=[]
    if BUFFER != "":
        i=-1
        while i != BUFFER.count(" "):
            if BUFFER.count(" ") >= 0:
                if BUFFER.count(" ") == 0: #1 because len() starts couting at 1
                    return complete(text, state)
                else:
                    print "Else triggered"
                    o=0
                    verb=[]
                    while complete(BUFFER.split()[0],o):
                        verb.append(complete(BUFFER.split()[0],o))
                        o=o+1
                    if len(verb) == 1:
                        verb=verb[0]
                        print verb
            if BUFFER.count(" ") >= 1:
                if  BUFFER.count(" ") == 1:
                    if verb == 'show':
                        return complete(text, state, ['mac', 'ip', 'arp'])
                else:
                    o=0
                    while complete(BUFFER[1],o,['mac', 'ip', 'arp']):
                        argtemp.append(complete(BUFFER[1],o,['mac', 'ip', 'arp']))
                        o=o+1
                    if len(argtemp) == 1:
                       argtemp==argtemp[0]
            i=i+1
    else:
        return complete(text,state)
readline.parse_and_bind("tab: complete")
readline.set_completer(precomplete)

EDIT: Full code:http://codepad.org/W3VHURUx

Upvotes: 1

Keith
Keith

Reputation: 43024

You might be interested in an existing implemention that does that in a general way.

The CLI toolkit does command and some parameter completions. However, doing this well from Python turns out to be not entirely possible. This is mainly due to the readline library (running in compiled code) having control of user input at that time so you have to have all the completions known beforehand before calling into the input method.

Upvotes: 0

nmichaels
nmichaels

Reputation: 50943

Look at readline and rlcompleter.

Upvotes: 0

Related Questions