diff cmd2.py @ 75:8b2603d1acc1

working except for combinations
author catherine@Elli.myhome.westell.com
date Fri, 27 Jun 2008 15:36:03 -0400
parents 4e290d75e92e
children dcd5d13e5603
line wrap: on
line diff
--- a/cmd2.py	Wed Jun 25 17:16:07 2008 -0400
+++ b/cmd2.py	Fri Jun 27 15:36:03 2008 -0400
@@ -129,50 +129,98 @@
         setPasteBuffer = getPasteBuffer
 
 pyparsing.ParserElement.setDefaultWhitespaceChars(' \t')    # see http://pyparsing.wikispaces.com/message/view/home/1352689    
-def punctuationParser(punctuators):
-    """
-    Produces a string parser based on a list of targets to search for.
-    Output is a parser function.
-    Parser's output is a tuple: (before the target, [elements of the target], after the target)
-    >>> p = punctuationParser([';', 'EOF'])
-    >>> p('is terminated;')
-    ('is terminated', [';'], '')
-    >>> p('is terminated EOF after the end')    
-    ('is terminated', ['EOF'], 'after the end')
-    >>> p('is not terminated')
-    >>> pattern1 = pyparsing.Literal(';') + pyparsing.Optional(pyparsing.Word(pyparsing.nums))
-    >>> p2 = punctuationParser([pattern1, 'EOF'])
-    >>> p2('the quick brown fox;4')
-    ('the quick brown fox', [';', '4'], '')
-    >>> p2('the quick brown foxEOF')
-    ('the quick brown fox', ['EOF'], '')
-    >>> p2('nothing')
-    """
-    processed = punctuators[:]
-    if not hasattr(processed[0], 'parseString'):
-        processed[0] = pyparsing.Literal(processed[0])
-    processed = reduce(lambda x, y: x ^ y, processed)
-    processed.ignore(pyparsing.sglQuotedString)
-    processed.ignore(pyparsing.dblQuotedString)
-    pattern = pyparsing.SkipTo(processed) + processed + pyparsing.restOfLine
-    def parser(txt):
-        result = pattern.searchString(txt)
-        if result:
-            return result[0][0].strip(), result[0][1:-1], result[0][-1].strip()
+       
+class UserCommand(str):
+    def __new__(cls, s, app):
+        return str.__new__(cls, s)
+    def __init__(self, s, app):
+        self.terminator = None
+        self.terminator_suffix = None
+        self.searchable = self.asEntered = s
+        self.app = app
+        self.output_destination_pattern = self.punctuationPattern(['>>', '>'])
+        self.input_source_pattern = self.punctuationPattern(['<'])
+        self.pipe_destination_pattern = self.punctuationPattern(['|'])
+    def punctuationPattern(self, punctuators):      
+        processed = punctuators[:]
+        if not hasattr(processed[0], 'parseString'):
+            processed[0] = pyparsing.Literal(processed[0])
+        processed = reduce(lambda x, y: x ^ y, processed)
+        processed.ignore(pyparsing.sglQuotedString)
+        processed.ignore(pyparsing.dblQuotedString)
+        pattern = pyparsing.SkipTo(processed) + processed + pyparsing.restOfLine
+        return pattern
+    def find_punctuation(self):
+        punctuators = ['|','>','>>','<']
+        punctuators.extend(self.app.terminators)          
+        punctuated = self.punctuationPattern(punctuators).searchString(self.asEntered)
+        if punctuated:
+            self.executable, self.searchable = punctuated[0][0], self.asEntered[len(punctuated[0][0]):]
         else:
-            return None
-    return parser
-        
-class UserCommand(str):
-    def __init__(self, s):
-        str.__init__(self, s)
-        self.executable = s
-        self.searchable = s
-        
+            self.executable, self.searchable = self.asEntered, ''
+    def complete(self):
+        terminator_finder = self.punctuationPattern(self.app.terminators)
+        result = terminator_finder.searchString(self.asEntered)
+        while not result:
+            inp = self.app.pseudo_raw_input(self.app.continuationPrompt)
+            self.asEntered = '%s\n%s' % (self.asEntered, inp)
+            result = terminator_finder.searchString(self.asEntered)
+        try:
+            self.terminator = result[0][1][0]
+            self.terminator_suffix = result[0][1][1]
+        except IndexError:
+            self.terminator = result[0][1]
+            self.terminator_suffix = None
+    def redirectedInput(self):
+        inputFrom = self.input_source_pattern.searchString(self.searchable)
+        if inputFrom:
+            if inputFrom[0][-1].strip():
+                input = self.app.fileimport(source=inputFrom[0][-1].strip())
+            else:
+                input = getPasteBuffer()
+            if self.terminator:
+                self.executable = '%s %s' % (self.executable, input)
+            else:
+                self.executable = '%s %s %s' % (self.executable, inputFrom[0][0], input)
+    def pipeDestination(self):
+        pipeTo = self.pipe_destination_pattern.searchString(self.searchable)
+        return (pipeTo and pipeTo[0][-1]) or None
+    def redirectedOutput(self):
+        outputTo = self.output_destination_pattern.searchString(self.searchable)
+        if outputTo:
+            dest = outputTo[0][-1].strip()
+            if outputTo[0][1] == '>>':
+                mode = 'a'
+            else:
+                mode = 'w'
+            return dest, mode
+        return None, None
+
+                
+            
+        """
+        Produces a string parser based on a list of targets to search for.
+        Output is a parser function.
+        Parser's output is a tuple: (before the target, [elements of the target], after the target)
+        >>> p = punctuationParser([';', 'EOF'])
+        >>> p('is terminated;')
+        ('is terminated', [';'], '')
+        >>> p('is terminated EOF after the end')    
+        ('is terminated', ['EOF'], 'after the end')
+        >>> p('is not terminated')
+        >>> pattern1 = pyparsing.Literal(';') + pyparsing.Optional(pyparsing.Word(pyparsing.nums))
+        >>> p2 = punctuationParser([pattern1, 'EOF'])
+        >>> p2('the quick brown fox;4')
+        ('the quick brown fox', [';', '4'], '')
+        >>> p2('the quick brown foxEOF')
+        ('the quick brown fox', ['EOF'], '')
+        >>> p2('nothing')
+        """
+    
 class Cmd(cmd.Cmd):
     caseInsensitive = True
