Python的raw_input()中的Tab完成

我知道我可以做到这一点,以确保在Python中完成标签的效果。

import readline COMMANDS = ['extra', 'extension', 'stuff', 'errors', 'email', 'foobar', 'foo'] def complete(text, state): for cmd in COMMANDS: if cmd.startswith(text): if not state: return cmd else: state -= 1 readline.parse_and_bind("tab: complete") readline.set_completer(complete) raw_input('Enter section name: ') 

我现在有兴趣做目录完成标签。 (/ home / user / doc>标签)

我将如何去做这样一个任务?

以下是如何执行文件系统path的增量完成的一个简单示例。 我修改了你的例子,把它组织成一个名为complete_[name]表示顶级命令的类。

我已经将完成函数切换到使用内部readline缓冲区来确定整个完成状态,这使得状态逻辑更简单一些。 path完成在_complete_path(path)方法中,并且我已经连接了额外的命令来对其参数执行path完成。

我相信代码可以进一步简化,但它应该为您提供一个体面的起点:

 import os import re import readline COMMANDS = ['extra', 'extension', 'stuff', 'errors', 'email', 'foobar', 'foo'] RE_SPACE = re.compile('.*\s+$', re.M) class Completer(object): def _listdir(self, root): "List directory 'root' appending the path separator to subdirs." res = [] for name in os.listdir(root): path = os.path.join(root, name) if os.path.isdir(path): name += os.sep res.append(name) return res def _complete_path(self, path=None): "Perform completion of filesystem path." if not path: return self._listdir('.') dirname, rest = os.path.split(path) tmp = dirname if dirname else '.' res = [os.path.join(dirname, p) for p in self._listdir(tmp) if p.startswith(rest)] # more than one match, or single match which does not exist (typo) if len(res) > 1 or not os.path.exists(path): return res # resolved to a single directory, so return list of files below it if os.path.isdir(path): return [os.path.join(path, p) for p in self._listdir(path)] # exact file match terminates this completion return [path + ' '] def complete_extra(self, args): "Completions for the 'extra' command." if not args: return self._complete_path('.') # treat the last arg as a path and complete it return self._complete_path(args[-1]) def complete(self, text, state): "Generic readline completion entry point." buffer = readline.get_line_buffer() line = readline.get_line_buffer().split() # show all commands if not line: return [c + ' ' for c in COMMANDS][state] # account for last argument ending in a space if RE_SPACE.match(buffer): line.append('') # resolve command to the implementation function cmd = line[0].strip() if cmd in COMMANDS: impl = getattr(self, 'complete_%s' % cmd) args = line[1:] if args: return (impl(args) + [None])[state] return [cmd + ' '][state] results = [c + ' ' for c in COMMANDS if c.startswith(cmd)] + [None] return results[state] comp = Completer() # we want to treat '/' as part of a word, so override the delimiters readline.set_completer_delims(' \t\n;') readline.parse_and_bind("tab: complete") readline.set_completer(comp.complete) raw_input('Enter section name: ') 

用法:

 % python complete.py Enter section name: ext<tab> extension extra Enter section name: extra foo<tab> foo.py foo.txt foo/ Enter section name: extra foo/<tab> foo/bar.txt foo/baz.txt Enter section name: extra foo/bar.txt 

更新如果用户input/ :则它会从根中完成path。

 % python complete.py Enter section name: extra /Use<tab> /Users/.localized /Users/Shared/ /Users/user1 /Users/user2 Enter section name: extra /Users/use<tab> /Users/user1 /Users/user2 

这足以使用raw_input()启用内置的目录选项卡完成:

 import readline readline.parse_and_bind("tab: complete")