# Command Handlers for the debugger. # Not in the debugger package, as I always want these interfaces to be # available, even if the debugger has not yet been (or can not be) # imported import warnings import win32ui from pywin.scintilla.control import CScintillaEditInterface from . import scriptutils IdToBarNames = { win32ui.IDC_DBG_STACK: ("Stack", 0), win32ui.IDC_DBG_BREAKPOINTS: ("Breakpoints", 0), win32ui.IDC_DBG_WATCH: ("Watch", 1), } class DebuggerCommandHandler: def HookCommands(self): commands = ( (self.OnStep, None, win32ui.IDC_DBG_STEP), (self.OnStepOut, self.OnUpdateOnlyBreak, win32ui.IDC_DBG_STEPOUT), (self.OnStepOver, None, win32ui.IDC_DBG_STEPOVER), (self.OnGo, None, win32ui.IDC_DBG_GO), (self.OnClose, self.OnUpdateClose, win32ui.IDC_DBG_CLOSE), (self.OnAdd, self.OnUpdateAddBreakpoints, win32ui.IDC_DBG_ADD), (self.OnClearAll, self.OnUpdateClearAllBreakpoints, win32ui.IDC_DBG_CLEAR), # (self.OnDebuggerToolbar, self.OnUpdateDebuggerToolbar, win32ui.ID_DEBUGGER_TOOLBAR), ) frame = win32ui.GetMainFrame() for methHandler, methUpdate, id in commands: frame.HookCommand(methHandler, id) if not methUpdate is None: frame.HookCommandUpdate(methUpdate, id) for id in list(IdToBarNames.keys()): frame.HookCommand(self.OnDebuggerBar, id) frame.HookCommandUpdate(self.OnUpdateDebuggerBar, id) def OnDebuggerToolbar(self, id, code): if code == 0: return not win32ui.GetMainFrame().OnBarCheck(id) def OnUpdateDebuggerToolbar(self, cmdui): win32ui.GetMainFrame().OnUpdateControlBarMenu(cmdui) cmdui.Enable(1) def _GetDebugger(self): try: import pywin.debugger return pywin.debugger.currentDebugger except ImportError: return None def _DoOrStart(self, doMethod, startFlag): d = self._GetDebugger() if d is not None and d.IsDebugging(): method = getattr(d, doMethod) method() else: scriptutils.RunScript( defName=None, defArgs=None, bShowDialog=0, debuggingType=startFlag ) def OnStep(self, msg, code): self._DoOrStart("do_set_step", scriptutils.RS_DEBUGGER_STEP) def OnStepOver(self, msg, code): self._DoOrStart("do_set_next", scriptutils.RS_DEBUGGER_STEP) def OnStepOut(self, msg, code): d = self._GetDebugger() if d is not None and d.IsDebugging(): d.do_set_return() def OnGo(self, msg, code): self._DoOrStart("do_set_continue", scriptutils.RS_DEBUGGER_GO) def OnClose(self, msg, code): d = self._GetDebugger() if d is not None: if d.IsDebugging(): d.set_quit() else: d.close() def OnUpdateClose(self, cmdui): d = self._GetDebugger() if d is not None and d.inited: cmdui.Enable(1) else: cmdui.Enable(0) def OnAdd(self, msg, code): doc, view = scriptutils.GetActiveEditorDocument() if doc is None: ## Don't do a messagebox, as this could be triggered from the app's ## idle loop whenever the debug toolbar is visible, giving a never-ending ## series of dialogs. This can happen when the OnUpdate handler ## for the toolbar button IDC_DBG_ADD fails, since MFC falls back to ## sending a normal command if the UI update command fails. ## win32ui.MessageBox('There is no active window - no breakpoint can be added') warnings.warn("There is no active window - no breakpoint can be added") return None pathName = doc.GetPathName() lineNo = view.LineFromChar(view.GetSel()[0]) + 1 # If I have a debugger, then tell it, otherwise just add a marker d = self._GetDebugger() if d is None: import pywin.framework.editor.color.coloreditor doc.MarkerToggle( lineNo, pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT ) else: if d.get_break(pathName, lineNo): win32ui.SetStatusText("Clearing breakpoint", 1) rc = d.clear_break(pathName, lineNo) else: win32ui.SetStatusText("Setting breakpoint", 1) rc = d.set_break(pathName, lineNo) if rc: win32ui.MessageBox(rc) d.GUIRespondDebuggerData() def OnClearAll(self, msg, code): win32ui.SetStatusText("Clearing all breakpoints") d = self._GetDebugger() if d is None: import pywin.framework.editor import pywin.framework.editor.color.coloreditor for doc in pywin.framework.editor.editorTemplate.GetDocumentList(): doc.MarkerDeleteAll( pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT ) else: d.clear_all_breaks() d.UpdateAllLineStates() d.GUIRespondDebuggerData() def OnUpdateOnlyBreak(self, cmdui): d = self._GetDebugger() ok = d is not None and d.IsBreak() cmdui.Enable(ok) def OnUpdateAddBreakpoints(self, cmdui): doc, view = scriptutils.GetActiveEditorDocument() if doc is None or not isinstance(view, CScintillaEditInterface): enabled = 0 else: enabled = 1 lineNo = view.LineFromChar(view.GetSel()[0]) + 1 import pywin.framework.editor.color.coloreditor cmdui.SetCheck( doc.MarkerAtLine( lineNo, pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT ) != 0 ) cmdui.Enable(enabled) def OnUpdateClearAllBreakpoints(self, cmdui): d = self._GetDebugger() cmdui.Enable(d is None or len(d.breaks) != 0) def OnUpdateDebuggerBar(self, cmdui): name, always = IdToBarNames.get(cmdui.m_nID) enabled = always d = self._GetDebugger() if d is not None and d.IsDebugging() and name is not None: enabled = 1 bar = d.GetDebuggerBar(name) cmdui.SetCheck(bar.IsWindowVisible()) cmdui.Enable(enabled) def OnDebuggerBar(self, id, code): name = IdToBarNames.get(id)[0] d = self._GetDebugger() if d is not None and name is not None: bar = d.GetDebuggerBar(name) newState = not bar.IsWindowVisible() win32ui.GetMainFrame().ShowControlBar(bar, newState, 1)