mirror of https://github.com/buggins/dlangide.git
debugger UI - stack trace, locals
This commit is contained in:
parent
87ca1f8ddd
commit
9dc84ab7c7
2
dub.json
2
dub.json
|
@ -14,7 +14,7 @@
|
|||
"copyFiles-windows": ["lib/win32/dcd-server.exe", "lib/win32/dcd-client.exe"],
|
||||
|
||||
"dependencies": {
|
||||
"dlangui": "~>0.7.24",
|
||||
"dlangui": "~>0.7.25",
|
||||
"libdparse": "==0.2.0"
|
||||
},
|
||||
|
||||
|
|
|
@ -177,6 +177,14 @@ class DebugVariableList {
|
|||
foreach(t; v.variables)
|
||||
variables ~= new DebugVariable(t);
|
||||
}
|
||||
|
||||
@property int length() { return variables ? cast(int)variables.length : 0; }
|
||||
|
||||
DebugVariable opIndex(int index) {
|
||||
if (!variables || index < 0 || index > variables.length)
|
||||
return null;
|
||||
return variables[index];
|
||||
}
|
||||
}
|
||||
|
||||
static __gshared _nextBreakpointId = 1;
|
||||
|
@ -204,6 +212,9 @@ interface Debugger : ProgramExecution {
|
|||
|
||||
/// update list of breakpoints
|
||||
void setBreakpoints(Breakpoint[] bp);
|
||||
|
||||
/// request stack trace and local vars for thread and frame
|
||||
void requestDebugContextInfo(ulong threadId, int frame);
|
||||
}
|
||||
|
||||
interface DebuggerCallback : ProgramExecutionStatusListener {
|
||||
|
@ -219,7 +230,7 @@ interface DebuggerCallback : ProgramExecutionStatusListener {
|
|||
void onResponse(ResponseCode code, string msg);
|
||||
|
||||
/// send debug context (threads, stack frames, local vars...)
|
||||
void onDebugContextInfo(DebugThreadList info);
|
||||
void onDebugContextInfo(DebugThreadList info, ulong threadId, int frame);
|
||||
}
|
||||
|
||||
enum ResponseCode : int {
|
||||
|
@ -302,8 +313,8 @@ class DebuggerProxy : Debugger, DebuggerCallback {
|
|||
}
|
||||
|
||||
/// send debug context (threads, stack frames, local vars...)
|
||||
void onDebugContextInfo(DebugThreadList info) {
|
||||
_callbackDelegate( delegate() { _callback.onDebugContextInfo(info); } );
|
||||
void onDebugContextInfo(DebugThreadList info, ulong threadId, int frame) {
|
||||
_callbackDelegate( delegate() { _callback.onDebugContextInfo(info, threadId, frame); } );
|
||||
}
|
||||
|
||||
void onResponse(ResponseCode code, string msg) {
|
||||
|
@ -359,6 +370,10 @@ class DebuggerProxy : Debugger, DebuggerCallback {
|
|||
void execRestart() {
|
||||
_debugger.postRequest(delegate() { _debugger.execRestart(); });
|
||||
}
|
||||
/// request stack trace and local vars for thread and frame
|
||||
void requestDebugContextInfo(ulong threadId, int frame) {
|
||||
_debugger.postRequest(delegate() { _debugger.requestDebugContextInfo(threadId, frame); });
|
||||
}
|
||||
/// update list of breakpoints
|
||||
void setBreakpoints(Breakpoint[] breakpoints) {
|
||||
Breakpoint[] cloned;
|
||||
|
|
|
@ -481,7 +481,7 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
|||
DebugThreadList _currentState;
|
||||
void updateState() {
|
||||
_currentState = null;
|
||||
submitRequest(new ThreadInfoRequest(), new StackListFramesRequest());
|
||||
submitRequest(new ThreadInfoRequest());
|
||||
}
|
||||
|
||||
// +asyncclass,result
|
||||
|
@ -526,6 +526,12 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
|||
_requests.submit(requests[0]);
|
||||
}
|
||||
|
||||
/// request stack trace and local vars for thread and frame
|
||||
void requestDebugContextInfo(ulong threadId, int frame) {
|
||||
Log.d("requestDebugContextInfo threadId=", threadId, " frame=", frame);
|
||||
submitRequest(new StackListFramesRequest(threadId, frame));
|
||||
}
|
||||
|
||||
class ThreadInfoRequest : GDBRequest {
|
||||
this() { command = "-thread-info"; }
|
||||
override void onResult() {
|
||||
|
@ -533,30 +539,43 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
|||
if (_currentState) {
|
||||
// TODO
|
||||
Log.d("Thread list is parsed");
|
||||
submitRequest(new StackListFramesRequest(_currentState.currentThreadId, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StackListFramesRequest : GDBRequest {
|
||||
this() { command = "-stack-list-frames"; }
|
||||
private ulong _threadId;
|
||||
private int _frameId;
|
||||
this(ulong threadId, int frameId) {
|
||||
_threadId = threadId;
|
||||
_frameId = frameId;
|
||||
if (!_threadId)
|
||||
_threadId = _currentState ? _currentState.currentThreadId : 0;
|
||||
command = "-stack-list-frames --thread " ~ to!string(_threadId);
|
||||
}
|
||||
override void onResult() {
|
||||
DebugStack stack = parseStack(params);
|
||||
if (stack) {
|
||||
// TODO
|
||||
Log.d("Stack frames list is parsed: " ~ to!string(stack));
|
||||
if (_currentState) {
|
||||
if (DebugThread currentThread = _currentState.currentThread) {
|
||||
if (DebugThread currentThread = _currentState.findThread(_threadId)) {
|
||||
currentThread.stack = stack;
|
||||
Log.d("Setting stack frames for current thread");
|
||||
}
|
||||
submitRequest(new LocalVariableListRequest(_currentState.currentThreadId, 0));
|
||||
submitRequest(new LocalVariableListRequest(_threadId, _frameId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LocalVariableListRequest : GDBRequest {
|
||||
ulong _threadId;
|
||||
int _frameId;
|
||||
this(ulong threadId, int frameId) {
|
||||
_threadId = threadId;
|
||||
_frameId = frameId;
|
||||
command = "-stack-list-locals --thread " ~ to!string(threadId) ~ " --frame " ~ to!string(frameId) ~ " --simple-values";
|
||||
}
|
||||
override void onResult() {
|
||||
|
@ -569,7 +588,7 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
|||
if (currentThread.length > 0) {
|
||||
currentThread[0].locals = variables;
|
||||
Log.d("Setting variables for current thread top frame");
|
||||
_callback.onDebugContextInfo(_currentState.clone());
|
||||
_callback.onDebugContextInfo(_currentState.clone(), _threadId, _frameId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import dlangide.ui.watchpanel;
|
|||
import ddebug.common.execution;
|
||||
import ddebug.common.debugger;
|
||||
|
||||
class DebuggerUIHandler : DebuggerCallback {
|
||||
class DebuggerUIHandler : DebuggerCallback, StackFrameSelectedHandler {
|
||||
|
||||
private IDEFrame _ide;
|
||||
private Debugger _debugger;
|
||||
|
@ -21,6 +21,7 @@ class DebuggerUIHandler : DebuggerCallback {
|
|||
private DebugFrame _location;
|
||||
private WatchPanel _watchPanel;
|
||||
private StackPanel _stackPanel;
|
||||
private DebugThreadList _debugInfo;
|
||||
|
||||
this(IDEFrame ide, Debugger debugger) {
|
||||
_ide = ide;
|
||||
|
@ -38,10 +39,22 @@ class DebuggerUIHandler : DebuggerCallback {
|
|||
}
|
||||
|
||||
/// send debug context (threads, stack frames, local vars...)
|
||||
void onDebugContextInfo(DebugThreadList info) {
|
||||
void onDebugContextInfo(DebugThreadList info, ulong threadId, int frameId) {
|
||||
Log.d("Debugger context received");
|
||||
_stackPanel.updateDebugInfo(info, info.currentThreadId, 0);
|
||||
_watchPanel.updateDebugInfo(info, info.currentThreadId, 0);
|
||||
_debugInfo = info;
|
||||
_stackPanel.updateDebugInfo(info, threadId, frameId);
|
||||
_watchPanel.updateDebugInfo(info, threadId, frameId);
|
||||
}
|
||||
|
||||
void onStackFrameSelected(ulong threadId, int frame) {
|
||||
if (_debugInfo) {
|
||||
if (DebugThread t = _debugInfo.findThread(threadId)) {
|
||||
if (frame < t.length)
|
||||
updateLocation(t[frame]);
|
||||
else
|
||||
updateLocation(t.frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onResponse(ResponseCode code, string msg) {
|
||||
|
@ -186,6 +199,7 @@ class DebuggerUIHandler : DebuggerCallback {
|
|||
_stackPanel = new StackPanel("stack");
|
||||
_stackPanel.dockAlignment = DockAlignment.Right;
|
||||
_ide.dockHost.addDockedWindow(_stackPanel);
|
||||
_stackPanel.stackFrameSelected = this;
|
||||
}
|
||||
|
||||
void switchToDevelopPerspective() {
|
||||
|
|
|
@ -5,7 +5,13 @@ import dlangui;
|
|||
import std.string : format;
|
||||
import ddebug.common.debugger;
|
||||
|
||||
class StackPanel : DockWindow {
|
||||
interface StackFrameSelectedHandler {
|
||||
void onStackFrameSelected(ulong threadId, int frame);
|
||||
}
|
||||
|
||||
class StackPanel : DockWindow, OnItemSelectedHandler, CellActivatedHandler {
|
||||
|
||||
Signal!StackFrameSelectedHandler stackFrameSelected;
|
||||
|
||||
this(string id) {
|
||||
super(id);
|
||||
|
@ -21,15 +27,16 @@ class StackPanel : DockWindow {
|
|||
_comboBox = new ComboBox("threadComboBox", ["Thread1"d]);
|
||||
_comboBox.layoutWidth = FILL_PARENT;
|
||||
_comboBox.selectedItemIndex = 0;
|
||||
_comboBox.itemClick = this;
|
||||
_grid = new StringGridWidget("stackGrid");
|
||||
_grid.resize(2, 20);
|
||||
_grid.cellActivated = this;
|
||||
_grid.resize(2, 0);
|
||||
_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);
|
||||
_grid.layoutWidth = FILL_PARENT;
|
||||
_grid.layoutHeight = FILL_PARENT;
|
||||
root.addChild(_comboBox);
|
||||
|
@ -82,6 +89,22 @@ class StackPanel : DockWindow {
|
|||
}
|
||||
}
|
||||
|
||||
void onCellActivated(GridWidgetBase source, int col, int row) {
|
||||
if (_debugInfo && _selectedThread && row < _selectedThread.length) {
|
||||
if (stackFrameSelected.assigned)
|
||||
stackFrameSelected(_currentThreadId, row);
|
||||
}
|
||||
}
|
||||
|
||||
bool onItemSelected(Widget source, int itemIndex) {
|
||||
if (_debugInfo && itemIndex < _debugInfo.length && _currentThreadId != _debugInfo[itemIndex].id) {
|
||||
_grid.selectCell(0, 0, true, null, false);
|
||||
if (stackFrameSelected.assigned)
|
||||
stackFrameSelected(_debugInfo[itemIndex].id, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void onPopupMenuItem(MenuItem item) {
|
||||
if (item.action)
|
||||
handleAction(item.action);
|
||||
|
@ -91,5 +114,18 @@ class StackPanel : DockWindow {
|
|||
override bool handleAction(const Action a) {
|
||||
return super.handleAction(a);
|
||||
}
|
||||
|
||||
override void layout(Rect rc) {
|
||||
if (visibility == Visibility.Gone) {
|
||||
return;
|
||||
}
|
||||
super.layout(rc);
|
||||
_grid.autoFitColumnWidth(2);
|
||||
int w = _grid.clientRect.width - _grid.colWidth(2);
|
||||
if (w < _grid.clientRect.width * 2 / 3)
|
||||
w = _grid.clientRect.width * 2 / 3;
|
||||
_grid.setColWidth(1, w);
|
||||
_grid.layout(_grid.pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,10 @@ import std.string : format;
|
|||
import ddebug.common.debugger;
|
||||
|
||||
class VariablesWindow : StringGridWidget {
|
||||
DebugFrame _frame;
|
||||
this(string ID = null) {
|
||||
super(ID);
|
||||
resize(3, 20);
|
||||
resize(3, 0);
|
||||
showColHeaders = true;
|
||||
showRowHeaders = false;
|
||||
layoutHeight = FILL_PARENT;
|
||||
|
@ -16,12 +17,23 @@ class VariablesWindow : StringGridWidget {
|
|||
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);
|
||||
autoFit();
|
||||
}
|
||||
void setFrame(DebugFrame frame) {
|
||||
_frame = frame;
|
||||
if (frame && frame.locals) {
|
||||
resize(3, frame.locals.length);
|
||||
for (int i = 0; i < frame.locals.length; i++) {
|
||||
DebugVariable var = frame.locals[i];
|
||||
setCellText(0, i, var.name.toUTF32);
|
||||
setCellText(1, i, var.value.toUTF32);
|
||||
setCellText(2, i, var.type.toUTF32);
|
||||
}
|
||||
autoFit();
|
||||
} else {
|
||||
resize(3, 0);
|
||||
autoFit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,6 +50,8 @@ class WatchPanel : DockWindow {
|
|||
protected VariablesWindow _autos;
|
||||
|
||||
override protected Widget createBodyWidget() {
|
||||
layoutWidth = FILL_PARENT;
|
||||
layoutHeight = FILL_PARENT;
|
||||
_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);
|
||||
|
@ -98,8 +112,9 @@ class WatchPanel : DockWindow {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
_locals.setFrame(_frame);
|
||||
_autos.setFrame(_frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue