更改Python Cmd模块处理自动完成的方式

2024-06-16 15:08:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个Cmd控制台设置为自动完成一个魔术卡名称:收集收集管理系统。

它使用文本参数查询数据库中的卡片,并使用结果自动完成/建议卡片。

但是,这些卡的名称有多个单词,并且Cmd从最后一个空格运行到行尾的自动完成。

例如:

mtgdb> add Mage<tab><tab>
Mage Slayer (Alara Reborn)     Magefire Wings (Alara Reborn)
mtgdb> add Mage S<tab><tab>
Sages of the Anima (Alara Reborn)
Sanctum Plowbeast (Alara Reborn)
Sangrite Backlash (Alara Reborn)
Sanity Gnawers (Alara Reborn)
Sen Triplets (Alara Reborn)
[...]
mtgdb> add Mage Sl<tab>
mtgdb> add Mage Slave of Bolas (Alara Reborn)

我尝试从line参数中手动获取所需内容,该参数从数据库中获取所需的结果,但这无法覆盖第一个单词:

mtgdb> add Mage Sl<tab>
mtgdb> add Mage Mage Slayer (Alara Reborn)

最后,我需要自动完成器像这样工作:

mtgdb> add Mage Sl<tab>
mtgdb> add Mage Slayer (Alara Reborn)

除了上面的手动解析尝试之外,我还尝试用加号替换空格,发现Cmd也非常乐意拆分这些字符。用下划线替换空格是可行的,但是Unhinged中有一张名为_____的卡,因此我必须通过杂技来解除字符串的绑定,因为我不能只是line.replace("_", " ")

下面是一些可运行的测试代码:

import cmd

commands = [
    "foo",
    "foo bar blah",
    "bar",
    "bar baz blah",
    "baz",
    "baz foo blah"]

class Console(cmd.Cmd):
    intro = "Test console for" + \
            "http://stackoverflow.com/questions/4001708/\n" + \
            "Type \"cmd<space><tab><tab>\" to test " + \
            "auto-completion with spaces in commands\nwith " + \
            "similar beginings."

    def do_cmd(self, line):
        print(line)

    def complete_cmd(self, text, line, start_index, end_index):
        if text:
            return [command for command in commands
                    if command.startswith(text)]
        else:
            return commands

if __name__ == "__main__":
    command = Console()
    command.cmdloop()

Tags: cmdadd参数linetabcommandcommands空格
3条回答

你可以做readline.set_completer_delims('')

但是,您的complete_*函数将不再被调用;您必须重写Cmd.completeCmd.completenames。有关详细信息,请查看cmd模块的源代码。

我确实重写了cmdloop函数,而且非常简单。我不需要改变任何事情。只需从模块中复制cmdloop函数(通过执行import cmdcmd.__file__查找代码),然后添加两行用于更改分隔符:

    try:
       import readline
       self.old_completer = readline.get_completer()
       readline.set_completer(self.complete)
       readline.parse_and_bind(self.completekey+": complete")
       # do not use - as delimiter
       old_delims = readline.get_completer_delims() # <-
       readline.set_completer_delims(old_delims.replace('-', '')) # <-
    except ImportError:
        pass

那是为了我。在您的情况下,您可能希望删除导致问题的分隔符。

不需要太复杂。大致如下:

import cmd

completions = [
    'Mage Slayer (Alara Reborn)',
    'Magefire Wings (Alara Reborn)',
    'Sages of the Anima (Alara Reborn)',
    'Sanctum Plowbeast (Alara Reborn)',
    'Sangrite Backlash (Alara Reborn)',
    'Sanity Gnawers (Alara Reborn)',
    'Sen Triplets (Alara Reborn)'
]

class mycmd(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)

    def do_quit(self, s):
        return True

    def do_add(self, s):
        pass

    def complete_add(self, text, line, begidx, endidx):
        mline = line.partition(' ')[2]
        offs = len(mline) - len(text)
        return [s[offs:] for s in completions if s.startswith(mline)]

if __name__ == '__main__':
    mycmd().cmdloop()

相关问题 更多 >