diff --git a/src/dlangide/builders/builder.d b/src/dlangide/builders/builder.d index 6f07359..0886a87 100644 --- a/src/dlangide/builders/builder.d +++ b/src/dlangide/builders/builder.d @@ -16,6 +16,7 @@ class Builder : BackgroundOperationWatcher { protected ExternalProcess _extprocess; protected OutputPanel _log; protected ProtectedTextStorage _box; + protected ProjectConfiguration _projectConfig; protected BuildConfiguration _buildConfig; protected BuildOperation _buildOp; protected bool _verbose; @@ -23,8 +24,9 @@ class Builder : BackgroundOperationWatcher { @property Project project() { return _project; } @property void project(Project p) { _project = p; } - this(AppFrame frame, Project project, OutputPanel log, BuildConfiguration buildConfig, BuildOperation buildOp, bool verbose) { + this(AppFrame frame, Project project, OutputPanel log, ProjectConfiguration projectConfig, BuildConfiguration buildConfig, BuildOperation buildOp, bool verbose) { super(frame); + _projectConfig = projectConfig; _buildConfig = buildConfig; _buildOp = buildOp; _verbose = verbose; @@ -62,7 +64,11 @@ class Builder : BackgroundOperationWatcher { } else if (_buildOp == BuildOperation.Clean) { params ~= "clean".dup; } else if (_buildOp == BuildOperation.Run) { - params ~= "run".dup; + if (_projectConfig.type == ProjectConfiguration.Type.Library) { + params ~= "test".dup; + } else { + params ~= "run".dup; + } } else if (_buildOp == BuildOperation.Upgrade) { params ~= "upgrade".dup; params ~= "--force-remove".dup; @@ -83,6 +89,10 @@ class Builder : BackgroundOperationWatcher { } } + if(_projectConfig.name != ProjectConfiguration.DEFAULT_NAME) { + params ~= "--config=".dup ~ _projectConfig.name; + } + if (_verbose) params ~= "-v".dup; diff --git a/src/dlangide/ui/commands.d b/src/dlangide/ui/commands.d index d7fd6b6..f1b68ba 100644 --- a/src/dlangide/ui/commands.d +++ b/src/dlangide/ui/commands.d @@ -16,6 +16,7 @@ enum IDEActions : int { FileClose, FileExit, EditPreferences, + ProjectConfigurations, BuildConfigurations, BuildWorkspace, RebuildWorkspace, @@ -68,6 +69,7 @@ const Action ACTION_FILE_EXIT = new Action(IDEActions.FileExit, "MENU_FILE_EXIT" const Action ACTION_WORKSPACE_BUILD = new Action(IDEActions.BuildWorkspace, "MENU_BUILD_WORKSPACE_BUILD"c); const Action ACTION_WORKSPACE_REBUILD = new Action(IDEActions.RebuildWorkspace, "MENU_BUILD_WORKSPACE_REBUILD"c); const Action ACTION_WORKSPACE_CLEAN = new Action(IDEActions.CleanWorkspace, "MENU_BUILD_WORKSPACE_CLEAN"c); +const Action ACTION_PROJECT_CONFIGURATIONS = new Action(IDEActions.ProjectConfigurations, "MENU_PROJECT_CONFIGURATIONS"c); const Action ACTION_BUILD_CONFIGURATIONS = new Action(IDEActions.BuildConfigurations, "MENU_BUILD_CONFIGURATIONS"c); const Action ACTION_PROJECT_BUILD = new Action(IDEActions.BuildProject, "MENU_BUILD_PROJECT_BUILD"c, "run-build", KeyCode.F7, 0); const Action ACTION_PROJECT_REBUILD = new Action(IDEActions.RebuildProject, "MENU_BUILD_PROJECT_REBUILD"c, "run-build-clean", KeyCode.F7, KeyFlag.Control); diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index 43c702b..3cc18f5 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -57,9 +57,33 @@ class BackgroundOperationWatcherTest : BackgroundOperationWatcher { } } +/// Subclass of toolbars that can update their items +class UpdateableToolBarComboBox : ToolBarComboBox { + this(string id, dstring[] items) { + super(id, items); + } + + @property items(dstring[] newItems) { + _adapter.items = newItems; + if(newItems.length > 0) { + selectedItemIndex = 0; + } + requestLayout(); + } + + @property dstring selectedItem() { + size_t index = _selectedItemIndex; + if(index < 0 || index >= _adapter.itemCount) return ""; + + return _adapter.items.get(index); + } +} + /// DIDE app frame class IDEFrame : AppFrame { + private UpdateableToolBarComboBox projectConfigurationCombo; + MenuItem mainMenuItems; WorkspacePanel _wsPanel; OutputPanel _logPanel; @@ -434,6 +458,17 @@ class IDEFrame : AppFrame { tb.addButtons(ACTION_FILE_OPEN, ACTION_FILE_SAVE, ACTION_SEPARATOR); tb.addButtons(ACTION_DEBUG_START); + + projectConfigurationCombo = new UpdateableToolBarComboBox("projectConfig", [ProjectConfiguration.DEFAULT_NAME.to!dstring]); + projectConfigurationCombo.onItemClickListener = delegate(Widget source, int index) { + if (currentWorkspace) { + currentWorkspace.setStartupProjectConfiguration(projectConfigurationCombo.selectedItem.to!string); + } + return true; + }; + projectConfigurationCombo.action = ACTION_PROJECT_CONFIGURATIONS; + tb.addControl(projectConfigurationCombo); + ToolBarComboBox cbBuildConfiguration = new ToolBarComboBox("buildConfig", ["Debug"d, "Release"d, "Unittest"d]); cbBuildConfiguration.onItemClickListener = delegate(Widget source, int index) { if (currentWorkspace && index < 3) { @@ -603,7 +638,7 @@ class IDEFrame : AppFrame { void openFileOrWorkspace(string filename) { if (filename.isWorkspaceFile) { - Workspace ws = new Workspace(); + Workspace ws = new Workspace(this); if (ws.load(filename)) { askForUnsavedEdits(delegate() { setWorkspace(ws); @@ -657,7 +692,7 @@ class IDEFrame : AppFrame { string defWsFile = project.defWorkspaceFile; _logPanel.logLine("Creating new workspace " ~ defWsFile); // new ws - Workspace ws = new Workspace(); + Workspace ws = new Workspace(this); ws.name = project.name; ws.description = project.description; ws.addProject(project); @@ -692,10 +727,15 @@ class IDEFrame : AppFrame { _logPanel.logLine("No project is opened"); return; } - Builder op = new Builder(this, currentWorkspace.startupProject, _logPanel, currentWorkspace.buildConfiguration, buildOp, false); + Builder op = new Builder(this, currentWorkspace.startupProject, _logPanel, currentWorkspace.projectConfiguration, currentWorkspace.buildConfiguration, buildOp, false); setBackgroundOperation(op); } - + + /// updates list of available configurations + void setProjectConfigurations(dstring[] items) { + projectConfigurationCombo.items = items; + } + /// handle files dropped to application window void onFilesDropped(string[] filenames) { //Log.d("onFilesDropped(", filenames, ")"); diff --git a/src/dlangide/workspace/project.d b/src/dlangide/workspace/project.d index 3d1f9df..af283af 100644 --- a/src/dlangide/workspace/project.d +++ b/src/dlangide/workspace/project.d @@ -224,6 +224,59 @@ string[] dmdSourcePaths() { return res; } +/// Stores info about project configuration +struct ProjectConfiguration { + /// name used to build the project + string name; + /// type, for libraries one can run tests, for apps - execute them + Type type; + + /// How to display default configuration in ui + immutable static string DEFAULT_NAME = "default"; + /// Default project configuration + immutable static ProjectConfiguration DEFAULT = ProjectConfiguration(DEFAULT_NAME, Type.Default); + + /// Type of configuration + enum Type { + Default, + Executable, + Library + } + + private static Type parseType(string s) + { + switch(s) + { + case "executable": return Type.Executable; + case "library": return Type.Library; + case "dynamicLibrary": return Type.Library; + case "staticLibrary": return Type.Library; + default: return Type.Default; + } + } + + /// parsing from setting file + static ProjectConfiguration[string] load(Setting s) + { + ProjectConfiguration[string] res = [DEFAULT_NAME: DEFAULT]; + if(s.map is null || "configurations" !in s.map || s.map["configurations"].array is null) + return res; + + foreach(conf; s.map["configurations"].array) + { + if(conf.map is null || "name" !in conf.map) continue; + Type t = Type.Default; + if("targetType" in conf.map) { + t = parseType(conf.map["targetType"].str); + } + string confName = conf.map["name"].str; + res[confName] = ProjectConfiguration(confName, t); + } + + return res; + } +} + /// DLANGIDE D project class Project : WorkspaceItem { protected Workspace _workspace; @@ -236,7 +289,7 @@ class Project : WorkspaceItem { protected string[] _sourcePaths; protected string[] _builderSourcePaths; - + protected ProjectConfiguration[string] _configurations; this(Workspace ws, string fname = null, string dependencyVersion = null) { super(fname); @@ -249,6 +302,12 @@ class Project : WorkspaceItem { @property bool isDependency() { return _isDependency; } @property string dependencyVersion() { return _dependencyVersion; } + /// returns project configurations + @property const(ProjectConfiguration[string]) configurations() const + { + return _configurations; + } + /// returns project's own source paths @property string[] sourcePaths() { return _sourcePaths; } /// returns project's own source paths @@ -393,6 +452,10 @@ class Project : WorkspaceItem { Log.i("Builder source paths: ", builderSourcePaths); if (!_isDependency) loadSelections(); + + _configurations = ProjectConfiguration.load(_projectFile); + Log.i("Project configurations: ", _configurations); + } catch (JSONException e) { Log.e("Cannot parse json", e); return false; diff --git a/src/dlangide/workspace/workspace.d b/src/dlangide/workspace/workspace.d index f219482..36091a6 100644 --- a/src/dlangide/workspace/workspace.d +++ b/src/dlangide/workspace/workspace.d @@ -1,10 +1,13 @@ module dlangide.workspace.workspace; import dlangide.workspace.project; +import dlangide.ui.frame; import dlangui.core.logger; +import std.conv; import std.path; import std.file; import std.json; +import std.range; import std.utf; import std.algorithm; @@ -44,11 +47,14 @@ bool isWorkspaceFile(string filename) { /// DlangIDE workspace class Workspace : WorkspaceItem { protected Project[] _projects; - + + protected IDEFrame _frame; protected BuildConfiguration _buildConfiguration; - - this(string fname = null) { + protected ProjectConfiguration _projectConfiguration = ProjectConfiguration.DEFAULT; + + this(IDEFrame frame, string fname = null) { super(fname); + _frame = frame; } @property Project[] projects() { @@ -58,14 +64,28 @@ class Workspace : WorkspaceItem { @property BuildConfiguration buildConfiguration() { return _buildConfiguration; } @property void buildConfiguration(BuildConfiguration config) { _buildConfiguration = config; } + @property ProjectConfiguration projectConfiguration() { return _projectConfiguration; } + @property void projectConfiguration(ProjectConfiguration config) { _projectConfiguration = config; } + protected Project _startupProject; @property Project startupProject() { return _startupProject; } - @property void startupProject(Project project) { _startupProject = project; } + @property void startupProject(Project project) { + _startupProject = project; + _frame.setProjectConfigurations(project.configurations.keys.map!(k => k.to!dstring).array); + } + /// setups currrent project configuration by name + void setStartupProjectConfiguration(string conf) + { + if(_startupProject && conf in _startupProject.configurations) { + _projectConfiguration = _startupProject.configurations[conf]; + } + } + protected void fillStartupProject() { if (!_startupProject && _projects.length) - _startupProject = _projects[0]; + startupProject = _projects[0]; } /// tries to find source file in one of projects, returns found project source file item, or null if not found diff --git a/views/res/i18n/en.ini b/views/res/i18n/en.ini index 1939fe4..68922e4 100644 --- a/views/res/i18n/en.ini +++ b/views/res/i18n/en.ini @@ -32,6 +32,7 @@ MENU_BUILD_PROJECT_BUILD=Build Project MENU_BUILD_PROJECT_REBUILD=Rebuild Project MENU_BUILD_PROJECT_CLEAN=Clean Project MENU_PROJECT=&PROJECT +MENU_PROJECT_CONFIGURATIONS=Project configurations MENU_PROJECT_SET_AS_STARTUP=Set as Startup Project MENU_PROJECT_SETTINGS=Project Settings MENU_PROJECT_REFRESH=Refresh Workspace Items diff --git a/views/res/i18n/ru.ini b/views/res/i18n/ru.ini index 82f24a2..4598b3b 100644 --- a/views/res/i18n/ru.ini +++ b/views/res/i18n/ru.ini @@ -11,6 +11,7 @@ MENU_EDIT_CUT=Вырезать MENU_EDIT_UNDO=&Отмена MENU_EDIT_REDO=&Повторить MENU_EDIT_PREFERENCES=&Настройки +MENU_PROJECT_CONFIGURATIONS=Конфигурации проекта MENU_VIEW=&Вид MENU_VIEW_LANGUAGE=&Язык интерфейса MENU_VIEW_LANGUAGE_EN=English