Move LocalHelpCommand and LocalExitCommand from ui.commandline to plugin.engine.
[hooke.git] / hooke / ui / commandline.py
index 132d65785cefa3850a4a9e1cd6e5984d6e427b8e..5f04c366623a0db03689ab29284b19bef6a664a3 100644 (file)
@@ -22,13 +22,20 @@ line.
 
 import codecs
 import cmd
+import logging
 import optparse
-import readline # including readline makes cmd.Cmd.cmdloop() smarter
+try:
+    import readline # including readline makes cmd.Cmd.cmdloop() smarter
+except ImportError, e:
+    import logging
+    logging.warn('Could not import readline, bash-like line editing disabled.')
 import shlex
 
 from ..command import CommandExit, Exit, Command, Argument, StoreValue
-from ..interaction import Request, BooleanRequest, ReloadUserInterfaceConfig
-from ..ui import UserInterface, CommandMessage
+from ..engine import CommandMessage
+from ..interaction import Request, ReloadUserInterfaceConfig
+from ..ui import UserInterface
+from ..util.convert import from_string
 from ..util.encoding import get_input_encoding, get_output_encoding
 
 
@@ -53,8 +60,27 @@ class CommandLineParser (optparse.OptionParser):
                 continue # 'help' is a default OptionParser option
             if a.optional == True:
                 name = name_fn(a.name)
+                type = a.type
+                if type == 'bool':
+                    if a.default == True:
+                        self.add_option(
+                            '--disable-%s' % name, dest=name, default=Default,
+                            action='store_false')
+                        self.command_opts.append(a)
+                        continue
+                    elif a.default == False:
+                        self.add_option(
+                            '--enable-%s' % name, dest=name, default=Default,
+                            action='store_true')
+                        self.command_opts.append(a)
+                        continue
+                    else:
+                        type = 'string'
+                elif type not in ['string', 'int', 'long', 'choice', 'float',
+                                  'complex']:
+                    type = 'string'
                 self.add_option(
-                    '--%s' % name, dest=name, default=Default)
+                    '--%s' % name, dest=name, type=type, default=Default)
                 self.command_opts.append(a)
             else:
                 self.command_args.append(a)
@@ -94,6 +120,7 @@ class DoCommand (CommandMethod):
     def __init__(self, *args, **kwargs):
         super(DoCommand, self).__init__(*args, **kwargs)
         self.parser = CommandLineParser(self.command, self.name_fn)
+        self.log = logging.getLogger('hooke')
 
     def __call__(self, args):
         try:
@@ -102,7 +129,8 @@ class DoCommand (CommandMethod):
             self.cmd.stdout.write(str(e).lstrip()+'\n')
             self.cmd.stdout.write('Failure\n')
             return
-        self.cmd.inqueue.put(CommandMessage(self.command, args))
+        self.log.debug('executing %s with %s' % (self.command.name, args))
+        self.cmd.inqueue.put(CommandMessage(self.command.name, args))
         while True:
             msg = self.cmd.outqueue.get()
             if isinstance(msg, Exit):
@@ -130,12 +158,15 @@ class DoCommand (CommandMethod):
         arg_index = 0
         for argument in self.parser.command_args:
             if argument.count == 1:
-                params[argument.name] = args[arg_index]
+                params[argument.name] = from_string(args[arg_index],
+                                                    argument.type)
             elif argument.count > 1:
-                params[argument.name] = \
-                    args[arg_index:arg_index+argument.count]
+                params[argument.name] = [
+                    from_string(a, argument.type)
+                    for a in args[arg_index:arg_index+argument.count]]
             else: # argument.count == -1:
-                params[argument.name] = args[arg_index:]
+                params[argument.name] = [
+                    from_string(a, argument.type) for a in args[arg_index:]]
             arg_index += argument.count
         return params
 
@@ -266,6 +297,8 @@ class DoCommand (CommandMethod):
 
 
 class HelpCommand (CommandMethod):
+    """Supersedes :class:`hooke.plugin.engine.HelpCommand`.
+    """
     def __init__(self, *args, **kwargs):
         super(HelpCommand, self).__init__(*args, **kwargs)
         self.parser = CommandLineParser(self.command, self.name_fn)
