简体   繁体   English

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

[英]Change how Python Cmd Module handles autocompletion

I have a Cmd console set up to auto-complete card names for a Magic: the Gathering collection management system. 我有一个Cmd控制台,用于自动完成Magic:收集管理系统的卡名称。

It uses the text parameter to query the database for cards, and uses the results to auto-complete/suggest cards. 它使用text参数查询数据库中的卡片,并使用结果自动完成/建议卡片。

However, these cards names have multiple words, and Cmd runs auto-completion from the last space to the end of the line. 但是,这些卡名称有多个单词,Cmd从最后一个空格到行尾自动完成。

For example: 例如:

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)

I tried manually grabbing what I wanted from the line parameter, which gets the results I want from the database, but this fails to overwrite the first word: 我尝试从line参数手动抓取我想要的东西,它从数据库中获取我想要的结果,但是这无法覆盖第一个单词:

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

In the end, I need the auto-completer to work like this: 最后,我需要自动完成器像这样工作:

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

Aside from the manual parsing attempt above, I also tried replacing spaces with plus signs, and discovered that Cmd is perfectly happy splitting on those as well. 除了上面的手动解析尝试之外,我还尝试用加号替换空格,并发现Cmd也非常乐意拆分它们。 Replacing spaces with underscores works, but there is one card in Unhinged which is named _____ , so I have to go through acrobatics to demunge the strings since I can't just line.replace("_", " ") . 用下划线替换空格是有效的,但是Unhinged中有一张名为_____卡片,因此我不得不通过杂技来开始弦乐,因为我不能只使用line.replace("_", " ")

Here's some runnable test code: 这是一些可运行的测试代码:

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()

It shouldn't need to be overly complicated. 它不应该过于复杂。 Something like the following: 类似于以下内容:

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()

I did override of the cmdloop function, and it was pretty straightforward. 我确实覆盖了cmdloop函数,它非常简单。 I didn't have to change anything else. 我没有必要改变其他任何东西。 Just copy the cmdloop function from the module (find code by doing import cmd , cmd.__file__ ), and add the two lines for changing delimiters: 只需从模块中复制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

That did it for me. 这样做对我来说。 In your case you may want to remove whichever delimiter is causing the issues. 在您的情况下,您可能希望删除导致问题的分隔符。

You could do readline.set_completer_delims('') . 你可以做readline.set_completer_delims('')

However, your complete_* functions won't be called anymore; 但是,您的complete_*函数将不再被调用; you will have to override Cmd.complete or Cmd.completenames . 您必须覆盖Cmd.completeCmd.completenames Look at the sourcecode of the cmd module for details. 有关详细信息,请查看cmd模块的源代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM