store breakpoints for workspace - close #69

This commit is contained in:
Vadim Lopatin 2015-12-15 12:40:29 +03:00
parent c52afa7b75
commit 1b3d8d41ac
7 changed files with 181 additions and 10 deletions

View File

@ -14,7 +14,7 @@
"copyFiles-windows": ["lib/win32/dcd-server.exe", "lib/win32/dcd-client.exe"],
"dependencies": {
"dlangui": "~>0.7.17",
"dlangui": "~>0.7.18",
"libdparse": "==0.2.0"
},

View File

@ -18,7 +18,7 @@ class Breakpoint {
string fullFilePath;
string projectFilePath;
int line;
bool enabled;
bool enabled = true;
string projectName;
this() {
id = nextBreakpointId++;

View File

@ -1,6 +1,7 @@
module dlangide.ui.dsourceedit;
import dlangui.core.logger;
import dlangui.core.signals;
import dlangui.widgets.editors;
import dlangui.widgets.srcedit;
import dlangui.widgets.menu;
@ -16,12 +17,17 @@ import dlangide.ui.commands;
import dlangide.ui.settings;
import dlangide.tools.d.dsyntax;
import dlangide.tools.editorTool;
import ddebug.common.debugger;
import std.algorithm;
import std.utf : toUTF8, toUTF32;
interface BreakpointListChangeListener {
void onBreakpointListChanged(ProjectSourceFile sourceFile, Breakpoint[] breakpoints);
}
/// DIDE source file editor
class DSourceEdit : SourceEdit {
class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
this(string ID) {
super(ID);
styleId = null;
@ -36,12 +42,15 @@ class DSourceEdit : SourceEdit {
popupMenu = editPopupItem;
showIcons = true;
showFolding = true;
content.marksChanged = this;
}
this() {
this("SRCEDIT");
}
Signal!BreakpointListChangeListener breakpointListChanged;
/// handle theme change: e.g. reload some themed resources
override void onThemeChanged() {
backgroundColor = style.customColor("edit_background");
@ -184,15 +193,87 @@ class DSourceEdit : SourceEdit {
return super.handleAction(a);
}
protected void addBreakpoint(int line) {
import std.path;
Breakpoint bp = new Breakpoint();
bp.file = baseName(filename);
bp.line = line + 1;
bp.fullFilePath = filename;
if (projectSourceFile) {
bp.projectName = toUTF8(projectSourceFile.project.name);
bp.projectFilePath = projectSourceFile.project.absoluteToRelativePath(filename);
}
LineIcon icon = new LineIcon(LineIconType.breakpoint, line, bp);
content.lineIcons.add(icon);
notifyBreakpointListChanged();
}
protected void removeBreakpoint(int line, LineIcon icon) {
content.lineIcons.remove(icon);
notifyBreakpointListChanged();
}
void setBreakpointList(Breakpoint[] breakpoints) {
// remove all existing breakpoints
content.lineIcons.removeByType(LineIconType.breakpoint);
// add new breakpoints
foreach(bp; breakpoints) {
LineIcon icon = new LineIcon(LineIconType.breakpoint, bp.line - 1, bp);
content.lineIcons.add(icon);
}
}
Breakpoint[] getBreakpointList() {
LineIcon[] icons = content.lineIcons.findByType(LineIconType.breakpoint);
Breakpoint[] breakpoints;
foreach(icon; icons) {
Breakpoint bp = cast(Breakpoint)icon.objectParam;
if (bp)
breakpoints ~= bp;
}
return breakpoints;
}
protected void onMarksChange(EditableContent content, LineIcon[] movedMarks, LineIcon[] removedMarks) {
bool changed = false;
foreach(moved; movedMarks) {
if (moved.type == LineIconType.breakpoint) {
Breakpoint bp = cast(Breakpoint)moved.objectParam;
if (bp) {
// update Breakpoint line
bp.line = moved.line + 1;
changed = true;
}
}
}
foreach(removed; removedMarks) {
if (removed.type == LineIconType.breakpoint) {
Breakpoint bp = cast(Breakpoint)removed.objectParam;
if (bp) {
changed = true;
}
}
}
if (changed)
notifyBreakpointListChanged();
}
protected void notifyBreakpointListChanged() {
if (projectSourceFile) {
if (breakpointListChanged.assigned)
breakpointListChanged(projectSourceFile, getBreakpointList());
}
}
protected void handleBreakpointAction(const Action a) {
int line = a.longParam >= 0 ? cast(int)a.longParam : caretPos.line;
LineIcon icon = content.lineIcons.findByLineAndType(line, LineIconType.breakpoint);
switch(a.id) {
case IDEActions.DebugToggleBreakpoint:
if (icon)
content.lineIcons.remove(icon);
removeBreakpoint(line, icon);
else
content.lineIcons.add(new LineIcon(LineIconType.breakpoint, line));
addBreakpoint(line);
break;
case IDEActions.DebugEnableBreakpoint:
break;

View File

@ -67,7 +67,7 @@ class BackgroundOperationWatcherTest : BackgroundOperationWatcher {
}
/// DIDE app frame
class IDEFrame : AppFrame, ProgramExecutionStatusListener {
class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeListener {
private ToolBarComboBox projectConfigurationCombo;
@ -332,6 +332,8 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener {
TabItem tab = _tabs.tab(filename);
tab.objectParam = file;
editor.modifiedStateChange = &onModifiedStateChange;
editor.breakpointListChanged = this; //onBreakpointListChanged
editor.setBreakpointList(currentWorkspace.getSourceFileBreakpoints(file));
applySettings(editor, settings);
_tabs.selectTab(index, true);
if( filename.endsWith(".d") )
@ -878,6 +880,14 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener {
});
}
void onBreakpointListChanged(ProjectSourceFile sourcefile, Breakpoint[] breakpoints) {
if (!currentWorkspace)
return;
if (sourcefile) {
currentWorkspace.setSourceFileBreakpoints(sourcefile, breakpoints);
}
}
void refreshProjectItem(const Object obj) {
if (currentWorkspace is null)
return;

View File

@ -192,6 +192,10 @@ class ProjectSourceFile : ProjectItem {
this(string filename) {
super(filename);
}
/// file path relative to project directory
@property string projectFilePath() {
return project.absoluteToRelativePath(filename);
}
}
class WorkspaceItem {
@ -436,6 +440,12 @@ class Project : WorkspaceItem {
return buildNormalizedPath(_dir, path);
}
string absoluteToRelativePath(string path) {
if (!isAbsolute(path))
return path;
return relativePath(path, _dir);
}
@property ProjectSourceFile mainSourceFile() { return _mainSourceFile; }
@property ProjectFolder items() {
return _items;

View File

@ -91,6 +91,24 @@ class Workspace : WorkspaceItem {
_projectConfiguration = _startupProject.configurations[conf];
}
}
void updateBreakpointFiles(Breakpoint[] breakpoints) {
foreach(bp; breakpoints) {
Project project = findProjectByName(bp.projectName);
if (project)
bp.fullFilePath = project.relativeToAbsolutePath(bp.projectFilePath);
}
}
Breakpoint[] getSourceFileBreakpoints(ProjectSourceFile file) {
Breakpoint[] res = _settings.getProjectBreakpoints(toUTF8(file.project.name), file.projectFilePath);
updateBreakpointFiles(res);
return res;
}
void setSourceFileBreakpoints(ProjectSourceFile file, Breakpoint[] breakpoints) {
_settings.setProjectBreakpoints(toUTF8(file.project.name), file.projectFilePath, breakpoints);
}
protected void fillStartupProject() {
string s = _settings.startupProjectName;
@ -127,6 +145,15 @@ class Workspace : WorkspaceItem {
return null;
}
/// find project in workspace by filename
Project findProjectByName(string name) {
foreach (Project p; _projects) {
if (p.name.toUTF8.equal(name))
return p;
}
return null;
}
void addProject(Project p) {
_projects ~= p;
p.workspace = this;

View File

@ -4,6 +4,8 @@ import dlangui.core.settings;
import dlangui.core.i18n;
import ddebug.common.debugger;
import std.array;
/// local settings for workspace (not supposed to put under source control)
class WorkspaceSettings : SettingsFile {
@ -24,6 +26,44 @@ class WorkspaceSettings : SettingsFile {
}
}
/// get all breakpoints for project (for specified source file only, if specified)
Breakpoint[] getProjectBreakpoints(string projectName, string projectFilePath) {
Breakpoint[] res;
for (int i = cast(int)_breakpoints.length - 1; i >= 0; i--) {
Breakpoint bp = _breakpoints[i];
if (!bp.projectName.equal(projectName))
continue;
if (!projectFilePath.empty && !bp.projectFilePath.equal(projectFilePath))
continue;
res ~= bp;
}
return res;
}
/// get all breakpoints for project (for specified source file only, if specified)
void setProjectBreakpoints(string projectName, string projectFilePath, Breakpoint[] bps) {
bool changed = false;
for (int i = cast(int)_breakpoints.length - 1; i >= 0; i--) {
Breakpoint bp = _breakpoints[i];
if (!bp.projectName.equal(projectName))
continue;
if (!projectFilePath.empty && !bp.projectFilePath.equal(projectFilePath))
continue;
for (auto j = i; j < _breakpoints.length - 1; j++)
_breakpoints[j] = _breakpoints[j + 1];
_breakpoints.length--;
changed = true;
}
if (bps.length) {
changed = true;
foreach(bp; bps)
_breakpoints ~= bp;
}
if (changed) {
setBreakpoints(_breakpoints);
}
}
void setBreakpoints(Breakpoint[] bps) {
Setting obj = _setting.settingByPath("breakpoints", SettingType.ARRAY);
obj.clear(SettingType.ARRAY);
@ -53,10 +93,13 @@ class WorkspaceSettings : SettingsFile {
_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");
Setting item = obj[i];
bp.id = cast(int)item.getInteger("id");
bp.file = item.getString("file");
bp.projectName = item.getString("projectName");
bp.projectFilePath = item.getString("projectFilePath");
bp.line = cast(int)item.getInteger("line");
bp.enabled = item.getBoolean("enabled");
_breakpoints ~= bp;
}
}