diff options
Diffstat (limited to 'Lib/idlelib')
-rw-r--r-- | Lib/idlelib/Debugger.py | 47 | ||||
-rw-r--r-- | Lib/idlelib/EditorWindow.py | 7 | ||||
-rw-r--r-- | Lib/idlelib/PyShell.py | 130 |
3 files changed, 110 insertions, 74 deletions
diff --git a/Lib/idlelib/Debugger.py b/Lib/idlelib/Debugger.py index 04196235e5b..27e8c2b56c5 100644 --- a/Lib/idlelib/Debugger.py +++ b/Lib/idlelib/Debugger.py @@ -77,11 +77,6 @@ class Debugger: return if self.stackviewer: self.stackviewer.close(); self.stackviewer = None - # Remove all EditWindow BREAK tags when closing debugger: - edit_windows = self.pyshell.flist.inversedict.keys() - for window in edit_windows: - window.text.tag_remove("BREAK", 1.0, END) - window.break_set = False # Clean up pyshell if user clicked debugger control close widget. # (Causes a harmless extra cycle through close_debugger() if user # toggled debugger from pyshell Debug menu) @@ -311,48 +306,34 @@ class Debugger: if gv: gv.load_dict(gdict, force, self.pyshell.interp.rpcclt) - def set_breakpoint_here(self, edit): - text = edit.text - filename = edit.io.filename - if not filename: - text.bell() - return - lineno = int(float(text.index("insert"))) + def set_breakpoint_here(self, filename, lineno): msg = self.idb.set_break(filename, lineno) if msg: text.bell() return - text.tag_add("BREAK", "insert linestart", "insert lineend +1char") - edit.break_set = True - def clear_breakpoint_here(self, edit): - text = edit.text - filename = edit.io.filename - if not filename: - text.bell() - return - lineno = int(float(text.index("insert"))) + def clear_breakpoint_here(self, filename, lineno): msg = self.idb.clear_break(filename, lineno) if msg: text.bell() return - text.tag_remove("BREAK", "insert linestart",\ - "insert lineend +1char") - # Don't bother to track break_set status - - def clear_file_breaks(self, edit): - text = edit.text - filename = edit.io.filename - if not filename: - text.bell() - return + + def clear_file_breaks(self, filename): msg = self.idb.clear_all_file_breaks(filename) if msg: text.bell() return - text.tag_remove("BREAK", "1.0", END) - edit.break_set = False + def load_breakpoints(self): + "Load PyShellEditorWindow breakpoints into subprocess debugger" + pyshell_edit_windows = self.pyshell.flist.inversedict.keys() + for editwin in pyshell_edit_windows: + filename = editwin.io.filename + try: + for lineno in editwin.breakpoints: + self.set_breakpoint_here(filename, lineno) + except AttributeError: + continue class StackViewer(ScrolledList): diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py index f5e3add0e99..81770582087 100644 --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -58,7 +58,6 @@ class EditorWindow: self.top.instanceDict=flist.inversedict self.recentFilesPath=os.path.join(idleConf.GetUserCfgDir(), 'recent-files.lst') - self.break_set = False self.vbar = vbar = Scrollbar(top, name='vbar') self.text_frame = text_frame = Frame(top) self.text = text = Text(text_frame, name='text', padx=5, wrap='none', @@ -625,9 +624,6 @@ class EditorWindow: if not self.get_saved(): title = "*%s*" % title icon = "*%s" % icon - if self.break_set: - shell = self.flist.pyshell - shell.interp.debugger.clear_file_breaks(self) self.top.wm_title(title) self.top.wm_iconname(icon) @@ -696,9 +692,6 @@ class EditorWindow: #print self.io.filename if self.io.filename: self.UpdateRecentFilesList(newFile=self.io.filename) - if self.break_set: - shell = self.flist.pyshell - shell.interp.debugger.clear_file_breaks(self) WindowList.unregister_callback(self.postwindowsmenu) if self.close_hook: self.close_hook() diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index 790609a366f..2320ccd4468 100644 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -44,11 +44,15 @@ else: file.write(warnings.formatwarning(message, category, filename, lineno)) warnings.showwarning = idle_showwarning -# We need to patch linecache.checkcache, because we don't want it -# to throw away our <pyshell#...> entries. -# Rather than repeating its code here, we save those entries, -# then call the original function, and then restore the saved entries. -def linecache_checkcache(orig_checkcache=linecache.checkcache): +def linecache_checkcache(): + """Extend linecache.checkcache to preserve the <pyshell#...> entries + + Rather than repeating the linecache code, patch it by saving the pyshell# + entries, call linecache.checkcache(), and then restore the saved + entries. + + """ + orig_checkcache=linecache.checkcache cache = linecache.cache save = {} for filename in cache.keys(): @@ -56,36 +60,91 @@ def linecache_checkcache(orig_checkcache=linecache.checkcache): save[filename] = cache[filename] orig_checkcache() cache.update(save) + linecache.checkcache = linecache_checkcache + class PyShellEditorWindow(EditorWindow): "Regular text edit window when a shell is present" - # XXX ought to merge with regular editor window + + # XXX KBK 19Oct02 Breakpoints are currently removed if module is + # changed or closed. Future plans include saving breakpoints in a + # project file and possibly preserving breakpoints by changing their + # line numbers as a module is modified. def __init__(self, *args): + self.breakpoints = [] apply(EditorWindow.__init__, (self,) + args) self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here) - self.text.bind("<<clear-breakpoint-here>>", - self.clear_breakpoint_here) + self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here) self.text.bind("<<open-python-shell>>", self.flist.open_shell) - rmenu_specs = [ - ("Set Breakpoint", "<<set-breakpoint-here>>"), - ("Clear Breakpoint", "<<clear-breakpoint-here>>") - ] + rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"), + ("Clear Breakpoint", "<<clear-breakpoint-here>>")] def set_breakpoint_here(self, event=None): - if not self.flist.pyshell or not self.flist.pyshell.interp.debugger: - self.text.bell() + text = self.text + filename = self.io.filename + if not filename: + text.bell() return - self.flist.pyshell.interp.debugger.set_breakpoint_here(self) + lineno = int(float(text.index("insert"))) + try: + i = self.breakpoints.index(lineno) + except: # only add if missing, i.e. do once + self.breakpoints.append(lineno) + text.tag_add("BREAK", "insert linestart", "insert lineend +1char") + try: # update the subprocess debugger + debug = self.flist.pyshell.interp.debugger + debug.set_breakpoint_here(filename, lineno) + except: # but debugger may not be active right now.... + pass def clear_breakpoint_here(self, event=None): - if not self.flist.pyshell or not self.flist.pyshell.interp.debugger: - self.text.bell() + text = self.text + filename = self.io.filename + if not filename: + text.bell() return - self.flist.pyshell.interp.debugger.clear_breakpoint_here(self) - + lineno = int(float(text.index("insert"))) + try: + self.breakpoints.remove(lineno) + except: + pass + text.tag_remove("BREAK", "insert linestart",\ + "insert lineend +1char") + try: + debug = self.flist.pyshell.interp.debugger + debug.clear_breakpoint_here(filename, lineno) + except: + pass + + def clear_file_breaks(self): + if self.breakpoints: + text = self.text + filename = self.io.filename + if not filename: + text.bell() + return + self.breakpoints = [] + text.tag_remove("BREAK", "1.0", END) + try: + debug = self.flist.pyshell.interp.debugger + debug.clear_file_breaks(filename) + except: + pass + + def saved_change_hook(self): + "Extend base method - clear breaks if module is modified" + if not self.get_saved(): + self.clear_file_breaks() + EditorWindow.saved_change_hook(self) + + def _close(self): + "Extend base method - clear breaks when module is closed" + self.clear_file_breaks() + EditorWindow._close(self) + class PyShellFileList(FileList): "Extend base class: file list when a shell is present" @@ -174,7 +233,8 @@ class ModifiedInterpreter(InteractiveInterpreter): # Instead, find the executable by looking relative to # sys.prefix. executable = os.path.join(sys.prefix, 'Resources', - 'Python.app', 'Contents', 'MacOS', 'python') + 'Python.app', 'Contents', + 'MacOS', 'python') return executable else: return sys.executable @@ -207,19 +267,19 @@ class ModifiedInterpreter(InteractiveInterpreter): def restart_subprocess(self): # close only the subprocess debugger - db = self.getdebugger() - if db: + debug = self.getdebugger() + if debug: RemoteDebugger.close_subprocess_debugger(self.rpcclt) # kill subprocess, spawn a new one, accept connection self.rpcclt.close() self.spawn_subprocess() self.rpcclt.accept() # restart remote debugger - if db: + if debug: gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt) - # reload remote debugger breakpoints - pass # XXX KBK 04Sep02 TBD - + # reload remote debugger breakpoints for all PyShellEditWindows + debug.load_breakpoints() + active_seq = None def poll_subprocess(self): @@ -265,6 +325,14 @@ class ModifiedInterpreter(InteractiveInterpreter): if clt is not None: clt.close() + debugger = None + + def setdebugger(self, debugger): + self.debugger = debugger + + def getdebugger(self): + return self.debugger + def remote_stack_viewer(self): import RemoteObjectBrowser oid = self.rpcclt.remotecall("exec", "stackviewer", ("flist",), {}) @@ -382,14 +450,6 @@ class ModifiedInterpreter(InteractiveInterpreter): if key[:1] + key[-1:] != "<>": del c[key] - debugger = None - - def setdebugger(self, debugger): - self.debugger = debugger - - def getdebugger(self): - return self.debugger - def display_executing_dialog(self): tkMessageBox.showerror( "Already executing", @@ -567,6 +627,8 @@ class PyShell(OutputWindow): def open_remote_debugger(self): gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self) self.interp.setdebugger(gui) + # Load all PyShellEditorWindow breakpoints: + gui.load_breakpoints() sys.ps1 = "[DEBUG ON]\n>>> " self.showprompt() self.set_debugger_indicator() |