Cambiar cómo Python Cmd Module maneja la autocompletación

Tengo una consola Cmd configurada para completar automáticamente los nombres de las tarjetas para un sistema de gestión de colecciones Magic: the Gathering.

Utiliza el parámetro de texto para consultar las tarjetas en la base de datos y usa los resultados para completar / sugerir tarjetas automáticamente.

Sin embargo, los nombres de estas tarjetas tienen varias palabras y Cmd se ejecuta automáticamente desde el último espacio hasta el final de la línea.

Por ejemplo:

mtgdb> add Mage Mage Slayer (Alara Reborn) Magefire Wings (Alara Reborn) mtgdb> add Mage S 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 mtgdb> add Mage Slave of Bolas (Alara Reborn) 

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

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

Al final, necesito el auto-completador para trabajar así:

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

Aparte del bash de análisis manual anterior, también intenté reemplazar espacios con signos más, y descubrí que Cmd también está perfectamente feliz al dividirlos. Reemplazar espacios con guiones bajos funciona, pero hay una tarjeta en Unhinged que se llama _____ , por lo que tengo que pasar por acrobacias para separar las cadenas, ya que no puedo simplemente line.replace("_", " ") .

Aquí hay un código de prueba ejecutable:

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

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

Podría hacer readline.set_completer_delims('') .

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

Hice la anulación de la función cmdloop, y fue bastante sencillo. No tuve que cambiar nada más. Simplemente copie la función cmdloop del módulo (busque el código haciendo import cmd , cmd.__file__ ) y agregue las dos líneas para cambiar los 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 cualquier delimitador que esté causando los problemas.