Command line UI now handles EOF during request/response interactions.
authorW. Trevor King <wking@drexel.edu>
Fri, 20 Aug 2010 10:43:17 +0000 (06:43 -0400)
committerW. Trevor King <wking@drexel.edu>
Fri, 20 Aug 2010 10:43:17 +0000 (06:43 -0400)
For example
  $ echo | ./bin/hk.py -c 'new_playlist'
                       -c 'glob_curves_to_playlist test/data/*' --persist
used to loop forever thinking it was getting invalid responses to
  Exit? [y/N]

Also, change str() to unicode() in DoCommand.__call__ to handle
non-ascii messages (e.g. ยต (micro) from SI units).

hooke/interaction.py
hooke/plugin/engine.py
hooke/ui/commandline.py

index f5c39bf..168c905 100644 (file)
@@ -86,6 +86,14 @@ class Response (Interaction):
         super(Response, self).__init__(type)
         self.value = value
 
+class EOFResponse (Response):
+    """End of user input.
+
+    After this point, no more user interaction is possible.
+    """
+    def __init__(self):
+        super(EOFResponse, self).__init__('EOF', None)
+
 class BooleanRequest (Request):
     def __init__(self, msg, default=None):
         super(BooleanRequest, self).__init__(
index 6564549..e4176d1 100644 (file)
@@ -22,7 +22,7 @@ associated :class:`hooke.command.Command`\s for basic
 interaction.
 """
 
-from ..command import CommandExit, Exit, Command, Argument
+from ..command import Exit, Command, Argument
 from ..interaction import BooleanRequest
 from . import Builtin
 
index 01a66f8..efed634 100644 (file)
@@ -30,10 +30,11 @@ except ImportError, e:
     import logging
     logging.warn('could not import readline, bash-like line editing disabled.')
 import shlex
+import sys
 
 from ..command import CommandExit, Exit, Command, Argument, StoreValue
-from ..engine import CommandMessage
-from ..interaction import Request, ReloadUserInterfaceConfig
+from ..engine import CommandMessage, CloseEngine
+from ..interaction import EOFResponse, Request, ReloadUserInterfaceConfig
 from ..ui import UserInterface
 from ..util.convert import from_string
 from ..util.encoding import get_input_encoding, get_output_encoding
@@ -41,6 +42,13 @@ from ..util.encoding import get_input_encoding, get_output_encoding
 
 # Define a few helper classes.
 
+class EOF (EOFError):
+    """Raise upon reaching the end of the input file.
+
+    After this point, no more user interaction is possible.
+    """
+    pass
+
 class Default (object):
     """Marker for options not given on the command line.
     """
@@ -154,9 +162,12 @@ class DoCommand (CommandMethod):
                 self.cmd.ui.reload_config(msg.config)
                 continue
             elif isinstance(msg, Request):
-                self._handle_request(msg)
+                try:
+                    self._handle_request(msg)
+                except EOF:
+                    return True
                 continue
-            self.cmd.stdout.write(str(msg).rstrip()+'\n')
+            self.cmd.stdout.write(unicode(msg).rstrip()+'\n')
 
     def _parse_args(self, args):
         options,args = self.parser.parse_args(args)
@@ -226,7 +237,17 @@ class DoCommand (CommandMethod):
                 self.cmd.stdout.write(''.join([
                         error.__class__.__name__, ': ', str(error), '\n']))
             self.cmd.stdout.write(prompt_string)
-            value = parser(msg, self.cmd.stdin.readline())
+            stdin = sys.stdin
+            try:
+                sys.stdin = self.cmd.stdin
+                raw_response = raw_input()
+            except EOFError, e:
+                self.cmd.inqueue.put(EOFResponse())
+                self.cmd.inqueue.put(CloseEngine())
+                raise EOF
+            finally:
+                sys.stdin = stdin
+            value = parser(msg, raw_response)
             try:
                 response = msg.response(value)
                 break