diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py index ccd03e46e16147..63f4951b6d977f 100644 --- a/Lib/idlelib/debugger.py +++ b/Lib/idlelib/debugger.py @@ -13,6 +13,7 @@ class Idb(bdb.Bdb): def __init__(self, gui): self.gui = gui # An instance of Debugger or proxy of remote. + self._interrupt = False bdb.Bdb.__init__(self) def user_line(self, frame): @@ -32,6 +33,28 @@ def user_exception(self, frame, info): message = self.__frame2message(frame) self.gui.interaction(message, frame, info) + def user_interrupt(self, value): + # Clear sys.settrace to prevent debugger trace in Idb + sys.settrace(None) + + old_value = self._interrupt + self._interrupt = value + return old_value + + def break_here(self, frame): + if self._interrupt: + self._interrupt = False + return True + return bdb.Bdb.break_here(self, frame) + + def set_continue(self): + bdb.Bdb.set_continue(self) + # The code in bdb will clear sys.settrace + # if there are no breakpoints. This resets + # it so that Ctrl-C still works. + if sys.gettrace() is None: + sys.settrace(self.trace_dispatch) + def in_rpc_code(self, frame): if frame.f_code.co_filename.count('rpc.py'): return True @@ -265,22 +288,27 @@ def __frame2fileline(self, frame): return filename, lineno def cont(self): + self.idb.user_interrupt(False) self.idb.set_continue() self.abort_loop() def step(self): + self.idb.user_interrupt(False) self.idb.set_step() self.abort_loop() def next(self): + self.idb.user_interrupt(False) self.idb.set_next(self.frame) self.abort_loop() def ret(self): + self.idb.user_interrupt(False) self.idb.set_return(self.frame) self.abort_loop() def quit(self): + self.idb.user_interrupt(False) self.idb.set_quit() self.abort_loop() diff --git a/Lib/idlelib/debugger_r.py b/Lib/idlelib/debugger_r.py index 26204438858d8a..4936a0ef0462c0 100644 --- a/Lib/idlelib/debugger_r.py +++ b/Lib/idlelib/debugger_r.py @@ -117,6 +117,9 @@ def clear_all_file_breaks(self, filename): msg = self.idb.clear_all_file_breaks(filename) return msg + def user_interrupt(self, value): + return self.idb.user_interrupt(value) + #----------called by a FrameProxy---------- def frame_attr(self, fid, name): @@ -190,7 +193,7 @@ def start_debugger(rpchandler, gui_adap_oid): idb = debugger.Idb(gui_proxy) idb_adap = IdbAdapter(idb) rpchandler.register(idb_adap_oid, idb_adap) - return idb_adap_oid + return idb_adap_oid, idb #======================================= @@ -343,6 +346,10 @@ def clear_all_file_breaks(self, filename): msg = self.call("clear_all_file_breaks", filename) return msg + def user_interrupt(self, value): + return self.call("user_interrupt", value) + + def start_remote_debugger(rpcclt, pyshell): """Start the subprocess debugger, initialize the debugger GUI and RPC link diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index e68233a5a4131e..31862a033b7e4e 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1211,10 +1211,8 @@ def cancel_callback(self, event=None): self.endoffile = False self.canceled = True if (self.executing and self.interp.rpcclt): - if self.interp.getdebugger(): - self.interp.restart_subprocess() - else: - self.interp.interrupt_subprocess() + self.interp.write("\nKeyboardInterrupt\n") + self.interp.interrupt_subprocess() if self.reading: self.top.quit() # exit the nested mainloop() in readline() return "break" diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 577c49eb67b20d..4e4a655b4bfa97 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -562,6 +562,7 @@ class Executive: def __init__(self, rpchandler): self.rpchandler = rpchandler + self.idb = None if idlelib.testing is False: self.locals = __main__.__dict__ self.calltip = calltip.Calltip() @@ -605,13 +606,18 @@ def runcode(self, code): def interrupt_the_server(self): if interruptable: thread.interrupt_main() + elif self.idb: + self.idb.user_interrupt(True) def start_the_debugger(self, gui_adap_oid): - return debugger_r.start_debugger(self.rpchandler, gui_adap_oid) + oid, idb = debugger_r.start_debugger(self.rpchandler, gui_adap_oid) + self.idb = idb + return oid def stop_the_debugger(self, idb_adap_oid): "Unregister the Idb Adapter. Link objects and Idb then subject to GC" self.rpchandler.unregister(idb_adap_oid) + self.idb = None def get_the_calltip(self, name): return self.calltip.fetch_tip(name)