2010-10-22 6 views
8

Ho una console Cmd impostata per il completamento automatico dei nomi delle carte per un sistema di gestione delle raccolte Magic: the Gathering.Modifica del modo in cui Python Cmd Module gestisce il completamento automatico

Utilizza il parametro di testo per interrogare il database per le carte e utilizza i risultati per completare/suggerire automaticamente le carte.

Tuttavia, questi nomi carte hanno più parole, e Cmd corre completamento automatico dal ultima spazio alla fine della riga.

Ad esempio:

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) 

ho provato afferrando manualmente quello che volevo dal parametro line, che ottiene i risultati che voglio dal database, ma questo non riesce a sovrascrivere la prima parola:

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

alla fine, ho bisogno di auto-completer a lavorare in questo modo:

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

Oltre al tentativo di parsing manuale qui sopra, ho anche provato a sostituire gli spazi con i segni più, e ho scoperto che Cmd è perfettamente felice di suddividere anche quelli. Sostituire spazi con caratteri di sottolineatura funziona, ma c'è una scheda in Unhinged che si chiama _____, quindi devo passare attraverso acrobazie per eliminare le stringhe dal momento che non posso solo line.replace("_", " ").

Ecco alcuni codice di prova eseguibile:

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

Ecco alcune buone informazioni qui: http://stackoverflow.com/questions/187621/how-to-make-a-python-command-line-program-autocomplete-arbitrary-things-not-int –

+0

puoi fornire codice di prova eseguibile? Sembra possibile correggere – nosklo

+0

Sì, l'ho visto anch'io, @offsound, è dove ho avuto l'idea di usare Cmd. Prenderò un po 'di codice di test. –

risposta

10

Non dovrebbe essere eccessivamente complicato. Qualcosa come il seguente:

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

Ho usato lo stesso" trucco "per completare il percorso consentito. Scambia l'ultima riga per il ritorno [fp [offs:] per fp in glob.glob (mline + '*')] –

+0

Se si eseguono alcune chiamate .lower(), è possibile rendere insensibile anche la distinzione tra maiuscole e minuscole. 'return [s [offs:] per s in completamenti se s.lower(). Startswith (mline.lower())]' –

0

Si potrebbe fare readline.set_completer_delims('').

Tuttavia, le funzioni complete_* non verranno più chiamate; dovrai ignorare Cmd.complete o Cmd.completenames. Guarda il codice sorgente del modulo cmd per i dettagli.

+0

Saltare le funzioni 'complete_ *' non è qualcosa che voglio fare, ma modificare il modo in cui vengono spediti è perfetto. Non solo "Cmd.complete", ma anche "Cmd.parseline". Pubblicherò ciò che cambio nella domanda dopo che l'ho scoperto. Grazie! –

+1

in realtà, questo lo fa: 'readline.set_completer_delims ('\ t \ n ... @ # $%^& *() - = + [{]} \\ |;: \'", <>? ') ' – wesen

0

Ho eseguito l'override della funzione cmdloop ed è stato piuttosto semplice. Non ho dovuto cambiare nient'altro. Basta copiare la funzione cmdloop dal modulo (trovare il codice facendo import cmd, cmd.__file__), e aggiungere le due linee di delimitatori che cambiano:

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 

che ha fatto per me. Nel tuo caso potresti voler rimuovere qualsiasi delimitatore causi i problemi.

Problemi correlati