diff --git a/README.md b/README.md index 3fb4e4b..8de7a00 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,5 @@ [](https://gitter.im/buggins/dlangide?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/buggins/dlangide) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=H2ADZV8S6TDHQ "Donate once-off to this project using Paypal") -WTF?! (What The Fork) -====================== -Now you can set dmd includes paths (for correct work with DCD) in workspace settings file (newworkspace.dlangidews) -
-example:
-{
- "name" : "newworkspace",
- "description" : null,
- "projects" : {
- "newproject" : "newproject/dub.json"
- },
- "includePath" : [
- "/usr/include/dlang/dmd/"
- ]
-}
-
-PS.
- Sorry about bad code. Please correct me.
-
Dlang IDE
=========
@@ -82,6 +63,14 @@ Keywan Ghadami improved it to use DCD as a library.
Now DCD is embedded into DlangIDE, and no separate executables are needed.
+Importing of existing project
+=============================
+
+DlangIDE supports only DUB project format.
+
+To import existing DUB project, use menu item "File" / "Open project or workspace" and select dub.json or dub.sdl of your project to import.
+
+
Debugger support
================
@@ -193,3 +182,22 @@ OSX: open solution file with Mono-D
Choose dlangide as startup project.
Coding style: [https://github.com/buggins/dlangui/blob/master/CODING_STYLE.md](https://github.com/buggins/dlangui/blob/master/CODING_STYLE.md)
+
+
+Workspace include path setting
+==============================
+
+Now you can set dmd includes paths (for correct work with DCD) in workspace settings file (newworkspace.dlangidews)
+
+example:
+{
+ "name" : "newworkspace",
+ "description" : null,
+ "projects" : {
+ "newproject" : "newproject/dub.json"
+ },
+ "includePath" : [
+ "/usr/include/dlang/dmd/"
+ ]
+}
+
diff --git a/dub.json b/dub.json
index 026d787..220ab31 100644
--- a/dub.json
+++ b/dub.json
@@ -12,7 +12,7 @@
"stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/hdpi"],
"dependencies": {
- "dlangui": "==0.9.99",
+ "dlangui": "==0.9.120",
"dcd": "~>0.9.1"
},
diff --git a/src/dlangide/tools/d/dcdinterface.d b/src/dlangide/tools/d/dcdinterface.d
index c465825..a8b1a21 100644
--- a/src/dlangide/tools/d/dcdinterface.d
+++ b/src/dlangide/tools/d/dcdinterface.d
@@ -30,9 +30,14 @@ enum DCDResult : int {
FAIL,
}
+struct CompletionSymbol {
+ dstring name;
+ char kind;
+}
+
alias DocCommentsResultSet = Tuple!(DCDResult, "result", string[], "docComments");
alias FindDeclarationResultSet = Tuple!(DCDResult, "result", string, "fileName", ulong, "offset");
-alias CompletionResultSet = Tuple!(DCDResult, "result", dstring[], "output", char[], "completionKinds");
+alias CompletionResultSet = Tuple!(DCDResult, "result", CompletionSymbol[], "output");
class DCDTask {
@@ -72,11 +77,14 @@ class DCDTask {
if (_cancelled)
return;
createRequest();
+ if (_cancelled)
+ return;
performRequest();
synchronized(this) {
if (_cancelled)
return;
- _guiExecutor.executeInUiThread(&postResults);
+ if (_guiExecutor)
+ _guiExecutor.executeInUiThread(&postResults);
}
}
}
@@ -183,6 +191,29 @@ class DCDInterface : Thread {
return "";
}
+ /// DCD doc comments task
+ class ModuleCacheWarmupTask : DCDTask {
+
+ this(CustomEventTarget guiExecutor, string[] importPaths) {
+ super(guiExecutor, importPaths, null, null, 0);
+ }
+
+ override void performRequest() {
+ debug(DCD) Log.d("DCD - warm up module cache with import paths ", _importPaths);
+ getModuleCache(_importPaths);
+ debug(DCD) Log.d("DCD - module cache warm up finished");
+ }
+ override void postResults() {
+ }
+ }
+
+ DCDTask warmUp(string[] importPaths) {
+ debug(DCD) Log.d("DCD warmUp: ", importPaths);
+ ModuleCacheWarmupTask task = new ModuleCacheWarmupTask(null, importPaths);
+ _queue.put(task);
+ return task;
+ }
+
/// DCD doc comments task
class DocCommentsTask : DCDTask {
@@ -275,16 +306,17 @@ class DCDInterface : Thread {
result.result = DCDResult.SUCCESS;
result.output.length = response.completions.length;
- result.completionKinds.length = response.completions.length;
int i=0;
foreach(s;response.completions) {
char type = 0;
if (i < response.completionKinds.length)
type = response.completionKinds[i];
- result.completionKinds[i] = type;
- result.output[i++] = to!dstring(s);
+ result.output[i].kind = type;
+ result.output[i].name = to!dstring(s);
+ i++;
}
- debug(DCD) Log.d("DCD output:\n", response.completions);
+ postProcessCompletions(result.output);
+ debug(DCD) Log.d("DCD response:\n", response, "\nCompletion result:\n", result.output);
}
override void postResults() {
_callback(result);
@@ -301,6 +333,87 @@ class DCDInterface : Thread {
}
+int completionTypePriority(char t) {
+ switch(t) {
+ case 'c': // - class name
+ return 10;
+ case 'i': // - interface name
+ return 10;
+ case 's': // - struct name
+ return 10;
+ case 'u': // - union name
+ return 10;
+ case 'v': // - variable name
+ return 5;
+ case 'm': // - member variable name
+ return 3;
+ case 'k': // - keyword, built-in version, scope statement
+ return 20;
+ case 'f': // - function or method
+ return 2;
+ case 'g': // - enum name
+ return 9;
+ case 'e': // - enum member
+ return 8;
+ case 'P': // - package name
+ return 30;
+ case 'M': // - module name
+ return 20;
+ case 'a': // - array
+ return 15;
+ case 'A': // - associative array
+ return 15;
+ case 'l': // - alias name
+ return 15;
+ case 't': // - template name
+ return 14;
+ case 'T': // - mixin template name
+ return 14;
+ default:
+ return 50;
+ }
+}
+
+int compareCompletionSymbol(ref CompletionSymbol v1, ref CompletionSymbol v2) {
+ import std.algorithm : cmp;
+ int p1 = v1.kind.completionTypePriority;
+ int p2 = v2.kind.completionTypePriority;
+ if (p1 < p2)
+ return -1;
+ if (p1 > p2)
+ return 1;
+ return v1.name.cmp(v2.name);
+}
+
+bool lessCompletionSymbol(ref CompletionSymbol v1, ref CompletionSymbol v2) {
+ return compareCompletionSymbol(v1, v2) < 0;
+}
+
+void postProcessCompletions(ref CompletionSymbol[] completions) {
+ import std.algorithm.sorting : sort;
+ completions.sort!(lessCompletionSymbol);
+ CompletionSymbol[] res;
+ bool hasKeywords = false;
+ bool hasNonKeywords = false;
+ bool[dstring] found;
+ foreach(s; completions) {
+ if (s.kind == 'k')
+ hasKeywords = true;
+ else
+ hasNonKeywords = true;
+ }
+ // remove duplicates; remove keywords if non-keyword items are found
+ foreach(s; completions) {
+ if (!(s.name in found)) {
+ found[s.name] = true;
+ if (s.kind != 'k' || !hasNonKeywords) {
+ res ~= s;
+ }
+ }
+ }
+ completions = res;
+}
+
/// to test broken DCD after DUB invocation
/// run it after DCD ModuleCache is instantiated
diff --git a/src/dlangide/tools/d/deditortool.d b/src/dlangide/tools/d/deditortool.d
index bde0927..29fe92d 100644
--- a/src/dlangide/tools/d/deditortool.d
+++ b/src/dlangide/tools/d/deditortool.d
@@ -63,6 +63,7 @@ class DEditorTool : EditorTool
override void cancelGetDocComments() {
if (_getDocCommentsTask) {
+ Log.d("Cancelling getDocComments()");
_getDocCommentsTask.cancel();
_getDocCommentsTask = null;
}
@@ -70,6 +71,7 @@ class DEditorTool : EditorTool
override void cancelGoToDefinition() {
if (_goToDefinitionTask) {
+ Log.d("Cancelling goToDefinition()");
_goToDefinitionTask.cancel();
_goToDefinitionTask = null;
}
@@ -77,6 +79,7 @@ class DEditorTool : EditorTool
override void cancelGetCompletions() {
if (_getCompletionsTask) {
+ Log.d("Cancelling getCompletions()");
_getCompletionsTask.cancel();
_getCompletionsTask = null;
}
@@ -125,6 +128,7 @@ class DEditorTool : EditorTool
DCDTask _getCompletionsTask;
override void getCompletions(DSourceEdit editor, TextPosition caretPosition, void delegate(dstring[] completions, string[] icons) callback) {
+ cancelGetCompletions();
string[] importPaths = editor.importPaths();
string content = toUTF8(editor.text);
@@ -134,7 +138,7 @@ class DEditorTool : EditorTool
dstring[] labels;
foreach(index, label; output.output) {
string iconId;
- char ch = index < output.completionKinds.length ? output.completionKinds[index] : 0;
+ char ch = label.kind;
switch(ch) {
case 'c': // - class name
iconId = "symbol-class";
@@ -188,12 +192,11 @@ class DEditorTool : EditorTool
iconId = "symbol-mixintemplate";
break;
default:
+ iconId = "symbol-other";
break;
}
- if (!iconId)
- iconId = "symbol-other";
icons ~= iconId;
- labels ~= label;
+ labels ~= label.name;
}
callback(labels, icons);
_getCompletionsTask = null;
diff --git a/src/dlangide/tools/d/dsyntax.d b/src/dlangide/tools/d/dsyntax.d
index bdcad07..b2d91ed 100644
--- a/src/dlangide/tools/d/dsyntax.d
+++ b/src/dlangide/tools/d/dsyntax.d
@@ -653,11 +653,15 @@ class SimpleDSyntaxSupport : SyntaxSupport {
dstring lineText = _content.line(line);
TextLineMeasure lineMeasurement = _content.measureLine(line);
TextLineMeasure prevLineMeasurement = _content.measureLine(prevLine);
+ bool prevLineSpaceOnly = false;
+ if (prevLineMeasurement.empty && prevLineMeasurement.len) {
+ prevLineSpaceOnly = true;
+ }
while (prevLineMeasurement.empty && prevLine > 0) {
prevLine--;
prevLineMeasurement = _content.measureLine(prevLine);
}
- if (lineMeasurement.firstNonSpaceX >= 0 && lineMeasurement.firstNonSpaceX < prevLineMeasurement.firstNonSpaceX) {
+ if (lineMeasurement.firstNonSpaceX >= 0 && lineMeasurement.firstNonSpaceX <= prevLineMeasurement.firstNonSpaceX) {
dstring prevLineText = _content.line(prevLine);
TokenPropString prevLineTokenProps = _content.lineTokenProps(prevLine);
dchar lastOpChar = 0;
@@ -674,7 +678,16 @@ class SimpleDSyntaxSupport : SyntaxSupport {
if (lastOpChar == '{')
spacex = _content.nextTab(spacex);
dstring txt = _content.fillSpace(spacex);
- EditOperation op2 = new EditOperation(EditAction.Replace, TextRange(TextPosition(line, 0), TextPosition(line, lineMeasurement.firstNonSpace >= 0 ? lineMeasurement.firstNonSpace : 0)), [txt]);
+ dstring[] newContent;
+ auto startPos = TextPosition(line, 0);
+ auto endPos = TextPosition(line, lineMeasurement.firstNonSpace >= 0 ? lineMeasurement.firstNonSpace : 0);
+ if (prevLineSpaceOnly) {
+ // clear spaces from previous line
+ startPos.line--;
+ newContent ~= ""d;
+ }
+ newContent ~= txt;
+ EditOperation op2 = new EditOperation(EditAction.Replace, TextRange(startPos, endPos), newContent);
_opInProgress = true;
_content.performOperation(op2, source);
_opInProgress = false;
diff --git a/src/dlangide/ui/commands.d b/src/dlangide/ui/commands.d
index 0d438d6..dd11b17 100644
--- a/src/dlangide/ui/commands.d
+++ b/src/dlangide/ui/commands.d
@@ -46,8 +46,10 @@ enum IDEActions : int {
HelpAbout,
HelpViewHelp,
+ HelpDonate,
WindowCloseDocument,
WindowCloseAllDocuments,
+ WindowShowHomeScreen,
CreateNewWorkspace,
AddToCurrentWorkspace,
//ProjectFolderAddItem,
@@ -129,8 +131,10 @@ const Action ACTION_EDIT_TOGGLE_BLOCK_COMMENT = (new Action(EditorActions.Toggle
const Action ACTION_EDIT_PREFERENCES = (new Action(IDEActions.EditPreferences, "MENU_EDIT_PREFERENCES"c, null)).disableByDefault();
const Action ACTION_HELP_ABOUT = new Action(IDEActions.HelpAbout, "MENU_HELP_ABOUT"c);
const Action ACTION_HELP_VIEW_HELP = new Action(IDEActions.HelpViewHelp, "MENU_HELP_VIEW_HELP"c);
+const Action ACTION_HELP_DONATE = new Action(IDEActions.HelpDonate, "MENU_HELP_DONATE"c);
const Action ACTION_WINDOW_CLOSE_DOCUMENT = new Action(IDEActions.WindowCloseDocument, "MENU_WINDOW_CLOSE_DOCUMENT"c, null, KeyCode.KEY_W, KeyFlag.Control);
const Action ACTION_WINDOW_CLOSE_ALL_DOCUMENTS = new Action(IDEActions.WindowCloseAllDocuments, "MENU_WINDOW_CLOSE_ALL_DOCUMENTS"c);
+const Action ACTION_WINDOW_SHOW_HOME_SCREEN = new Action(IDEActions.WindowShowHomeScreen, "MENU_WINDOW_SHOW_HOME_SCREEN"c);
const Action ACTION_CREATE_NEW_WORKSPACE = new Action(IDEActions.CreateNewWorkspace, "OPTION_CREATE_NEW_WORKSPACE"c);
const Action ACTION_ADD_TO_CURRENT_WORKSPACE = new Action(IDEActions.AddToCurrentWorkspace, "OPTION_ADD_TO_CURRENT_WORKSPACE"c);
diff --git a/src/dlangide/ui/dsourceedit.d b/src/dlangide/ui/dsourceedit.d
index fbdeb66..046dd16 100644
--- a/src/dlangide/ui/dsourceedit.d
+++ b/src/dlangide/ui/dsourceedit.d
@@ -95,6 +95,7 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
@property IDESettings settings() {
return _settings;
}
+ protected int _previousFontSizeSetting;
void applySettings() {
if (!_settings)
return;
@@ -111,6 +112,12 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
face ~= ",";
face ~= DEFAULT_SOURCE_EDIT_FONT_FACES;
fontFace = face;
+ int newFontSizeSetting = _settings.editorFontSize;
+ bool needChangeFontSize = _previousFontSizeSetting == 0 || (_previousFontSizeSetting != newFontSizeSetting && _previousFontSizeSetting.pointsToPixels == fontSize);
+ if (needChangeFontSize) {
+ fontSize = newFontSizeSetting.pointsToPixels;
+ _previousFontSizeSetting = newFontSizeSetting;
+ }
}
protected EditorTool _editorTool;
@@ -504,17 +511,25 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
lineCount = 1;
// TODO
EditBox widget = new EditBox("docComments");
+ widget.styleId = "POPUP_MENU";
widget.readOnly = true;
//TextWidget widget = new TextWidget("docComments");
//widget.maxLines = lineCount * 2;
//widget.text = "Test popup"d; //text.dup;
widget.text = text.dup;
+
+ Point bestSize = widget.fullContentSizeWithBorders();
//widget.layoutHeight = lineCount * widget.fontSize;
- widget.minHeight = (lineCount + 1) * widget.fontSize;
- widget.maxWidth = width * 3 / 4;
- widget.minWidth = width / 8;
+ if (bestSize.y > height / 3)
+ bestSize.y = height / 3;
+ if (bestSize.x > width * 3 / 4)
+ bestSize.x = width * 3 / 4;
+ widget.minHeight = bestSize.y; //max((lineCount + 1) * widget.fontSize, bestSize.y);
+ widget.maxHeight = bestSize.y;
+
+ widget.maxWidth = bestSize.x; //width * 3 / 4;
+ widget.minWidth = bestSize.x; //width / 8;
// widget.layoutWidth = width / 3;
- widget.styleId = "POPUP_MENU";
widget.hscrollbarMode = ScrollBarMode.Auto;
widget.vscrollbarMode = ScrollBarMode.Auto;
uint pos = PopupAlign.Above;
diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d
index c741a11..d79de53 100644
--- a/src/dlangide/ui/frame.d
+++ b/src/dlangide/ui/frame.d
@@ -44,7 +44,6 @@ import std.array : empty;
import std.string : split;
import std.path;
-immutable string HELP_PAGE_URL = "https://github.com/buggins/dlangide/wiki";
// TODO: get version from GIT commit
//version is now stored in file views/VERSION
immutable dstring DLANGIDE_VERSION = toUTF32(import("VERSION"));
@@ -667,6 +666,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
_wsPanel.workspaceActionListener = &handleAction;
_wsPanel.dockAlignment = DockAlignment.Left;
_dockHost.addDockedWindow(_wsPanel);
+ _wsPanel.visibility = Visibility.Gone;
_logPanel = new OutputPanel("output");
_logPanel.compilerLogIssueClickHandler = &onCompilerLogIssueClick;
@@ -731,11 +731,9 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
MenuItem windowItem = new MenuItem(new Action(3, "MENU_WINDOW"c));
//windowItem.add(new Action(30, "MENU_WINDOW_PREFERENCES"));
- windowItem.add(ACTION_WINDOW_CLOSE_DOCUMENT);
- windowItem.add(ACTION_WINDOW_CLOSE_ALL_DOCUMENTS);
+ windowItem.add(ACTION_WINDOW_CLOSE_DOCUMENT, ACTION_WINDOW_CLOSE_ALL_DOCUMENTS, ACTION_WINDOW_SHOW_HOME_SCREEN);
MenuItem helpItem = new MenuItem(new Action(4, "MENU_HELP"c));
- helpItem.add(ACTION_HELP_VIEW_HELP);
- helpItem.add(ACTION_HELP_ABOUT);
+ helpItem.add(ACTION_HELP_VIEW_HELP, ACTION_HELP_ABOUT, ACTION_HELP_DONATE);
mainMenuItems.add(fileItem);
mainMenuItems.add(editItem);
mainMenuItems.add(projectItem);
@@ -831,6 +829,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
case IDEActions.FileOpen:
case IDEActions.WindowCloseDocument:
case IDEActions.WindowCloseAllDocuments:
+ case IDEActions.WindowShowHomeScreen:
case IDEActions.FileOpenWorkspace:
// disable when background operation in progress
if (!_currentBackgroundOperation)
@@ -914,6 +913,9 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
case IDEActions.HelpViewHelp:
Platform.instance.openURL(HELP_PAGE_URL);
return true;
+ case IDEActions.HelpDonate:
+ Platform.instance.openURL(HELP_DONATION_URL);
+ return true;
case IDEActions.HelpAbout:
//debug {
// testDCDFailAfterThreadCreation();
@@ -1033,6 +1035,9 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
closeAllDocuments();
});
return true;
+ case IDEActions.WindowShowHomeScreen:
+ showHomeScreen();
+ return true;
case IDEActions.FileOpenWorkspace:
// Already specified workspace
if (!a.stringParam.empty) {
@@ -1103,8 +1108,11 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
_logPanel.getTabs.selectTab("search");
if(searchPanel !is null) {
searchPanel.focus();
- dstring selectedText = currentEditor.getSelectedText();
+ dstring selectedText;
+ if (currentEditor)
+ selectedText = currentEditor.getSelectedText();
searchPanel.setSearchText(selectedText);
+ searchPanel.checkSearchMode();
}
return true;
case IDEActions.FileNewWorkspace:
@@ -1114,7 +1122,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
createNewProject(false);
return true;
case IDEActions.FileNew:
- addProjectItem(a.objectParam);
+ addProjectItem(cast(Object)a.objectParam);
return true;
case IDEActions.ProjectFolderRemoveItem:
removeProjectItem(a.objectParam);
@@ -1228,9 +1236,15 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
}
- void addProjectItem(const Object obj) {
+ /// add new file to project
+ void addProjectItem(Object obj) {
if (currentWorkspace is null)
return;
+ if (obj is null && _wsPanel !is null && !currentEditorSourceFile) {
+ obj = _wsPanel.selectedProjectItem;
+ if (!obj)
+ obj = currentWorkspace.startupProject;
+ }
Project project;
ProjectFolder folder;
if (cast(Project)obj) {
@@ -1320,6 +1334,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
if (!project)
return;
currentWorkspace.startupProject = project;
+ warmUpImportPaths(project);
if (_wsPanel)
_wsPanel.updateDefault();
}
@@ -1370,8 +1385,10 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
currentTheme.fontSize = settings.uiFontSize;
needUpdateTheme = true;
}
- if (needUpdateTheme)
+ if (needUpdateTheme) {
+ Log.d("updating theme after UI font change");
Platform.instance.onThemeChanged();
+ }
requestLayout();
}
@@ -1387,15 +1404,21 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
}
const auto msg = UIString.fromId("MSG_OPENED_PROJECT"c);
_logPanel.logLine(toUTF32("Project file " ~ project.filename ~ " is opened ok"));
+
+ warmUpImportPaths(project);
return true;
}
+ public void warmUpImportPaths(Project project) {
+ dcdInterface.warmUp(project.importPaths);
+ }
+
void openFileOrWorkspace(string filename) {
// Open DlangIDE workspace file
if (filename.isWorkspaceFile) {
Workspace ws = new Workspace(this);
if (ws.load(filename)) {
- askForUnsavedEdits(delegate() {
+ askForUnsavedEdits(delegate() {
setWorkspace(ws);
hideHomeScreen();
// Write workspace to recent workspaces list
@@ -1425,6 +1448,11 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
const auto msg = UIString.fromId("MSG_TRY_OPEN_PROJECT"c).value;
_logPanel.logLine(msg ~ toUTF32(" " ~ filename));
Project project = new Project(currentWorkspace, filename);
+ if (!loadProject(project)) {
+ //window.showMessageBox(UIString.fromId("MSG_OPEN_PROJECT"c), UIString.fromId("ERROR_INVALID_WS_OR_PROJECT_FILE"c));
+ //_logPanel.logLine("File is not recognized as DlangIDE project or workspace file");
+ return;
+ }
string defWsFile = project.defWorkspaceFile;
if (currentWorkspace) {
Project existing = currentWorkspace.findProject(project.filename);
@@ -1504,8 +1532,14 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
_tabs.setFocus();
}
if (ws) {
+ _wsPanel.visibility = Visibility.Visible;
_settings.updateRecentWorkspace(ws.filename);
_settings.setRecentPath(ws.dir, "FILE_OPEN_WORKSPACE_PATH");
+ if (ws.startupProject) {
+ warmUpImportPaths(ws.startupProject);
+ }
+ } else {
+ _wsPanel.visibility = Visibility.Gone;
}
}
diff --git a/src/dlangide/ui/homescreen.d b/src/dlangide/ui/homescreen.d
index 6e185aa..7c476fa 100644
--- a/src/dlangide/ui/homescreen.d
+++ b/src/dlangide/ui/homescreen.d
@@ -11,6 +11,10 @@ import dlangui.core.i18n;
import std.path;
import std.utf : toUTF32;
+immutable string HELP_PAGE_URL = "https://github.com/buggins/dlangide/wiki";
+immutable string HELP_DONATION_URL = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=H2ADZV8S6TDHQ";
+
+
class HomeScreen : ScrollWidget {
protected IDEFrame _frame;
protected HorizontalLayout _content;
@@ -66,6 +70,14 @@ class HomeScreen : ScrollWidget {
_column2.addChild(new UrlImageTextButton(null, UIString.fromId("DUB_REP"c).value, "http://code.dlang.org/"));
_column2.addChild(new UrlImageTextButton(null, UIString.fromId("DLANG_UI"c).value, "https://github.com/buggins/dlangui"));
_column2.addChild(new UrlImageTextButton(null, UIString.fromId("DLANG_IDE"c).value, "https://github.com/buggins/dlangide"));
+ _column2.addChild(new UrlImageTextButton(null, UIString.fromId("DLANG_IDE_HELP"c).value, HELP_PAGE_URL));
+ _column2.addChild(new UrlImageTextButton(null, UIString.fromId("DLANG_TOUR"c).value, "https://tour.dlang.org/"));
+ _column2.addChild(new UrlImageTextButton(null, UIString.fromId("DLANG_VIBED"c).value, "http://vibed.org/"));
+ _column2.addChild(new UrlImageTextButton(null, UIString.fromId("DLANG_FORUM"c).value, "http://forum.dlang.org/"));
+ _column1.addChild(new VSpacer());
+ _column2.addChild((new TextWidget(null, UIString.fromId("DLANG_IDE_DONATE"c))).fontSize(20).textColor(linkColor));
+ _column2.addChild(new UrlImageTextButton(null, UIString.fromId("DLANG_IDE_DONATE_PAYPAL"c).value, HELP_DONATION_URL));
+
_column2.addChild(new VSpacer());
contentWidget = _content;
}
diff --git a/src/dlangide/ui/newfile.d b/src/dlangide/ui/newfile.d
index 047297d..ab47509 100644
--- a/src/dlangide/ui/newfile.d
+++ b/src/dlangide/ui/newfile.d
@@ -122,6 +122,11 @@ class NewFileDlg : Dialog {
_edLocation.addFilter(FileFilterEntry(UIString.fromRaw("DlangIDE files"d), "*.dlangidews;*.d;*.dd;*.di;*.ddoc;*.dh;*.json;*.xml;*.ini;*.dt"));
_edLocation.caption = "Select directory"d;
+ _edFileName.editorAction.connect(&onEditorAction);
+ _edFilePath.editorAction.connect(&onEditorAction);
+ _edModuleName.editorAction.connect(&onEditorAction);
+ _edLocation.editorAction.connect(&onEditorAction);
+
// fill templates
dstring[] names;
foreach(t; _templates)
@@ -156,6 +161,23 @@ class NewFileDlg : Dialog {
}
+ /// called after window with dialog is shown
+ override void onShow() {
+ super.onShow();
+ _edFileName.selectAll();
+ _edFileName.setFocus();
+ }
+
+ protected bool onEditorAction(const Action action) {
+ if (action.id == EditorActions.InsertNewLine) {
+ if (!validate())
+ return false;
+ close(_buttonActions[0]);
+ return true;
+ }
+ return false;
+ }
+
StringListWidget _projectTemplateList;
EditBox _templateDescription;
DirEditLine _edLocation;
@@ -216,7 +238,7 @@ class NewFileDlg : Dialog {
if (!exists(_location) || !isDir(_location))
return setError("Location directory does not exist");
- if (_currentTemplate.isModule) {
+ if (_currentTemplate.kind == FileKind.MODULE || _currentTemplate.kind == FileKind.PACKAGE) {
string sourcePath, relativePath;
if (!findSource(_location, sourcePath, relativePath))
return setError("Location is outside of source path");
@@ -231,9 +253,16 @@ class NewFileDlg : Dialog {
buf ~= ch;
}
_packageName = buf.dup;
- string m = !_packageName.empty ? _packageName ~ '.' ~ _moduleName : _moduleName;
+ string m;
+ if (_currentTemplate.kind == FileKind.MODULE) {
+ m = !_packageName.empty ? _packageName ~ '.' ~ _moduleName : _moduleName;
+ } else {
+ m = _packageName;
+ }
_edModuleName.text = toUTF32(m);
_packageName = m;
+ if (_currentTemplate.kind == FileKind.PACKAGE && _packageName.length == 0)
+ return setError("Package should be located in subdirectory");
} else {
string projectPath = _project.dir;
if (!isSubdirOf(_location, projectPath))
@@ -248,9 +277,12 @@ class NewFileDlg : Dialog {
private FileCreationResult _result;
bool createItem() {
try {
- if (_currentTemplate.isModule) {
+ if (_currentTemplate.kind == FileKind.MODULE) {
string txt = "module " ~ _packageName ~ ";\n\n" ~ _currentTemplate.srccode;
write(_fullPathName, txt);
+ } else if (_currentTemplate.kind == FileKind.PACKAGE) {
+ string txt = "package " ~ _packageName ~ ";\n\n" ~ _currentTemplate.srccode;
+ write(_fullPathName, txt);
} else {
write(_fullPathName, _currentTemplate.srccode);
}
@@ -284,17 +316,27 @@ class NewFileDlg : Dialog {
_currentTemplateIndex = index;
_currentTemplate = _templates[index];
_templateDescription.text = _currentTemplate.description;
+ if (_currentTemplate.kind == FileKind.PACKAGE) {
+ _edFileName.enabled = false;
+ _edFileName.text = "package"d;
+ } else {
+ if (_edFileName.text == "package")
+ _edFileName.text = "newfile";
+ _edFileName.enabled = true;
+ }
//updateDirLayout();
validate();
}
void initTemplates() {
_templates ~= new ProjectTemplate("Empty module"d, "Empty D module file."d, ".d",
- "\n", true);
+ "\n", FileKind.MODULE);
+ _templates ~= new ProjectTemplate("Package"d, "D package."d, ".d",
+ "\n", FileKind.PACKAGE);
_templates ~= new ProjectTemplate("Text file"d, "Empty text file."d, ".txt",
- "\n", true);
+ "\n", FileKind.TEXT);
_templates ~= new ProjectTemplate("JSON file"d, "Empty json file."d, ".json",
- "{\n}\n", true);
+ "{\n}\n", FileKind.TEXT);
_templates ~= new ProjectTemplate("Vibe-D Diet Template file"d, "Empty Vibe-D Diet Template."d, ".dt",
q{
doctype html
@@ -303,22 +345,27 @@ html
title Hello, World
body
h1 Hello World
-}, true);
+}, FileKind.TEXT);
}
}
+enum FileKind {
+ MODULE,
+ PACKAGE,
+ TEXT,
+}
+
class ProjectTemplate {
dstring name;
dstring description;
string fileExtension;
string srccode;
- bool isModule;
- this(dstring name, dstring description, string fileExtension, string srccode, bool isModule) {
+ FileKind kind;
+ this(dstring name, dstring description, string fileExtension, string srccode, FileKind kind) {
this.name = name;
this.description = description;
this.fileExtension = fileExtension;
this.srccode = srccode;
- this.isModule = isModule;
+ this.kind = kind;
}
}
-
diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d
index de53897..2d0d533 100644
--- a/src/dlangide/ui/searchPanel.d
+++ b/src/dlangide/ui/searchPanel.d
@@ -30,10 +30,6 @@ class SearchLogWidget : LogWidget {
onThemeChanged();
}
- protected dstring _textToHighlight;
- @property dstring textToHighlight() { return _textToHighlight; }
- @property void textToHighlight(dstring s) { _textToHighlight = s; }
-
protected uint _filenameColor = 0x0000C0;
protected uint _errorColor = 0xFF0000;
protected uint _warningColor = 0x606000;
@@ -156,6 +152,8 @@ class SearchWidget : TabWidget {
SearchLogWidget _resultLog;
int _resultLogMatchIndex;
ComboBox _searchScope;
+ ImageCheckButton _cbCaseSensitive;
+ ImageCheckButton _cbWholeWords;
protected IDEFrame _frame;
protected SearchMatchList[] _matchedList;
@@ -210,6 +208,18 @@ class SearchWidget : TabWidget {
_searchScope = new ComboBox("searchScope", ["File"d, "Project"d, "Dependencies"d, "Everywhere"d]);
_searchScope.selectedItemIndex = 0;
_layout.addChild(_searchScope);
+
+ _cbCaseSensitive = new ImageCheckButton("cbCaseSensitive", "find_case_sensitive");
+ _cbCaseSensitive.tooltipText = "EDIT_FIND_CASE_SENSITIVE";
+ _cbCaseSensitive.styleId = "TOOLBAR_BUTTON";
+ _cbCaseSensitive.checked = true;
+ _layout.addChild(_cbCaseSensitive);
+
+ _cbWholeWords = new ImageCheckButton("cbWholeWords", "find_whole_words");
+ _cbWholeWords.tooltipText = "EDIT_FIND_WHOLE_WORDS";
+ _cbWholeWords.styleId = "TOOLBAR_BUTTON";
+ _layout.addChild(_cbWholeWords);
+
addChild(_layout);
_resultLog = new SearchLogWidget("SearchLogWidget");
@@ -245,7 +255,7 @@ class SearchWidget : TabWidget {
bool findText(dstring source) {
Log.d("Finding " ~ source);
- _resultLog.textToHighlight = ""d;
+ _resultLog.setTextToHighlight(""d, 0);
_resultLog.text = ""d;
_matchedList = [];
_resultLogMatchIndex = 0;
@@ -254,9 +264,11 @@ class SearchWidget : TabWidget {
switch (_searchScope.text) {
case "File":
- SearchMatchList match = findMatches(_frame.currentEditor.filename, source);
- if(match.matches.length > 0)
- _matchedList ~= match;
+ if (_frame.currentEditor) {
+ SearchMatchList match = findMatches(_frame.currentEditor.filename, source);
+ if(match.matches.length > 0)
+ _matchedList ~= match;
+ }
break;
case "Project":
foreach(Project project; _frame._wsPanel.workspace.projects) {
@@ -289,7 +301,7 @@ class SearchWidget : TabWidget {
default:
assert(0);
}
- _resultLog.textToHighlight = source;
+ _resultLog.setTextToHighlight(source, TextSearchFlag.CaseSensitive);
return true;
}
@@ -306,23 +318,41 @@ class SearchWidget : TabWidget {
}
super.onDraw(buf);
}
-
+
+ void checkSearchMode() {
+ if (!_frame.currentEditor && _searchScope.selectedItemIndex == 0)
+ _searchScope.selectedItemIndex = 1;
+ }
+
+ uint makeSearchFlags() {
+ uint res = 0;
+ if (_cbCaseSensitive.checked)
+ res |= TextSearchFlag.CaseSensitive;
+ if (_cbWholeWords.checked)
+ res |= TextSearchFlag.WholeWords;
+ return res;
+ }
+
//Find the match/matchList that corrosponds to the line in _resultLog
bool onMatchClick(int line) {
line++;
foreach(matchList; _matchedList){
line--;
if (line == 0) {
- _frame.openSourceFile(matchList.filename);
- _frame.currentEditor.setFocus();
+ if (_frame.openSourceFile(matchList.filename)) {
+ _frame.currentEditor.setTextToHighlight(_findText.text, makeSearchFlags);
+ _frame.currentEditor.setFocus();
+ }
return true;
}
foreach(match; matchList.matches) {
line--;
if (line == 0) {
- _frame.openSourceFile(matchList.filename);
- _frame.currentEditor.setCaretPos(match.line, to!int(match.col));
- _frame.currentEditor.setFocus();
+ if (_frame.openSourceFile(matchList.filename)) {
+ _frame.currentEditor.setCaretPos(match.line, to!int(match.col));
+ _frame.currentEditor.setTextToHighlight(_findText.text, makeSearchFlags);
+ _frame.currentEditor.setFocus();
+ }
return true;
}
}
diff --git a/src/dlangide/ui/settings.d b/src/dlangide/ui/settings.d
index ee7aa42..384c094 100644
--- a/src/dlangide/ui/settings.d
+++ b/src/dlangide/ui/settings.d
@@ -65,10 +65,6 @@ SettingsPage createSettingsPages() {
// Root page
SettingsPage res = new SettingsPage("", UIString.fromRaw(""d));
- // Common page
- SettingsPage common = res.addChild("common", UIString.fromId("OPTION_COMMON"c));
- common.addCheckbox("common/autoOpenLastProject", UIString.fromId("OPTION_AUTO_OPEN_LAST_PROJECT"c));
-
// UI settings page
SettingsPage ui = res.addChild("interface", UIString.fromId("OPTION_INTERFACE"c));
ui.addStringComboBox("interface/theme", UIString.fromId("OPTION_THEME"c), [
@@ -126,6 +122,8 @@ SettingsPage createSettingsPages() {
// editor font faces
texted.addStringComboBox("editors/textEditor/fontFace", UIString.fromId("OPTION_FONT_FACE"c), createFaceList(true));
+ texted.addIntComboBox("editors/textEditor/fontSize", UIString.fromId("OPTION_FONT_SIZE"c),
+ createIntValueList([6,7,8,9,10,11,12,14,16,18,20,22,24,26,28,30,32]));
texted.addNumberEdit("editors/textEditor/tabSize", UIString.fromId("OPTION_TAB"c), 1, 16, 4);
texted.addCheckbox("editors/textEditor/useSpacesForTabs", UIString.fromId("OPTION_USE_SPACES"c));
@@ -134,6 +132,10 @@ SettingsPage createSettingsPages() {
texted.addCheckbox("editors/textEditor/showWhiteSpaceMarks", UIString.fromId("OPTION_SHOW_SPACES"c));
texted.addCheckbox("editors/textEditor/showTabPositionMarks", UIString.fromId("OPTION_SHOW_TABS"c));
+ // Common page
+ SettingsPage common = res.addChild("common", UIString.fromId("OPTION_COMMON"c));
+ common.addCheckbox("common/autoOpenLastProject", UIString.fromId("OPTION_AUTO_OPEN_LAST_PROJECT"c));
+
SettingsPage dlang = res.addChild("dlang", UIString.fromRaw("D"d));
SettingsPage dub = dlang.addChild("dlang/dub", UIString.fromRaw("DUB"d));
diff --git a/src/dlangide/ui/wspanel.d b/src/dlangide/ui/wspanel.d
index 958daea..5c5e59e 100644
--- a/src/dlangide/ui/wspanel.d
+++ b/src/dlangide/ui/wspanel.d
@@ -149,6 +149,17 @@ class WorkspacePanel : DockWindow {
return _workspace;
}
+ /// returns currently selected project item
+ @property ProjectItem selectedProjectItem() {
+ TreeItem ti = _tree.items.selectedItem;
+ if (!ti)
+ return null;
+ Object obj = ti.objectParam;
+ if (!obj)
+ return null;
+ return cast(ProjectItem)obj;
+ }
+
ProjectSourceFile findSourceFileItem(string filename, bool fullFileName=true) {
if (_workspace)
return _workspace.findSourceFileItem(filename, fullFileName);
diff --git a/src/dlangide/workspace/idesettings.d b/src/dlangide/workspace/idesettings.d
index f70e6a8..2e4f4f1 100644
--- a/src/dlangide/workspace/idesettings.d
+++ b/src/dlangide/workspace/idesettings.d
@@ -24,6 +24,7 @@ class IDESettings : SettingsFile {
ed.setBooleanDef("showWhiteSpaceMarks", true);
ed.setBooleanDef("showTabPositionMarks", true);
ed.setStringDef("fontFace", "Default");
+ ed.setIntegerDef("fontSize", 11);
Setting ui = uiSettings();
ui.setStringDef("theme", "ide_theme_default");
ui.setStringDef("language", "en");
@@ -170,10 +171,10 @@ class IDESettings : SettingsFile {
@property bool showTabPositionMarks() { return editorSettings.getBoolean("showTabPositionMarks", true); }
/// set tab position marks enabled flag
@property IDESettings showTabPositionMarks(bool enabled) { editorSettings.setBoolean("showTabPositionMarks", enabled); return this; }
- /// string value of font face
+ /// string value of font face in text editors
@property string editorFontFace() { return editorSettings.getString("fontFace", "Default"); }
-
-
+ /// int value of font size in text editors
+ @property int editorFontSize() { return cast(int)editorSettings.getInteger("fontSize", 11); }
/// true if smart indents are enabled
@property bool smartIndentsAfterPaste() { return editorSettings.getBoolean("smartIndentsAfterPaste", true); }
diff --git a/src/dlangide/workspace/project.d b/src/dlangide/workspace/project.d
index fc2db3b..9e1f71b 100644
--- a/src/dlangide/workspace/project.d
+++ b/src/dlangide/workspace/project.d
@@ -202,6 +202,17 @@ class ProjectFolder : ProjectItem {
_children.remove(i);
}
}
+ sortItems();
+ }
+
+ /// predicate for sorting project items
+ static bool compareProjectItemsLess(ProjectItem item1, ProjectItem item2) {
+ return ((item1.isFolder && !item2.isFolder) || ((item1.isFolder == item2.isFolder) && (item1.name < item2.name)));
+ }
+
+ void sortItems() {
+ import std.algorithm.sorting : sort;
+ sort!compareProjectItemsLess(_children.asArray);
}
string relativeToAbsolutePath(string path) {
@@ -218,6 +229,7 @@ class ProjectFolder : ProjectItem {
}
}
+
/// Project source file
class ProjectSourceFile : ProjectItem {
this(string filename) {
diff --git a/views/VERSION b/views/VERSION
index 7114f72..758f9c1 100644
--- a/views/VERSION
+++ b/views/VERSION
@@ -1 +1 @@
-v0.7.52
\ No newline at end of file
+v0.7.71
\ No newline at end of file
diff --git a/views/res/i18n/en.ini b/views/res/i18n/en.ini
index 1f22da7..278f1ed 100644
--- a/views/res/i18n/en.ini
+++ b/views/res/i18n/en.ini
@@ -1,7 +1,7 @@
ABOUT=About DlangIDE
HOME=DlangIDE Home
DESCRIPTION=D language IDE written in D
-COPYRIGHT=(c) Vadim Lopatin 2015
+COPYRIGHT=(c) Vadim Lopatin 2017
START_WITH=Start with:
RECENT=Recent:
NO_RECENT=No recent items
@@ -10,6 +10,12 @@ D_LANG=D Programming Language
DUB_REP=DUB repository
DLANG_UI=DLangUI on GitHub
DLANG_IDE=DLangIDE on GitHub
+DLANG_IDE_HELP=DLangIDE online documentation
+DLANG_TOUR=DLang Tour
+DLANG_VIBED=Vibe-D
+DLANG_FORUM=Dlang Forum
+DLANG_IDE_DONATE=Support DlangIDE
+DLANG_IDE_DONATE_PAYPAL=Donate via PayPal
EXIT=Exit
ALL_FILES=All files
@@ -86,10 +92,12 @@ MENU_WINDOW=&Window
MENU_WINDOW_PREFERENCES=&Preferences
MENU_WINDOW_CLOSE_DOCUMENT=Close document
MENU_WINDOW_CLOSE_ALL_DOCUMENTS=Close all documents
+MENU_WINDOW_SHOW_HOME_SCREEN=Show home screen
MENU_HELP=&Help
-MENU_HELP_VIEW_HELP=&View help
+MENU_HELP_VIEW_HELP=Online help
MENU_HELP_ABOUT=&About
+MENU_HELP_DONATE=Donate via PayPal
MENU_VIEW=&View
MENU_VIEW_LANGUAGE=Interface &Language
diff --git a/views/res/i18n/ru.ini b/views/res/i18n/ru.ini
index 408d04e..3f32da5 100644
--- a/views/res/i18n/ru.ini
+++ b/views/res/i18n/ru.ini
@@ -1,7 +1,7 @@
ABOUT=О DlangIDE
HOME=Домашняя страница DlangIDE
DESCRIPTION=IDE для языка D написанная на D
-COPYRIGHT=(c) Вадим Лопатин 2015
+COPYRIGHT=(c) Вадим Лопатин 2017
START_WITH=Начать с:
RECENT=Недавнее:
NO_RECENT=Нет недавно открытых файлов/проектов
@@ -10,6 +10,12 @@ D_LANG=Язык программирования D
DUB_REP=Хранилище DUB
DLANG_UI=DLangUI на GitHub
DLANG_IDE=DLangIDE на GitHub
+DLANG_IDE_HELP=DLangIDE документация
+DLANG_TOUR=Интерактивный тур D
+DLANG_VIBED=Vibe-D
+DLANG_FORUM=Форум D
+DLANG_IDE_DONATE=Поддержать DlangIDE
+DLANG_IDE_DONATE_PAYPAL=PayPal
EXIT=Выход
ALL_FILES=Все файлы
@@ -86,10 +92,12 @@ MENU_WINDOW=&Окно
MENU_WINDOW_PREFERENCES=&Настройки
MENU_WINDOW_CLOSE_DOCUMENT=Закрыть документ
MENU_WINDOW_CLOSE_ALL_DOCUMENTS=Закрыть все документы
+MENU_WINDOW_SHOW_HOME_SCREEN=Домашняя страница
MENU_HELP=&Справка
-MENU_HELP_VIEW_HELP=&Просмотр справки
+MENU_HELP_VIEW_HELP=Онлайн справка
MENU_HELP_ABOUT=&О программе
+MENU_HELP_DONATE=Поддержать проект через PayPal
MENU_VIEW=&Вид
MENU_VIEW_LANGUAGE=&Язык интерфейса