diff options
Diffstat (limited to 'Lib/stdwin')
-rwxr-xr-x | Lib/stdwin/basewin.py | 65 | ||||
-rwxr-xr-x | Lib/stdwin/srcwin.py | 103 | ||||
-rwxr-xr-x | Lib/stdwin/wdb.py | 282 | ||||
-rwxr-xr-x | Lib/stdwin/wdbframewin.py | 108 | ||||
-rwxr-xr-x | Lib/stdwin/wdbsrcwin.py | 97 |
5 files changed, 655 insertions, 0 deletions
diff --git a/Lib/stdwin/basewin.py b/Lib/stdwin/basewin.py new file mode 100755 index 0000000..f896fe2 --- /dev/null +++ b/Lib/stdwin/basewin.py @@ -0,0 +1,65 @@ +# basewin.py + +import stdwin +import mainloop +from stdwinevents import * + +class BaseWindow: + + def init(self, title): + self.win = stdwin.open(title) + self.win.dispatch = self.dispatch + mainloop.register(self.win) + return self + +# def reopen(self): +# title = self.win.gettitle() +# winpos = self.win.getwinpos() +# winsize = self.win.getwinsize() +# origin = self.win.getorigin() +# docsize = self.win.getdocsize() +# mainloop.unregister(self.win) +# del self.win.dispatch +# self.win.close() +# stdwin.setdefwinpos(winpos) +# stdwin.setdefwinsize(winsize) +# self.win = stdwin.open(title) +# stdwin.setdefwinpos(0, 0) +# stdwin.setdefwinsize(0, 0) +# self.win.setdocsize(docsize) +# self.win.setorigin(origin) +# self.win.dispatch = self.dispatch +# mainloop.register(self.win) + + def popup(self): + if self.win is not stdwin.getactive(): + self.win.setactive() + + def close(self): + mainloop.unregister(self.win) + del self.win.dispatch + self.win.close() + + def dispatch(self, event): + type, win, detail = event + if type == WE_CHAR: + self.char(detail) + elif type == WE_COMMAND: + self.command(detail) + elif type == WE_MOUSE_DOWN: + self.mouse_down(detail) + elif type == WE_MOUSE_MOVE: + self.mouse_move(detail) + elif type == WE_MOUSE_UP: + self.mouse_up(detail) + elif type == WE_DRAW: + self.draw(detail) + elif type == WE_CLOSE: + self.close() + + def no_op(self, detail): + pass + char = command = mouse_down = mouse_move = mouse_up = draw = no_op + + def refreshall(self): + self.win.change((-10, 0), (10000, 30000)) diff --git a/Lib/stdwin/srcwin.py b/Lib/stdwin/srcwin.py new file mode 100755 index 0000000..3f323ba --- /dev/null +++ b/Lib/stdwin/srcwin.py @@ -0,0 +1,103 @@ +# srcwin.py -- a source listing window + +import stdwin +from stdwinevents import * +import basewin + +WIDTH = 40 +MAXHEIGHT = 24 + +class SourceWindow(basewin.BaseWindow): + + def init(self, filename): + self.filename = filename + # + f = open(self.filename, 'r') # raise exception if not found + self.contents = f.read() + f.seek(0) + self.linecount = len(f.readlines()) + f.close() + # + self.lineheight = lh = stdwin.lineheight() + self.leftmargin = stdwin.textwidth('00000000') + self.rightmargin = 30000 # Infinity + self.bottom = lh * self.linecount + # + stdwin.setdefwinpos(0, 0) + width = WIDTH*stdwin.textwidth('0') + height = lh*min(MAXHEIGHT, self.linecount) + stdwin.setdefwinsize(width, height) + self = basewin.BaseWindow.init(self, filename) + # + self.win.setdocsize(0, self.bottom + lh) + self.initeditor() + return self + + def initeditor(self): + r = (self.leftmargin, 0), (self.rightmargin, self.bottom) + self.editor = self.win.textcreate(r) + self.editor.settext(self.contents) + + def closeeditor(self): + self.editor.close() + + def reopen(self): + self.closeeditor() + basewin.BaseWindow.reopen(self) + self.initeditor() + + def close(self): + self.closeeditor() + basewin.BaseWindow.close(self) + + # Override this method to format line numbers differently + def getmark(self, lineno): + return `lineno` + + def dispatch(self, event): + if event[0] == WE_NULL: return # Dummy tested by mainloop + if event[0] == WE_DRAW or not self.editor.event(event): + basewin.BaseWindow.dispatch(self, event) + + def draw(self, detail): + dummy = self.editor.draw(detail) + # Draw line numbers + (left, top), (right, bottom) = detail + topline = top/self.lineheight + botline = bottom/self.lineheight + 1 + botline = min(self.linecount, botline) + d = self.win.begindrawing() + try: + h, v = 0, self.lineheight * topline + for lineno in range(topline+1, botline+1): + d.text((h, v), self.getmark(lineno)) + v = v + self.lineheight + finally: + d.close() + + def changemark(self, lineno): + left = 0 + top = (lineno-1) * self.lineheight + right = self.leftmargin + bottom = lineno * self.lineheight + d = self.win.begindrawing() + try: + d.erase((left, top), (right, bottom)) + d.text((left, top), self.getmark(lineno)) + finally: + d.close() + + def showline(self, lineno): + left = 0 + top = (lineno-1) * self.lineheight + right = self.leftmargin + bottom = lineno * self.lineheight + self.win.show((left, top), (right, bottom)) + + +TESTFILE = 'srcwin.py' + +def test(): + import mainloop + sw = SourceWindow().init(TESTFILE) + mainloop.mainloop() diff --git a/Lib/stdwin/wdb.py b/Lib/stdwin/wdb.py new file mode 100755 index 0000000..89b03f5 --- /dev/null +++ b/Lib/stdwin/wdb.py @@ -0,0 +1,282 @@ +# wdb.py -- a window-based Python debugger + +import stdwin +from stdwinevents import * +import sys +import basewin +import bdb +import repr + +WIDTH = 40 +HEIGHT = 8 + +WdbDone = 'wdb.WdbDone' # Exception to continue execution + + +class Wdb(bdb.Bdb, basewin.BaseWindow): # Window debugger + + def init(self): + self.sourcewindows = {} + self.framewindows = {} + self = bdb.Bdb.init(self) + width = WIDTH*stdwin.textwidth('0') + height = HEIGHT*stdwin.lineheight() + stdwin.setdefwinsize(width, height) + self = basewin.BaseWindow.init(self, '--Stack--') + self.closed = 0 + return self + + def reset(self): + if self.closed: raise RuntimeError, 'already closed' + bdb.Bdb.reset(self) + self.forget() + + def forget(self): + self.lineno = None + self.stack = [] + self.curindex = 0 + self.curframe = None + for fn in self.sourcewindows.keys(): + self.sourcewindows[fn].resetlineno() + + def setup(self, f, t): + self.forget() + self.stack, self.curindex = self.get_stack(f, t) + self.curframe = self.stack[self.curindex][0] + # Build a list of current frames + cfl = [] + for f, i in self.stack: cfl.append(f) + # Remove deactivated frame windows + for name in self.framewindows.keys(): + fw = self.framewindows[name] + if fw.frame not in cfl: fw.close() + else: fw.refreshframe() + # Refresh the stack window + self.refreshstack() + + # Override Bdb methods (except user_call, for now) + + def user_line(self, frame): + # This function is called when we stop or break at this line + self.interaction(frame, None) + + def user_return(self, frame, return_value): + # This function is called when a return trap is set here + frame.f_locals['__return__'] = return_value + self.settitle('--Return--') + self.interaction(frame, None) + self.settitle('--Stack--') + + def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): + # This function is called if an exception occurs, + # but only if we are to stop at or just below this level + frame.f_locals['__exception__'] = exc_type, exc_value + self.settitle(exc_type + ': ' + repr.repr(exc_value)) + self.interaction(frame, exc_traceback) + self.settitle('--Stack--') + + # Change the title + + def settitle(self, title): + self.savetitle = self.win.gettitle() + self.win.settitle(title) + + # General interaction function + + def interaction(self, frame, traceback): + import mainloop + self.popup() + self.setup(frame, traceback) + try: + mainloop.mainloop() + except WdbDone: + pass + self.forget() + + # Functions whose name is do_X for some character X + # are callable directly from the keyboard. + + def do_up(self): + if self.curindex == 0: + stdwin.fleep() + else: + self.curindex = self.curindex - 1 + self.curframe = self.stack[self.curindex][0] + self.refreshstack() + do_u = do_up + + def do_down(self): + if self.curindex + 1 == len(self.stack): + stdwin.fleep() + else: + self.curindex = self.curindex + 1 + self.curframe = self.stack[self.curindex][0] + self.refreshstack() + do_d = do_down + + def do_step(self): + self.set_step() + raise WdbDone + do_s = do_step + + def do_next(self): + self.set_next(self.curframe) + raise WdbDone + do_n = do_next + + def do_return(self): + self.set_return(self.curframe) + raise WdbDone + do_r = do_return + + def do_continue(self): + self.set_continue() + raise WdbDone + do_c = do_cont = do_continue + + def do_quit(self): + self.close() + raise WdbDone + do_q = do_quit + + def do_list(self): + fn = self.curframe.f_code.co_filename + if not self.sourcewindows.has_key(fn): + import wdbsrcwin + try: + self.sourcewindows[fn] = \ + wdbsrcwin.DebuggerSourceWindow(). \ + init(self, fn) + except IOError: + stdwin.fleep() + return + w = self.sourcewindows[fn] + lineno = self.stack[self.curindex][1] + w.setlineno(lineno) + w.popup() + do_l = do_list + + def do_frame(self): + name = 'locals' + `self.curframe`[16:-1] + if self.framewindows.has_key(name): + self.framewindows[name].popup() + else: + import wdbframewin + self.framewindows[name] = \ + wdbframewin.FrameWindow().init(self, \ + self.curframe, \ + self.curframe.f_locals, name) + do_f = do_frame + + def do_globalframe(self): + name = 'globals' + `self.curframe`[16:-1] + if self.framewindows.has_key(name): + self.framewindows[name].popup() + else: + import wdbframewin + self.framewindows[name] = \ + wdbframewin.FrameWindow().init(self, \ + self.curframe, \ + self.curframe.f_globals, name) + do_g = do_globalframe + + # Link between the debugger and the window + + def refreshstack(self): + height = stdwin.lineheight() * (1 + len(self.stack)) + self.win.setdocsize((0, height)) + self.refreshall() # XXX be more subtle later + # Also pass the information on to the source windows + filename = self.curframe.f_code.co_filename + lineno = self.curframe.f_lineno + for fn in self.sourcewindows.keys(): + w = self.sourcewindows[fn] + if fn == filename: + w.setlineno(lineno) + else: + w.resetlineno() + + # The remaining methods override BaseWindow methods + + def close(self): + if not self.closed: + basewin.BaseWindow.close(self) + self.closed = 1 + for key in self.sourcewindows.keys(): + self.sourcewindows[key].close() + for key in self.framewindows.keys(): + self.framewindows[key].close() + self.set_quit() + + def char(self, detail): + try: + func = eval('self.do_' + detail) + except (AttributeError, SyntaxError): + stdwin.fleep() + return + func() + + def command(self, detail): + if detail == WC_UP: + self.do_up() + elif detail == WC_DOWN: + self.do_down() + + def mouse_down(self, detail): + (h, v), clicks, button, mask = detail + i = v / stdwin.lineheight() + if 0 <= i < len(self.stack): + if i != self.curindex: + self.curindex = i + self.curframe = self.stack[self.curindex][0] + self.refreshstack() + elif clicks == 2: + self.do_frame() + else: + stdwin.fleep() + + def draw(self, detail): + import linecache, codehack, string + d = self.win.begindrawing() + try: + h, v = 0, 0 + for f, lineno in self.stack: + fn = f.f_code.co_filename + if f is self.curframe: + s = '> ' + else: + s = ' ' + s = s + fn + '(' + `lineno` + ')' + s = s + codehack.getcodename(f.f_code) + if f.f_locals.has_key('__args__'): + args = f.f_locals['__args__'] + if args is not None: + s = s + repr.repr(args) + if f.f_locals.has_key('__return__'): + rv = f.f_locals['__return__'] + s = s + '->' + s = s + repr.repr(rv) + line = linecache.getline(fn, lineno) + if line: s = s + ': ' + string.strip(line) + d.text((h, v), s) + v = v + d.lineheight() + finally: + d.close() + + +def run(statement): + x = Wdb().init() + try: x.run(statement) + finally: x.close() + +def runctx(statement, globals, locals): + x = Wdb().init() + try: x.runctx(statement, globals, locals) + finally: x.close() + +TESTCMD = 'import x; x.main()' + +def test(): + import linecache + linecache.checkcache() + run(TESTCMD) diff --git a/Lib/stdwin/wdbframewin.py b/Lib/stdwin/wdbframewin.py new file mode 100755 index 0000000..422baa2 --- /dev/null +++ b/Lib/stdwin/wdbframewin.py @@ -0,0 +1,108 @@ +# wdb.py -- a window-based Python debugger + +import stdwin +from stdwinevents import * +import basewin +import sys + +WIDTH = 40 +MAXHEIGHT = 16 + +class FrameWindow(basewin.BaseWindow): + + def init(self, debugger, frame, dict, name): + self.debugger = debugger + self.frame = frame # Not used except for identity tests + self.dict = dict + self.name = name + nl = max(4, len(self.dict)) + nl = min(nl, MAXHEIGHT) + width = WIDTH*stdwin.textwidth('0') + height = nl*stdwin.lineheight() + stdwin.setdefwinsize(width, height) + self = basewin.BaseWindow.init(self, '--Frame ' + name + '--') + self.initeditor() + self.displaylist = ['>>>', '', '-'*WIDTH] + self.refreshframe() + return self + + def initeditor(self): + r = (stdwin.textwidth('>>> '), 0), (30000, stdwin.lineheight()) + self.editor = self.win.textcreate(r) + + def closeeditor(self): + self.editor.close() + + def dispatch(self, event): + type, win, detail = event + if type == WE_NULL: return # Dummy tested by mainloop + if type in (WE_DRAW, WE_COMMAND) \ + or not self.editor.event(event): + basewin.BaseWindow.dispatch(self, event) + + def close(self): + del self.debugger.framewindows[self.name] + del self.debugger, self.dict + self.closeeditor() + basewin.BaseWindow.close(self) + + def command(self, detail): + if detail == WC_RETURN: + self.re_eval() + else: + dummy = self.editor.event(WE_COMMAND, \ + self.win, detail) + + def re_eval(self): + import string, repr + expr = string.strip(self.editor.gettext()) + if expr == '': + output = '' + else: + globals = self.frame.f_globals + locals = self.frame.f_locals + try: + value = eval(expr, globals, locals) + output = repr.repr(value) + except: + output = sys.exc_type + ': ' + `sys.exc_value` + self.displaylist[1] = output + lh = stdwin.lineheight() + r = (-10, 0), (30000, 2*lh) + self.win.change(r) + self.editor.setfocus(0, len(expr)) + + def draw(self, detail): + (left, top), (right, bottom) = detail + dummy = self.editor.draw(detail) + d = self.win.begindrawing() + try: + lh = d.lineheight() + h, v = 0, 0 + for line in self.displaylist: + if v+lh > top and v < bottom: + d.text((h, v), line) + v = v + lh + finally: + d.close() + + def refreshframe(self): + import repr + del self.displaylist[3:] + self.re_eval() + names = self.dict.keys() + for key, label in ('__args__', 'Args: '), \ + ('__return__', 'Return: '): + if self.dict.has_key(key): + names.remove(key) + value = self.dict[key] + label = label + repr.repr(value) + self.displaylist.append(label) + names.sort() + for name in names: + value = self.dict[name] + line = name + ' = ' + repr.repr(value) + self.displaylist.append(line) + self.win.setdocsize(0, \ + stdwin.lineheight() * len(self.displaylist)) + self.refreshall() # XXX Be more subtle later diff --git a/Lib/stdwin/wdbsrcwin.py b/Lib/stdwin/wdbsrcwin.py new file mode 100755 index 0000000..c5de928 --- /dev/null +++ b/Lib/stdwin/wdbsrcwin.py @@ -0,0 +1,97 @@ +# wdbsrcwin.py -- source window for wdb + +import stdwin +from stdwinevents import * +import srcwin + + +class DebuggerSourceWindow(srcwin.SourceWindow): + + def init(self, debugger, filename): + self.debugger = debugger + self.curlineno = 0 + self.focus = 0 + return srcwin.SourceWindow.init(self, filename) + + def close(self): + del self.debugger.sourcewindows[self.filename] + del self.debugger + srcwin.SourceWindow.close(self) + + def dispatch(self, event): + type, win, detail = event + if type == WE_CHAR: + self.char(detail) + elif type == WE_COMMAND: + self.command(detail) + elif type == WE_MOUSE_DOWN: + self.mouse_down(detail) + else: + srcwin.SourceWindow.dispatch(self, event) + + def char(self, detail): + self.debugger.char(detail) + + def command(self, detail): + self.debugger.command(detail) + + def mouse_down(self, detail): + (h, v), clicks, button, mask = detail + if h >= self.leftmargin: + srcwin.SourceWindow.dispatch(self, \ + (WE_MOUSE_DOWN, self.win, detail)) + return + lineno = v/self.lineheight + 1 + if 1 <= lineno <= self.linecount: + if self.debugger.get_break(self.filename, lineno): + f = self.debugger.clear_break + else: + f = self.debugger.set_break + err = f(self.filename, lineno) + if err: stdwin.message(err) + else: self.changemark(lineno) + else: + stdwin.fleep() + + def getmark(self, lineno): + s = `lineno` + if lineno == self.focus: + s = '[' + s + ']' + else: + s = ' ' + s + ' ' + if lineno == self.curlineno: + s = s + '->' + else: + s = s + ' ' + br = self.debugger.breaks + if br.has_key(self.filename) and lineno in br[self.filename]: + s = s + 'B' + else: + s = s + ' ' + return s + + def setlineno(self, newlineno): + if newlineno != self.curlineno: + oldlineno = self.curlineno + self.curlineno = newlineno + self.changemark(oldlineno) + self.changemark(newlineno) + if newlineno != 0: + self.showline(newlineno) + + def resetlineno(self): + self.setlineno(0) + + def setfocus(self, newfocus): + if newfocus != self.focus: + oldfocus = self.focus + self.focus = newfocus + self.changemark(oldfocus) + self.changemark(newfocus) + if newfocus != 0: + self.showline(newfocus) + + def resetfocus(self): + self.setfocus(0) + +# XXX Should get rid of focus stuff again |