blob: c1f9b49f49c095b69da499ba5ef71fc96b7ceca0 [file] [log] [blame]
Just van Rossum40f9b7b1999-01-30 22:39:17 +00001import sys
2import bdb
3import types
4import os
5
6import W
7import WASTEconst
8import PyBrowser
9import Qd
10import Evt
11import Lists
12import MacOS
13_filenames = {}
14
15SIMPLE_TYPES = (
16 types.NoneType,
17 types.IntType,
18 types.LongType,
19 types.FloatType,
20 types.ComplexType,
21 types.StringType
22)
23
24
25class Debugger(bdb.Bdb):
26
27 def __init__(self, title = 'Debugger'):
28 bdb.Bdb.__init__(self)
29 self.closed = 1
30 self.title = title
31 self.breaksviewer = None
32 self.reset()
33 self.tracing = 0
34 self.tracingmonitortime = Evt.TickCount()
35 self.editors = {}
36
37 prefs = W.getapplication().getprefs()
38 if prefs.debugger:
39 for file, breaks in prefs.debugger.breaks.items():
40 for b in breaks:
41 self.set_break(file, b)
42 self.bounds, self.horpanes, self.verpanes = prefs.debugger.windowsettings
43 self.tracemagic = prefs.debugger.tracemagic
44 else:
45 self.breaks = {}
46 self.horpanes = (0.4, 0.6)
47 self.verpanes = (0.3, 0.35, 0.35)
48 self.bounds = (600, 400)
49 self.tracemagic = 0
50 self.laststacksel = None
51
52 def reset(self):
53 self.currentframe = None
54 self.file = None
55 self.laststack = None
56 self.reason = 'Not running'
57 self.continuewithoutdebugger = 0
58 bdb.Bdb.reset(self)
59 self.forget()
60
61 def start(self, bottomframe = None, running = 0):
62 W.getapplication().DebuggerQuit = bdb.BdbQuit
63 import Menu
64 Menu.HiliteMenu(0)
65 if self.closed:
66 self.setupwidgets(self.title)
67 self.closed = 0
68 if not self.w.parent.debugger_quitting:
69 self.w.select()
70 raise W.AlertError, 'There is another debugger session busy.'
71 self.reset()
72 self.botframe = bottomframe
73 if running:
74 self.set_continue()
Just van Rossumdc3c6172001-06-19 21:37:33 +000075 self.reason = 'Running\xc9'
Just van Rossum40f9b7b1999-01-30 22:39:17 +000076 self.setstate('running')
77 else:
78 self.set_step()
79 self.reason = 'stopped'
80 self.setstate('stopped')
81 sys.settrace(self.trace_dispatch)
82
83 def stop(self):
84 self.set_quit()
85 if self.w.parent:
86 self.exit_mainloop()
87 self.resetwidgets()
88
89 def set_continue_without_debugger(self):
90 sys.settrace(None)
91 self.set_quit()
92 self.clear_tracefuncs()
93 self.continuewithoutdebugger = 1
Just van Rossumcee9a481999-09-26 12:11:50 +000094 if hasattr(self, "w") and self.w.parent:
Just van Rossum40f9b7b1999-01-30 22:39:17 +000095 self.exit_mainloop()
96 self.resetwidgets()
97
98 def clear_tracefuncs(self):
99 try:
100 raise 'spam'
101 except:
102 pass
103 frame = sys.exc_traceback.tb_frame
104 while frame is not None:
105 del frame.f_trace
106 frame = frame.f_back
107
108 def postmortem(self, exc_type, exc_value, traceback):
109 if self.closed:
110 self.setupwidgets(self.title)
111 self.closed = 0
112 if not self.w.parent.debugger_quitting:
113 raise W.AlertError, 'There is another debugger session busy.'
114 self.reset()
115 if traceback:
116 self.botframe = traceback.tb_frame
117 while traceback.tb_next <> None:
118 traceback = traceback.tb_next
119 frame = traceback.tb_frame
120 else:
121 self.botframe = None
122 frame = None
123 self.w.panes.bottom.buttons.killbutton.enable(1)
124 self.reason = '(dead) ' + self.formatexception(exc_type, exc_value)
125 self.w.select()
126 self.setup(frame, traceback)
127 self.setstate('dead')
128 self.showstack(self.curindex)
129 self.showframe(self.curindex)
130
131 def setupwidgets(self, title):
132 self.w = w = W.Window(self.bounds, title, minsize = (500, 300))
133
134 w.panes = W.HorizontalPanes((8, 4, -8, -8), self.horpanes)
135
136 w.panes.browserpanes = browserpanes = W.VerticalPanes(None, self.verpanes)
137
138 browserpanes.stacklist = W.Group(None)
139 browserpanes.stacklist.title = W.TextBox((4, 0, 0, 12), 'Stack')
140 browserpanes.stacklist.stack = W.List((0, 16, 0, 0), callback = self.do_stack, flags = Lists.lOnlyOne)
141
142 browserpanes.locals = W.Group(None)
143 browserpanes.locals.title = W.TextBox((4, 0, 0, 12), 'Local variables')
144 browserpanes.locals.browser = PyBrowser.BrowserWidget((0, 16, 0, 0))
145
146 browserpanes.globals = W.Group(None)
147 browserpanes.globals.title = W.TextBox((4, 0, 0, 12), 'Global variables')
148 browserpanes.globals.browser = PyBrowser.BrowserWidget((0, 16, 0, 0))
149
150 w.panes.bottom = bottom = W.Group(None)
151 bottom.src = src = W.Group((0, 52, 0, 0))
152 source = SourceViewer((1, 1, -15, -15), readonly = 1, debugger = self)
153 src.optionsmenu = W.PopupMenu((-16, 0, 16, 16), [])
154 src.optionsmenu.bind('<click>', self.makeoptionsmenu)
155
156 src._barx = W.Scrollbar((0, -16, -15, 16), source.hscroll, max = 32767)
157 src._bary = W.Scrollbar((-16, 15, 16, -15), source.vscroll, max = 32767)
158 src.source = source
159 src.frame = W.Frame((0, 0, -15, -15))
160
161 bottom.tracingmonitor = TracingMonitor((0, 23, 6, 6))
162 bottom.state = W.TextBox((12, 20, 0, 16), self.reason)
163
164 bottom.srctitle = W.TextBox((12, 36, 0, 14))
165 bottom.buttons = buttons = W.Group((12, 0, 0, 16))
166
167 buttons.runbutton = W.Button((0, 0, 50, 16), "Run", self.do_run)
168 buttons.stopbutton = W.Button((58, 0, 50, 16), "Stop", self.do_stop)
169 buttons.killbutton = W.Button((116, 0, 50, 16), "Kill", self.do_kill)
170 buttons.line = W.VerticalLine((173, 0, 0, 0))
171 buttons.stepbutton = W.Button((181, 0, 50, 16), "Step", self.do_step)
172 buttons.stepinbutton = W.Button((239, 0, 50, 16), "Step in", self.do_stepin)
173 buttons.stepoutbutton = W.Button((297, 0, 50, 16), "Step out", self.do_stepout)
174
175 w.bind('cmdr', buttons.runbutton.push)
176 w.bind('cmd.', buttons.stopbutton.push)
177 w.bind('cmdk', buttons.killbutton.push)
178 w.bind('cmds', buttons.stepbutton.push)
179 w.bind('cmdt', buttons.stepinbutton.push)
180 w.bind('cmdu', buttons.stepoutbutton.push)
181
182 w.bind('<close>', self.close)
183
184 w.open()
185 w.xxx___select(w.panes.bottom.src.source)
186
187 def makeoptionsmenu(self):
188 options = [('Clear breakpoints', self.w.panes.bottom.src.source.clearbreakpoints),
189 ('Clear all breakpoints', self.clear_all_breaks),
Just van Rossumdc3c6172001-06-19 21:37:33 +0000190 ('Edit breakpoints\xc9', self.edit_breaks), '-',
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000191 (self.tracemagic and
192 'Disable __magic__ tracing' or 'Enable __magic__ tracing', self.togglemagic)]
193 self.w.panes.bottom.src.optionsmenu.set(options)
194
195 def edit_breaks(self):
196 if self.breaksviewer:
197 self.breaksviewer.select()
198 else:
199 self.breaksviewer = BreakpointsViewer(self)
200
201 def togglemagic(self):
202 self.tracemagic = not self.tracemagic
203
204 def setstate(self, state):
205 self.w.panes.bottom.tracingmonitor.reset()
206 self.w.panes.bottom.state.set(self.reason)
207 buttons = self.w.panes.bottom.buttons
208 if state == 'stopped':
209 buttons.runbutton.enable(1)
210 buttons.stopbutton.enable(0)
211 buttons.killbutton.enable(1)
212 buttons.stepbutton.enable(1)
213 buttons.stepinbutton.enable(1)
214 buttons.stepoutbutton.enable(1)
215 elif state == 'running':
216 buttons.runbutton.enable(0)
217 buttons.stopbutton.enable(1)
218 buttons.killbutton.enable(1)
219 buttons.stepbutton.enable(0)
220 buttons.stepinbutton.enable(0)
221 buttons.stepoutbutton.enable(0)
222 elif state == 'idle':
223 buttons.runbutton.enable(0)
224 buttons.stopbutton.enable(0)
225 buttons.killbutton.enable(0)
226 buttons.stepbutton.enable(0)
227 buttons.stepinbutton.enable(0)
228 buttons.stepoutbutton.enable(0)
229 elif state == 'dead':
230 buttons.runbutton.enable(0)
231 buttons.stopbutton.enable(0)
232 buttons.killbutton.enable(1)
233 buttons.stepbutton.enable(0)
234 buttons.stepinbutton.enable(0)
235 buttons.stepoutbutton.enable(0)
236 else:
237 print 'unknown state:', state
238
239 def resetwidgets(self):
240 self.reason = ''
241 self.w.panes.bottom.srctitle.set('')
242 self.w.panes.bottom.src.source.set('')
243 self.w.panes.browserpanes.stacklist.stack.set([])
244 self.w.panes.browserpanes.locals.browser.set({})
245 self.w.panes.browserpanes.globals.browser.set({})
246 self.setstate('idle')
247
248 # W callbacks
249
250 def close(self):
251 self.set_quit()
252 self.exit_mainloop()
253 self.closed = 1
254
255 self.unregister_editor(self.w.panes.bottom.src.source,
256 self.w.panes.bottom.src.source.file)
257 self.horpanes = self.w.panes.getpanesizes()
258 self.verpanes = self.w.panes.browserpanes.getpanesizes()
259 self.bounds = self.w.getbounds()
260 prefs = W.getapplication().getprefs()
261 prefs.debugger.breaks = self.breaks
262 prefs.debugger.windowsettings = self.bounds, self.horpanes, self.verpanes
263 prefs.debugger.tracemagic = self.tracemagic
264 prefs.save()
265
266 # stack list callback
267
268 def do_stack(self, isdbl):
269 sel = self.w.panes.browserpanes.stacklist.stack.getselection()
270 if isdbl:
271 if sel:
272 frame, lineno = self.stack[sel[0] + 1]
273 filename = frame.f_code.co_filename
274 editor = self.w._parentwindow.parent.openscript(filename, lineno)
275 if self.breaks.has_key(filename):
276 editor.showbreakpoints(1)
277 else:
278 if sel and sel <> self.laststacksel:
279 self.showframe(sel[0] + 1)
280 self.laststacksel = sel
281
282 def geteditor(self, filename):
283 if filename[:1] == '<' and filename[-1:] == '>':
284 editor = W.getapplication().getscript(filename[1:-1])
285 else:
286 editor = W.getapplication().getscript(filename)
287 return editor
288
289 # button callbacks
290
291 def do_run(self):
292 self.running()
293 self.set_continue()
294 self.exit_mainloop()
295
296 def do_stop(self):
297 self.set_step()
298
299 def do_kill(self):
300 self.set_quit()
301 self.exit_mainloop()
302 self.resetwidgets()
303
304 def do_step(self):
305 self.running()
306 self.set_next(self.curframe)
307 self.exit_mainloop()
308
309 def do_stepin(self):
310 self.running()
311 self.set_step()
312 self.exit_mainloop()
313
314 def do_stepout(self):
315 self.running()
316 self.set_return(self.curframe)
317 self.exit_mainloop()
318
319 def running(self):
320 W.SetCursor('watch')
Just van Rossumdc3c6172001-06-19 21:37:33 +0000321 self.reason = 'Running\xc9'
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000322 self.setstate('running')
323 #self.w.panes.bottom.src.source.set('')
324 #self.w.panes.browserpanes.stacklist.stack.set([])
325 #self.w.panes.browserpanes.locals.browser.set({})
326 #self.w.panes.browserpanes.globals.browser.set({})
327
328 def exit_mainloop(self):
329 self.w.parent.debugger_quitting = 1
330
331 #
332
333 def showframe(self, stackindex):
334 (frame, lineno) = self.stack[stackindex]
335 W.SetCursor('watch')
336 filename = frame.f_code.co_filename
337 if filename <> self.file:
338 editor = self.geteditor(filename)
339 if editor:
340 self.w.panes.bottom.src.source.set(editor.get(), filename)
341 else:
342 try:
343 f = open(filename, 'rb')
344 data = f.read()
345 f.close()
346 except IOError:
347 if filename[-3:] == '.py':
348 import imp
349 modname = os.path.basename(filename)[:-3]
350 try:
351 f, filename, (suff, mode, dummy) = imp.find_module(modname)
352 except ImportError:
Just van Rossumdc3c6172001-06-19 21:37:33 +0000353 self.w.panes.bottom.src.source.set("can't find file")
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000354 else:
355 if f:
356 f.close()
357 if f and suff == '.py':
358 f = open(filename, 'rb')
359 data = f.read()
360 f.close()
361 self.w.panes.bottom.src.source.set(data, filename)
362 else:
Just van Rossumdc3c6172001-06-19 21:37:33 +0000363 self.w.panes.bottom.src.source.set("can't find file")
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000364 else:
Just van Rossumdc3c6172001-06-19 21:37:33 +0000365 self.w.panes.bottom.src.source.set("can't find file")
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000366 else:
367 self.w.panes.bottom.src.source.set(data, filename)
368 self.file = filename
369 self.w.panes.bottom.srctitle.set('Source: ' + filename + ((lineno > 0) and (' (line %d)' % lineno) or ' '))
370 self.goto_line(lineno)
371 self.lineno = lineno
372 self.showvars((frame, lineno))
373
374 def showvars(self, (frame, lineno)):
375 if frame.f_locals is not frame.f_globals:
376 locals = frame.f_locals
377 else:
378 locals = {'Same as Globals':''}
379 filteredlocals = {}
380 for key, value in locals.items():
381 # empty key is magic for Python 1.4; '.' is magic for 1.5...
382 if not key or key[0] <> '.':
383 filteredlocals[key] = value
384 self.w.panes.browserpanes.locals.browser.set(filteredlocals)
385 self.w.panes.browserpanes.globals.browser.set(frame.f_globals)
386
387 def showstack(self, stackindex):
388 stack = []
389 for frame, lineno in self.stack[1:]:
390 filename = frame.f_code.co_filename
391 try:
392 filename = _filenames[filename]
393 except KeyError:
394 if filename[:1] + filename[-1:] <> '<>':
395 filename = os.path.basename(filename)
396 _filenames[frame.f_code.co_filename] = filename
397 funcname = frame.f_code.co_name
398 if funcname == '?':
399 funcname = '<toplevel>'
400 stack.append(filename + ': ' + funcname)
401 if stack <> self.laststack:
402 self.w.panes.browserpanes.stacklist.stack.set(stack)
403 self.laststack = stack
404 sel = [stackindex - 1]
405 self.w.panes.browserpanes.stacklist.stack.setselection(sel)
406 self.laststacksel = sel
407
408 def goto_line(self, lineno):
409 if lineno > 0:
410 self.w.panes.bottom.src.source.selectline(lineno - 1)
411 else:
412 self.w.panes.bottom.src.source.setselection(0, 0)
413
414 # bdb entry points
415
416# def user_call(self, frame, argument_list):
417# self.reason = 'Calling'
418# self.interaction(frame, None)
419
420 def user_line(self, frame):
421 # This function is called when we stop or break at this line
422 self.reason = 'Stopped'
423 self.interaction(frame, None)
424
425 def user_return(self, frame, return_value):
426 # This function is called when a return trap is set here
427 fname = frame.f_code.co_name
428 if fname <> '?':
429 self.reason = 'Returning from %s()' % frame.f_code.co_name
430 frame.f_locals['__return__'] = return_value
431 elif frame.f_back is self.botframe:
432 self.reason = 'Done'
433 else:
434 self.reason = 'Returning'
435 self.interaction(frame, None, 1)
436
437 def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
438 # This function is called when we stop or break at this line
439 self.reason = self.formatexception(exc_type, exc_value)
440 self.interaction(frame, exc_traceback)
441
442 def formatexception(self, exc_type, exc_value):
443 if exc_type == SyntaxError:
444 try:
445 value, (filename, lineno, charno, line) = exc_value
446 except:
447 pass
448 else:
449 return str(exc_type) + ': ' + str(value)
450 if type(exc_type) == types.ClassType:
451 nice = exc_type.__name__
452 else:
453 nice = str(exc_type)
454 value = str(exc_value)
455 if exc_value and value:
456 nice = nice + ": " + value
457 return nice
458
459 def forget(self):
460 self.stack = []
461 self.curindex = 0
462 self.curframe = None
463
464 def setup(self, f, t, isreturning = 0):
465 self.forget()
466 self.stack, self.curindex = self.get_stack(f, t)
467 self.curframe = self.stack[self.curindex - isreturning][0]
468
469 def interaction(self, frame, traceback, isreturning = 0):
470 saveport = Qd.GetPort()
471 self.w.select()
472 try:
473 self.setup(frame, traceback, isreturning)
474 self.setstate('stopped')
475 stackindex = self.curindex
476 if isreturning:
477 if frame.f_back is not self.botframe:
478 stackindex = stackindex - 1
479 self.showstack(stackindex)
480 self.showframe(stackindex)
481 self.w.parent.debugger_mainloop()
482 self.forget()
483 finally:
484 Qd.SetPort(saveport)
485
486 # bdb customization
487
488 def trace_dispatch(self, frame, event, arg, TickCount = Evt.TickCount):
489 if TickCount() - self.tracingmonitortime > 15:
490 self.tracingmonitortime = TickCount()
491 self.w.panes.bottom.tracingmonitor.toggle()
492 try:
493 try:
494 MacOS.EnableAppswitch(0)
495 if self.quitting:
496 # returning None is not enough, a former BdbQuit exception
497 # might have been eaten by the print statement
498 raise bdb.BdbQuit
499 if event == 'line':
500 return self.dispatch_line(frame)
501 if event == 'call':
502 return self.dispatch_call(frame, arg)
503 if event == 'return':
504 return self.dispatch_return(frame, arg)
505 if event == 'exception':
506 return self.dispatch_exception(frame, arg)
507 print 'bdb.Bdb.dispatch: unknown debugging event:', `event`
508 return self.trace_dispatch
509 finally:
510 MacOS.EnableAppswitch(-1)
511 except KeyboardInterrupt:
512 self.set_step()
513 return self.trace_dispatch
514 except bdb.BdbQuit:
515 if self.continuewithoutdebugger:
516 self.clear_tracefuncs()
517 return
518 else:
519 raise bdb.BdbQuit
520 except:
521 print 'XXX Exception during debugger interaction.', \
522 self.formatexception(sys.exc_type, sys.exc_value)
523 import traceback
524 traceback.print_exc()
525 return self.trace_dispatch
526
527 def dispatch_call(self, frame, arg):
528 if not self.tracemagic and \
529 frame.f_code.co_name[:2] == '__' == frame.f_code.co_name[-2:] and \
530 frame.f_code.co_name <> '__init__':
531 return
532 if self.botframe is None:
533 # First call of dispatch since reset()
534 self.botframe = frame.f_back # xxx !!! added f_back
535 return self.trace_dispatch
536 if not (self.stop_here(frame) or self.break_anywhere(frame)):
537 # No need to trace this function
538 return # None
539 self.user_call(frame, arg)
540 if self.quitting:
541 raise bdb.BdbQuit
542 return self.trace_dispatch
543
544 def set_continue(self):
545 # Don't stop except at breakpoints or when finished
546 self.stopframe = self.botframe
547 self.returnframe = None
548 self.quitting = 0
549 # unlike in bdb/pdb, there's a chance that breakpoints change
550 # *while* a program (this program ;-) is running. It's actually quite likely.
551 # So we don't delete frame.f_trace until the bottom frame if there are no breakpoints.
552
553 def set_break(self, filename, lineno):
554 if not self.breaks.has_key(filename):
555 self.breaks[filename] = []
556 list = self.breaks[filename]
557 if lineno in list:
558 return 'There is already a breakpoint there!'
559 list.append(lineno)
560 list.sort() # I want to keep them neatly sorted; easier for drawing
561 if hasattr(bdb, "Breakpoint"):
562 # 1.5.2b1 specific
563 bp = bdb.Breakpoint(filename, lineno, 0, None)
564 self.update_breaks(filename)
565
566 def clear_break(self, filename, lineno):
567 bdb.Bdb.clear_break(self, filename, lineno)
568 self.update_breaks(filename)
569
570 def clear_all_file_breaks(self, filename):
571 bdb.Bdb.clear_all_file_breaks(self, filename)
572 self.update_breaks(filename)
573
574 def clear_all_breaks(self):
575 bdb.Bdb.clear_all_breaks(self)
576 for editors in self.editors.values():
577 for editor in editors:
578 editor.drawbreakpoints()
579
580 # special
581
582 def toggle_break(self, filename, lineno):
583 if self.get_break(filename, lineno):
584 self.clear_break(filename, lineno)
585 else:
586 self.set_break(filename, lineno)
587
588 def clear_breaks_above(self, filename, above):
589 if not self.breaks.has_key(filename):
590 return 'There are no breakpoints in that file!'
591 for lineno in self.breaks[filename][:]:
592 if lineno > above:
593 self.breaks[filename].remove(lineno)
594 if not self.breaks[filename]:
595 del self.breaks[filename]
596
597 # editor stuff
598
599 def update_breaks(self, filename):
600 if self.breaksviewer:
601 self.breaksviewer.update()
602 if self.editors.has_key(filename):
603 for editor in self.editors[filename]:
604 if editor._debugger: # XXX
605 editor.drawbreakpoints()
606 else:
607 print 'xxx dead editor!'
608
609 def update_allbreaks(self):
610 if self.breaksviewer:
611 self.breaksviewer.update()
612 for filename in self.breaks.keys():
613 if self.editors.has_key(filename):
614 for editor in self.editors[filename]:
615 if editor._debugger: # XXX
616 editor.drawbreakpoints()
617 else:
618 print 'xxx dead editor!'
619
620 def register_editor(self, editor, filename):
621 if not filename:
622 return
623 if not self.editors.has_key(filename):
624 self.editors[filename] = [editor]
625 elif editor not in self.editors[filename]:
626 self.editors[filename].append(editor)
627
628 def unregister_editor(self, editor, filename):
629 if not filename:
630 return
631 try:
632 self.editors[filename].remove(editor)
633 if not self.editors[filename]:
634 del self.editors[filename]
635 # if this was an untitled window, clear the breaks.
636 if filename[:1] == '<' and filename[-1:] == '>' and \
637 self.breaks.has_key(filename):
638 self.clear_all_file_breaks(filename)
639 except (KeyError, ValueError):
640 pass
641
642
643class SourceViewer(W.PyEditor):
644
645 def __init__(self, *args, **kwargs):
646 apply(W.PyEditor.__init__, (self,) + args, kwargs)
647 self.bind('<click>', self.clickintercept)
648
649 def clickintercept(self, point, modifiers):
650 if self._parentwindow._currentwidget <> self and not self.pt_in_breaks(point):
651 self._parentwindow.xxx___select(self)
652 return 1
653
654 def _getviewrect(self):
655 l, t, r, b = self._bounds
656 if self._debugger:
657 return (l + 12, t + 2, r - 1, b - 2)
658 else:
659 return (l + 5, t + 2, r - 1, b - 2)
660
661 def select(self, onoff, isclick = 0):
662 if W.SelectableWidget.select(self, onoff):
663 return
664 self.SetPort()
665 #if onoff:
666 # self.ted.WEActivate()
667 #else:
668 # self.ted.WEDeactivate()
669 self.drawselframe(onoff)
670
671 def drawselframe(self, onoff):
672 pass
673
674
675class BreakpointsViewer:
676
677 def __init__(self, debugger):
678 self.debugger = debugger
679 import Lists
680 self.w = W.Window((300, 250), 'Breakpoints', minsize = (200, 200))
681 self.w.panes = W.HorizontalPanes((8, 8, -8, -32), (0.3, 0.7))
682 self.w.panes.files = W.List(None, callback = self.filehit) #, flags = Lists.lOnlyOne)
683 self.w.panes.gr = W.Group(None)
684 self.w.panes.gr.breaks = W.List((0, 0, -130, 0), callback = self.linehit) #, flags = Lists.lOnlyOne)
Just van Rossumdc3c6172001-06-19 21:37:33 +0000685 self.w.panes.gr.openbutton = W.Button((-80, 4, 0, 16), 'View\xc9', self.openbuttonhit)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000686 self.w.panes.gr.deletebutton = W.Button((-80, 28, 0, 16), 'Delete', self.deletebuttonhit)
687
688 self.w.bind('<close>', self.close)
689 self.w.bind('backspace', self.w.panes.gr.deletebutton.push)
690
691 self.setup()
692 self.w.open()
693 self.w.panes.gr.openbutton.enable(0)
694 self.w.panes.gr.deletebutton.enable(0)
695 self.curfile = None
696
697 def deletebuttonhit(self):
698 if self.w._currentwidget == self.w.panes.files:
699 self.del_filename()
700 else:
701 self.del_number()
702 self.checkbuttons()
703
704 def del_number(self):
705 if self.curfile is None:
706 return
707 sel = self.w.panes.gr.breaks.getselectedobjects()
708 for lineno in sel:
709 self.debugger.clear_break(self.curfile, lineno)
710
711 def del_filename(self):
712 sel = self.w.panes.files.getselectedobjects()
713 for filename in sel:
714 self.debugger.clear_all_file_breaks(filename)
715 self.debugger.update_allbreaks()
716
717 def setup(self):
718 files = self.debugger.breaks.keys()
719 files.sort()
720 self.w.panes.files.set(files)
721
722 def close(self):
723 self.debugger.breaksviewer = None
724 self.debugger = None
725
726 def update(self):
727 sel = self.w.panes.files.getselectedobjects()
728 self.setup()
729 self.w.panes.files.setselectedobjects(sel)
730 sel = self.w.panes.files.getselection()
731 if len(sel) == 0 and self.curfile:
732 self.w.panes.files.setselectedobjects([self.curfile])
733 self.filehit(0)
734
735 def select(self):
736 self.w.select()
737
738 def selectfile(self, file):
739 self.w.panes.files.setselectedobjects([file])
740 self.filehit(0)
741
742 def openbuttonhit(self):
743 self.filehit(1)
744
745 def filehit(self, isdbl):
746 sel = self.w.panes.files.getselectedobjects()
747 if isdbl:
748 for filename in sel:
749 lineno = None
750 if filename == self.curfile:
751 linesel = self.w.panes.gr.breaks.getselectedobjects()
752 if linesel:
753 lineno = linesel[-1]
754 elif self.w.panes.gr.breaks:
755 lineno = self.w.panes.gr.breaks[0]
756 editor = self.w._parentwindow.parent.openscript(filename, lineno)
757 editor.showbreakpoints(1)
758 return
759 if len(sel) == 1:
760 file = sel[0]
761 filebreaks = self.debugger.breaks[file][:]
762 if self.curfile == file:
763 linesel = self.w.panes.gr.breaks.getselectedobjects()
764 self.w.panes.gr.breaks.set(filebreaks)
765 if self.curfile == file:
766 self.w.panes.gr.breaks.setselectedobjects(linesel)
767 self.curfile = file
768 else:
769 if len(sel) <> 0:
770 self.curfile = None
771 self.w.panes.gr.breaks.set([])
772 self.checkbuttons()
773
774 def linehit(self, isdbl):
775 if isdbl:
776 files = self.w.panes.files.getselectedobjects()
777 if len(files) <> 1:
778 return
779 filename = files[0]
780 linenos = self.w.panes.gr.breaks.getselectedobjects()
781 if not linenos:
782 return
783 lineno = linenos[-1]
784 editor = self.w._parentwindow.parent.openscript(filename, lineno)
785 editor.showbreakpoints(1)
786 self.checkbuttons()
787
788 def checkbuttons(self):
789 if self.w.panes.files.getselection():
790 self.w.panes.gr.openbutton.enable(1)
791 self.w._parentwindow.setdefaultbutton(self.w.panes.gr.openbutton)
792 if self.w._currentwidget == self.w.panes.files:
793 if self.w.panes.files.getselection():
794 self.w.panes.gr.deletebutton.enable(1)
795 else:
796 self.w.panes.gr.deletebutton.enable(0)
797 else:
798 if self.w.panes.gr.breaks.getselection():
799 self.w.panes.gr.deletebutton.enable(1)
800 else:
801 self.w.panes.gr.deletebutton.enable(0)
802 else:
803 self.w.panes.gr.openbutton.enable(0)
804 self.w.panes.gr.deletebutton.enable(0)
805
806
807class TracingMonitor(W.Widget):
808
809 def __init__(self, *args, **kwargs):
810 apply(W.Widget.__init__, (self,) + args, kwargs)
811 self.state = 0
812
813 def toggle(self):
814 if hasattr(self, "_parentwindow") and self._parentwindow is not None:
815 self.state = self.state % 2 + 1
816 port = Qd.GetPort()
817 self.SetPort()
818 self.draw()
819 Qd.SetPort(port)
820
821 def reset(self):
822 if self._parentwindow:
823 self.state = 0
824 port = Qd.GetPort()
825 self.SetPort()
826 self.draw()
827 Qd.SetPort(port)
828
829 def draw(self, visRgn = None):
830 if self.state == 2:
831 Qd.PaintOval(self._bounds)
832 else:
833 Qd.EraseOval(self._bounds)
834
835
836# convenience funcs
837
838def postmortem(exc_type, exc_value, tb):
839 d = getdebugger()
840 d.postmortem(exc_type, exc_value, tb)
841
842def start(bottomframe = None):
843 d = getdebugger()
844 d.start(bottomframe)
845
846def startfromhere():
847 d = getdebugger()
848 try:
849 raise 'spam'
850 except:
851 frame = sys.exc_traceback.tb_frame.f_back
852 d.start(frame)
853
854def startfrombottom():
855 d = getdebugger()
856 d.start(_getbottomframe(), 1)
857
858def stop():
859 d = getdebugger()
860 d.stop()
861
862def cont():
863 sys.settrace(None)
864 d = getdebugger()
865 d.set_continue_without_debugger()
866
867def _getbottomframe():
868 try:
869 raise 'spam'
870 except:
871 pass
872 frame = sys.exc_traceback.tb_frame
873 while 1:
874 if frame.f_code.co_name == 'mainloop' or frame.f_back is None:
875 break
876 frame = frame.f_back
877 return frame
878
879_debugger = None
880
881def getdebugger():
882 if not __debug__:
Just van Rossumdc3c6172001-06-19 21:37:33 +0000883 raise W.AlertError, "Can't debug in \"Optimize bytecode\" mode.\r(see \"Default startup options\" in EditPythonPreferences)"
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000884 global _debugger
885 if _debugger is None:
886 _debugger = Debugger()
887 return _debugger