Commit a5ba5423 authored by Seblu's avatar Seblu
Browse files

Add a completion class to handle completion

parent 905a492c
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -31,11 +31,11 @@ settings = {
try:
    # Early debug loading
    if "CC_DEBUG" in os.environ:
        settings["debug"] = "True"
        cccli.debug = True
        settings["debug"] = "True"

    # load a printer
    printer = Printer(False)
    printer = Printer()

    # Parse line argument
    oparser = optparse.OptionParser(usage="usage: %prog [options] [commands]",
@@ -127,12 +127,12 @@ try:
            raise BadArgument("Invalid %s number"%i)
    # check login
    if "login" not in settings:
        printer.setinteractive()
        printer.set_interactive()
        settings["login"] = printer.ask("Login: ")

    # check password
    if "pass" not in settings:
        printer.setinteractive()
        printer.set_interactive()
        settings["pass"] = printer.getpass("Password: ")

    # print settings
@@ -150,6 +150,7 @@ except cliError as e:
    printer.error("cliError: %s"%str(e))
except Exception as e:
    if cccli.debug:
        if "printer" in locals():
            printer.fatal("%s: %s"%(type(e), str(e)), quit=False)
        raise
    printer.warn("This is a not expected error, please report it!")
+32 −19
Original line number Diff line number Diff line
@@ -33,24 +33,11 @@ class Cli(object):
        # line stuff
        if line:
            sys.stdin = StringIO.StringIO(line)
        # start printer
        self.printer = Printer()
        # set interactive mode
        self.interactive = sys.stderr.isatty() and sys.stdin.isatty()
        # start printer and load history
        self.printer = Printer(self.interactive,
                               historyfile=self.settings.get("history", ""),
                               historysize=self.settings.get("hsize", None))
        # load alias
        self.alias.load(self.settings.get("alias", ""))
        # print debug
        self.printer.debug("Interactive: %s"%self.interactive)
        self.printer.debug("Alias: %s"%self.alias)
        self.printer.debug("Loaded history: %s"%len(self.printer.history))
        # connecting
        self._connect()
        # auth
        self._auth()
        # set prompt
        if self.interactive:
        if sys.stderr.isatty() and sys.stdin.isatty():
            self.printer.debug("Interactive mode")
            self.prompt = "%s%s%s%s>%s%s%s "%(color["["],
                                              color["light"],
                                              color["]"],
@@ -58,6 +45,21 @@ class Cli(object):
                                              color["["],
                                              color["reset"],
                                              color["]"])
            self.printer.set_interactive()
            # load history
            self.printer.history.load(self.settings.get("history", ""))
            self.printer.history.maxsize(self.settings.get("hsize", None))
            self.printer.debug("Loaded history: %s"%len(self.printer.history))
            # enable completion
            self.printer.completion.set_completer(self._completer)
            # set prompt
        # load alias
        self.alias.load(self.settings.get("alias", ""))
        self.printer.debug("Alias: %s"%self.alias)
        # connecting
        self._connect()
        # auth
        self._auth()
        # parsing
        self._parse()
        # save history
@@ -114,8 +116,7 @@ class Cli(object):
                break
            except SystemExit:
                break
        if self.interactive:
            self.printer.out("tcho!")
        self.printer.interactive("tcho!")

    def _exec_command(self, argv):
        '''Execute command'''
@@ -154,6 +155,18 @@ class Cli(object):
            self.printer.error("%s: %s"%(type(e), str(e)))
            self.printer.warn("This is a not expected error, please report it!")

    def _completer(self, texte, state):
        '''Return the list of completion'''
        comp = self.printer.completion
        stripped = comp.get_buf()[:comp.get_begin() + 1].lstrip()
        if state == 0 and texte == "" and stripped != "":
            return None
        cl = [ c for c in  Command.list() if c.startswith(texte) ]
        if state < len(cl):
            return cl[state]
        return None


class CliHandler(RpcHandler):
    '''Handle RPC incoming request'''

+47 −34
Original line number Diff line number Diff line
@@ -48,19 +48,13 @@ color = {

class Printer(object):
    '''Print relative class'''
    def __init__(self, interactive=False, historyfile=None, historysize=None):
    def __init__(self):
        self.readline = None
        self.history = History()
        self.historyfile = historyfile
        self.historysize = historysize
        if interactive:
            self.setinteractive()

    def isinteractive(self):
        '''Return if printer is in interactive mode'''
        return self.readline is not None
        self.completion = Completion()

    def setinteractive(self):
    def set_interactive(self):
        '''Set interactive mode'''
        if self.readline is not None:
            return
        try:
@@ -70,12 +64,8 @@ class Printer(object):
        self.readline = readline
        # enable history
        self.history.readline = readline
        # load history
        self.history.read(self.historyfile)
        self.history.maxsize(self.historysize)
        # start prompt completer
        self.readline.set_completer(self.completer)
        self.readline.parse_and_bind("tab: complete")
        # enable completion
        self.completion.readline = readline

    def out(self, message="", fd=sys.stdout, nl=os.linesep, flush=True):
        '''Print a message in fd ended by nl'''
@@ -107,6 +97,11 @@ class Printer(object):
        if cccli.debug:
            self.out(message, fd, nl)

    def interactive(self, message, fd=sys.stderr, nl=os.linesep):
        '''Print only in interactive mode'''
        if self.readline is not None:
            self.out(message, fd, nl)

    def getline(self, prompt, history=True):
        '''Read a line from stdin'''
        try:
@@ -157,15 +152,6 @@ class Printer(object):
        rows, cols, px_x, px_y = struct.unpack("HHHH", resp)
        return rows, cols

    def completer(self, texte, state):
        r = self.readline
        if state == 0 and texte == "" and r.get_line_buffer()[:r.get_begidx() + 1].lstrip() != "":
            return None
        cl = [ c for c in  Command.list() if c.startswith(texte) ]
        if state < len(cl):
            return cl[state]
        return None


class History(object):
    '''History class'''
@@ -229,6 +215,33 @@ class History(object):
        '''Clear history'''
        self.readline.clear_history()

# Need to be at end of file to fix cross loading of printer by command and command by printer
# So i maybe should change the design of import
from cccli.command import Command

class Completion(object):
    '''Handle completion functions'''
    def __init__(self):
        self.readline = None

    def __getattribute__(self, name):
         r = object.__getattribute__(self, "readline")
         if name == "readline":
             return r
         if r is None:
             return lambda *a,**k: None
         return object.__getattribute__(self, name)

    def get_buf(self):
        '''Return current readline buffer'''
        return self.readline.get_line_buffer()

    def get_begin(self):
        '''Get the beginning index of the readline tab-completion scope'''
        return self.readline.get_begidx()

    def get_end(self):
        '''Get the ending index of the readline tab-completion scope'''
        return self.readline.get_begidx()

    def set_completer(self, func):
        '''Set completer function'''
        self.readline.set_completer(func)
        self.readline.parse_and_bind("tab: complete")