-    terminators = [';', pyparsing.LineEnd() + pyparsing.LineEnd()]    
     multilineCommands = []          # commands that need a terminator to be finished
+    terminators = [';', pyparsing.LineEnd() + pyparsing.LineEnd()]        
     terminatorKeepingCommands = []  # commands that expect to process their own terminators (else it will be stripped during parse)
     continuationPrompt = '> '    
     shortcuts = {'?': 'help', '!': 'shell', '@': 'load'}
@@ -214,10 +262,6 @@
     def __init__(self, *args, **kwargs):        
         cmd.Cmd.__init__(self, *args, **kwargs)
         self.history = History()
-        self.commmand_terminator_finder = punctuationParser(self.terminators)
-        self.output_destination_finder = punctuationParser(['>>', '>'])
-        self.input_source_finder = punctuationParser(['<'])
-        self.pipe_destination_finder = punctuationParser(['|'])
         
     def do_shortcuts(self, args):
         """Lists single-key shortcuts available."""
@@ -239,18 +283,6 @@
             command = command.lower()
         return command, args
     
-    def completedStatement(self, firstline):
-        statement = firstline
-        termination_found = self.commmand_terminator_finder(statement)        
-        while not termination_found:
-            inp = self.pseudo_raw_input(self.continuationPrompt)
-            statement = '%s\n%s' % (statement, inp)
-            termination_found = self.commmand_terminator_finder(statement)
-        return termination_found[0], termination_found[-1] 
-        # assembling a list of lines and joining them at the end would be faster, 
-        # but statementHasEnded needs a string arg; anyway, we're getting
-        # user input and users are slow.
-    
     def onecmd(self, line, assumeComplete=False):
         """Interpret the argument as though it had been typed in response
         to the prompt.
@@ -264,53 +296,38 @@
         statekeeper = None
         stop = 0        
         command, args = self.extractCommand(line)
-        statement = originalStatement = ' '.join([command, args])
+        originalStatement = ' '.join([command, args])
+        statement = UserCommand(originalStatement, self)
         if (not assumeComplete) and (command in self.multilineCommands):
-            statement, afterTerminator = self.completedStatement(statement)
-            inputFrom = self.input_source_finder(afterTerminator)
-            if inputFrom:
-                statement = "%s %s" % (statement, inputFrom[0])
-        else:
-            inputFrom = self.input_source_finder(statement)
-            if inputFrom:
-                statement = inputFrom[0]
-            
-        if inputFrom:
-            source = inputFrom[-1]
-            if source:
-                statement = '%s %s' % (statement, self.fileimport(source=source))
-            else:
-                statement = '%sy %s' % (statement, getPasteBuffer())
-        
-        pipeTo = self.pipe_destination_finder(afterTerminator)
+            statement.complete()
+        statement.find_punctuation()
+        statement.redirectedInput()
+        pipeTo = statement.pipeDestination()
         if pipeTo:
-            pipeTo = pipeTo[-1]
             statekeeper = Statekeeper(self, ('stdout',))               
-            pipeTo = subprocess.Popen(pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
-            self.stdout = pipeTo.stdin
+            dest = subprocess.Popen(pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
+            self.stdout = dest.stdin
         else:  # can't pipe output AND send it to a file
-            outputTo = self.output_destination_finder(afterTerminator)
-            if outputTo:
-                destination = outputTo[-1]
+            outputTo, outputMode = statement.redirectedOutput()
+            if outputMode:
                 statekeeper = Statekeeper(self, ('stdout',))                
-                mode = ((outputTo[1][0] == '>>') and 'a') or 'w'
-                if destination:
-                    self.stdout = open(destination, mode)
+                if outputTo:
+                    self.stdout = open(outputTo, outputMode)
                 else:
                     self.stdout = tempfile.TemporaryFile()
-                    if mode == 'a':
+                    if outputMode == 'a':
                         self.stdout.write(getPasteBuffer())
 
-        stop = cmd.Cmd.onecmd(self, statement)
+        stop = cmd.Cmd.onecmd(self, statement.executable)
         try:
             if command not in self.excludeFromHistory:
                 self.history.append(originalStatement)
         finally:
             if statekeeper:
                 if pipeTo:
-                    for result in pipeTo.communicate():              
+                    for result in dest.communicate():              
                         statekeeper.stdout.write(result or '')                        
-                elif outputTo and not destination:
+                elif outputMode and not outputTo:
                     self.stdout.seek(0)
                     writeToPasteBuffer(self.stdout.read())
                 self.stdout.close()
@@ -403,8 +420,6 @@
         i, n = 0, len(line)
         while i < n and line[i] in self.identchars: i = i+1
         cmd, arg = line[:i], line[i:].strip()
-        if cmd not in self.terminatorKeepingCommands:
-            arg = self.strip_terminators(arg)
         return cmd, arg, line
     
     def showParam(self, param):