comparison 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
comparison
equal deleted inserted replaced
74:4e290d75e92e 75:8b2603d1acc1
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 def punctuationParser(punctuators): 132
133 """ 133 class UserCommand(str):
134 Produces a string parser based on a list of targets to search for. 134 def __new__(cls, s, app):
135 Output is a parser function. 135 return str.__new__(cls, s)
136 Parser's output is a tuple: (before the target, [elements of the target], after the target) 136 def __init__(self, s, app):
137 >>> p = punctuationParser([';', 'EOF']) 137 self.terminator = None
138 >>> p('is terminated;') 138 self.terminator_suffix = None
139 ('is terminated', [';'], '') 139 self.searchable = self.asEntered = s
140 >>> p('is terminated EOF after the end') 140 self.app = app
141 ('is terminated', ['EOF'], 'after the end') 141 self.output_destination_pattern = self.punctuationPattern(['>>', '>'])
142 >>> p('is not terminated') 142 self.input_source_pattern = self.punctuationPattern(['<'])
143 >>> pattern1 = pyparsing.Literal(';') + pyparsing.Optional(pyparsing.Word(pyparsing.nums)) 143 self.pipe_destination_pattern = self.punctuationPattern(['|'])
144 >>> p2 = punctuationParser([pattern1, 'EOF']) 144 def punctuationPattern(self, punctuators):
145 >>> p2('the quick brown fox;4') 145 processed = punctuators[:]
146 ('the quick brown fox', [';', '4'], '') 146 if not hasattr(processed[0], 'parseString'):
147 >>> p2('the quick brown foxEOF') 147 processed[0] = pyparsing.Literal(processed[0])
148 ('the quick brown fox', ['EOF'], '') 148 processed = reduce(lambda x, y: x ^ y, processed)
149 >>> p2('nothing') 149 processed.ignore(pyparsing.sglQuotedString)
150 """ 150 processed.ignore(pyparsing.dblQuotedString)
151 processed = punctuators[:] 151 pattern = pyparsing.SkipTo(processed) + processed + pyparsing.restOfLine
152 if not hasattr(processed[0], 'parseString'): 152 return pattern
153 processed[0] = pyparsing.Literal(processed[0]) 153 def find_punctuation(self):
154 processed = reduce(lambda x, y: x ^ y, processed) 154 punctuators = ['|','>','>>','<']
155 processed.ignore(pyparsing.sglQuotedString) 155 punctuators.extend(self.app.terminators)
156 processed.ignore(pyparsing.dblQuotedString) 156 punctuated = self.punctuationPattern(punctuators).searchString(self.asEntered)
157 pattern = pyparsing.SkipTo(processed) + processed + pyparsing.restOfLine 157 if punctuated:
158 def parser(txt): 158 self.executable, self.searchable = punctuated[0][0], self.asEntered[len(punctuated[0][0]):]
159 result = pattern.searchString(txt)
160 if result:
161 return result[0][0].strip(), result[0][1:-1], result[0][-1].strip()
162 else: 159 else:
163 return None 160 self.executable, self.searchable = self.asEntered, ''
164 return parser 161 def complete(self):
165 162 terminator_finder = self.punctuationPattern(self.app.terminators)
166 class UserCommand(str): 163 result = terminator_finder.searchString(self.asEntered)
167 def __init__(self, s): 164 while not result:
168 str.__init__(self, s) 165 inp = self.app.pseudo_raw_input(self.app.continuationPrompt)
169 self.executable = s 166 self.asEntered = '%s\n%s' % (self.asEntered, inp)
170 self.searchable = s 167 result = terminator_finder.searchString(self.asEntered)
171 168 try:
169 self.terminator = result[0][1][0]
170 self.terminator_suffix = result[0][1][1]
171 except IndexError:
172 self.terminator = result[0][1]
173 self.terminator_suffix = None
174 def redirectedInput(self):
175 inputFrom = self.input_source_pattern.searchString(self.searchable)
176 if inputFrom:
177 if inputFrom[0][-1].strip():
178 input = self.app.fileimport(source=inputFrom[0][-1].strip())
179 else:
180 input = getPasteBuffer()
181 if self.terminator:
182 self.executable = '%s %s' % (self.executable, input)
183 else:
184 self.executable = '%s %s %s' % (self.executable, inputFrom[0][0], input)
185 def pipeDestination(self):
186 pipeTo = self.pipe_destination_pattern.searchString(self.searchable)
187 return (pipeTo and pipeTo[0][-1]) or None
188 def redirectedOutput(self):
189 outputTo = self.output_destination_pattern.searchString(self.searchable)
190 if outputTo:
191 dest = outputTo[0][-1].strip()
192 if outputTo[0][1] == '>>':
193 mode = 'a'
194 else:
195 mode = 'w'
196 return dest, mode
197 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
172 class Cmd(cmd.Cmd): 220 class Cmd(cmd.Cmd):
173 caseInsensitive = True 221 caseInsensitive = True
174 terminators = [';', pyparsing.LineEnd() + pyparsing.LineEnd()]
175 multilineCommands = [] # commands that need a terminator to be finished 222 multilineCommands = [] # commands that need a terminator to be finished
223 terminators = [';', pyparsing.LineEnd() + pyparsing.LineEnd()]
176 terminatorKeepingCommands = [] # commands that expect to process their own terminators (else it will be stripped during parse) 224 terminatorKeepingCommands = [] # commands that expect to process their own terminators (else it will be stripped during parse)
177 continuationPrompt = '> ' 225 continuationPrompt = '> '
178 shortcuts = {'?': 'help', '!': 'shell', '@': 'load'} 226 shortcuts = {'?': 'help', '!': 'shell', '@': 'load'}
179 excludeFromHistory = '''run r list l history hi ed edit li eof'''.split() 227 excludeFromHistory = '''run r list l history hi ed edit li eof'''.split()
180 defaultExtension = 'txt' 228 defaultExtension = 'txt'
212 pass 260 pass
213 261
214 def __init__(self, *args, **kwargs): 262 def __init__(self, *args, **kwargs):
215 cmd.Cmd.__init__(self, *args, **kwargs) 263 cmd.Cmd.__init__(self, *args, **kwargs)
216 self.history = History() 264 self.history = History()
217 self.commmand_terminator_finder = punctuationParser(self.terminators)
218 self.output_destination_finder = punctuationParser(['>>', '>'])
219 self.input_source_finder = punctuationParser(['<'])
220 self.pipe_destination_finder = punctuationParser(['|'])
221 265
222 def do_shortcuts(self, args): 266 def do_shortcuts(self, args):
223 """Lists single-key shortcuts available.""" 267 """Lists single-key shortcuts available."""
224 result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in self.shortcuts.items()) 268 result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in self.shortcuts.items())
225 self.stdout.write("Single-key shortcuts for other commands:\n%s\n" % (result)) 269 self.stdout.write("Single-key shortcuts for other commands:\n%s\n" % (result))
237 (command, args) = statement, '' 281 (command, args) = statement, ''
238 if self.caseInsensitive: 282 if self.caseInsensitive:
239 command = command.lower() 283 command = command.lower()
240 return command, args 284 return command, args
241 285
242 def completedStatement(self, firstline):
243 statement = firstline
244 termination_found = self.commmand_terminator_finder(statement)
245 while not termination_found:
246 inp = self.pseudo_raw_input(self.continuationPrompt)
247 statement = '%s\n%s' % (statement, inp)
248 termination_found = self.commmand_terminator_finder(statement)
249 return termination_found[0], termination_found[-1]
250 # assembling a list of lines and joining them at the end would be faster,
251 # but statementHasEnded needs a string arg; anyway, we're getting
252 # user input and users are slow.
253
254 def onecmd(self, line, assumeComplete=False): 286 def onecmd(self, line, assumeComplete=False):
255 """Interpret the argument as though it had been typed in response 287 """Interpret the argument as though it had been typed in response
256 to the prompt. 288 to the prompt.
257 289
258 This may be overridden, but should not normally need to be; 290 This may be overridden, but should not normally need to be;
262 294
263 """ 295 """
264 statekeeper = None 296 statekeeper = None
265 stop = 0 297 stop = 0
266 command, args = self.extractCommand(line) 298 command, args = self.extractCommand(line)
267 statement = originalStatement = ' '.join([command, args]) 299 originalStatement = ' '.join([command, args])
300 statement = UserCommand(originalStatement, self)
268 if (not assumeComplete) and (command in self.multilineCommands): 301 if (not assumeComplete) and (command in self.multilineCommands):
269 statement, afterTerminator = self.completedStatement(statement) 302 statement.complete()
270 inputFrom = self.input_source_finder(afterTerminator) 303 statement.find_punctuation()
271 if inputFrom: 304 statement.redirectedInput()
272 statement = "%s %s" % (statement, inputFrom[0]) 305 pipeTo = statement.pipeDestination()
273 else:
274 inputFrom = self.input_source_finder(statement)
275 if inputFrom:
276 statement = inputFrom[0]
277
278 if inputFrom:
279 source = inputFrom[-1]
280 if source:
281 statement = '%s %s' % (statement, self.fileimport(source=source))
282 else:
283 statement = '%sy %s' % (statement, getPasteBuffer())
284
285 pipeTo = self.pipe_destination_finder(afterTerminator)
286 if pipeTo: 306 if pipeTo:
287 pipeTo = pipeTo[-1]
288 statekeeper = Statekeeper(self, ('stdout',)) 307 statekeeper = Statekeeper(self, ('stdout',))
289 pipeTo = subprocess.Popen(pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 308 dest = subprocess.Popen(pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
290 self.stdout = pipeTo.stdin 309 self.stdout = dest.stdin
291 else: # can't pipe output AND send it to a file 310 else: # can't pipe output AND send it to a file
292 outputTo = self.output_destination_finder(afterTerminator) 311 outputTo, outputMode = statement.redirectedOutput()
293 if outputTo: 312 if outputMode:
294 destination = outputTo[-1]
295 statekeeper = Statekeeper(self, ('stdout',)) 313 statekeeper = Statekeeper(self, ('stdout',))
296 mode = ((outputTo[1][0] == '>>') and 'a') or 'w' 314 if outputTo:
297 if destination: 315 self.stdout = open(outputTo, outputMode)
298 self.stdout = open(destination, mode)
299 else: 316 else:
300 self.stdout = tempfile.TemporaryFile() 317 self.stdout = tempfile.TemporaryFile()
301 if mode == 'a': 318 if outputMode == 'a':
302 self.stdout.write(getPasteBuffer()) 319 self.stdout.write(getPasteBuffer())
303 320
304 stop = cmd.Cmd.onecmd(self, statement) 321 stop = cmd.Cmd.onecmd(self, statement.executable)
305 try: 322 try:
306 if command not in self.excludeFromHistory: 323 if command not in self.excludeFromHistory:
307 self.history.append(originalStatement) 324 self.history.append(originalStatement)
308 finally: 325 finally:
309 if statekeeper: 326 if statekeeper:
310 if pipeTo: 327 if pipeTo:
311 for result in pipeTo.communicate(): 328 for result in dest.communicate():
312 statekeeper.stdout.write(result or '') 329 statekeeper.stdout.write(result or '')
313 elif outputTo and not destination: 330 elif outputMode and not outputTo:
314 self.stdout.seek(0) 331 self.stdout.seek(0)
315 writeToPasteBuffer(self.stdout.read()) 332 writeToPasteBuffer(self.stdout.read())
316 self.stdout.close() 333 self.stdout.close()
317 statekeeper.restore() 334 statekeeper.restore()
318 335
401 if shortcut and hasattr(self, 'do_%s' % shortcut): 418 if shortcut and hasattr(self, 'do_%s' % shortcut):
402 line = '%s %s' % (shortcut, line[1:]) 419 line = '%s %s' % (shortcut, line[1:])
403 i, n = 0, len(line) 420 i, n = 0, len(line)
404 while i < n and line[i] in self.identchars: i = i+1 421 while i < n and line[i] in self.identchars: i = i+1
405 cmd, arg = line[:i], line[i:].strip() 422 cmd, arg = line[:i], line[i:].strip()
406 if cmd not in self.terminatorKeepingCommands:
407 arg = self.strip_terminators(arg)
408 return cmd, arg, line 423 return cmd, arg, line
409 424
410 def showParam(self, param): 425 def showParam(self, param):
411 param = self.clean(param) 426 param = self.clean(param)
412 if param in self.settable: 427 if param in self.settable: