Mercurial > python-cmd2
comparison cmd2.py @ 76:dcd5d13e5603
fixed problem with interpreting terminators
author | catherine@Elli.myhome.westell.com |
---|---|
date | Sat, 28 Jun 2008 10:31:12 -0400 |
parents | 8b2603d1acc1 |
children | bb44928c3856 |
comparison
equal
deleted
inserted
replaced
75:8b2603d1acc1 | 76:dcd5d13e5603 |
---|---|
127 def getPasteBuffer(): | 127 def getPasteBuffer(): |
128 raise OSError, pastebufferr % ('xclip', 'On Debian/Ubuntu, install with "sudo apt-get install xclip"') | 128 raise OSError, pastebufferr % ('xclip', 'On Debian/Ubuntu, install with "sudo apt-get install xclip"') |
129 setPasteBuffer = getPasteBuffer | 129 setPasteBuffer = getPasteBuffer |
130 | 130 |
131 pyparsing.ParserElement.setDefaultWhitespaceChars(' \t') # see http://pyparsing.wikispaces.com/message/view/home/1352689 | 131 pyparsing.ParserElement.setDefaultWhitespaceChars(' \t') # see http://pyparsing.wikispaces.com/message/view/home/1352689 |
132 | 132 |
133 class Arguments(str): | |
134 def __new__(cls, s, parent): | |
135 result = str.__new__(cls, s) | |
136 result.parent = parent | |
137 return result | |
138 | |
133 class UserCommand(str): | 139 class UserCommand(str): |
134 def __new__(cls, s, app): | 140 def __new__(cls, s, app): |
135 return str.__new__(cls, s) | 141 return str.__new__(cls, s) |
136 def __init__(self, s, app): | 142 def __init__(self, s, app): |
137 self.terminator = None | 143 self.terminator = None |
138 self.terminator_suffix = None | 144 self.terminator_suffix = None |
145 s = s.strip() | |
146 shortcut = app.shortcuts.get(s[0]) | |
147 if shortcut and hasattr(app, 'do_%s' % shortcut): | |
148 s = '%s %s' % (shortcut, s[1:]) | |
139 self.searchable = self.asEntered = s | 149 self.searchable = self.asEntered = s |
140 self.app = app | 150 self.app = app |
141 self.output_destination_pattern = self.punctuationPattern(['>>', '>']) | 151 self.output_destination_pattern = self.punctuationPattern(['>>', '>']) |
142 self.input_source_pattern = self.punctuationPattern(['<']) | 152 self.input_source_pattern = self.punctuationPattern(['<']) |
143 self.pipe_destination_pattern = self.punctuationPattern(['|']) | 153 self.pipe_destination_pattern = self.punctuationPattern(['|']) |
148 processed = reduce(lambda x, y: x ^ y, processed) | 158 processed = reduce(lambda x, y: x ^ y, processed) |
149 processed.ignore(pyparsing.sglQuotedString) | 159 processed.ignore(pyparsing.sglQuotedString) |
150 processed.ignore(pyparsing.dblQuotedString) | 160 processed.ignore(pyparsing.dblQuotedString) |
151 pattern = pyparsing.SkipTo(processed) + processed + pyparsing.restOfLine | 161 pattern = pyparsing.SkipTo(processed) + processed + pyparsing.restOfLine |
152 return pattern | 162 return pattern |
153 def find_punctuation(self): | 163 def parse(self): |
154 punctuators = ['|','>','>>','<'] | 164 punctuators = ['|','>','>>','<'] |
155 punctuators.extend(self.app.terminators) | 165 punctuators.extend(self.app.terminators) |
156 punctuated = self.punctuationPattern(punctuators).searchString(self.asEntered) | 166 punctuated = self.punctuationPattern(punctuators).searchString(self.asEntered) |
157 if punctuated: | 167 if punctuated: |
158 self.executable, self.searchable = punctuated[0][0], self.asEntered[len(punctuated[0][0]):] | 168 self.executable, self.searchable = punctuated[0][0], self.asEntered[len(punctuated[0][0]):] |
159 else: | 169 else: |
160 self.executable, self.searchable = self.asEntered, '' | 170 self.executable, self.searchable = self.asEntered, '' |
171 self.executable = self.executable.strip() | |
172 try: | |
173 self.cmd, self.arg = (pyparsing.Word(self.app.identchars)+pyparsing.restOfLine).parseString(self.executable) | |
174 self.arg = Arguments(self.arg, self) | |
175 except pyparsing.ParseException: | |
176 self.cmd, self.arg = None, None | |
177 | |
161 def complete(self): | 178 def complete(self): |
162 terminator_finder = self.punctuationPattern(self.app.terminators) | 179 terminator_finder = self.punctuationPattern(self.app.terminators) |
163 result = terminator_finder.searchString(self.asEntered) | 180 result = terminator_finder.searchString(self.asEntered) |
164 while not result: | 181 while not result: |
165 inp = self.app.pseudo_raw_input(self.app.continuationPrompt) | 182 inp = self.app.pseudo_raw_input(self.app.continuationPrompt) |
166 self.asEntered = '%s\n%s' % (self.asEntered, inp) | 183 self.asEntered = '%s\n%s' % (self.asEntered, inp) |
167 result = terminator_finder.searchString(self.asEntered) | 184 result = terminator_finder.searchString(self.asEntered) |
168 try: | 185 self.terminator = result[0][1] |
169 self.terminator = result[0][1][0] | 186 if len(result[0]) > 3: |
170 self.terminator_suffix = result[0][1][1] | 187 self.terminator_suffix = result[0][2] |
171 except IndexError: | 188 else: |
172 self.terminator = result[0][1] | |
173 self.terminator_suffix = None | 189 self.terminator_suffix = None |
174 def redirectedInput(self): | 190 def redirectedInput(self): |
175 inputFrom = self.input_source_pattern.searchString(self.searchable) | 191 inputFrom = self.input_source_pattern.searchString(self.searchable) |
176 if inputFrom: | 192 if inputFrom: |
177 if inputFrom[0][-1].strip(): | 193 if inputFrom[0][-1].strip(): |
193 mode = 'a' | 209 mode = 'a' |
194 else: | 210 else: |
195 mode = 'w' | 211 mode = 'w' |
196 return dest, mode | 212 return dest, mode |
197 return None, None | 213 return None, None |
198 | |
199 | |
200 | |
201 """ | |
202 Produces a string parser based on a list of targets to search for. | |
203 Output is a parser function. | |
204 Parser's output is a tuple: (before the target, [elements of the target], after the target) | |
205 >>> p = punctuationParser([';', 'EOF']) | |
206 >>> p('is terminated;') | |
207 ('is terminated', [';'], '') | |
208 >>> p('is terminated EOF after the end') | |
209 ('is terminated', ['EOF'], 'after the end') | |
210 >>> p('is not terminated') | |
211 >>> pattern1 = pyparsing.Literal(';') + pyparsing.Optional(pyparsing.Word(pyparsing.nums)) | |
212 >>> p2 = punctuationParser([pattern1, 'EOF']) | |
213 >>> p2('the quick brown fox;4') | |
214 ('the quick brown fox', [';', '4'], '') | |
215 >>> p2('the quick brown foxEOF') | |
216 ('the quick brown fox', ['EOF'], '') | |
217 >>> p2('nothing') | |
218 """ | |
219 | 214 |
220 class Cmd(cmd.Cmd): | 215 class Cmd(cmd.Cmd): |
221 caseInsensitive = True | 216 caseInsensitive = True |
222 multilineCommands = [] # commands that need a terminator to be finished | 217 multilineCommands = [] # commands that need a terminator to be finished |
223 terminators = [';', pyparsing.LineEnd() + pyparsing.LineEnd()] | 218 terminators = [';', pyparsing.LineEnd() + pyparsing.LineEnd()] |
298 command, args = self.extractCommand(line) | 293 command, args = self.extractCommand(line) |
299 originalStatement = ' '.join([command, args]) | 294 originalStatement = ' '.join([command, args]) |
300 statement = UserCommand(originalStatement, self) | 295 statement = UserCommand(originalStatement, self) |
301 if (not assumeComplete) and (command in self.multilineCommands): | 296 if (not assumeComplete) and (command in self.multilineCommands): |
302 statement.complete() | 297 statement.complete() |
303 statement.find_punctuation() | 298 statement.parse() |
304 statement.redirectedInput() | 299 statement.redirectedInput() |
305 pipeTo = statement.pipeDestination() | 300 pipeTo = statement.pipeDestination() |
306 if pipeTo: | 301 if pipeTo: |
307 statekeeper = Statekeeper(self, ('stdout',)) | 302 statekeeper = Statekeeper(self, ('stdout',)) |
308 dest = subprocess.Popen(pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) | 303 dest = subprocess.Popen(pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) |
316 else: | 311 else: |
317 self.stdout = tempfile.TemporaryFile() | 312 self.stdout = tempfile.TemporaryFile() |
318 if outputMode == 'a': | 313 if outputMode == 'a': |
319 self.stdout.write(getPasteBuffer()) | 314 self.stdout.write(getPasteBuffer()) |
320 | 315 |
321 stop = cmd.Cmd.onecmd(self, statement.executable) | 316 stop = cmd.Cmd.onecmd(self, statement) |
322 try: | 317 try: |
323 if command not in self.excludeFromHistory: | 318 if command not in self.excludeFromHistory: |
324 self.history.append(originalStatement) | 319 self.history.append(originalStatement) |
325 finally: | 320 finally: |
326 if statekeeper: | 321 if statekeeper: |
409 def parseline(self, line): | 404 def parseline(self, line): |
410 """Parse the line into a command name and a string containing | 405 """Parse the line into a command name and a string containing |
411 the arguments. Returns a tuple containing (command, args, line). | 406 the arguments. Returns a tuple containing (command, args, line). |
412 'command' and 'args' may be None if the line couldn't be parsed. | 407 'command' and 'args' may be None if the line couldn't be parsed. |
413 """ | 408 """ |
414 line = line.strip() | 409 if not line.executable: |
415 if not line: | |
416 return None, None, line | 410 return None, None, line |
417 shortcut = self.shortcuts.get(line[0]) | 411 return line.cmd, line.arg, line.executable |
418 if shortcut and hasattr(self, 'do_%s' % shortcut): | |
419 line = '%s %s' % (shortcut, line[1:]) | |
420 i, n = 0, len(line) | |
421 while i < n and line[i] in self.identchars: i = i+1 | |
422 cmd, arg = line[:i], line[i:].strip() | |
423 return cmd, arg, line | |
424 | |
425 def showParam(self, param): | 412 def showParam(self, param): |
426 param = self.clean(param) | 413 param = self.clean(param) |
427 if param in self.settable: | 414 if param in self.settable: |
428 val = getattr(self, param) | 415 val = getattr(self, param) |
429 self.stdout.write('%s: %s\n' % (param, str(getattr(self, param)))) | 416 self.stdout.write('%s: %s\n' % (param, str(getattr(self, param)))) |