Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: third_party/twisted_8_1/twisted/conch/manhole.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.conch.test.test_manhole -*-
2 # Copyright (c) 2001-2007 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Line-input oriented interactive interpreter loop.
7
8 Provides classes for handling Python source input and arbitrary output
9 interactively from a Twisted application. Also included is syntax coloring
10 code with support for VT102 terminals, control code handling (^C, ^D, ^Q),
11 and reasonable handling of Deferreds.
12
13 @author: U{Jp Calderone<mailto:exarkun@twistedmatrix.com>}
14 """
15
16 import code, sys, StringIO, tokenize
17
18 from twisted.conch import recvline
19
20 from twisted.internet import defer
21 from twisted.python.htmlizer import TokenPrinter
22
23 class FileWrapper:
24 """Minimal write-file-like object.
25
26 Writes are translated into addOutput calls on an object passed to
27 __init__. Newlines are also converted from network to local style.
28 """
29
30 softspace = 0
31 state = 'normal'
32
33 def __init__(self, o):
34 self.o = o
35
36 def flush(self):
37 pass
38
39 def write(self, data):
40 self.o.addOutput(data.replace('\r\n', '\n'))
41
42 def writelines(self, lines):
43 self.write(''.join(lines))
44
45 class ManholeInterpreter(code.InteractiveInterpreter):
46 """Interactive Interpreter with special output and Deferred support.
47
48 Aside from the features provided by L{code.InteractiveInterpreter}, this
49 class captures sys.stdout output and redirects it to the appropriate
50 location (the Manhole protocol instance). It also treats Deferreds
51 which reach the top-level specially: each is formatted to the user with
52 a unique identifier and a new callback and errback added to it, each of
53 which will format the unique identifier and the result with which the
54 Deferred fires and then pass it on to the next participant in the
55 callback chain.
56 """
57
58 numDeferreds = 0
59 def __init__(self, handler, locals=None, filename="<console>"):
60 code.InteractiveInterpreter.__init__(self, locals)
61 self._pendingDeferreds = {}
62 self.handler = handler
63 self.filename = filename
64 self.resetBuffer()
65
66 def resetBuffer(self):
67 """Reset the input buffer."""
68 self.buffer = []
69
70 def push(self, line):
71 """Push a line to the interpreter.
72
73 The line should not have a trailing newline; it may have
74 internal newlines. The line is appended to a buffer and the
75 interpreter's runsource() method is called with the
76 concatenated contents of the buffer as source. If this
77 indicates that the command was executed or invalid, the buffer
78 is reset; otherwise, the command is incomplete, and the buffer
79 is left as it was after the line was appended. The return
80 value is 1 if more input is required, 0 if the line was dealt
81 with in some way (this is the same as runsource()).
82
83 """
84 self.buffer.append(line)
85 source = "\n".join(self.buffer)
86 more = self.runsource(source, self.filename)
87 if not more:
88 self.resetBuffer()
89 return more
90
91 def runcode(self, *a, **kw):
92 orighook, sys.displayhook = sys.displayhook, self.displayhook
93 try:
94 origout, sys.stdout = sys.stdout, FileWrapper(self.handler)
95 try:
96 code.InteractiveInterpreter.runcode(self, *a, **kw)
97 finally:
98 sys.stdout = origout
99 finally:
100 sys.displayhook = orighook
101
102 def displayhook(self, obj):
103 self.locals['_'] = obj
104 if isinstance(obj, defer.Deferred):
105 # XXX Ick, where is my "hasFired()" interface?
106 if hasattr(obj, "result"):
107 self.write(repr(obj))
108 elif id(obj) in self._pendingDeferreds:
109 self.write("<Deferred #%d>" % (self._pendingDeferreds[id(obj)][0 ],))
110 else:
111 d = self._pendingDeferreds
112 k = self.numDeferreds
113 d[id(obj)] = (k, obj)
114 self.numDeferreds += 1
115 obj.addCallbacks(self._cbDisplayDeferred, self._ebDisplayDeferre d,
116 callbackArgs=(k, obj), errbackArgs=(k, obj))
117 self.write("<Deferred #%d>" % (k,))
118 elif obj is not None:
119 self.write(repr(obj))
120
121 def _cbDisplayDeferred(self, result, k, obj):
122 self.write("Deferred #%d called back: %r" % (k, result), True)
123 del self._pendingDeferreds[id(obj)]
124 return result
125
126 def _ebDisplayDeferred(self, failure, k, obj):
127 self.write("Deferred #%d failed: %r" % (k, failure.getErrorMessage()), T rue)
128 del self._pendingDeferreds[id(obj)]
129 return failure
130
131 def write(self, data, async=False):
132 self.handler.addOutput(data, async)
133
134 CTRL_C = '\x03'
135 CTRL_D = '\x04'
136 CTRL_BACKSLASH = '\x1c'
137 CTRL_L = '\x0c'
138
139 class Manhole(recvline.HistoricRecvLine):
140 """Mediator between a fancy line source and an interactive interpreter.
141
142 This accepts lines from its transport and passes them on to a
143 L{ManholeInterpreter}. Control commands (^C, ^D, ^\) are also handled
144 with something approximating their normal terminal-mode behavior. It
145 can optionally be constructed with a dict which will be used as the
146 local namespace for any code executed.
147 """
148
149 namespace = None
150
151 def __init__(self, namespace=None):
152 recvline.HistoricRecvLine.__init__(self)
153 if namespace is not None:
154 self.namespace = namespace.copy()
155
156 def connectionMade(self):
157 recvline.HistoricRecvLine.connectionMade(self)
158 self.interpreter = ManholeInterpreter(self, self.namespace)
159 self.keyHandlers[CTRL_C] = self.handle_INT
160 self.keyHandlers[CTRL_D] = self.handle_EOF
161 self.keyHandlers[CTRL_L] = self.handle_FF
162 self.keyHandlers[CTRL_BACKSLASH] = self.handle_QUIT
163
164
165 def handle_INT(self):
166 """
167 Handle ^C as an interrupt keystroke by resetting the current input
168 variables to their initial state.
169 """
170 self.pn = 0
171 self.lineBuffer = []
172 self.lineBufferIndex = 0
173 self.interpreter.resetBuffer()
174
175 self.terminal.nextLine()
176 self.terminal.write("KeyboardInterrupt")
177 self.terminal.nextLine()
178 self.terminal.write(self.ps[self.pn])
179
180
181 def handle_EOF(self):
182 if self.lineBuffer:
183 self.terminal.write('\a')
184 else:
185 self.handle_QUIT()
186
187
188 def handle_FF(self):
189 """
190 Handle a 'form feed' byte - generally used to request a screen
191 refresh/redraw.
192 """
193 self.terminal.eraseDisplay()
194 self.terminal.cursorHome()
195 self.drawInputLine()
196
197
198 def handle_QUIT(self):
199 self.terminal.loseConnection()
200
201
202 def _needsNewline(self):
203 w = self.terminal.lastWrite
204 return not w.endswith('\n') and not w.endswith('\x1bE')
205
206 def addOutput(self, bytes, async=False):
207 if async:
208 self.terminal.eraseLine()
209 self.terminal.cursorBackward(len(self.lineBuffer) + len(self.ps[self .pn]))
210
211 self.terminal.write(bytes)
212
213 if async:
214 if self._needsNewline():
215 self.terminal.nextLine()
216
217 self.terminal.write(self.ps[self.pn])
218
219 if self.lineBuffer:
220 oldBuffer = self.lineBuffer
221 self.lineBuffer = []
222 self.lineBufferIndex = 0
223
224 self._deliverBuffer(oldBuffer)
225
226 def lineReceived(self, line):
227 more = self.interpreter.push(line)
228 self.pn = bool(more)
229 if self._needsNewline():
230 self.terminal.nextLine()
231 self.terminal.write(self.ps[self.pn])
232
233 class VT102Writer:
234 """Colorizer for Python tokens.
235
236 A series of tokens are written to instances of this object. Each is
237 colored in a particular way. The final line of the result of this is
238 generally added to the output.
239 """
240
241 typeToColor = {
242 'identifier': '\x1b[31m',
243 'keyword': '\x1b[32m',
244 'parameter': '\x1b[33m',
245 'variable': '\x1b[1;33m',
246 'string': '\x1b[35m',
247 'number': '\x1b[36m',
248 'op': '\x1b[37m'}
249
250 normalColor = '\x1b[0m'
251
252 def __init__(self):
253 self.written = []
254
255 def color(self, type):
256 r = self.typeToColor.get(type, '')
257 return r
258
259 def write(self, token, type=None):
260 if token and token != '\r':
261 c = self.color(type)
262 if c:
263 self.written.append(c)
264 self.written.append(token)
265 if c:
266 self.written.append(self.normalColor)
267
268 def __str__(self):
269 s = ''.join(self.written)
270 return s.strip('\n').splitlines()[-1]
271
272 def lastColorizedLine(source):
273 """Tokenize and colorize the given Python source.
274
275 Returns a VT102-format colorized version of the last line of C{source}.
276 """
277 w = VT102Writer()
278 p = TokenPrinter(w.write).printtoken
279 s = StringIO.StringIO(source)
280
281 tokenize.tokenize(s.readline, p)
282
283 return str(w)
284
285 class ColoredManhole(Manhole):
286 """A REPL which syntax colors input as users type it.
287 """
288
289 def getSource(self):
290 """Return a string containing the currently entered source.
291
292 This is only the code which will be considered for execution
293 next.
294 """
295 return ('\n'.join(self.interpreter.buffer) +
296 '\n' +
297 ''.join(self.lineBuffer))
298
299
300 def characterReceived(self, ch, moreCharactersComing):
301 if self.mode == 'insert':
302 self.lineBuffer.insert(self.lineBufferIndex, ch)
303 else:
304 self.lineBuffer[self.lineBufferIndex:self.lineBufferIndex+1] = [ch]
305 self.lineBufferIndex += 1
306
307 if moreCharactersComing:
308 # Skip it all, we'll get called with another character in
309 # like 2 femtoseconds.
310 return
311
312 if ch == ' ':
313 # Don't bother to try to color whitespace
314 self.terminal.write(ch)
315 return
316
317 source = self.getSource()
318
319 # Try to write some junk
320 try:
321 coloredLine = lastColorizedLine(source)
322 except tokenize.TokenError:
323 # We couldn't do it. Strange. Oh well, just add the character.
324 self.terminal.write(ch)
325 else:
326 # Success! Clear the source on this line.
327 self.terminal.eraseLine()
328 self.terminal.cursorBackward(len(self.lineBuffer) + len(self.ps[self .pn]) - 1)
329
330 # And write a new, colorized one.
331 self.terminal.write(self.ps[self.pn] + coloredLine)
332
333 # And move the cursor to where it belongs
334 n = len(self.lineBuffer) - self.lineBufferIndex
335 if n:
336 self.terminal.cursorBackward(n)
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/conch/ls.py ('k') | third_party/twisted_8_1/twisted/conch/manhole_ssh.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698