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

Side by Side Diff: third_party/twisted_8_1/twisted/manhole/ui/gtk2manhole.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 # -*- Python -*-
2 # $Id: gtk2manhole.py,v 1.9 2003/09/07 19:58:09 acapnotic Exp $
3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
4 # See LICENSE for details.
5
6
7 """Manhole client with a GTK v2.x front-end.
8 """
9
10 __version__ = '$Revision: 1.9 $'[11:-2]
11
12 from twisted import copyright
13 from twisted.internet import reactor
14 from twisted.python import components, failure, log, util
15 from twisted.spread import pb
16 from twisted.spread.ui import gtk2util
17
18 from twisted.manhole.service import IManholeClient
19 from zope.interface import implements
20
21 # The pygtk.require for version 2.0 has already been done by the reactor.
22 import gtk
23
24 import code, types, inspect
25
26 # TODO:
27 # Make wrap-mode a run-time option.
28 # Explorer.
29 # Code doesn't cleanly handle opening a second connection. Fix that.
30 # Make some acknowledgement of when a command has completed, even if
31 # it has no return value so it doesn't print anything to the console.
32
33 class OfflineError(Exception):
34 pass
35
36 class ManholeWindow(components.Componentized, gtk2util.GladeKeeper):
37 gladefile = util.sibpath(__file__, "gtk2manhole.glade")
38
39 _widgets = ('input','output','manholeWindow')
40
41 def __init__(self):
42 self.defaults = {}
43 gtk2util.GladeKeeper.__init__(self)
44 components.Componentized.__init__(self)
45
46 self.input = ConsoleInput(self._input)
47 self.input.toplevel = self
48 self.output = ConsoleOutput(self._output)
49
50 # Ugh. GladeKeeper actually isn't so good for composite objects.
51 # I want this connected to the ConsoleInput's handler, not something
52 # on this class.
53 self._input.connect("key_press_event", self.input._on_key_press_event)
54
55 def setDefaults(self, defaults):
56 self.defaults = defaults
57
58 def login(self):
59 client = self.getComponent(IManholeClient)
60 d = gtk2util.login(client, **self.defaults)
61 d.addCallback(self._cbLogin)
62 d.addCallback(client._cbLogin)
63 d.addErrback(self._ebLogin)
64
65 def _cbDisconnected(self, perspective):
66 self.output.append("%s went away. :(\n" % (perspective,), "local")
67 self._manholeWindow.set_title("Manhole")
68
69 def _cbLogin(self, perspective):
70 peer = perspective.broker.transport.getPeer()
71 self.output.append("Connected to %s\n" % (peer,), "local")
72 perspective.notifyOnDisconnect(self._cbDisconnected)
73 self._manholeWindow.set_title("Manhole - %s" % (peer))
74 return perspective
75
76 def _ebLogin(self, reason):
77 self.output.append("Login FAILED %s\n" % (reason.value,), "exception")
78
79 def _on_aboutMenuItem_activate(self, widget, *unused):
80 import sys
81 from os import path
82 self.output.append("""\
83 a Twisted Manhole client
84 Versions:
85 %(twistedVer)s
86 Python %(pythonVer)s on %(platform)s
87 GTK %(gtkVer)s / PyGTK %(pygtkVer)s
88 %(module)s %(modVer)s
89 http://twistedmatrix.com/
90 """ % {'twistedVer': copyright.longversion,
91 'pythonVer': sys.version.replace('\n', '\n '),
92 'platform': sys.platform,
93 'gtkVer': ".".join(map(str, gtk.gtk_version)),
94 'pygtkVer': ".".join(map(str, gtk.pygtk_version)),
95 'module': path.basename(__file__),
96 'modVer': __version__,
97 }, "local")
98
99 def _on_openMenuItem_activate(self, widget, userdata=None):
100 self.login()
101
102 def _on_manholeWindow_delete_event(self, widget, *unused):
103 reactor.stop()
104
105 def _on_quitMenuItem_activate(self, widget, *unused):
106 reactor.stop()
107
108 def on_reload_self_activate(self, *unused):
109 from twisted.python import rebuild
110 rebuild.rebuild(inspect.getmodule(self.__class__))
111
112
113 tagdefs = {
114 'default': {"family": "monospace"},
115 # These are message types we get from the server.
116 'stdout': {"foreground": "black"},
117 'stderr': {"foreground": "#AA8000"},
118 'result': {"foreground": "blue"},
119 'exception': {"foreground": "red"},
120 # Messages generate locally.
121 'local': {"foreground": "#008000"},
122 'log': {"foreground": "#000080"},
123 'command': {"foreground": "#666666"},
124 }
125
126 # TODO: Factor Python console stuff back out to pywidgets.
127
128 class ConsoleOutput:
129 _willScroll = None
130 def __init__(self, textView):
131 self.textView = textView
132 self.buffer = textView.get_buffer()
133
134 # TODO: Make this a singleton tag table.
135 for name, props in tagdefs.iteritems():
136 tag = self.buffer.create_tag(name)
137 # This can be done in the constructor in newer pygtk (post 1.99.14)
138 for k, v in props.iteritems():
139 tag.set_property(k, v)
140
141 self.buffer.tag_table.lookup("default").set_priority(0)
142
143 self._captureLocalLog()
144
145 def _captureLocalLog(self):
146 return log.startLogging(_Notafile(self, "log"), setStdout=False)
147
148 def append(self, text, kind=None):
149 # XXX: It seems weird to have to do this thing with always applying
150 # a 'default' tag. Can't we change the fundamental look instead?
151 tags = ["default"]
152 if kind is not None:
153 tags.append(kind)
154
155 self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(),
156 text, *tags)
157 # Silly things, the TextView needs to update itself before it knows
158 # where the bottom is.
159 if self._willScroll is None:
160 self._willScroll = gtk.idle_add(self._scrollDown)
161
162 def _scrollDown(self, *unused):
163 self.textView.scroll_to_iter(self.buffer.get_end_iter(), 0,
164 True, 1.0, 1.0)
165 self._willScroll = None
166 return False
167
168 class History:
169 def __init__(self, maxhist=10000):
170 self.ringbuffer = ['']
171 self.maxhist = maxhist
172 self.histCursor = 0
173
174 def append(self, htext):
175 self.ringbuffer.insert(-1, htext)
176 if len(self.ringbuffer) > self.maxhist:
177 self.ringbuffer.pop(0)
178 self.histCursor = len(self.ringbuffer) - 1
179 self.ringbuffer[-1] = ''
180
181 def move(self, prevnext=1):
182 '''
183 Return next/previous item in the history, stopping at top/bottom.
184 '''
185 hcpn = self.histCursor + prevnext
186 if hcpn >= 0 and hcpn < len(self.ringbuffer):
187 self.histCursor = hcpn
188 return self.ringbuffer[hcpn]
189 else:
190 return None
191
192 def histup(self, textbuffer):
193 if self.histCursor == len(self.ringbuffer) - 1:
194 si, ei = textbuffer.get_start_iter(), textbuffer.get_end_iter()
195 self.ringbuffer[-1] = textbuffer.get_text(si,ei)
196 newtext = self.move(-1)
197 if newtext is None:
198 return
199 textbuffer.set_text(newtext)
200
201 def histdown(self, textbuffer):
202 newtext = self.move(1)
203 if newtext is None:
204 return
205 textbuffer.set_text(newtext)
206
207
208 class ConsoleInput:
209 toplevel, rkeymap = None, None
210 __debug = False
211
212 def __init__(self, textView):
213 self.textView=textView
214 self.rkeymap = {}
215 self.history = History()
216 for name in dir(gtk.keysyms):
217 try:
218 self.rkeymap[getattr(gtk.keysyms, name)] = name
219 except TypeError:
220 pass
221
222 def _on_key_press_event(self, entry, event):
223 stopSignal = False
224 ksym = self.rkeymap.get(event.keyval, None)
225
226 mods = []
227 for prefix, mask in [('ctrl', gtk.gdk.CONTROL_MASK), ('shift', gtk.gdk.S HIFT_MASK)]:
228 if event.state & mask:
229 mods.append(prefix)
230
231 if mods:
232 ksym = '_'.join(mods + [ksym])
233
234 if ksym:
235 rvalue = getattr(
236 self, 'key_%s' % ksym, lambda *a, **kw: None)(entry, event)
237
238 if self.__debug:
239 print ksym
240 return rvalue
241
242 def getText(self):
243 buffer = self.textView.get_buffer()
244 iter1, iter2 = buffer.get_bounds()
245 text = buffer.get_text(iter1, iter2, False)
246 return text
247
248 def setText(self, text):
249 self.textView.get_buffer().set_text(text)
250
251 def key_Return(self, entry, event):
252 text = self.getText()
253 # Figure out if that Return meant "next line" or "execute."
254 try:
255 c = code.compile_command(text)
256 except SyntaxError, e:
257 # This could conceivably piss you off if the client's python
258 # doesn't accept keywords that are known to the manhole's
259 # python.
260 point = buffer.get_iter_at_line_offset(e.lineno, e.offset)
261 buffer.place(point)
262 # TODO: Componentize!
263 self.toplevel.output.append(str(e), "exception")
264 except (OverflowError, ValueError), e:
265 self.toplevel.output.append(str(e), "exception")
266 else:
267 if c is not None:
268 self.sendMessage()
269 # Don't insert Return as a newline in the buffer.
270 self.history.append(text)
271 self.clear()
272 # entry.emit_stop_by_name("key_press_event")
273 return True
274 else:
275 # not a complete code block
276 return False
277
278 return False
279
280 def key_Up(self, entry, event):
281 # if I'm at the top, previous history item.
282 textbuffer = self.textView.get_buffer()
283 if textbuffer.get_iter_at_mark(textbuffer.get_insert()).get_line() == 0:
284 self.history.histup(textbuffer)
285 return True
286 return False
287
288 def key_Down(self, entry, event):
289 textbuffer = self.textView.get_buffer()
290 if textbuffer.get_iter_at_mark(textbuffer.get_insert()).get_line() == (
291 textbuffer.get_line_count() - 1):
292 self.history.histdown(textbuffer)
293 return True
294 return False
295
296 key_ctrl_p = key_Up
297 key_ctrl_n = key_Down
298
299 def key_ctrl_shift_F9(self, entry, event):
300 if self.__debug:
301 import pdb; pdb.set_trace()
302
303 def clear(self):
304 buffer = self.textView.get_buffer()
305 buffer.delete(*buffer.get_bounds())
306
307 def sendMessage(self):
308 buffer = self.textView.get_buffer()
309 iter1, iter2 = buffer.get_bounds()
310 text = buffer.get_text(iter1, iter2, False)
311 self.toplevel.output.append(pythonify(text), 'command')
312 # TODO: Componentize better!
313 try:
314 return self.toplevel.getComponent(IManholeClient).do(text)
315 except OfflineError:
316 self.toplevel.output.append("Not connected, command not sent.\n",
317 "exception")
318
319
320 def pythonify(text):
321 '''
322 Make some text appear as though it was typed in at a Python prompt.
323 '''
324 lines = text.split('\n')
325 lines[0] = '>>> ' + lines[0]
326 return '\n... '.join(lines) + '\n'
327
328 class _Notafile:
329 """Curry to make failure.printTraceback work with the output widget."""
330 def __init__(self, output, kind):
331 self.output = output
332 self.kind = kind
333
334 def write(self, txt):
335 self.output.append(txt, self.kind)
336
337 def flush(self):
338 pass
339
340 class ManholeClient(components.Adapter, pb.Referenceable):
341 implements(IManholeClient)
342
343 capabilities = {
344 # "Explorer": 'Set',
345 "Failure": 'Set'
346 }
347
348 def _cbLogin(self, perspective):
349 self.perspective = perspective
350 perspective.notifyOnDisconnect(self._cbDisconnected)
351 return perspective
352
353 def remote_console(self, messages):
354 for kind, content in messages:
355 if isinstance(content, types.StringTypes):
356 self.original.output.append(content, kind)
357 elif (kind == "exception") and isinstance(content, failure.Failure):
358 content.printTraceback(_Notafile(self.original.output,
359 "exception"))
360 else:
361 self.original.output.append(str(content), kind)
362
363 def remote_receiveExplorer(self, xplorer):
364 pass
365
366 def remote_listCapabilities(self):
367 return self.capabilities
368
369 def _cbDisconnected(self, perspective):
370 self.perspective = None
371
372 def do(self, text):
373 if self.perspective is None:
374 raise OfflineError
375 return self.perspective.callRemote("do", text)
376
377 components.registerAdapter(ManholeClient, ManholeWindow, IManholeClient)
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/manhole/ui/gtk2manhole.glade ('k') | third_party/twisted_8_1/twisted/manhole/ui/gtkmanhole.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698