@@ -297,63 +330,6 @@ class CompleteCommand (CommandMethod):
         pass
 
 
-# Define some additional commands
-
-class LocalHelpCommand (Command):
-    """Called with an argument, prints that command's documentation.
-
-    With no argument, lists all available help topics as well as any
-    undocumented commands.
-    """
-    def __init__(self):
-        super(LocalHelpCommand, self).__init__(name='help', help=self.__doc__)
-        # We set .arguments now (vs. using th arguments option to __init__),
-        # to overwrite the default help argument.  We don't override
-        # :meth:`cmd.Cmd.do_help`, so `help --help` is not a valid command.
-        self.arguments = [
-            Argument(name='command', type='string', optional=True,
-                     help='The name of the command you want help with.')
-            ]
-
-    def _run(self, hooke, inqueue, outqueue, params):
-        raise NotImplementedError # cmd.Cmd already implements .do_help()
-
-class LocalExitCommand (Command):
-    """Exit Hooke cleanly.
-    """
-    def __init__(self):
-        super(LocalExitCommand, self).__init__(
-            name='exit', aliases=['quit', 'EOF'], help=self.__doc__,
-            arguments = [
-                Argument(name='force', type='bool', default=False,
-                         help="""
-Exit without prompting the user.  Use if you save often or don't make
-typing mistakes ;).
-""".strip()),
-                ])
-
-    def _run(self, hooke, inqueue, outqueue, params):
-        """The guts of the `do_exit/_quit/_EOF` commands.
-
-        A `True` return stops :meth:`.cmdloop` execution.
-        """
-        _exit = True
-        if params['force'] == False:
-            not_saved = [p.name for p in hooke.playlists
-                         if p.is_saved() == False]
-            msg = 'Exit?'
-            default = True
-            if len(not_saved) > 0:
-                msg = 'Unsaved playlists (%s).  %s' \
-                    % (', '.join([str(p) for p in not_saved]), msg)
-                default = False
-            outqueue.put(BooleanRequest(msg, default))
-            result = inqueue.get()
-            assert result.type == 'boolean'
-            _exit = result.value
-        if _exit == True:
-            raise Exit()
-
 
 # Now onto the main attraction.
 
@@ -362,7 +338,6 @@ class HookeCmd (cmd.Cmd):
         cmd.Cmd.__init__(self)
         self.ui = ui
         self.commands = commands
-        self.local_commands = [LocalExitCommand(), LocalHelpCommand()]
         self.prompt = 'hooke> '
         self._add_command_methods()
         self.inqueue = inqueue
@@ -372,7 +347,9 @@ class HookeCmd (cmd.Cmd):
         return name.replace(' ', '_')
 
     def _add_command_methods(self):
-        for command in self.commands + self.local_commands:
+        for command in self.commands:
+            if command.name == 'exit':
+                command.aliases.extend(['quit', 'EOF'])
             for name in [command.name] + command.aliases:
                 name = self._name_fn(name)
                 setattr(self.__class__, 'help_%s' % name,
@@ -399,11 +376,13 @@ class HookeCmd (cmd.Cmd):
         argv = shlex.split(line, comments=True, posix=True)
         if len(argv) == 0:
             return None, None, '' # return an empty line
-        elif argv[0] == '?':
-            argv[0] = 'help'
-        elif argv[0] == '!':
-            argv[0] = 'system'
-        return argv[0], argv[1:], line
+        cmd = argv[0]
+        args = argv[1:]
+        if cmd == '?':
+            cmd = 'help'
+        elif cmd == '!':
+            cmd = 'system'
+        return cmd, args, line
 
     def do_help(self, arg):
         """Wrap Cmd.do_help to handle our .parseline argument list.
@@ -412,7 +391,7 @@ class HookeCmd (cmd.Cmd):
             return cmd.Cmd.do_help(self, '')
         return cmd.Cmd.do_help(self, arg[0])
 
-    def empytline(self):
+    def emptyline(self):
         """Override Cmd.emptyline to not do anything.
 
         Repeating the last non-empty command seems unwise.  Explicit
@@ -420,6 +399,7 @@ class HookeCmd (cmd.Cmd):
         """
         pass
 
+
 class CommandLine (UserInterface):
     """Command line interface.  Simple and powerful.
     """