Implementazione completamento nomi file con cmd è un po 'complicato perché il sottostante libreria readline interpreta i caratteri speciali come '/' e '-' (e altri) come separatori, e questo stabilisce che stringa all'interno di linea è di essere sostituito dai completamenti.
Per esempio,
> load /hom<tab>
chiamate complete_load() con
text='hom', line='load /hom', begidx=6, endidx=9
text is line[begidx:endidx]
'testo' non è "/ hom", perché la libreria readline analizzato la linea e restituisce la stringa dopo il '/'separatore. Il file complete_load() deve restituire un elenco di stringhe di completamento che iniziano con "hom", non "/ hom", poiché i completamenti sostituiranno la sottostringa iniziando dal begidx. Se la funzione complete_load() restituisce erroneamente [ '/ home'], la linea diventa,
> load //home
che non è buono.
Altri caratteri sono considerati separatori tramite readline, non solo barre, , quindi non è possibile assumere la sottostringa prima che "testo" sia una directory principale.Per esempio:
> load /home/mike/my-file<tab>
chiamate complete_load() con
text='file', line='load /home/mike/my-file', begidx=19, endidx=23
Supponendo/home/microfono contiene i file my-file1 e la mia-file2, i completamenti dovrebbe essere [ 'file1', ' file2 '], non [' my-file1 ',' my-file2 '], né ['/home/mike/my-file1 ','/home/mike/my-file2 ']. Se si restituisce i percorsi completi, il risultato è:
> load /home/mike/my-file/home/mike/my-file1
L'approccio che ho preso è stato quello di utilizzare il modulo glob per trovare i percorsi completi. Glob funziona per percorsi assoluti e percorsi relativi. Dopo aver trovato i percorsi, rimuovo la porzione "fissa", che è la sottostringa prima dell'hymidx.
In primo luogo, analizzare l'argomento porzione fissa, che è la sottostringa tra lo spazio e l'begidx.
index = line.rindex(' ', 0, begidx) # -1 if not found
fixed = line[index + 1: begidx]
L'argomento è tra lo spazio e la fine della riga. Aggiungi una stella per rendere un modello di ricerca glob.
aggiungo un '/' ai risultati che sono le directory, in quanto ciò rende più facile di attraversare le directory con il completamento scheda (altrimenti è necessario premere il tasto scheda due volte per ogni directory), e rende evidente a l'utente quali elementi di completamento sono le directory e quali sono i file.
Infine rimuovere la parte "fissa" dei percorsi, quindi readline sostituirà solo la parte "testo".
import os
import glob
import cmd
def _append_slash_if_dir(p):
if p and os.path.isdir(p) and p[-1] != os.sep:
return p + os.sep
else:
return p
class MyShell(cmd.Cmd):
prompt = "> "
def do_quit(self, line):
return True
def do_load(self, line):
print("load " + line)
def complete_load(self, text, line, begidx, endidx):
before_arg = line.rfind(" ", 0, begidx)
if before_arg == -1:
return # arg not found
fixed = line[before_arg+1:begidx] # fixed portion of the arg
arg = line[before_arg+1:endidx]
pattern = arg + '*'
completions = []
for path in glob.glob(pattern):
path = _append_slash_if_dir(path)
completions.append(path.replace(fixed, "", 1))
return completions
MyShell().cmdloop()
Trovo difficile credere che nessuno abbia risposto a questo –