.__setup_params() -> ._setup_params() in hooke/plugin/*.py.
[hooke.git] / hooke / plugin / command_stack.py
index abb03b7012cb8cae467c498c4c5acb84688fbe67..59ca5ddbe79e98782ff5d60f3d038cf2293349cf 100644 (file)
@@ -24,10 +24,12 @@ and several associated :class:`~hooke.command.Command`\s exposing
 """
 
 import logging
+import os.path
 from Queue import Queue
 
 from ..command import Command, Argument, Success, Failure
-from ..command_stack import CommandStack
+from ..command_stack import FileCommandStack
+from ..config import Setting
 from ..engine import CloseEngine, CommandMessage
 from . import Builtin
 
@@ -37,6 +39,11 @@ from . import Builtin
 class CommandStackCommand (Command):
     """Subclass to avoid pushing control commands to the stack.
     """
+    def __init__(self, *args, **kwargs):
+        super(CommandStackCommand, self).__init__(*args, **kwargs)
+        stack = [a for a in self.arguments if a.name == 'stack'][0]
+        stack.default = False
+
     def _set_state(self, state):
         try:
             self.plugin.set_state(state)
@@ -74,7 +81,8 @@ class CaptureCommand (CommandStackCommand):
                 return
             assert isinstance(msg, CommandMessage), type(msg)
             cmd = hooke.command_by_name[msg.command]
-            if isinstance(cmd, CommandStackCommand):
+            if (msg.explicit_user_call == False
+                or isinstance(cmd, CommandStackCommand)):
                 if isinstance(cmd, StopCaptureCommand):
                     outqueue = Queue()  # Grab StopCaptureCommand's completion.
                 cmd.run(hooke, inqueue, outqueue, **msg.arguments)
@@ -92,16 +100,23 @@ class CaptureCommand (CommandStackCommand):
 # The plugin itself
 
 class CommandStackPlugin (Builtin):
+    """Commands for managing a command stack (similar to macros).
+    """
     def __init__(self):
         super(CommandStackPlugin, self).__init__(name='command_stack')
         self._commands = [
             StartCaptureCommand(self), StopCaptureCommand(self),
            ReStartCaptureCommand(self),
             PopCommand(self), GetCommand(self), GetStateCommand(self),
-           SaveCommand(self), LoadCommand(self),
+           SaveCommand(self), LoadCommand(self), ExecuteCommand(self),
            ]
-       self.command_stack = CommandStack()
-       self.path = None
+        self._settings = [
+            Setting(section=self.setting_section, help=self.__doc__),
+            Setting(section=self.setting_section, option='path',
+                    value=os.path.join('resources', 'command_stack'),
+                    help='Directory containing command stack files.'), # TODO: allow colon separated list, like $PATH.
+            ]
+       self.command_stack = FileCommandStack()
         self.state = 'inactive'
         # inactive <-> active.
         self._valid_transitions = {
@@ -109,6 +124,9 @@ class CommandStackPlugin (Builtin):
             'active': ['inactive'],
             }
 
+    def default_settings(self):
+        return self._settings
+
     def log(self, msg):
         log = logging.getLogger('hooke')
         log.debug('%s %s' % (self.name, msg))
@@ -134,7 +152,7 @@ class StartCaptureCommand (CaptureCommand):
 
     def _run(self, hooke, inqueue, outqueue, params):
         self._set_state('active')
-        self.plugin.command_stack = CommandStack()  # clear command stack
+        self.plugin.command_stack = FileCommandStack()  # clear command stack
         super(StartCaptureCommand, self)._run(hooke, inqueue, outqueue, params)
 
 
@@ -198,18 +216,81 @@ class SaveCommand (CommandStackCommand):
     """
     def __init__(self, plugin):
         super(SaveCommand, self).__init__(
-            name='save command stack', help=self.__doc__, plugin=plugin)
+            name='save command stack',
+            arguments=[
+                Argument(name='output', type='file',
+                         help="""
+File name for the output command stack.  Defaults to overwriting the
+input command stack.  If the command stack does not have an input file
+(e.g. it is the default) then the file name defaults to `default`.
+""".strip()),
+                ],
+            help=self.__doc__, plugin=plugin)
 
     def _run(self, hooke, inqueue, outqueue, params):
-        pass
+        params = self._setup_params(hooke, params)
+        self.plugin.command_stack.save(params['output'])
 
+    def _setup_params(self, hooke, params):
+        if params['output'] == None and self.plugin.command_stack.path == None:
+            params['output'] = 'default'
+        if params['output'] != None:
+            params['output'] = os.path.join(
+                self.plugin.config['path'], params['output'])
+        return params
 
 class LoadCommand (CommandStackCommand):
     """Load the command stack.
+
+    .. warning:: This is *not safe* with untrusted input.
     """
     def __init__(self, plugin):
         super(LoadCommand, self).__init__(
-            name='load command stack', help=self.__doc__, plugin=plugin)
+            name='load command stack',
+            arguments=[
+                Argument(name='input', type='file',
+                         help="""
+File name for the input command stack.
+""".strip()),
+                ],
+            help=self.__doc__, plugin=plugin)
+
+    def _run(self, hooke, inqueue, outqueue, params):
+        params = self._setup_params(hooke, params)
+        self.plugin.command_stack.clear()
+        self.plugin.command_stack.load(params['input'])
+
+    def _setup_params(self, hooke, params):
+        if params['input'] == None and self.plugin.command_stack.path == None:
+            params['input'] = 'default'
+        if params['input'] != None:
+            params['input'] = os.path.join(
+                self.plugin.config['path'], params['input'])
+        return params
+
+
+class ExecuteCommand (Command):
+    """Execute a :class:`~hooke.command_stack.CommandStack`.
+    """
+    def __init__(self, plugin):
+        super(ExecuteCommand, self).__init__(
+            name='execute command stack',
+            arguments=[
+                Argument(name='commands', type='command stack',
+                         help="""
+Command stack to apply to each curve.  Defaults to the plugin's
+current stack.
+""".strip()),
+                ],
+            help=self.__doc__, plugin=plugin)
 
     def _run(self, hooke, inqueue, outqueue, params):
-        pass
+        params = self._setup_params(hooke=hooke, params=params)
+        if len(params['commands']) == 0:
+            return
+        params['commands'].execute(hooke=hooke, stack=params['stack'])
+
+    def _setup_params(self, hooke, params):
+        if params['commands'] == None:
+            params['commands'] = self.plugin.command_stack
+        return params