2010-10-22 18 views
8

Tengo una consola Cmd configurada para completar automáticamente los nombres de las tarjetas para un sistema de administración de la colección Magic: the Gathering.Cambiar cómo Python Cmd Module maneja la autocompletación

Utiliza el parámetro de texto para consultar la base de datos de tarjetas, y utiliza los resultados para autocompletar/sugerir tarjetas.

Sin embargo, estos nombres de tarjetas tienen varias palabras, y Cmd ejecuta la autocompletacion desde el último espacio hasta el final de la línea.

Por ejemplo:

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) 

Intenté agarrar manualmente lo que quería de parámetro line, que consiga los resultados que quiero de la base de datos, pero esto no puede sobrescribir la primera palabra:

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

al final, necesito el auto más completa para trabajar de esta manera:

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

Además del intento de análisis manual anterior, también traté de reemplazar espacios con signos más y descubrí que Cmd está muy feliz dividiéndolos también. Reemplazar espacios con guiones bajos funciona, pero hay una carta en Unhinged que se llama _____, así que tengo que pasar por acrobacias para demunge las cadenas ya que no puedo simplemente line.replace("_", " ").

Aquí hay un código ejecutable de prueba:

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

Hay alguna buena información aquí: http://stackoverflow.com/questions/187621/how-to-make-a-python-command-line-program-autocomplete-arbitrary-things-not-int –

+0

puede proporcionar código de prueba ejecutable? Eso parece posible reparar – nosklo

+0

Sí, también vi eso, @offsound, de ahí surgió la idea de usar Cmd. Prepararé un código de prueba. –

Respuesta

10

No debería ser demasiado complicado. Algo como lo siguiente:

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

He usado el mismo" truco "para completar la ruta permitida. Cambio la última línea para devolver [fp [offs:] para fp en glob.glob (mline + '*')] –

+0

Si lanza unas pocas llamadas .lower(), también puede hacer que la terminación del comando sea insensible. 'return [s [offs:] para s en terminaciones si s.lower(). Startswith (mline.lower())]' –

0

Usted podría hacer readline.set_completer_delims('').

Sin embargo, sus funciones complete_* ya no serán llamadas; tendrá que anular Cmd.complete o Cmd.completenames. Mire el código fuente del módulo cmd para más detalles.

+0

Explotar las funciones 'complete_ *' no es algo que quiera hacer, pero alterar la forma en que se envían es perfecto. No solo 'Cmd.complete', sino' Cmd.parseline' también. Voy a publicar lo que cambio en la pregunta una vez que lo haya resuelto. ¡Gracias! –

+1

en realidad, esto lo hace: 'readline.set_completer_delims ('\ t \ n ... @ # $%^& *() - = + [{]} \\ |;: \'", <>? ') ' – wesen

0

No reemplacé la función cmdloop, y fue bastante sencillo. No tuve que cambiar nada más. Sólo tienes que copiar la función cmdloop desde el módulo (encontrar el código haciendo import cmd, cmd.__file__), y añadir las dos líneas de cambio de delimitadores:

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 

Eso lo hizo por mí. En su caso, es posible que desee eliminar el delimitador que está causando los problemas.

Cuestiones relacionadas