From 44f6c97428ed030ef7a00968cc3190ce4239ad68 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Mon, 14 Dec 2015 12:22:35 +0300 Subject: [PATCH] breakpoints support --- dub.json | 2 +- src/ddebug/common/debugger.d | 44 ++++++--- src/ddebug/gdb/gdbinterface.d | 6 ++ src/dlangide/workspace/project.d | 4 - src/dlangide/workspace/projectsettings.d | 1 + src/dlangide/workspace/workspace.d | 108 +++++++++++---------- src/dlangide/workspace/workspacesettings.d | 48 +++++++++ 7 files changed, 147 insertions(+), 66 deletions(-) diff --git a/dub.json b/dub.json index 27f5800..768dd1b 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.12", + "dlangui": "~>0.7.15", "libdparse": "==0.2.0" }, diff --git a/src/ddebug/common/debugger.d b/src/ddebug/common/debugger.d index 0b72407..682b5a2 100644 --- a/src/ddebug/common/debugger.d +++ b/src/ddebug/common/debugger.d @@ -12,19 +12,21 @@ enum DebuggingState { stopped } -interface DebuggerCallback : ProgramExecutionStatusListener { - /// debugger message line - void onDebuggerMessage(string msg); - - /// debugger is started and loaded program, you can set breakpoints at this time - void onProgramLoaded(bool successful, bool debugInfoLoaded); - - /// state changed: running / paused / stopped - void onDebugState(DebuggingState state, string msg, int param); - - void onResponse(ResponseCode code, string msg); +class Breakpoint { + int id; + string file; + string fullFilePath; + string projectFilePath; + int line; + bool enabled; + string projectName; + this() { + id = nextBreakpointId++; + } } +private static __gshared nextBreakpointId = 1; + interface Debugger : ProgramExecution { void setDebuggerCallback(DebuggerCallback callback); void setDebuggerExecutable(string debuggerExecutable); @@ -43,6 +45,22 @@ interface Debugger : ProgramExecution { void execStepIn(); /// step out void execStepOut(); + + /// update list of breakpoints + void setBreakpoints(Breakpoint[] bp); +} + +interface DebuggerCallback : ProgramExecutionStatusListener { + /// debugger message line + void onDebuggerMessage(string msg); + + /// debugger is started and loaded program, you can set breakpoints at this time + void onProgramLoaded(bool successful, bool debugInfoLoaded); + + /// state changed: running / paused / stopped + void onDebugState(DebuggingState state, string msg, int param); + + void onResponse(ResponseCode code, string msg); } enum ResponseCode : int { @@ -173,6 +191,10 @@ class DebuggerProxy : Debugger, DebuggerCallback { void execStepOut() { _debugger.postRequest(delegate() { _debugger.execStepOut(); }); } + /// update list of breakpoints + void setBreakpoints(Breakpoint[] bp) { + _debugger.postRequest(delegate() { _debugger.setBreakpoints(bp); }); + } } abstract class DebuggerBase : Thread, Debugger { diff --git a/src/ddebug/gdb/gdbinterface.d b/src/ddebug/gdb/gdbinterface.d index 530d0d0..e7940da 100644 --- a/src/ddebug/gdb/gdbinterface.d +++ b/src/ddebug/gdb/gdbinterface.d @@ -280,6 +280,12 @@ class GDBInterface : ConsoleDebuggerInterface { _stepOutRequestId = sendCommand("-exec-finish"); } + /// update list of breakpoints + void setBreakpoints(Breakpoint[] bp) { + // TODO + } + + // ~message void handleStreamLineCLI(string s) { Log.d("GDB CLI: ", s); diff --git a/src/dlangide/workspace/project.d b/src/dlangide/workspace/project.d index af71f8e..a061135 100644 --- a/src/dlangide/workspace/project.d +++ b/src/dlangide/workspace/project.d @@ -7,7 +7,6 @@ import dlangui.core.collections; import dlangui.core.settings; import std.path; import std.file; -import std.json; import std.utf; import std.algorithm; import std.process; @@ -589,9 +588,6 @@ class Project : WorkspaceItem { _configurations = ProjectConfiguration.load(_projectFile); Log.i("Project configurations: ", _configurations); - } catch (JSONException e) { - Log.e("Cannot parse json", e); - return false; } catch (Exception e) { Log.e("Cannot read project file", e); return false; diff --git a/src/dlangide/workspace/projectsettings.d b/src/dlangide/workspace/projectsettings.d index 15a7a63..8ac809d 100644 --- a/src/dlangide/workspace/projectsettings.d +++ b/src/dlangide/workspace/projectsettings.d @@ -8,6 +8,7 @@ import dlangide.workspace.idesettings; const AVAILABLE_TOOLCHAINS = ["default", "dmd", "ldc", "gdc"]; const AVAILABLE_ARCH = ["default", "x86", "x86_64"]; +/// local settings for project (not supposed to put under source control) class ProjectSettings : SettingsFile { this(string filename) { diff --git a/src/dlangide/workspace/workspace.d b/src/dlangide/workspace/workspace.d index 7930677..3978e1c 100644 --- a/src/dlangide/workspace/workspace.d +++ b/src/dlangide/workspace/workspace.d @@ -1,16 +1,19 @@ module dlangide.workspace.workspace; import dlangide.workspace.project; +import dlangide.workspace.workspacesettings; import dlangide.ui.frame; import dlangui.core.logger; +import dlangui.core.settings; import std.conv; import std.path; import std.file; -import std.json; import std.range; import std.utf; import std.algorithm; +import ddebug.common.debugger; + enum BuildOperation { Build, Clean, @@ -38,6 +41,7 @@ class WorkspaceException : Exception } immutable string WORKSPACE_EXTENSION = ".dlangidews"; +immutable string WORKSPACE_SETTINGS_EXTENSION = ".wssettings"; /// return true if filename matches rules for workspace file names bool isWorkspaceFile(string filename) { @@ -47,6 +51,8 @@ bool isWorkspaceFile(string filename) { /// DlangIDE workspace class Workspace : WorkspaceItem { protected Project[] _projects; + protected SettingsFile _workspaceFile; + protected WorkspaceSettings _settings; protected IDEFrame _frame; protected BuildConfiguration _buildConfiguration; @@ -54,6 +60,8 @@ class Workspace : WorkspaceItem { this(IDEFrame frame, string fname = null) { super(fname); + _workspaceFile = new SettingsFile(fname); + _settings = new WorkspaceSettings(fname ? fname ~ WORKSPACE_SETTINGS_EXTENSION : null); _frame = frame; } @@ -73,6 +81,7 @@ class Workspace : WorkspaceItem { @property void startupProject(Project project) { _startupProject = project; _frame.setProjectConfigurations(project.configurations.keys.map!(k => k.to!dstring).array); + _settings.startupProjectName = toUTF8(project.name); } /// setups currrent project configuration by name @@ -84,8 +93,19 @@ class Workspace : WorkspaceItem { } protected void fillStartupProject() { - if (!_startupProject && _projects.length) - startupProject = _projects[0]; + string s = _settings.startupProjectName; + if ((!_startupProject || !_startupProject.name.toUTF8.equal(s)) && _projects.length) { + if (!s.empty) { + foreach(p; _projects) { + if (p.name.toUTF8.equal(s)) { + _startupProject = p; + } + } + } + if (!_startupProject) { + startupProject = _projects[0]; + } + } } /// tries to find source file in one of projects, returns found project source file item, or null if not found @@ -128,32 +148,25 @@ class Workspace : WorkspaceItem { return toForwardSlashSeparator(relativePath(path, _dir)); } - override bool save(string fname = null) { if (fname.length > 0) filename = fname; - try { - JSONValue content; - JSONValue[string] json; - json["name"] = JSONValue(toUTF8(_name)); - json["description"] = JSONValue(toUTF8(_description)); - JSONValue[string] projects; - foreach (Project p; _projects) { - if (p.isDependency) - continue; // don't save dependency - string pname = toUTF8(p.name); - string ppath = absoluteToRelativePath(p.filename); - projects[pname] = JSONValue(ppath); - } - json["projects"] = projects; - content = json; - string js = content.toPrettyString; - write(_filename, js); - } catch (JSONException e) { - Log.e("Cannot parse json", e); + if (!filename) // no file name specified return false; - } catch (Exception e) { - Log.e("Cannot read workspace file", e); + _settings.save(filename ~ WORKSPACE_SETTINGS_EXTENSION); + _workspaceFile.setString("name", toUTF8(_name)); + _workspaceFile.setString("description", toUTF8(_description)); + Setting projects = _workspaceFile.objectByPath("projects", true); + projects.clear(SettingType.OBJECT); + foreach (Project p; _projects) { + if (p.isDependency) + continue; // don't save dependency + string pname = toUTF8(p.name); + string ppath = absoluteToRelativePath(p.filename); + projects[pname] = ppath; + } + if (!_workspaceFile.save(_filename, true)) { + Log.e("Cannot save workspace file"); return false; } return true; @@ -166,34 +179,29 @@ class Workspace : WorkspaceItem { return false; } Log.d("Reading workspace from file ", _filename); - - try { - string jsonSource = readText!string(_filename); - JSONValue json = parseJSON(jsonSource); - _name = toUTF32(json["name"].str); - _description = toUTF32(json["description"].str); - Log.d("workspace name: ", _name); - Log.d("workspace description: ", _description); - JSONValue projects = json["projects"]; - foreach(string key, ref JSONValue value; projects) { - string path = value.str; - Log.d("project: ", key, " path:", path); - if (!isAbsolute(path)) - path = buildNormalizedPath(_dir, path); //, "dub.json" - Project project = new Project(this, path); - _projects ~= project; - project.load(); - - } - string js = json.toPrettyString; - write(_filename, js); - } catch (JSONException e) { - Log.e("Cannot parse json", e); + if (!_workspaceFile.load(_filename)) { + Log.e("Cannot read workspace file"); return false; - } catch (Exception e) { - Log.e("Cannot read workspace file", e); + } + _settings.load(filename ~ WORKSPACE_SETTINGS_EXTENSION); + _name = toUTF32(_workspaceFile["name"].str); + _description = toUTF32(_workspaceFile["description"].str); + Log.d("workspace name: ", _name); + Log.d("workspace description: ", _description); + if (_name.empty()) { + Log.e("empty workspace name"); return false; } + Setting projects = _workspaceFile.objectByPath("projects", true); + foreach(string key, Setting value; projects) { + string path = value.str; + Log.d("project: ", key, " path:", path); + if (!isAbsolute(path)) + path = buildNormalizedPath(_dir, path); //, "dub.json" + Project project = new Project(this, path); + _projects ~= project; + project.load(); + } fillStartupProject(); return true; } diff --git a/src/dlangide/workspace/workspacesettings.d b/src/dlangide/workspace/workspacesettings.d index ec6a1da..25cab58 100644 --- a/src/dlangide/workspace/workspacesettings.d +++ b/src/dlangide/workspace/workspacesettings.d @@ -2,15 +2,63 @@ module dlangide.workspace.workspacesettings; import dlangui.core.settings; import dlangui.core.i18n; +import ddebug.common.debugger; +/// local settings for workspace (not supposed to put under source control) class WorkspaceSettings : SettingsFile { this(string filename) { super(filename); } + private Breakpoint[] _breakpoints; + + private string _startupProjectName; + @property string startupProjectName() { + return _startupProjectName; + } + @property void startupProjectName(string s) { + if (s.equal(_startupProjectName)) { + _startupProjectName = s; + save(); + } + } + + void setBreakpoints(Breakpoint[] bps) { + Setting obj = _setting.settingByPath("breakpoints", SettingType.ARRAY); + obj.clear(SettingType.ARRAY); + int index = 0; + foreach(bp; bps) { + Setting bpObj = new Setting(); + bpObj.setInteger("id", bp.id); + bpObj.setString("file", bp.file); + bpObj.setInteger("line", bp.line); + bpObj.setBoolean("enabled", bp.enabled); + bpObj.setString("projectName", bp.projectName); + bpObj.setString("projectFilePath", bp.projectFilePath); + obj[index++] = bpObj; + } + _breakpoints = bps; + save(); + } + + Breakpoint[] getBreakpoints() { + return _breakpoints; + } + /// override to do something after loading - e.g. set defaults override void afterLoad() { + _startupProjectName = _setting.getString("startupProject"); + Setting obj = _setting.settingByPath("breakpoints", SettingType.ARRAY); + _breakpoints = null; + for (int i = 0; i < obj.length; i++) { + Breakpoint bp = new Breakpoint(); + bp.id = cast(int)obj.getInteger("id"); + bp.file = obj.getString("file"); + bp.line = cast(int)obj.getInteger("line"); + bp.enabled = obj.getBoolean("enabled"); + _breakpoints ~= bp; + } } override void updateDefaults() {