diff --git a/README.md b/README.md
index 93b6598..c1aeaf1 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,9 @@ Currently supported features:
* Shows tree with project source files
* Can open and edit source files from project or file system in multi-tab editor
* Build and run project with DUB
-* Build log highlight and navigation to place of error or warning by clicking on log line
+* Build log highlight and navigation to place of error or warning by clicking on log line (contributed by Extrawurst)
* DUB dependencies update
-* DUB package configuration selection (implemented by NCrashed)
+* DUB package configuration selection (contributed by NCrashed)
* Dependency projects are shown in workspace tree
Source editor features:
diff --git a/src/ddc/lexer/tokenizer.d b/src/ddc/lexer/tokenizer.d
index 34bbc27..04a6bf9 100644
--- a/src/ddc/lexer/tokenizer.d
+++ b/src/ddc/lexer/tokenizer.d
@@ -2596,8 +2596,16 @@ class Tokenizer
for (;;) {
int i = _pos;
int endPos = int.max;
+ bool lastBackSlash = false;
for(; i < _len; i++) {
- if (_lineText[i] == delimiter && (i == 0 || _lineText[i - 1] != '\\')) {
+ dchar ch = _lineText[i];
+ if (ch == '\\') {
+ if (lastBackSlash)
+ lastBackSlash = false;
+ else
+ lastBackSlash = true;
+ }
+ if (ch == delimiter && !lastBackSlash) {
endPos = i;
break;
}
diff --git a/src/ddebug/windows/mago.d b/src/ddebug/windows/mago.d
index 4e5aa1b..48e3aab 100644
--- a/src/ddebug/windows/mago.d
+++ b/src/ddebug/windows/mago.d
@@ -9,6 +9,11 @@ import std.string;
//const GUID CLSID_MAGO = {0xE348A53A, 0x470A, 0x4A70, [0x9B, 0x55, 0x1E, 0x02, 0xF3, 0x52, 0x79, 0x0D]};
const GUID IID_MAGO_NATIVE_ENGINE = {0x97348AC0, 0x2B6B, 0x4B99, [0xA2, 0x45, 0x4C, 0x7E, 0x2C, 0x09, 0xD4, 0x03]};
+//const GUID CLSID_PORT_SUPPLIER = {0x3484EFB2, 0x0A52, 0x4EB2, [0x86, 0x9C, 0x1F, 0x7E, 0x66, 0x8E, 0x1B, 0x87]};
+//const GUID CLSID_PORT_SUPPLIER = {0x3B476D38, 0xA401, 0x11D2, [0xAA, 0xD4, 0x00, 0xC0, 0x4F, 0x99, 0x01, 0x71]}; //3B476D38-A401-11D2-AAD4-00C04F990171
+const GUID CLSID_PORT_SUPPLIER = {0x708C1ECA, 0xFF48, 0x11D2, [0x90, 0x4F, 0x00, 0xC0, 0x4F, 0xA3, 0x02, 0xA1]}; //{708C1ECA-FF48-11D2-904F-00C04FA302A1}
+//const GUID CLSID_PORT_SUPPLIER = {0xF561BF8D, 0xBFBA, 0x4FC6, [0xAE, 0xA7, 0x24, 0x45, 0xD0, 0xEA, 0xC1, 0xC5]};
+//const GUID CLSID_PORT_SUPPLIER = {0x708C1ECA, 0xFF48, 0x11D2, [0x90, 0x4F, 0x00, 0x04, 0xA3, 0x2, 0xA1]};
class ComObject : IUnknown
{
@@ -69,6 +74,46 @@ class DebugCallback : ComObject, IDebugEventCallback2 {
}
+string formatHResult(HRESULT hr) {
+ switch(hr) {
+ case S_OK: return "S_OK";
+ case S_FALSE: return "S_FALSE";
+ case E_NOTIMPL: return "E_NOTIMPL";
+ case E_NOINTERFACE: return "E_NOINTERFACE";
+ case E_FAIL: return "E_FAIL";
+ case E_HANDLE: return "E_HANDLE";
+ case 0x80040154: return "REGDB_E_CLASSNOTREG";
+ default:
+ return format("%08x", hr);
+ }
+}
+
+IDebugPortSupplier2 createPortSupplier() {
+ HRESULT hr;
+ IDebugPortSupplier2 portSupplier = null;
+ LPOLESTR str;
+ StringFromCLSID(&CLSID_PORT_SUPPLIER, &str);
+ hr = CoCreateInstance(&CLSID_PORT_SUPPLIER, //CLSID_MAGO,
+ null,
+ CLSCTX_INPROC, //CLSCTX_ALL,
+ &IID_IDebugPortSupplier2, //IID_MAGO_NATIVE_ENGINE,
+ cast(void**)&portSupplier); //piUnknown);
+ if (FAILED(hr) || !portSupplier) {
+ Log.e("Failed to create port supplier ", formatHResult(hr));
+ return null;
+ }
+ Log.i("Port supplier is created");
+ return portSupplier;
+}
+
+class DebugPortRequest : ComObject, IDebugPortRequest2 {
+ static const wchar[] portName = "magoDebuggerPort\0";
+ HRESULT GetPortName(/+[out]+/ BSTR* pbstrPortName) {
+ pbstrPortName = cast(BSTR*)portName.ptr;
+ return S_OK;
+ }
+}
+
void testMago() {
HRESULT hr;
IUnknown* piUnknown;
@@ -76,11 +121,30 @@ void testMago() {
IDebugEngineLaunch2 debugEngineLaunch = null;
hr=CoInitialize(null); // Initialize OLE
if (FAILED(hr)) {
- Log.e("OLE 2 failed to initialize");
+ Log.e("OLE 2 failed to initialize", formatHResult(hr));
+ return;
+ }
+
+ IDebugPortSupplier2 portSupplier = createPortSupplier();
+ if (!portSupplier) {
+ Log.e("Failed to create port supplier");
+ return;
+ }
+ if (portSupplier.CanAddPort() != S_OK) {
+ Log.e("Cannot add debug port ", portSupplier.CanAddPort());
+ return;
+ }
+ IDebugPort2 debugPort = null;
+ DebugPortRequest debugPortRequest = new DebugPortRequest();
+ // Add a port
+ hr = portSupplier.AddPort(
+ /+[in]+/ debugPortRequest,
+ /+[out]+/ &debugPort);
+ if (FAILED(hr) || !debugPort) {
+ Log.e("Failed to create debub port ", formatHResult(hr));
return;
}
- IDebugCoreServer2 coreServer = null;
//hr = CoCreateInstance(&CLSID_MAGO, null, CLSCTX_ALL, &IID_IDebugEngine2, cast(void**)&piUnknown);
hr = CoCreateInstance(&IID_MAGO_NATIVE_ENGINE, //CLSID_MAGO,
@@ -92,7 +156,7 @@ void testMago() {
Log.d("Debug interface is not null");
}
if (FAILED(hr) || !debugEngine) {
- Log.e("Failed to create MAGO interface instance ", hr);
+ Log.e("Failed to create MAGO interface instance ", formatHResult(hr));
return;
}
@@ -103,7 +167,7 @@ void testMago() {
hr = debugEngine.QueryInterface(cast(GUID*)&IID_IDebugEngineLaunch2, cast(void**)&debugEngineLaunch);
if (FAILED(hr) || !debugEngineLaunch) {
- Log.e("Failed to get IID_IDebugEngineLaunch2 interface ", hr);
+ Log.e("Failed to get IID_IDebugEngineLaunch2 interface ", formatHResult(hr));
return;
}
@@ -139,7 +203,7 @@ void testMago() {
);
if (FAILED(hr) || !process) {
- Log.e("Failed to run process ", format("%08x", hr));
+ Log.e("Failed to run process ", formatHResult(hr));
return;
}
Log.d("LaunchSuspended executed ok");
diff --git a/src/dlangide.d b/src/dlangide.d
index 1532c56..dd85e45 100644
--- a/src/dlangide.d
+++ b/src/dlangide.d
@@ -17,6 +17,8 @@ extern (C) int UIAppMain(string[] args) {
// embed non-standard resources listed in views/resources.list into executable
embeddedResourceList.addResources(embedResourcesFromList!("resources.list")());
+ Platform.instance.uiTheme = "ide_theme_default";
+
// you can override default hinting mode here
//FontManager.hintingMode = HintingMode.Light;
//FontManager.hintingMode = HintingMode.AutoHint;
diff --git a/src/dlangide/ui/dsourceedit.d b/src/dlangide/ui/dsourceedit.d
index 2f5e824..3813404 100644
--- a/src/dlangide/ui/dsourceedit.d
+++ b/src/dlangide/ui/dsourceedit.d
@@ -24,7 +24,7 @@ class DSourceEdit : SourceEdit {
this(string ID) {
super(ID);
styleId = null;
- backgroundColor = 0xFFFFFF;
+ backgroundColor = style.customColor("edit_background");
setTokenHightlightColor(TokenCategory.Comment, 0x008000); // green
setTokenHightlightColor(TokenCategory.Keyword, 0x0000FF); // blue
setTokenHightlightColor(TokenCategory.String, 0xA31515); // brown
@@ -42,6 +42,12 @@ class DSourceEdit : SourceEdit {
this() {
this("SRCEDIT");
}
+
+ /// handle theme change: e.g. reload some themed resources
+ override void onThemeChanged() {
+ backgroundColor = style.customColor("edit_background");
+ }
+
protected IDESettings _settings;
@property DSourceEdit settings(IDESettings s) {
_settings = s;
diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d
index bbef2d0..d9ce14c 100644
--- a/src/dlangide/ui/frame.d
+++ b/src/dlangide/ui/frame.d
@@ -13,6 +13,7 @@ import dlangui.widgets.combobox;
import dlangui.widgets.popup;
import dlangui.dialogs.dialog;
import dlangui.dialogs.filedlg;
+import dlangui.dialogs.settingsdialog;
import dlangui.core.stdaction;
import dlangui.core.files;
@@ -112,6 +113,7 @@ class IDEFrame : AppFrame {
_settings.updateDefaults();
_settings.save();
super.init();
+ applySettings(_settings);
}
/// move focus to editor in currently selected tab
@@ -181,7 +183,7 @@ class IDEFrame : AppFrame {
TabItem tab = _tabs.tab(filename);
tab.objectParam = file;
editor.onModifiedStateChangeListener = &onModifiedStateChange;
- editor.settings(settings).applySettings();
+ applySettings(editor, settings);
_tabs.selectTab(index, true);
} else {
destroy(editor);
@@ -427,7 +429,7 @@ class IDEFrame : AppFrame {
mainMenuItems.add(helpItem);
MainMenu mainMenu = new MainMenu(mainMenuItems);
- mainMenu.backgroundColor = 0xd6dbe9;
+ //mainMenu.backgroundColor = 0xd6dbe9;
return mainMenu;
}
@@ -494,6 +496,8 @@ class IDEFrame : AppFrame {
/// override to handle specific actions state (e.g. change enabled state for supported actions)
override bool handleActionStateRequest(const Action a) {
switch (a.id) {
+ case IDEActions.EditPreferences:
+ return true;
case IDEActions.FileExit:
case IDEActions.FileOpen:
case IDEActions.WindowCloseAllDocuments:
@@ -624,6 +628,9 @@ class IDEFrame : AppFrame {
auto results = _editorTool.getCompletions(currentEditor, currentEditor.getCaretPosition);
currentEditor.showCompletionPopup(results);
return true;
+ case IDEActions.EditPreferences:
+ showPreferences();
+ return true;
default:
return super.handleAction(a);
}
@@ -631,6 +638,41 @@ class IDEFrame : AppFrame {
return false;
}
+ void showPreferences() {
+ //Log.d("settings before copy:\n", _settings.setting.toJSON(true));
+ Setting s = _settings.copySettings();
+ //Log.d("settings after copy:\n", s.toJSON(true));
+ SettingsDialog dlg = new SettingsDialog(UIString("DlangIDE settings"d), window, s, createSettingsPages());
+ dlg.onDialogResult = delegate(Dialog dlg, const Action result) {
+ if (result.id == ACTION_APPLY.id) {
+ //Log.d("settings after edit:\n", s.toJSON(true));
+ _settings.applySettings(s);
+ applySettings(_settings);
+ _settings.save();
+ }
+ };
+ dlg.show();
+ }
+
+ void applySettings(IDESettings settings) {
+ for (int i = _tabs.tabCount - 1; i >= 0; i--) {
+ DSourceEdit ed = cast(DSourceEdit)_tabs.tabBody(i);
+ if (ed) {
+ applySettings(ed, settings);
+ }
+ }
+ FontManager.fontGamma = settings.fontGamma;
+ FontManager.hintingMode = settings.hintingMode;
+ FontManager.minAnitialiasedFontSize = settings.minAntialiasedFontSize;
+ Platform.instance.uiLanguage = settings.uiLanguage;
+ Platform.instance.uiTheme = settings.uiTheme;
+ requestLayout();
+ }
+
+ void applySettings(DSourceEdit editor, IDESettings settings) {
+ editor.settings(settings).applySettings();
+ }
+
private bool loadProject(Project project) {
if (!project.load()) {
_logPanel.logLine("Cannot read project " ~ project.filename);
diff --git a/src/dlangide/ui/homescreen.d b/src/dlangide/ui/homescreen.d
index deaf2f5..ed09043 100644
--- a/src/dlangide/ui/homescreen.d
+++ b/src/dlangide/ui/homescreen.d
@@ -14,8 +14,9 @@ class HomeScreen : ScrollWidget {
protected VerticalLayout _recentItems;
this(string ID, IDEFrame frame) {
super(ID);
- backgroundColor = 0xFFFFFF;
+ styleId = STYLE_EDIT_BOX;
_frame = frame;
+ uint linkColor = currentTheme.customColor("link_color", 0x2020FF);
_content = new HorizontalLayout("HOME_SCREEN_BODY");
_content.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
VerticalLayout _column1 = new VerticalLayout();
@@ -24,11 +25,11 @@ class HomeScreen : ScrollWidget {
_column2.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT).padding(Rect(20, 20, 20, 20));
_content.addChild(_column1);
_content.addChild(_column2);
- _column1.addChild((new TextWidget(null, "Dlang IDE"d)).fontSize(32).textColor(0x000080));
+ _column1.addChild((new TextWidget(null, "Dlang IDE"d)).fontSize(32).textColor(linkColor));
_column1.addChild((new TextWidget(null, "D language IDE written in D"d)).fontSize(20));
- _column1.addChild((new TextWidget(null, "(c) Vadim Lopatin 2015"d)).fontSize(22).textColor(0x000080));
+ _column1.addChild((new TextWidget(null, "(c) Vadim Lopatin 2015"d)).fontSize(22).textColor(linkColor));
_column1.addChild(new VSpacer());
- _column1.addChild((new TextWidget(null, "Start with:"d)).fontSize(20).textColor(0x000040));
+ _column1.addChild((new TextWidget(null, "Start with:"d)).fontSize(20).textColor(linkColor));
_startItems = new VerticalLayout();
_recentItems = new VerticalLayout();
_startItems.addChild(new ImageTextButton(ACTION_FILE_OPEN_WORKSPACE));
@@ -36,11 +37,11 @@ class HomeScreen : ScrollWidget {
_startItems.addChild(new ImageTextButton(ACTION_FILE_NEW_PROJECT));
_column1.addChild(_startItems);
_column1.addChild(new VSpacer());
- _column1.addChild((new TextWidget(null, "Recent:"d)).fontSize(20).textColor(0x000040));
+ _column1.addChild((new TextWidget(null, "Recent:"d)).fontSize(20).textColor(linkColor));
_recentItems.addChild((new TextWidget(null, "No recent items"d)));
_column1.addChild(_recentItems);
_column1.addChild(new VSpacer());
- _column2.addChild((new TextWidget(null, "Useful Links:"d)).fontSize(20).textColor(0x000040));
+ _column2.addChild((new TextWidget(null, "Useful Links:"d)).fontSize(20).textColor(linkColor));
_column2.addChild(new UrlImageTextButton(null, "D Programming Language"d, "http://dlang.org/"));
_column2.addChild(new UrlImageTextButton(null, "DUB repository"d, "http://code.dlang.org/"));
_column2.addChild(new UrlImageTextButton(null, "DLangUI on GitHub"d, "https://github.com/buggins/dlangui"));
diff --git a/src/dlangide/ui/settings.d b/src/dlangide/ui/settings.d
index 0be6ba1..5c51ffe 100644
--- a/src/dlangide/ui/settings.d
+++ b/src/dlangide/ui/settings.d
@@ -1,6 +1,10 @@
module dlangide.ui.settings;
import dlangui.core.settings;
+import dlangui.core.i18n;
+import dlangui.graphics.fonts;
+import dlangui.widgets.lists;
+import dlangui.dialogs.settingsdialog;
const AVAILABLE_THEMES = ["theme_default", "theme_dark"];
@@ -21,6 +25,9 @@ class IDESettings : SettingsFile {
Setting ui = uiSettings();
ui.setStringDef("theme", "theme_default");
ui.setStringDef("language", "en");
+ ui.setIntegerDef("hintingMode", 1);
+ ui.setIntegerDef("minAntialiasedFontSize", 0);
+ ui.setFloatingDef("fontGamma", 0.8);
}
/// override to do something after loading - e.g. set defaults
@@ -102,4 +109,75 @@ class IDESettings : SettingsFile {
@property bool smartIndentsAfterPaste() { return editorSettings.getBoolean("smartIndentsAfterPaste", true); }
/// set smart indents enabled flag
@property IDESettings smartIndentsAfterPaste(bool enabled) { editorSettings.setBoolean("smartIndentsAfterPaste", enabled); return this; }
+
+ @property double fontGamma() {
+ double gamma = uiSettings.getFloating("fontGamma", 1.0);
+ if (gamma >= 0.5 && gamma <= 2.0)
+ return gamma;
+ return 1.0;
+ }
+
+ @property HintingMode hintingMode() {
+ long mode = uiSettings.getInteger("hintingMode", HintingMode.Normal);
+ if (mode >= HintingMode.Normal && mode <= HintingMode.Light)
+ return cast(HintingMode)mode;
+ return HintingMode.Normal;
+ }
+
+ @property int minAntialiasedFontSize() {
+ long sz = uiSettings.getInteger("minAntialiasedFontSize", 0);
+ if (sz >= 0)
+ return cast(int)sz;
+ return 0;
+ }
+
+}
+
+/// create DlangIDE settings pages tree
+SettingsPage createSettingsPages() {
+ SettingsPage res = new SettingsPage("", UIString(""d));
+ SettingsPage ed = res.addChild("editors", UIString("Editors"d));
+ SettingsPage texted = ed.addChild("editors/textEditor", UIString("Text Editors"d));
+ texted.addNumberEdit("editors/textEditor/tabSize", UIString("Tab size"d), 1, 16, 4);
+ texted.addCheckbox("editors/textEditor/useSpacesForTabs", UIString("Use spaces for tabs"d));
+ texted.addCheckbox("editors/textEditor/smartIndents", UIString("Smart indents"d));
+ texted.addCheckbox("editors/textEditor/smartIndentsAfterPaste", UIString("Smart indent after paste"d));
+ SettingsPage ui = res.addChild("interface", UIString("Interface"d));
+ ui.addStringComboBox("interface/theme", UIString("Theme"d), [
+ StringListValue("ide_theme_default", "Default"d),
+ StringListValue("ide_theme_dark", "Dark"d)]);
+ ui.addStringComboBox("interface/language", UIString("Language"d), [StringListValue("en", "English"d), StringListValue("ru", "Russian"d)]);
+ ui.addIntComboBox("interface/hintingMode", UIString("Font hinting mode"d), [StringListValue(0, "Normal"d), StringListValue(1, "Force Auto Hint"d),
+ StringListValue(2, "Disabled"d), StringListValue(3, "Light"d)]);
+ ui.addIntComboBox("interface/minAntialiasedFontSize", UIString("Minimum font size for antialiasing"d),
+ [StringListValue(0, "Always ON"d),
+ StringListValue(12, "12"d),
+ StringListValue(14, "14"d),
+ StringListValue(16, "16"d),
+ StringListValue(20, "20"d),
+ StringListValue(24, "24"d),
+ StringListValue(32, "32"d),
+ StringListValue(48, "48"d),
+ StringListValue(255, "Always OFF"d)]);
+ ui.addFloatComboBox("interface/fontGamma", UIString("Font gamma"d),
+ [
+ StringListValue(500, "0.5 "d),
+ StringListValue(600, "0.6 "d),
+ StringListValue(700, "0.7 "d),
+ StringListValue(800, "0.8 "d),
+ StringListValue(850, "0.85 "d),
+ StringListValue(900, "0.9 "d),
+ StringListValue(950, "0.95 "d),
+ StringListValue(1000, "1.0 "d),
+ StringListValue(1050, "1.05 "d),
+ StringListValue(1100, "1.1 "d),
+ StringListValue(1150, "1.15 "d),
+ StringListValue(1200, "1.2 "d),
+ StringListValue(1250, "1.25 "d),
+ StringListValue(1300, "1.3 "d),
+ StringListValue(1400, "1.4 "d),
+ StringListValue(1500, "1.5 "d),
+ StringListValue(1700, "1.7 "d),
+ StringListValue(2000, "2.0 "d)]);
+ return res;
}
diff --git a/src/dlangide/workspace/project.d b/src/dlangide/workspace/project.d
index 5728c43..5dc712f 100644
--- a/src/dlangide/workspace/project.d
+++ b/src/dlangide/workspace/project.d
@@ -480,7 +480,7 @@ class Project : WorkspaceItem {
if (!selectionsFile.load())
return false;
Setting versions = selectionsFile.objectByPath("versions");
- if (!versions)
+ if (!versions.isObject)
return false;
string[string] versionMap = versions.strMap;
foreach(packageName, packageVersion; versionMap) {
diff --git a/views/res/ide_theme_dark.xml b/views/res/ide_theme_dark.xml
new file mode 100644
index 0000000..bb43ee9
--- /dev/null
+++ b/views/res/ide_theme_dark.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/views/res/ide_theme_default.xml b/views/res/ide_theme_default.xml
new file mode 100644
index 0000000..b3561b8
--- /dev/null
+++ b/views/res/ide_theme_default.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/views/resources.list b/views/resources.list
index 2d7728f..51eb8d2 100644
--- a/views/resources.list
+++ b/views/resources.list
@@ -1,3 +1,5 @@
+res/ide_theme_default.xml
+res/ide_theme_dark.xml
res/i18n/en.ini
res/i18n/ru.ini
res/mdpi/cr3_logo.png