Moved QueueMessage and subclasses from hooke.ui to the more central hooke.engine.
[hooke.git] / hooke / ui / commandline.py
index c5f3353b000d71a9e8dd8652dda0b6e09492efc1..4b4914398b896682b0b6edee0e30ec3432e6a407 100644 (file)
@@ -2,15 +2,15 @@
 #
 # This file is part of Hooke.
 #
-# Hooke is free software: you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation, either
-# version 3 of the License, or (at your option) any later version.
+# Hooke is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
 #
-# Hooke is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
+# Hooke is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+# Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public
 # License along with Hooke.  If not, see
@@ -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 ..engine import CommandMessage
 from ..interaction import Request, BooleanRequest, ReloadUserInterfaceConfig
-from ..ui import UserInterface, CommandMessage
+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,6 +129,7 @@ class DoCommand (CommandMethod):
             self.cmd.stdout.write(str(e).lstrip()+'\n')
             self.cmd.stdout.write('Failure\n')
             return
+        self.log.debug('executing %s with %s' % (self.command.name, args))
         self.cmd.inqueue.put(CommandMessage(self.command, args))
         while True:
             msg = self.cmd.outqueue.get()
@@ -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
 
@@ -217,12 +248,17 @@ class DoCommand (CommandMethod):
         return msg.msg + d
 
     def _string_request_parser(self, msg, response):
+        response = response.strip()
+        if response == '':
+            return msg.default
         return response.strip()
 
     def _float_request_prompt(self, msg):
         return self._string_request_prompt(msg)
 
     def _float_request_parser(self, msg, resposne):
+        if response.strip() == '':
+            return msg.default
         return float(response)
 
     def _selection_request_prompt(self, msg):
@@ -234,9 +270,29 @@ class DoCommand (CommandMethod):
             prompt = '? '
         else:
             prompt = '? [%d] ' % msg.default
-        return '\n'.join([msg,options,prompt])
+        return '\n'.join([msg.msg,options,prompt])
     
     def _selection_request_parser(self, msg, response):
+        if response.strip() == '':
+            return msg.default
+        return int(response)
+
+    def _point_request_prompt(self, msg):
+        block = msg.curve.data[msg.block]
+        block_info = ('(curve: %s, block: %s, %d points)'
+                      % (msg.curve.name,
+                         block.info['name'],
+                         block.shape[0]))
+
+        if msg.default == None:
+            prompt = '? '
+        else:
+            prompt = '? [%d] ' % msg.default
+        return ' '.join([msg.msg,block_info,prompt])
+    
+    def _point_request_parser(self, msg, response):
+        if response.strip() == '':
+            return msg.default
         return int(response)
 
 
@@ -374,11 +430,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.
@@ -387,7 +445,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
@@ -395,6 +453,7 @@ class HookeCmd (cmd.Cmd):
         """
         pass
 
+
 class CommandLine (UserInterface):
     """Command line interface.  Simple and powerful.
     """
@@ -411,7 +470,9 @@ class CommandLine (UserInterface):
 
     def run(self, commands, ui_to_command_queue, command_to_ui_queue):
         cmd = self._cmd(commands, ui_to_command_queue, command_to_ui_queue)
-        cmd.cmdloop(self._splash_text())
+        cmd.cmdloop(self._splash_text(extra_info={
+                    'get-details':'run `license`',
+                    }))
 
     def run_lines(self, commands, ui_to_command_queue, command_to_ui_queue,
                   lines):