Spaces:
Sleeping
Sleeping
# 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) | |