# HG changeset patch # User catherine@Elli.myhome.westell.com # Date 1214595363 14400 # Node ID 8b2603d1acc19f3f609d4628f66ac43d872cf6df # Parent 4e290d75e92e99ce64651aa16491ea4e958c8800 working except for combinations diff -r 4e290d75e92e -r 8b2603d1acc1 cmd2.py --- 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):