14.3.3 访问完成缓冲区
SimpleCompleter中的完成算法只查看传入函数的文本参数,而没有使用readline内部状态的任何其他信息。还可以使用readline函数来管理输入缓冲区的文本。
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 BufferAwareCompleter:
def __init__(self,options):
self.options = options
self.current_candidates = []
def complete(self,text,state):
response = None
if state == 0:
# This is the first time for this text,
# so build a match list.
origline = readline.get_line_buffer()
begin = readline.get_begidx()
end = readline.get_endidx()
being_completed = origline[begin:end]
words = origline.split()
logging.debug('origline=%s',repr(origline))
logging.debug('begin=%s',begin)
logging.debug('end=%s',end)
logging.debug('being_completed=%s',being_completed)
logging.debug('words=%s',words)
if not words:
self.current_candidates = sorted(
self.options.keys()
)
else:
try:
if begin == 0:
# First word
candidates = self.options.keys()
else:
# Later word
first = words[0]
candidates = self.options[first]
if being_completed:
# Match options with portion of input
# being completed
self.current_candidates = [
w for w in candidates
if w.startswith(being_completed)
]
else:
# Matching empty string,
# use all candidates
self.current_candidates = candidates
logging.debug('candidates=%s',
self.current_candidates)
except (KeyError,IndexError) as err:
logging.error('completion error: %s',err)
self.current_candidates = []
try:
response = self.current_candidates[state]
except IndexError:
response = None
logging.debug('complete(%s,%s) => %s',
repr(text),state,response)
return response
def input_loop():
line = ''
while line != 'stop':
line = input('Prompt ("stop" to quit): ')
print('Dispatch {}'.format(line))
# Register our completer function.
completer = BufferAwareCompleter({
'list':['files','directories'],
'print':['byname','bysize'],
'stop':[],
})
readline.set_completer(completer.complete)
# Use the tab key for completion.
readline.parse_and_bind('tab: complete')
# Prompt the user for text.
input_loop()
这个例子要完成有子选项的命令。complete()方法需要在输入缓冲区中查看完成的位置,来确定它是第一个词的一部分还是后一个词的一部分。如果目标是第一个词,则将使用选项字典的键作为候选项。如果不是第一个词,则使用第一个词在选项字典中查找候选项。
这里有3个顶层命令,其中两个有子命令。
list
files
directories
byname
bysize
stop
按照前面的同样的动作序列,两次按下tab会给出3个顶层命令。
日志包括以下信息:
如果第一个词是’list’(单词后面有一个空格),则完成候选项是不同的。
从日志可以看到,所完成的文本不是一整行,则只是list后的部分。