14.3.2 完成文本
下一个程序有一组内置命令,用户输入指令时将使用tab完成功能。
try:
import gnureadline as readline
except ImportError:
import readline
import logging
LOG_FILENAME = '/tmp/completer.log'
logging.basicConfig(
format='%(message)s',
filename=LOG_FILENAME,
level=logging.DEBUG,
)
class SimpleCompleter:
def __init__(self,options):
self.options = sorted(options)
def complete(self,text,state):
response = None
if state == 0:
# This is the first time for this text,
# so build a match list.
if text:
self.matches = [
s
for s in self.options
if s and s.startswith(text)
]
logging.debug('%s matches:%s',
repr(text),self.matches)
else:
self.matches = self.options[:]
logging.debug('(empty input) matches:%s',
self.matches)
# Return the state'th item from the match list,
# if that many items are present.
try:
response = self.matches[state]
except IndexError:
response = None
logging.debug('complete(%s,%s) => %s',
repr(text),state,repr(response))
return response
def input_loop():
line=''
while line != 'stop':
line = input('Prompt ("stop" to quit): ')
print('Dispatch {}'.format(line))
# Register the completer function.
OPTIONS = ['start','stop','list','print']
readline.set_completer(SimpleCompleter(OPTIONS).complete)
# Use the tab key for completion.
readline.parse_and_bind('tab:complete')
# Prompt the user for text.
input_loop()
这个程序中的input_loop()函数进行逐行读取,直至输入值为"stop"。更复杂的程序还可以具体解析输入行,并运行命令。
SimpleCompleter类维护了一个"选项"列表,作为自动完成的候选项。实例的complete()方法使用readline注册为完成源。参数是一个要完成的文本串(text)和一个状态值(state),状态值指示对这个文本调用函数的次数。这个函数会反复调用,每次调用将使状态值递增。如果对应这个状态值有一个候选动作,则应当返回一个串,如果没有更多的候选项,则返回None。之前代码清单中的complete()实现会在state为0时查找一组匹配,然后在后续调用时返回所有候选匹配,一次返回一个。
运行前一个代码清单中的代码时,会生成以下初始输出:
按两次tab,会显示一个选项列表。
日志文件显示出这里分别利用了两个状态值序列调用complete()。
第一个程序来自第一次按下tab键。完成算法会查询所有候选项,不过并不扩展空的输入行。然后,第二次按下tab键时,重新计算候选项列表,以便显示给用户。
如果下一个输入为l,然后是另一个tab,则会生成以下输出:
日志反映了complete()的不同参数:
现在按下回车(Enter)会导致input()返回这个值,并且while循环继续。
对于以s开头的命令,完成这种命令有两种可能的情况。键入s,然后按下tab,可以发现start和stop是候选项,不过自动完成特性只能部分完成屏幕上的文本,即增加一个t。
日志文件显示了以下信息:
屏幕上也会生成输出:
说明:如果一个完成器函数产生一个异常,那么它会悄无声息地将其忽略,并且readline会认为没有匹配的完成选择。