Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Vitaly Livshic 2017-09-11 15:23:20 +03:00
commit 12753affdc
18 changed files with 405 additions and 84 deletions

View File

@ -1,24 +1,5 @@
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/buggins/dlangide?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/buggins/dlangide.svg?branch=master)](https://travis-ci.org/buggins/dlangide) [![PayPayl donate button](https://img.shields.io/badge/paypal-donate-yellow.svg)](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)
<pre>
example:
{
"name" : "newworkspace",
"description" : null,
"projects" : {
"newproject" : "newproject/dub.json"<br>
},
"includePath" : [
"/usr/include/dlang/dmd/"
]
}
</pre>
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)
<pre>
example:
{
"name" : "newworkspace",
"description" : null,
"projects" : {
"newproject" : "newproject/dub.json"<br>
},
"includePath" : [
"/usr/include/dlang/dmd/"
]
}
</pre>

View File

@ -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"
},

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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));

View File

@ -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);

View File

@ -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); }

View File

@ -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) {

View File

@ -1 +1 @@
v0.7.52
v0.7.71

View File

@ -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

View File

@ -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=&Язык интерфейса