[Zope-Checkins] CVS: Zope/inst - zctl.in:1.1.2.5

Chris McDonough chrism@zope.com
Tue, 3 Sep 2002 03:12:25 -0400


Update of /cvs-repository/Zope/inst
In directory cvs.zope.org:/tmp/cvs-serv17823

Modified Files:
      Tag: chrism-install-branch
	zctl.in 
Log Message:
Add command completion to zctl.  Remove some cruft as well.


=== Zope/inst/zctl.in 1.1.2.4 => 1.1.2.5 ===
--- Zope/inst/zctl.in:1.1.2.4	Mon Sep  2 15:18:14 2002
+++ Zope/inst/zctl.in	Tue Sep  3 03:12:24 2002
@@ -23,7 +23,7 @@
 try:
     import readline
 except:
-    pass
+    readline = None
 
 _marker = []
 
@@ -336,7 +336,7 @@
     #   Helper functions
     #
     def _report( self, msg='', level=1 ):
-        msg = TextBlockFormatter.format(msg, max_width=71, indent=9)
+        msg = TextBlockFormatter.format(msg, max_width=73, indent=6)
         self._reporter( msg, level )
 
     def _help( self, method_name ):
@@ -385,15 +385,6 @@
         status = os.system( cmdline )
         return status
 
-    def _spawnPython(self, args, wait=0):
-        args.insert(0, sys.executable)
-        if wait:
-            wait = os.P_WAIT
-        else:
-            wait = os.P_NOWAIT
-        pidorstatus = os.spawnv(wait, sys.executable, args)
-        return pidorstatus
-
     def _checkService( self, host, port ):
         """
             Return 1 if server is found at (host, port), 0 otherwise.
@@ -503,8 +494,10 @@
     """
         Interactive command processor.
     """
-    def __init__( self, prompt='zopectl> ', verbosity=1 ):
-
+    def __init__( self, completekey='tab', prompt='zctl> ', verbosity=1 ):
+        if completekey and readline:
+            readline.set_completer(self.complete)
+            readline.parse_and_bind(completekey + ': complete')
         self._engine    = ZopeCtl( self._report )
         self.prompt     = prompt
         self._verbosity = verbosity
@@ -534,6 +527,80 @@
 
         return cmd.Cmd.default( self, line )
 
+    def parseline(self, line):
+        line = line.strip()
+        if not line:
+            return None, None, line
+        elif line[0] == '?':
+            line = 'help ' + line[1:]
+        elif line[0] == '!':
+            if hasattr(self, 'do_shell'):
+                line = 'shell ' + line[1:]
+            else:
+                return None, None, line
+        i, n = 0, len(line)
+        while i < n and line[i] in self.identchars: i = i+1
+        cmd, arg = line[:i], line[i:].strip()
+        return cmd, arg, line
+
+    def completedefault(self, *ignored):
+        return []
+
+    def completenames(self, text, *ignored):
+        dotext = 'do_'+text
+        return [a[3:] for a in self.get_names() if a.startswith(dotext)]
+
+    def complete(self, text, state):
+        """Return the next possible completion for 'text'.
+
+        If a command has not been entered, then complete against command list.
+        Otherwise try to call complete_<command> to get list of completions.
+        """
+        if state == 0:
+            import readline
+            origline = readline.get_line_buffer()
+            line = origline.lstrip()
+            stripped = len(origline) - len(line)
+            begidx = readline.get_begidx() - stripped
+            endidx = readline.get_endidx() - stripped
+            if begidx>0:
+                cmd, args, foo = self.parseline(line)
+                if cmd == '':
+                    compfunc = self.completedefault
+                else:
+                    try:
+                        compfunc = getattr(self, 'complete_' + cmd)
+                    except AttributeError:
+                        compfunc = self.completedefault
+            else:
+                compfunc = self.completenames
+            self.completion_matches = compfunc(text, line, begidx, endidx)
+        try:
+            return self.completion_matches[state]
+        except IndexError:
+            return None
+
+    def get_names(self):
+        # Inheritance says we have to look in class and
+        # base classes; order is not important.
+        names = []
+        classes = [self.__class__]
+        while classes:
+            aclass = classes[0]
+            if aclass.__bases__:
+                classes = classes + list(aclass.__bases__)
+            names = names + dir(aclass)
+            del classes[0]
+        return names
+
+    def complete_help(self, *args):
+        return self.completenames(*args)
+
+    def complete_show(self, text, *ignored):
+        meta = ['config', 'directives', 'python', 'command-line',
+                'config-path']
+        return [a for a in meta if a.startswith(text) ]
+    
     do_start         = _MAKEDO( 'start' )
     do_start         = _MAKEDO( 'start' )
     do_restart       = _MAKEDO( 'restart' )
@@ -607,6 +674,9 @@
         else:
             return 0
 
+    
 if __name__ == '__main__':
 
-    _ZopeCtlCmd().main()
+    cmd = _ZopeCtlCmd()
+    cmd.main()
+