Das Wichtigste zuerst:
@__blackjack__: Danke für deine Hilfe
Hat etwas gedauert aber letzten Endes habe ich verstanden, das die Funktion die an "readline.set_completer" übergeben wird vom Prinzip her nicht anderes ist als ein Generator der nach und nach die Elemente einer Liste aus Zeichenketten zurück gibt. Dabei ist der Parameter "state" der Index für die Liste. Wenn "state" gleich 0 ist sollte man die Liste erstellen und das letzte Element der Liste sollte keine Zeichenkette sein.
Und ich konnte sogar noch was anderes lernen: Das es Comprehensions für Listen gibt wusste ich ... das es aber auch welche für dicts und sets gibt war mir neu ...
Wie dem auch sei, meine CMD-Alternative häng ich mal unten dran. Vielleicht kann jemand diese brauchen ...
Code: Alles auswählen
class MyCmd():
# ---< def __init__(self, completekey=None) >---
def __init__(self, completekey=None):
self.running = True
self.prompt = "> "
self._cmds = dict()
for cmd in [s[3:] for s in dir(self.__class__) if s.startswith("do_")]:
key = cmd.replace("_", " ")
self._cmds[key] = {"function": getattr(self, f"do_{cmd}")}
completer = getattr(self, f"complete_{cmd}", None)
if completer:
self._cmds[key]["completer"] = completer
self.completekey = completekey if completekey else "tab"
self._old_completer = readline.get_completer()
readline.set_completer(self.completer)
readline.parse_and_bind(f"{self.completekey}: complete")
self._completions = list()
# ---< def normalize(self, line, keep_last_space) >---
def normalize(self, line, keep_last_space):
result = ""
if line:
last = keep_last_space and (line[-1] == " ")
result = " ".join(line.split())
if last:
result = f"{result} "
return result
# ---< def completer(self, text, state) >---
def completer(self, text, state):
if not state:
self._completions = list()
line = self.normalize(readline.get_line_buffer(), True)
spaces = line.count(" ")
if spaces == 0:
self._completions = list({s.split()[0] for s in self._cmds if s.startswith(text)})
elif spaces == 1:
cmd = line.split()[0]
if cmd in self._cmds:
completer = self._cmds[cmd].get("completer", None)
if completer:
self._completions = [s for s in completer(state) if s.startswith(text)]
else:
subcmds = list({s.split()[1] for s in self._cmds if " " in s})
self._completions = [s for s in subcmds if s.startswith(text)]
else:
cmd = " ".join(line.split()[:2])
if cmd in self._cmds:
completer = self._cmds[cmd].get("completer", None)
if completer:
self._completions = [s for s in completer(state) if s.startswith(text)]
if len(self._completions) == 1:
self._completions = [f"{self._completions[0]} "]
self._completions.append(None)
return self._completions[state]
# ---< def cmdloop(self) >---
def cmdloop(self):
self.preloop()
while True:
line = self.get_line()
if not self.running:
break
line = self.precmd(line)
self.onecmd(line)
self.postcmd(line)
self.postloop()
# ---< def get_line(self) >---
def get_line(self):
line = ""
try:
line = input(self.prompt)
except (EOFError, KeyboardInterrupt):
print()
self.running = False
return self.normalize(line, False)
# ---< def preloop(self) >---
def preloop(self):
pass
# ---< def postloop(self) >---
def postloop(self):
readline.set_completer(self._old_completer)
# ---< def precmd(self, line) >---
def precmd(self, line):
return line
# ---< def postcmd(self, line) >---
def postcmd(self, line):
pass
# ---< def onecmd(self, line) >---
def onecmd(self, line):
if line:
cmd, _, rest = line.partition(" ")
if cmd not in self._cmds:
subcmd, _, rest = rest.partition(" ")
cmd = f"{cmd} {subcmd}"
func = self._cmds.get(cmd, None)
if func:
func["function"](rest)
else:
self.default(line)
# ---< def default(self, line) >---
def default(self, line):
print(f"Unknown Syntax: {line}")