mirror of https://github.com/buggins/dlangide.git
breakpoints, bookmarks, workspace; close #72
This commit is contained in:
parent
1b3d8d41ac
commit
fff1d3e87c
|
@ -52,6 +52,9 @@ class DebuggerUIHandler : DebuggerCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onBreakpointListUpdated(Breakpoint[] breakpoints) {
|
||||||
|
}
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
_debugger.run();
|
_debugger.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ interface BreakpointListChangeListener {
|
||||||
void onBreakpointListChanged(ProjectSourceFile sourceFile, Breakpoint[] breakpoints);
|
void onBreakpointListChanged(ProjectSourceFile sourceFile, Breakpoint[] breakpoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface BookmarkListChangeListener {
|
||||||
|
void onBookmarkListChanged(ProjectSourceFile sourceFile, EditorBookmark[] bookmarks);
|
||||||
|
}
|
||||||
|
|
||||||
/// DIDE source file editor
|
/// DIDE source file editor
|
||||||
class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
this(string ID) {
|
this(string ID) {
|
||||||
|
@ -50,6 +54,7 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal!BreakpointListChangeListener breakpointListChanged;
|
Signal!BreakpointListChangeListener breakpointListChanged;
|
||||||
|
Signal!BookmarkListChangeListener bookmarkListChanged;
|
||||||
|
|
||||||
/// handle theme change: e.g. reload some themed resources
|
/// handle theme change: e.g. reload some themed resources
|
||||||
override void onThemeChanged() {
|
override void onThemeChanged() {
|
||||||
|
@ -185,6 +190,10 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
case IDEActions.DebugEnableBreakpoint:
|
case IDEActions.DebugEnableBreakpoint:
|
||||||
case IDEActions.DebugDisableBreakpoint:
|
case IDEActions.DebugDisableBreakpoint:
|
||||||
handleBreakpointAction(a);
|
handleBreakpointAction(a);
|
||||||
|
return true;
|
||||||
|
case EditorActions.ToggleBookmark:
|
||||||
|
super.handleAction(a);
|
||||||
|
notifyBookmarkListChanged();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -234,8 +243,37 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
return breakpoints;
|
return breakpoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBookmarkList(EditorBookmark[] bookmarks) {
|
||||||
|
// remove all existing breakpoints
|
||||||
|
content.lineIcons.removeByType(LineIconType.bookmark);
|
||||||
|
// add new breakpoints
|
||||||
|
foreach(bp; bookmarks) {
|
||||||
|
LineIcon icon = new LineIcon(LineIconType.bookmark, bp.line - 1);
|
||||||
|
content.lineIcons.add(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorBookmark[] getBookmarkList() {
|
||||||
|
import std.path;
|
||||||
|
LineIcon[] icons = content.lineIcons.findByType(LineIconType.bookmark);
|
||||||
|
EditorBookmark[] bookmarks;
|
||||||
|
if (projectSourceFile) {
|
||||||
|
foreach(icon; icons) {
|
||||||
|
EditorBookmark bp = new EditorBookmark();
|
||||||
|
bp.line = icon.line + 1;
|
||||||
|
bp.file = baseName(filename);
|
||||||
|
bp.projectName = projectSourceFile.project.name8;
|
||||||
|
bp.fullFilePath = filename;
|
||||||
|
bp.projectFilePath = projectSourceFile.project.absoluteToRelativePath(filename);
|
||||||
|
bookmarks ~= bp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bookmarks;
|
||||||
|
}
|
||||||
|
|
||||||
protected void onMarksChange(EditableContent content, LineIcon[] movedMarks, LineIcon[] removedMarks) {
|
protected void onMarksChange(EditableContent content, LineIcon[] movedMarks, LineIcon[] removedMarks) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
bool bookmarkChanged = false;
|
||||||
foreach(moved; movedMarks) {
|
foreach(moved; movedMarks) {
|
||||||
if (moved.type == LineIconType.breakpoint) {
|
if (moved.type == LineIconType.breakpoint) {
|
||||||
Breakpoint bp = cast(Breakpoint)moved.objectParam;
|
Breakpoint bp = cast(Breakpoint)moved.objectParam;
|
||||||
|
@ -244,6 +282,13 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
bp.line = moved.line + 1;
|
bp.line = moved.line + 1;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
} else if (moved.type == LineIconType.bookmark) {
|
||||||
|
EditorBookmark bp = cast(EditorBookmark)moved.objectParam;
|
||||||
|
if (bp) {
|
||||||
|
// update Breakpoint line
|
||||||
|
bp.line = moved.line + 1;
|
||||||
|
bookmarkChanged = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach(removed; removedMarks) {
|
foreach(removed; removedMarks) {
|
||||||
|
@ -252,10 +297,17 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
if (bp) {
|
if (bp) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
} else if (removed.type == LineIconType.bookmark) {
|
||||||
|
EditorBookmark bp = cast(EditorBookmark)removed.objectParam;
|
||||||
|
if (bp) {
|
||||||
|
bookmarkChanged = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (changed)
|
if (changed)
|
||||||
notifyBreakpointListChanged();
|
notifyBreakpointListChanged();
|
||||||
|
if (bookmarkChanged)
|
||||||
|
notifyBookmarkListChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void notifyBreakpointListChanged() {
|
protected void notifyBreakpointListChanged() {
|
||||||
|
@ -265,6 +317,13 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void notifyBookmarkListChanged() {
|
||||||
|
if (projectSourceFile) {
|
||||||
|
if (bookmarkListChanged.assigned)
|
||||||
|
bookmarkListChanged(projectSourceFile, getBookmarkList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void handleBreakpointAction(const Action a) {
|
protected void handleBreakpointAction(const Action a) {
|
||||||
int line = a.longParam >= 0 ? cast(int)a.longParam : caretPos.line;
|
int line = a.longParam >= 0 ? cast(int)a.longParam : caretPos.line;
|
||||||
LineIcon icon = content.lineIcons.findByLineAndType(line, LineIconType.breakpoint);
|
LineIcon icon = content.lineIcons.findByLineAndType(line, LineIconType.breakpoint);
|
||||||
|
|
|
@ -67,7 +67,7 @@ class BackgroundOperationWatcherTest : BackgroundOperationWatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DIDE app frame
|
/// DIDE app frame
|
||||||
class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeListener {
|
class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeListener, BookmarkListChangeListener {
|
||||||
|
|
||||||
private ToolBarComboBox projectConfigurationCombo;
|
private ToolBarComboBox projectConfigurationCombo;
|
||||||
|
|
||||||
|
@ -194,6 +194,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
||||||
debuggerProxy.setDebuggerExecutable(debuggerExecutable);
|
debuggerProxy.setDebuggerExecutable(debuggerExecutable);
|
||||||
_execution = debuggerProxy;
|
_execution = debuggerProxy;
|
||||||
_debugHandler = new DebuggerUIHandler(this, debuggerProxy);
|
_debugHandler = new DebuggerUIHandler(this, debuggerProxy);
|
||||||
|
_debugHandler.onBreakpointListUpdated(currentWorkspace.getBreakpoints());
|
||||||
_debugHandler.run();
|
_debugHandler.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,8 +333,12 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
||||||
TabItem tab = _tabs.tab(filename);
|
TabItem tab = _tabs.tab(filename);
|
||||||
tab.objectParam = file;
|
tab.objectParam = file;
|
||||||
editor.modifiedStateChange = &onModifiedStateChange;
|
editor.modifiedStateChange = &onModifiedStateChange;
|
||||||
|
if (file) {
|
||||||
editor.breakpointListChanged = this; //onBreakpointListChanged
|
editor.breakpointListChanged = this; //onBreakpointListChanged
|
||||||
|
editor.bookmarkListChanged = this; //onBreakpointListChanged
|
||||||
editor.setBreakpointList(currentWorkspace.getSourceFileBreakpoints(file));
|
editor.setBreakpointList(currentWorkspace.getSourceFileBreakpoints(file));
|
||||||
|
editor.setBookmarkList(currentWorkspace.getSourceFileBookmarks(file));
|
||||||
|
}
|
||||||
applySettings(editor, settings);
|
applySettings(editor, settings);
|
||||||
_tabs.selectTab(index, true);
|
_tabs.selectTab(index, true);
|
||||||
if( filename.endsWith(".d") )
|
if( filename.endsWith(".d") )
|
||||||
|
@ -874,6 +879,8 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeWorkspace() {
|
void closeWorkspace() {
|
||||||
|
if (currentWorkspace)
|
||||||
|
currentWorkspace.save();
|
||||||
askForUnsavedEdits(delegate() {
|
askForUnsavedEdits(delegate() {
|
||||||
setWorkspace(null);
|
setWorkspace(null);
|
||||||
showHomeScreen();
|
showHomeScreen();
|
||||||
|
@ -886,6 +893,15 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
||||||
if (sourcefile) {
|
if (sourcefile) {
|
||||||
currentWorkspace.setSourceFileBreakpoints(sourcefile, breakpoints);
|
currentWorkspace.setSourceFileBreakpoints(sourcefile, breakpoints);
|
||||||
}
|
}
|
||||||
|
if (_debugHandler)
|
||||||
|
_debugHandler.onBreakpointListUpdated(currentWorkspace.getBreakpoints());
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBookmarkListChanged(ProjectSourceFile sourcefile, EditorBookmark[] bookmarks) {
|
||||||
|
if (!currentWorkspace)
|
||||||
|
return;
|
||||||
|
if (sourcefile)
|
||||||
|
currentWorkspace.setSourceFileBookmarks(sourcefile, bookmarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshProjectItem(const Object obj) {
|
void refreshProjectItem(const Object obj) {
|
||||||
|
@ -1220,6 +1236,8 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
||||||
/// return false to prevent closing
|
/// return false to prevent closing
|
||||||
bool onCanClose() {
|
bool onCanClose() {
|
||||||
askForUnsavedEdits(delegate() {
|
askForUnsavedEdits(delegate() {
|
||||||
|
if (currentWorkspace)
|
||||||
|
currentWorkspace.save();
|
||||||
window.close();
|
window.close();
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -63,6 +63,10 @@ class ProjectItem {
|
||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property string name8() {
|
||||||
|
return _name.toUTF8;
|
||||||
|
}
|
||||||
|
|
||||||
/// returns true if item is folder
|
/// returns true if item is folder
|
||||||
@property const bool isFolder() {
|
@property const bool isFolder() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -234,6 +238,10 @@ class WorkspaceItem {
|
||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property string name8() {
|
||||||
|
return _name.toUTF8;
|
||||||
|
}
|
||||||
|
|
||||||
/// name
|
/// name
|
||||||
@property void name(dstring s) {
|
@property void name(dstring s) {
|
||||||
_name = s;
|
_name = s;
|
||||||
|
@ -722,3 +730,11 @@ bool isValidFileName(string s) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EditorBookmark {
|
||||||
|
string file;
|
||||||
|
string fullFilePath;
|
||||||
|
string projectFilePath;
|
||||||
|
int line;
|
||||||
|
string projectName;
|
||||||
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ class Workspace : WorkspaceItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateBreakpointFiles(Breakpoint[] breakpoints) {
|
private void updateBreakpointFiles(Breakpoint[] breakpoints) {
|
||||||
foreach(bp; breakpoints) {
|
foreach(bp; breakpoints) {
|
||||||
Project project = findProjectByName(bp.projectName);
|
Project project = findProjectByName(bp.projectName);
|
||||||
if (project)
|
if (project)
|
||||||
|
@ -100,6 +100,14 @@ class Workspace : WorkspaceItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateBookmarkFiles(EditorBookmark[] bookmarks) {
|
||||||
|
foreach(bp; bookmarks) {
|
||||||
|
Project project = findProjectByName(bp.projectName);
|
||||||
|
if (project)
|
||||||
|
bp.fullFilePath = project.relativeToAbsolutePath(bp.projectFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Breakpoint[] getSourceFileBreakpoints(ProjectSourceFile file) {
|
Breakpoint[] getSourceFileBreakpoints(ProjectSourceFile file) {
|
||||||
Breakpoint[] res = _settings.getProjectBreakpoints(toUTF8(file.project.name), file.projectFilePath);
|
Breakpoint[] res = _settings.getProjectBreakpoints(toUTF8(file.project.name), file.projectFilePath);
|
||||||
updateBreakpointFiles(res);
|
updateBreakpointFiles(res);
|
||||||
|
@ -110,6 +118,23 @@ class Workspace : WorkspaceItem {
|
||||||
_settings.setProjectBreakpoints(toUTF8(file.project.name), file.projectFilePath, breakpoints);
|
_settings.setProjectBreakpoints(toUTF8(file.project.name), file.projectFilePath, breakpoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditorBookmark[] getSourceFileBookmarks(ProjectSourceFile file) {
|
||||||
|
EditorBookmark[] res = _settings.getProjectBookmarks(toUTF8(file.project.name), file.projectFilePath);
|
||||||
|
updateBookmarkFiles(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSourceFileBookmarks(ProjectSourceFile file, EditorBookmark[] bookmarks) {
|
||||||
|
_settings.setProjectBookmarks(toUTF8(file.project.name), file.projectFilePath, bookmarks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns all workspace breakpoints
|
||||||
|
Breakpoint[] getBreakpoints() {
|
||||||
|
Breakpoint[] res = _settings.getBreakpoints();
|
||||||
|
updateBreakpointFiles(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
protected void fillStartupProject() {
|
protected void fillStartupProject() {
|
||||||
string s = _settings.startupProjectName;
|
string s = _settings.startupProjectName;
|
||||||
if ((!_startupProject || !_startupProject.name.toUTF8.equal(s)) && _projects.length) {
|
if ((!_startupProject || !_startupProject.name.toUTF8.equal(s)) && _projects.length) {
|
||||||
|
@ -178,9 +203,9 @@ class Workspace : WorkspaceItem {
|
||||||
override bool save(string fname = null) {
|
override bool save(string fname = null) {
|
||||||
if (fname.length > 0)
|
if (fname.length > 0)
|
||||||
filename = fname;
|
filename = fname;
|
||||||
if (!filename) // no file name specified
|
if (_filename.empty) // no file name specified
|
||||||
return false;
|
return false;
|
||||||
_settings.save(filename ~ WORKSPACE_SETTINGS_EXTENSION);
|
_settings.save(_filename ~ WORKSPACE_SETTINGS_EXTENSION);
|
||||||
_workspaceFile.setString("name", toUTF8(_name));
|
_workspaceFile.setString("name", toUTF8(_name));
|
||||||
_workspaceFile.setString("description", toUTF8(_description));
|
_workspaceFile.setString("description", toUTF8(_description));
|
||||||
Setting projects = _workspaceFile.objectByPath("projects", true);
|
Setting projects = _workspaceFile.objectByPath("projects", true);
|
||||||
|
|
|
@ -3,6 +3,7 @@ module dlangide.workspace.workspacesettings;
|
||||||
import dlangui.core.settings;
|
import dlangui.core.settings;
|
||||||
import dlangui.core.i18n;
|
import dlangui.core.i18n;
|
||||||
import ddebug.common.debugger;
|
import ddebug.common.debugger;
|
||||||
|
import dlangide.workspace.project;
|
||||||
|
|
||||||
import std.array;
|
import std.array;
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ class WorkspaceSettings : SettingsFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Breakpoint[] _breakpoints;
|
private Breakpoint[] _breakpoints;
|
||||||
|
private EditorBookmark[] _bookmarks;
|
||||||
|
|
||||||
private string _startupProjectName;
|
private string _startupProjectName;
|
||||||
@property string startupProjectName() {
|
@property string startupProjectName() {
|
||||||
|
@ -79,13 +81,71 @@ class WorkspaceSettings : SettingsFile {
|
||||||
obj[index++] = bpObj;
|
obj[index++] = bpObj;
|
||||||
}
|
}
|
||||||
_breakpoints = bps;
|
_breakpoints = bps;
|
||||||
save();
|
//save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get all bookmarks for project (for specified source file only, if specified)
|
||||||
|
EditorBookmark[] getProjectBookmarks(string projectName, string projectFilePath) {
|
||||||
|
EditorBookmark[] res;
|
||||||
|
for (int i = cast(int)_bookmarks.length - 1; i >= 0; i--) {
|
||||||
|
EditorBookmark bp = _bookmarks[i];
|
||||||
|
if (!bp.projectName.equal(projectName))
|
||||||
|
continue;
|
||||||
|
if (!projectFilePath.empty && !bp.projectFilePath.equal(projectFilePath))
|
||||||
|
continue;
|
||||||
|
res ~= bp;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get all bookmarks for project (for specified source file only, if specified)
|
||||||
|
void setProjectBookmarks(string projectName, string projectFilePath, EditorBookmark[] bps) {
|
||||||
|
bool changed = false;
|
||||||
|
for (int i = cast(int)_bookmarks.length - 1; i >= 0; i--) {
|
||||||
|
EditorBookmark bp = _bookmarks[i];
|
||||||
|
if (!bp.projectName.equal(projectName))
|
||||||
|
continue;
|
||||||
|
if (!projectFilePath.empty && !bp.projectFilePath.equal(projectFilePath))
|
||||||
|
continue;
|
||||||
|
for (auto j = i; j < _bookmarks.length - 1; j++)
|
||||||
|
_bookmarks[j] = _bookmarks[j + 1];
|
||||||
|
_bookmarks.length--;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (bps.length) {
|
||||||
|
changed = true;
|
||||||
|
foreach(bp; bps)
|
||||||
|
_bookmarks ~= bp;
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
setBookmarks(_bookmarks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBookmarks(EditorBookmark[] bps) {
|
||||||
|
Setting obj = _setting.settingByPath("bookmarks", SettingType.ARRAY);
|
||||||
|
obj.clear(SettingType.ARRAY);
|
||||||
|
int index = 0;
|
||||||
|
foreach(bp; bps) {
|
||||||
|
Setting bpObj = new Setting();
|
||||||
|
bpObj.setString("file", bp.file);
|
||||||
|
bpObj.setInteger("line", bp.line);
|
||||||
|
bpObj.setString("projectName", bp.projectName);
|
||||||
|
bpObj.setString("projectFilePath", bp.projectFilePath);
|
||||||
|
obj[index++] = bpObj;
|
||||||
|
}
|
||||||
|
_bookmarks = bps;
|
||||||
|
//save();
|
||||||
}
|
}
|
||||||
|
|
||||||
Breakpoint[] getBreakpoints() {
|
Breakpoint[] getBreakpoints() {
|
||||||
return _breakpoints;
|
return _breakpoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditorBookmark[] getBookmarks() {
|
||||||
|
return _bookmarks;
|
||||||
|
}
|
||||||
|
|
||||||
/// override to do something after loading - e.g. set defaults
|
/// override to do something after loading - e.g. set defaults
|
||||||
override void afterLoad() {
|
override void afterLoad() {
|
||||||
_startupProjectName = _setting.getString("startupProject");
|
_startupProjectName = _setting.getString("startupProject");
|
||||||
|
@ -102,6 +162,17 @@ class WorkspaceSettings : SettingsFile {
|
||||||
bp.enabled = item.getBoolean("enabled");
|
bp.enabled = item.getBoolean("enabled");
|
||||||
_breakpoints ~= bp;
|
_breakpoints ~= bp;
|
||||||
}
|
}
|
||||||
|
obj = _setting.settingByPath("bookmarks", SettingType.ARRAY);
|
||||||
|
_bookmarks = null;
|
||||||
|
for (int i = 0; i < obj.length; i++) {
|
||||||
|
EditorBookmark bp = new EditorBookmark();
|
||||||
|
Setting item = obj[i];
|
||||||
|
bp.file = item.getString("file");
|
||||||
|
bp.projectName = item.getString("projectName");
|
||||||
|
bp.projectFilePath = item.getString("projectFilePath");
|
||||||
|
bp.line = cast(int)item.getInteger("line");
|
||||||
|
_bookmarks ~= bp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override void updateDefaults() {
|
override void updateDefaults() {
|
||||||
|
|
Loading…
Reference in New Issue