From 611c2f2cb72a367c85c1d2944732bcadcad97256 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Thu, 17 Dec 2015 11:48:57 +0300 Subject: [PATCH] debugger improvements --- dlangide-monod-linux.dproj | 2 + dlangide-monod-osx.dproj | 2 + dlangide_msvc.visualdproj | 2 + dub.json | 2 +- src/ddebug/common/debugger.d | 16 +++++++- src/ddebug/gdb/gdbinterface.d | 11 +++++- src/dlangide/ui/debuggerui.d | 31 ++++++++++++++++ src/dlangide/ui/frame.d | 1 + src/dlangide/ui/stackpanel.d | 43 +++++++++++++++++++++ src/dlangide/ui/watchpanel.d | 70 +++++++++++++++++++++++++++++++++++ 10 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 src/dlangide/ui/stackpanel.d create mode 100644 src/dlangide/ui/watchpanel.d diff --git a/dlangide-monod-linux.dproj b/dlangide-monod-linux.dproj index 717f216..03c5274 100644 --- a/dlangide-monod-linux.dproj +++ b/dlangide-monod-linux.dproj @@ -212,6 +212,8 @@ + + diff --git a/dlangide-monod-osx.dproj b/dlangide-monod-osx.dproj index a4e84a5..753e7e6 100644 --- a/dlangide-monod-osx.dproj +++ b/dlangide-monod-osx.dproj @@ -121,6 +121,8 @@ + + diff --git a/dlangide_msvc.visualdproj b/dlangide_msvc.visualdproj index 79312ec..238f2fc 100644 --- a/dlangide_msvc.visualdproj +++ b/dlangide_msvc.visualdproj @@ -462,6 +462,8 @@ + + diff --git a/dub.json b/dub.json index 7318539..b78a605 100644 --- a/dub.json +++ b/dub.json @@ -14,7 +14,7 @@ "copyFiles-windows": ["lib/win32/dcd-server.exe", "lib/win32/dcd-client.exe"], "dependencies": { - "dlangui": "~>0.7.21", + "dlangui": "~>0.7.22", "libdparse": "==0.2.0" }, diff --git a/src/ddebug/common/debugger.d b/src/ddebug/common/debugger.d index cf6f96f..4e5810f 100644 --- a/src/ddebug/common/debugger.d +++ b/src/ddebug/common/debugger.d @@ -4,6 +4,8 @@ import core.thread; import dlangui.core.logger; import ddebug.common.queue; import ddebug.common.execution; +import std.array : empty; +import std.algorithm : startsWith, endsWith, equal; enum DebuggingState { loaded, @@ -29,6 +31,16 @@ class LocationBase { class DebugLocation : LocationBase { ulong address; string func; + void fillMissingFields(LocationBase v) { + if (file.empty) + file = v.file; + if (fullFilePath.empty) + fullFilePath = v.fullFilePath; + if (projectFilePath.empty) + projectFilePath = v.projectFilePath; + if (!line) + line = v.line; + } } class Breakpoint : LocationBase { @@ -272,8 +284,8 @@ abstract class DebuggerBase : Thread, Debugger { } ~this() { - stop(); - destroy(_queue); + //stop(); + //destroy(_queue); _queue = null; } diff --git a/src/ddebug/gdb/gdbinterface.d b/src/ddebug/gdb/gdbinterface.d index e981449..db86ba9 100644 --- a/src/ddebug/gdb/gdbinterface.d +++ b/src/ddebug/gdb/gdbinterface.d @@ -9,7 +9,7 @@ import ddebug.gdb.gdbmiparser; import std.utf; import std.conv : to; import std.array : empty; -import std.algorithm : startsWith, equal; +import std.algorithm : startsWith, endsWith, equal; import core.thread; abstract class ConsoleDebuggerInterface : DebuggerBase, TextWriter { @@ -416,6 +416,8 @@ class GDBInterface : ConsoleDebuggerInterface { // ~message void handleStreamLineCLI(string s) { Log.d("GDB CLI: ", s); + if (s.length >= 2 && s.startsWith('\"') && s.endsWith('\"')) + s = parseCString(s); _callback.onDebuggerMessage(s); } @@ -456,8 +458,13 @@ class GDBInterface : ConsoleDebuggerInterface { if (reason.equal("end-stepping-range")) { _callback.onDebugState(DebuggingState.paused, StateChangeReason.endSteppingRange, location, bp); } else if (reason.equal("breakpoint-hit")) { - if (GDBBreakpoint gdbbp = findBreakpointByNumber(params.getString("bkptno"))) + if (GDBBreakpoint gdbbp = findBreakpointByNumber(params.getString("bkptno"))) { bp = gdbbp.bp; + if (!location && bp) { + location = new DebugLocation(); + location.fillMissingFields(bp); + } + } _callback.onDebugState(DebuggingState.paused, StateChangeReason.breakpointHit, location, bp); } else { _callback.onDebugState(DebuggingState.stopped, StateChangeReason.exited, null, null); diff --git a/src/dlangide/ui/debuggerui.d b/src/dlangide/ui/debuggerui.d index 883c133..9720ead 100644 --- a/src/dlangide/ui/debuggerui.d +++ b/src/dlangide/ui/debuggerui.d @@ -2,11 +2,14 @@ module dlangide.ui.debuggerui; import dlangui.core.logger; import dlangui.core.events; +import dlangui.widgets.docks; import dlangide.workspace.project; import dlangide.workspace.workspace; import dlangide.ui.frame; import dlangide.ui.commands; import dlangide.ui.dsourceedit; +import dlangide.ui.stackpanel; +import dlangide.ui.watchpanel; import ddebug.common.execution; import ddebug.common.debugger; @@ -26,6 +29,7 @@ class DebuggerUIHandler : DebuggerCallback { void onProgramExecutionStatus(ProgramExecution process, ExecutionStatus status, int exitCode) { Log.d("Debugger exit status: ", status, " ", exitCode); updateLocation(null); + switchToDevelopPerspective(); _ide.debugFinished(process, status, exitCode); //_callbackDelegate( delegate() { _callback.onProgramExecutionStatus(this, status, exitCode); } ); } @@ -42,6 +46,7 @@ class DebuggerUIHandler : DebuggerCallback { /// debugger is started and loaded program, you can set breakpoints at this time void onProgramLoaded(bool successful, bool debugInfoLoaded) { _ide.logPanel.logLine("Program is loaded"); + switchToDebugPerspective(); // TODO: check succes status and debug info if (_breakpoints.length) _debugger.setBreakpoints(_breakpoints); @@ -160,4 +165,30 @@ class DebuggerUIHandler : DebuggerCallback { return true; } } + + + private WatchPanel _watchPanel; + private StackPanel _stackPanel; + + void switchToDebugPerspective() { + _ide.dockHost.layoutPriority = [DockAlignment.Bottom, DockAlignment.Top, DockAlignment.Left, DockAlignment.Right]; + _watchPanel = new WatchPanel("watch"); + _watchPanel.dockAlignment = DockAlignment.Bottom; + _ide.dockHost.addDockedWindow(_watchPanel); + _stackPanel = new StackPanel("stack"); + _stackPanel.dockAlignment = DockAlignment.Right; + _ide.dockHost.addDockedWindow(_stackPanel); + } + + void switchToDevelopPerspective() { + _ide.dockHost.layoutPriority = [DockAlignment.Top, DockAlignment.Left, DockAlignment.Right, DockAlignment.Bottom]; + _watchPanel = null; + auto w = _ide.dockHost.removeDockedWindow("watch"); + if (w) + destroy(w); + _stackPanel = null; + w = _ide.dockHost.removeDockedWindow("stack"); + if (w) + destroy(w); + } } diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index 7115604..2651e6f 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -91,6 +91,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL applySettings(_settings); } + @property DockHost dockHost() { return _dockHost; } @property OutputPanel logPanel() { return _logPanel; } /// stop current program execution diff --git a/src/dlangide/ui/stackpanel.d b/src/dlangide/ui/stackpanel.d new file mode 100644 index 0000000..9a97f86 --- /dev/null +++ b/src/dlangide/ui/stackpanel.d @@ -0,0 +1,43 @@ +module dlangide.ui.stackpanel; + +import dlangui; + +class StackPanel : DockWindow { + + this(string id) { + super(id); + _caption.text = "Stack"d; + } + + override protected Widget createBodyWidget() { + VerticalLayout root = new VerticalLayout(); + root.layoutWeight = FILL_PARENT; + root.layoutHeight = FILL_PARENT; + ComboBox comboBox = new ComboBox("threadComboBox", ["Thread1"d]); + comboBox.layoutWidth = FILL_PARENT; + comboBox.selectedItemIndex = 0; + StringGridWidget grid = new StringGridWidget("stackGrid"); + grid.resize(2, 20); + grid.showColHeaders = true; + grid.showRowHeaders = false; + grid.layoutHeight = FILL_PARENT; + grid.layoutWidth = FILL_PARENT; + grid.setColTitle(0, "Function"d); + grid.setColTitle(1, "Address"d); + grid.setCellText(0, 0, "main()"d); + root.addChild(comboBox); + root.addChild(grid); + return root; + } + + protected void onPopupMenuItem(MenuItem item) { + if (item.action) + handleAction(item.action); + } + + /// override to handle specific actions + override bool handleAction(const Action a) { + return super.handleAction(a); + } +} + diff --git a/src/dlangide/ui/watchpanel.d b/src/dlangide/ui/watchpanel.d new file mode 100644 index 0000000..6538776 --- /dev/null +++ b/src/dlangide/ui/watchpanel.d @@ -0,0 +1,70 @@ +module dlangide.ui.watchpanel; + +import dlangui; + +class VariablesWindow : StringGridWidget { + this(string ID = null) { + super(ID); + resize(3, 20); + showColHeaders = true; + showRowHeaders = false; + layoutHeight = FILL_PARENT; + layoutWidth = FILL_PARENT; + setColTitle(0, "Variable"d); + setColTitle(1, "Value"d); + setColTitle(2, "Type"d); + setCellText(0, 0, "a"d); + setCellText(1, 0, "1"d); + setCellText(2, 0, "int"d); + setCellText(0, 1, "b"d); + setCellText(1, 1, "42"d); + setCellText(2, 1, "ulong"d); + } +} + +class WatchPanel : DockWindow { + + this(string id) { + super(id); + _caption.text = "Watch"d; + _showCloseButton = false; + } + + protected TabWidget _tabs; + protected VariablesWindow _locals; + protected VariablesWindow _autos; + + override protected Widget createBodyWidget() { + _tabs = new TabWidget("WatchPanelTabs", Align.Bottom); + _tabs.setStyles(null, STYLE_TAB_DOWN_DARK, STYLE_TAB_DOWN_BUTTON_DARK, STYLE_TAB_UP_BUTTON_DARK_TEXT); + _tabs.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); + _tabs.tabHost.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); + + _locals = new VariablesWindow("watchLocals"); + _autos = new VariablesWindow("watchAutos"); + _tabs.addTab(_locals, "Locals"d); + _tabs.addTab(_autos, "Autos"d); + _tabs.selectTab("watchAutos"); + + return _tabs; + } + + override protected void init() { + //styleId = STYLE_DOCK_WINDOW; + styleId = null; + _bodyWidget = createBodyWidget(); + //_bodyWidget.styleId = STYLE_DOCK_WINDOW_BODY; + addChild(_bodyWidget); + } + + protected void onPopupMenuItem(MenuItem item) { + if (item.action) + handleAction(item.action); + } + + /// override to handle specific actions + override bool handleAction(const Action a) { + return super.handleAction(a); + } +} +