help_* working in commandline UI.
authorW. Trevor King <wking@drexel.edu>
Sun, 9 May 2010 22:41:55 +0000 (18:41 -0400)
committerW. Trevor King <wking@drexel.edu>
Sun, 9 May 2010 22:41:55 +0000 (18:41 -0400)
Still to go:
  * DoCommand._parse_args
  * DoHelp._usage_string
  * CompleteCommand
  * Interactive communication between user and command

hooke/command.py
hooke/ui/commandline.py

index 5f5228d87db2fb9454000bcd413ba52f97722851..bfa4c9f1611fa414f3ab1c1c673eaa362af65c6b 100644 (file)
@@ -99,10 +99,13 @@ class Command (object):
         name_part = 'Command: %s' % self.name
         if len(self.aliases) > 0:
             name_part += ' (%s)' % ', '.join(self.aliases)
-        argument_part = ['Arguments:'] + [a.help() for a in self.arguments]
-        argument_part = '\n'.join(argument_part)
-        help_part = self._help
-        return '\n\n'.join([name_part, argument_part, help_part])
+        parts = [name_part]
+        if len(self.arguments) > 0:
+            argument_part = ['Arguments:'] + [a.help() for a in self.arguments]
+            argument_part = '\n'.join(argument_part)
+            parts.append(argument_part)
+        parts.append(self._help) # help part
+        return '\n\n'.join(parts)
 
 class Argument (object):
     """Structured user input for :class:`Command`\s.
index e4c533ff54277aefd77ae6a75ceb77ae67765a7a..02174c40374a870701c76c2c547baea3df3092bb 100644 (file)
@@ -5,76 +5,107 @@ line.
 import cmd
 import readline
 
-from ..ui import UserInterface
+from ..command import CommandExit, Command, Argument
+from ..ui import UserInterface, CommandMessage
 
+# Define a few helper classes.  The .__call__ methods of these
+# functions will provide the do_*, help_*, and complete_* methods of
+# HookeCmd.
+
+class CommandMethod (object):
+    def __init__(self, cmd, command):
+        self.cmd = cmd
+        self.command = command
+
+    def __call__(self, *args, **kwargs):
+        raise NotImplementedError
+
+class DoCommand (CommandMethod):
+    def __call__(self, args):
+        args = self._parse_args(self.command, args)
+        self.cmd.inqueue.put(CommandMessage(self.command, args))
+        while True:
+            msg = self.cmd.outqueue.get()
+            if isinstance(msg, CommandExit):
+                break
+            self.cmd.stdout.write(str(msg))
+
+    def _parse_args(self, command, args):
+        print 'ARGS:', args, type(args)
+        return {}
+
+class HelpCommand (CommandMethod):
+    def __call__(self):
+        blocks = [self.command.help(),
+                  '------',
+                  'Usage: ' + self._usage_string(),
+                  '']
+        self.cmd.stdout.write('\n'.join(blocks))
+
+    def _message(self):
+        return self.command.help()
+
+    def _usage_string(self):
+        return ' '.join([self.command.name, '[args]'])
+
+class CompleteCommand (CommandMethod):
+    def __call__(self, text, line, begidx, endidx):
+        pass
+
+
+# Now onto the main attraction.
 
 class HookeCmd (cmd.Cmd):
-    def __init__(self, hooke):
+    def __init__(self, hooke, inqueue, outqueue):
         cmd.Cmd.__init__(self)
         self.hooke = hooke
         self.prompt = 'hooke> '
-        self._add_do_methods()
+        self._add_command_methods()
+        self.inqueue = inqueue
+        self.outqueue = outqueue
 
     def _safe_name(self, name):
         return name.lower().replace(' ', '_')
 
-    def _add_do_methods(self):
+    def _add_command_methods(self):
         for command in self.hooke.commands:
+            command.name = self._safe_name(command.name)
+            command.aliases = [self._safe_name(n) for n in command.aliases]
             for name in [command.name] + command.aliases:
                 name = self._safe_name(name)
-                def do_fn(self, args):
-                    pass
-                setattr(self.__class__, 'do_%s' % name, do_fn)
-                def help_fn(self):
-                    pass
-                setattr(self.__class__, 'help_%s' % name, help_fn)
-                def complete_fn(self, text, line, begidx, endidx):
-                    pass
-                setattr(self.__class__, 'complete_%s' % name, complete_fn)
-
-    def _help(self, name, aliases, message, usage_args=None):
-        if len(aliases) == 0:
-            alias_string = ''
-        else:
-            alias_string = ' (%s)' % ', '.join(aliases)
-        if usage_args == None:
-            usage_string = name
-        else:
-            usage_string = '%s %s' % (name, usage_args)
-        self.stdout.write(("""
-%s%s
-
-%s
-------
-Usage: %s
-""" % (name, alias_string, message.strip(), usage_string)).lstrip())
-
-    def help_help(self):
-        return self._help('help', [], """
+                setattr(self.__class__, 'do_%s' % name,
+                        DoCommand(self, command))
+                setattr(self.__class__, 'help_%s' % name,
+                        HelpCommand(self, command))
+                setattr(self.__class__, 'complete_%s' % name,
+                        CompleteCommand(self, command))
+
+        exit_command = Command(
+            name='exit', aliases=['quit', 'EOF'],
+            help='Exit Hooke cleanly.')
+        exit_command.arguments = [] # remove help argument
+        for name in [exit_command.name] + exit_command.aliases:
+            setattr(self.__class__, 'do_%s' % name,
+                    lambda self, args : True)
+            # the True return stops .cmdloop execution
+            setattr(self.__class__, 'help_%s' % name,
+                    HelpCommand(self, exit_command))
+
+        help_command = Command(
+            name='help',
+            help="""
 Called with an argument, prints that command's documentation.
 
 With no argument, lists all available help topics as well as any
 undocumented commands.
-""",
-                          '[command]')
-
-    def do_exit(self, args):
-        return True # the True return stops .cmdloop execution
-
-    def help_exit(self):
-        return self._help('exit', ['quit', 'EOF'], "Exit Hooke cleanly.")
-
-    def do_quit(self, args):
-        return self.do_exit(args)
-
-    def help_quit(self):
-        return self.help_exit()
-
-    def do_EOF(self, args):
-        return self.do_exit(args) 
+""".strip())
+        help_command.arguments = [ # overwrite help argument
+            Argument(name='command', type='string', optional=True,
+                     help='The name of the command you want help with.')
+            ]
+        setattr(self.__class__, 'help_help',
+                HelpCommand(self, help_command))
 
-    def help_EOF(self):
-        return self.help_exit()
 
 class CommandLine (UserInterface):
     """Command line interface.  Simple and powerful.
@@ -83,5 +114,7 @@ class CommandLine (UserInterface):
         super(CommandLine, self).__init__(name='command line')
 
     def run(self, hooke, ui_to_command_queue, command_to_ui_queue):
-        cmd = HookeCmd(hooke)
+        cmd = HookeCmd(hooke,
+                       inqueue=ui_to_command_queue,
+                       outqueue=command_to_ui_queue)
         cmd.cmdloop(self._splash_text())