Reputation: 4434
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
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
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