星期三, 十一月 29, 2006

python Cmd file name auto completion

在 crablfs 中 cmdline[.py] 通过继承 cmd.Cmd 类来实现交互式命令行,但 cmdline 只能补全命令如 cm(cmd,cmt), li(list) 却不能补全需要操作的文件及其路径名,不如:
crablfs> cmd tar xfz mlter(m-2.9.3.tar.gz)

为解决这个问题,首先查看 cmd.py 的文档(www.python.org/doc)和源代码,可以看到,Cmd.cmdloop() 会通过 readline.set_completer() 设置为 Cmd.complete() 来完成自动补全。分析 Cmd.complete():
253     def complete(self, text, state):
254 """Return the next possible completion for 'text'.
255
256 If a command has not been entered, then complete against command list.
257 Otherwise try to call complete_ to get list of completions.
258 """
259 if state == 0:
260 import readline
261 origline = readline.get_line_buffer()
262 line = origline.lstrip()
263 stripped = len(origline) - len(line)
264 begidx = readline.get_begidx() - stripped
265 endidx = readline.get_endidx() - stripped
266 if begidx>0:
267 cmd, args, foo = self.parseline(line)
268 if cmd == '':
269 compfunc = self.completedefault
270 else:
271 try:
272 compfunc = getattr(self, 'complete_' + cmd)
273 except AttributeError:
274 compfunc = self.completedefault
275 else:
276 compfunc = self.completenames
277 self.completion_matches = compfunc(text, line, begidx, endidx)
278 try:
279 return self.completion_matches[state]
280 except IndexError:
281 return None

这里 text 是命令行上最后的那个参数(这应该是由 readline 自动得到的),例如'cm'就是'cm','cmd tar xfz mlter'则是'mlter'。state == 0 说明这个参数需要补全。

lstrip() 只去处头部的空格而,所以对"cmd tar xfz mlter"来说,stripped=0,
begidx = readline.get_begidx() - stripped
会计算出 mlter 的 m 所在的位置,这里是 12。

所以这时会调用自己设定的 completer:complete_$cmd 或 completedefault(当 complete_$cmd 没有编写时);如果 degidx 为 0,则会将 completenames 作为 completer,这个函数仅仅补全 Cmd 自己的命令。

因此,如果需要在 cmdline[.py] 的'cmd(command)', 'do'这些命令中使用文件名补全功能的话,需要编写一个相应的 completer(complete_$cmd),如下:
 78     def complete_command(self, text, line, begidx, endidx):
79 import readline
80 # import rlcompleter
81 # readline.parse_and_bind("tab: complete")
82 readline.set_completer_delims(' \t\n`~!@#$%^&*()-=+[{]}\\|;:\'",<>;?')
83 import glob
84 return glob.glob('%s*' % text)
85 complete_cmd = complete_command
86 complete_do = complete_cmd
重新设置 completer_delims 是为了把'/'这个符号从中剔除,否则如果运行:
crablfs> cmd tar xfz /sour(ces)
则 text 会变成 'sour' 而不是需要的 '/sour',因此是无法匹配的。

参考:
http://chinaunix.net/jh/55/614952.html'

没有评论: