diff --git a/src/dlangide/builders/builder.d b/src/dlangide/builders/builder.d index dd4e0ca..a96b9c1 100644 --- a/src/dlangide/builders/builder.d +++ b/src/dlangide/builders/builder.d @@ -16,14 +16,15 @@ alias BuildResultListener = void delegate(int); class Builder : BackgroundOperationWatcher { protected Project _project; + protected string _filename; // for rdmd protected ExternalProcess _extprocess; protected OutputPanel _log; protected ProtectedTextStorage _box; protected ProjectConfiguration _projectConfig; protected BuildConfiguration _buildConfig; protected BuildOperation _buildOp; - protected string _dubExecutable; - protected string _dubAdditionalParams; + protected string _executable; + protected string _additionalParams; protected BuildResultListener _listener; protected int _exitCode = int.min; protected string _toolchain; @@ -44,8 +45,8 @@ class Builder : BackgroundOperationWatcher { _projectConfig = projectConfig; _buildConfig = buildConfig; _buildOp = buildOp; - _dubExecutable = dubExecutable.empty ? "dub" : dubExecutable; - _dubAdditionalParams = dubAdditionalParams; + _executable = dubExecutable.empty ? "dub" : dubExecutable; + _additionalParams = dubAdditionalParams; _project = project; _log = log; _toolchain = toolchain; @@ -54,6 +55,23 @@ class Builder : BackgroundOperationWatcher { _box = new ProtectedTextStorage(); } + this(AppFrame frame, string filename, OutputPanel log, BuildConfiguration buildConfig, + BuildOperation buildOp, + string rdmdExecutable, + string rdmdAdditionalParams, + BuildResultListener listener = null) { + super(frame); + _listener = listener; + _buildOp = buildOp; + _filename = filename; + _buildConfig = buildConfig; + _executable = rdmdExecutable.empty ? "rdmd" : rdmdExecutable; + _additionalParams = rdmdAdditionalParams; + _log = log; + _extprocess = new ExternalProcess(); + _box = new ProtectedTextStorage(); + } + /// log lines void pollText() { dstring text = _box.readText(); @@ -70,60 +88,84 @@ class Builder : BackgroundOperationWatcher { ExternalProcessState state = _extprocess.state; if (state == ExternalProcessState.None) { _log.clear(); - char[] program = _dubExecutable.dup; + char[] program = _executable.dup; char[][] params; - char[] dir = _project.dir.dup; + char[] dir; - if (_buildOp == BuildOperation.Build || _buildOp == BuildOperation.Rebuild) { - params ~= "build".dup; - if (_buildOp == BuildOperation.Rebuild) { - params ~= "--force".dup; - } - if (!_arch.empty) - params ~= ("--arch=" ~ _arch).dup; - if (!_toolchain.empty) - params ~= ("--compiler=" ~ _toolchain).dup; - params ~= "--build-mode=allAtOnce".dup; - } else if (_buildOp == BuildOperation.Clean) { - params ~= "clean".dup; - } else if (_buildOp == BuildOperation.Run) { - 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; - import std.path; - import std.file; - string projectFile = project.filename; - string selectionsFile = projectFile.stripExtension ~ ".selections.json"; - if (selectionsFile.exists && selectionsFile.isFile) { - Log.i("Removing file ", selectionsFile); - remove(selectionsFile); - } - } + if(_buildOp == BuildOperation.RunWithRdmd) { + dir = std.path.dirName(_filename).dup; + + if (!_additionalParams.empty) + params ~= _additionalParams.dup; - if (_buildOp != BuildOperation.Clean && _buildOp != BuildOperation.Upgrade) { switch (_buildConfig) { default: case BuildConfiguration.Debug: - params ~= "--build=debug".dup; + params ~= "-debug".dup; break; case BuildConfiguration.Release: - params ~= "--build=release".dup; + params ~= "-release".dup; break; case BuildConfiguration.Unittest: - params ~= "--build=unittest".dup; + params ~= "-unittest".dup; break; } - if (!_dubAdditionalParams.empty) - params ~= _dubAdditionalParams.dup; - } + params ~= std.path.baseName(_filename).dup; - if(_projectConfig.name != ProjectConfiguration.DEFAULT_NAME) { - params ~= "--config=".dup ~ _projectConfig.name; + } else { + // dub + dir = _project.dir.dup; + if (_buildOp == BuildOperation.Build || _buildOp == BuildOperation.Rebuild) { + params ~= "build".dup; + if (_buildOp == BuildOperation.Rebuild) { + params ~= "--force".dup; + } + if (!_arch.empty) + params ~= ("--arch=" ~ _arch).dup; + if (!_toolchain.empty) + params ~= ("--compiler=" ~ _toolchain).dup; + params ~= "--build-mode=allAtOnce".dup; + } else if (_buildOp == BuildOperation.Clean) { + params ~= "clean".dup; + } else if (_buildOp == BuildOperation.Run) { + 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; + import std.path; + import std.file; + string projectFile = project.filename; + string selectionsFile = projectFile.stripExtension ~ ".selections.json"; + if (selectionsFile.exists && selectionsFile.isFile) { + Log.i("Removing file ", selectionsFile); + remove(selectionsFile); + } + } + + if (_buildOp != BuildOperation.Clean && _buildOp != BuildOperation.Upgrade) { + switch (_buildConfig) { + default: + case BuildConfiguration.Debug: + params ~= "--build=debug".dup; + break; + case BuildConfiguration.Release: + params ~= "--build=release".dup; + break; + case BuildConfiguration.Unittest: + params ~= "--build=unittest".dup; + break; + } + if (!_additionalParams.empty) + params ~= _additionalParams.dup; + } + + if(_projectConfig.name != ProjectConfiguration.DEFAULT_NAME) { + params ~= "--config=".dup ~ _projectConfig.name; + } } auto text = "Running (in " ~ dir ~ "): " ~ program ~ " " ~ params.join(' ') ~ "\n"; diff --git a/src/dlangide/ui/commands.d b/src/dlangide/ui/commands.d index 524c8af..2c36cde 100644 --- a/src/dlangide/ui/commands.d +++ b/src/dlangide/ui/commands.d @@ -28,6 +28,7 @@ enum IDEActions : int { UpdateProjectDependencies, SetStartupProject, ProjectSettings, + RunWithRdmd, DebugStart, DebugRestart, @@ -97,6 +98,7 @@ const Action ACTION_PROJECT_SET_STARTUP = new Action(IDEActions.SetStartupProjec const Action ACTION_PROJECT_SETTINGS = (new Action(IDEActions.ProjectSettings, "MENU_PROJECT_SETTINGS"c, null)).disableByDefault(); const Action ACTION_PROJECT_REFRESH = new Action(IDEActions.RefreshProject, "MENU_PROJECT_REFRESH"c); const Action ACTION_PROJECT_UPDATE_DEPENDENCIES = new Action(IDEActions.UpdateProjectDependencies, "MENU_PROJECT_UPDATE_DEPENDENCIES"c); +const Action ACTION_RUN_WITH_RDMD = new Action(IDEActions.RunWithRdmd, "MENU_BUILD_RUN_WITH_RDMD"c, "run-rdmd").disableByDefault(); const Action ACTION_DEBUG_START = new Action(IDEActions.DebugStart, "MENU_DEBUG_START_DEBUGGING"c, "debug-run"c, KeyCode.F5, KeyFlag.Control | KeyFlag.Shift); const Action ACTION_DEBUG_START_NO_DEBUG = new Action(IDEActions.DebugStartNoDebug, "MENU_DEBUG_START_NO_DEBUGGING"c, null, KeyCode.F5, KeyFlag.Control); diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index 0361e45..93f6214 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -405,6 +405,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL } window.windowCaption(tab.text.value ~ " - "d ~ frameWindowCaptionSuffix); } + requestActionsUpdate(); } // returns DSourceEdit from currently active tab (if it's editor), null if current tab is not editor or no tabs open @@ -530,6 +531,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL closeTab(tabId); } } + requestActionsUpdate(); } /// create app body widget @@ -560,10 +562,12 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL _logPanel.compilerLogIssueClickHandler = &onCompilerLogIssueClick; _logPanel.appendText(null, "DlangIDE is started\nHINT: Try to open some DUB project\n"d); string dubPath = findExecutablePath("dub"); + string rdmdPath = findExecutablePath("rdmd"); string dmdPath = findExecutablePath("dmd"); string ldcPath = findExecutablePath("ldc2"); string gdcPath = findExecutablePath("gdc"); _logPanel.appendText(null, dubPath ? ("dub path: "d ~ toUTF32(dubPath) ~ "\n"d) : ("dub is not found! cannot build projects without DUB\n"d)); + _logPanel.appendText(null, rdmdPath ? ("rdmd path: "d ~ toUTF32(rdmdPath) ~ "\n"d) : ("rdmd is not found!\n"d)); _logPanel.appendText(null, dmdPath ? ("dmd path: "d ~ toUTF32(dmdPath) ~ "\n"d) : ("dmd compiler is not found!\n"d)); _logPanel.appendText(null, ldcPath ? ("ldc path: "d ~ toUTF32(ldcPath) ~ "\n"d) : ("ldc compiler is not found!\n"d)); _logPanel.appendText(null, gdcPath ? ("gdc path: "d ~ toUTF32(gdcPath) ~ "\n"d) : ("gdc compiler is not found!\n"d)); @@ -601,7 +605,8 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL MenuItem buildItem = new MenuItem(new Action(22, "MENU_BUILD")); buildItem.add(ACTION_WORKSPACE_BUILD, ACTION_WORKSPACE_REBUILD, ACTION_WORKSPACE_CLEAN, - ACTION_PROJECT_BUILD, ACTION_PROJECT_REBUILD, ACTION_PROJECT_CLEAN); + ACTION_PROJECT_BUILD, ACTION_PROJECT_REBUILD, ACTION_PROJECT_CLEAN, + ACTION_RUN_WITH_RDMD); MenuItem debugItem = new MenuItem(new Action(23, "MENU_DEBUG")); debugItem.add(ACTION_DEBUG_START, ACTION_DEBUG_START_NO_DEBUG, @@ -652,8 +657,8 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL ACTION_FILE_SAVE, ACTION_FILE_SAVE_AS, ACTION_FILE_SAVE_ALL, ACTION_FILE_EXIT, ACTION_PROJECT_SET_STARTUP, ACTION_PROJECT_REFRESH, ACTION_PROJECT_UPDATE_DEPENDENCIES, ACTION_PROJECT_SETTINGS, ACTION_WORKSPACE_BUILD, ACTION_WORKSPACE_REBUILD, ACTION_WORKSPACE_CLEAN, - ACTION_PROJECT_BUILD, ACTION_PROJECT_REBUILD, ACTION_PROJECT_CLEAN, ACTION_DEBUG_START, - ACTION_DEBUG_START_NO_DEBUG, ACTION_DEBUG_CONTINUE, ACTION_DEBUG_STOP, ACTION_DEBUG_PAUSE, + ACTION_PROJECT_BUILD, ACTION_PROJECT_REBUILD, ACTION_PROJECT_CLEAN, ACTION_RUN_WITH_RDMD, + ACTION_DEBUG_START, ACTION_DEBUG_START_NO_DEBUG, ACTION_DEBUG_CONTINUE, ACTION_DEBUG_STOP, ACTION_DEBUG_PAUSE, ACTION_DEBUG_RESTART, ACTION_DEBUG_STEP_INTO, ACTION_DEBUG_STEP_OVER, @@ -692,7 +697,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL }; cbBuildConfiguration.action = ACTION_BUILD_CONFIGURATIONS; tb.addControl(cbBuildConfiguration); - tb.addButtons(ACTION_PROJECT_BUILD); + tb.addButtons(ACTION_PROJECT_BUILD, ACTION_SEPARATOR, ACTION_RUN_WITH_RDMD); tb = res.getOrAddToolbar("Edit"); tb.addButtons(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_SEPARATOR, @@ -744,6 +749,13 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL else a.state = ACTION_STATE_DISABLE; return true; + case IDEActions.RunWithRdmd: + // enable when D source file is in current tab + if (currentEditor && !_currentBackgroundOperation && currentEditor.id.endsWith(".d")) + a.state = ACTION_STATE_ENABLED; + else + a.state = ACTION_STATE_DISABLE; + return true; case IDEActions.DebugStop: a.state = isExecutionActive ? ACTION_STATE_ENABLED : ACTION_STATE_DISABLE; return true; @@ -820,6 +832,9 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL case IDEActions.CleanWorkspace: buildProject(BuildOperation.Clean, cast(Project)a.objectParam); return true; + case IDEActions.RunWithRdmd: + runWithRdmd(currentEditor.id); + return true; case IDEActions.DebugStartNoDebug: buildAndRunProject(cast(Project)a.objectParam); return true; @@ -1320,6 +1335,16 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL setBackgroundOperation(op); } + void runWithRdmd(string filename, BuildResultListener listener = null) { + string rdmdExecutable = _settings.rdmdExecutable; + string rdmdAdditionalParams = _settings.rdmdAdditionalParams; + Builder op = new Builder(this, filename, _logPanel, currentWorkspace ? currentWorkspace.buildConfiguration : BuildConfiguration.Debug, + BuildOperation.RunWithRdmd, + rdmdExecutable, rdmdAdditionalParams, + listener); + setBackgroundOperation(op); + } + /// updates list of available configurations void setProjectConfigurations(dstring[] items) { projectConfigurationCombo.items = items; diff --git a/src/dlangide/ui/settings.d b/src/dlangide/ui/settings.d index 979b542..b016613 100644 --- a/src/dlangide/ui/settings.d +++ b/src/dlangide/ui/settings.d @@ -26,6 +26,9 @@ SettingsPage createSettingsPages() { SettingsPage dub = dlang.addChild("dlang/dub", UIString("DUB"d)); dub.addExecutableFileNameEdit("dlang/dub/executable", UIString("DUB executable"d), "dub"); dub.addStringEdit("dlang/dub/additional_params", UIString("DUB additional params"d), ""); + SettingsPage rdmd = dlang.addChild("dlang/rdmd", UIString("rdmd"d)); + rdmd.addExecutableFileNameEdit("dlang/rdmd/executable", UIString("rdmd executable"d), "rdmd"); + rdmd.addStringEdit("dlang/rdmd/additional_params", UIString("rdmd additional params"d), ""); SettingsPage ddebug = dlang.addChild("dlang/debugger", UIString("Debugger"d)); ddebug.addExecutableFileNameEdit("dlang/debugger/executable", UIString("Debugger executable"d), "gdb"); SettingsPage terminal = dlang.addChild("dlang/terminal", UIString("Terminal"d)); diff --git a/src/dlangide/workspace/idesettings.d b/src/dlangide/workspace/idesettings.d index aa0ba92..9a5f826 100644 --- a/src/dlangide/workspace/idesettings.d +++ b/src/dlangide/workspace/idesettings.d @@ -30,6 +30,8 @@ class IDESettings : SettingsFile { terminalSettings.setStringDef("executable", "xterm"); dubSettings.setStringDef("executable", "dub"); dubSettings.setStringDef("additional_params", ""); + rdmdSettings.setStringDef("executable", "rdmd"); + rdmdSettings.setStringDef("additional_params", ""); dmdToolchainSettings.setStringDef("executable", "dmd"); dmdToolchainSettings.setStringDef("dub_additional_params", ""); ldcToolchainSettings.setStringDef("executable", "ldc2"); @@ -69,6 +71,11 @@ class IDESettings : SettingsFile { return res; } + @property Setting rdmdSettings() { + Setting res = _setting.objectByPath("dlang/rdmd", true); + return res; + } + @property Setting dmdToolchainSettings() { Setting res = _setting.objectByPath("dlang/toolchains/dmd", true); return res; @@ -181,6 +188,14 @@ class IDESettings : SettingsFile { return dubSettings.getString("additional_params", ""); } + @property string rdmdExecutable() { + return rdmdSettings.getString("executable", "rdmd"); + } + + @property string rdmdAdditionalParams() { + return rdmdSettings.getString("additional_params", ""); + } + string getToolchainCompilerExecutable(string toolchainName) { if (toolchainName.equal("dmd")) return dmdToolchainSettings.getString("executable", "dmd"); diff --git a/src/dlangide/workspace/projectsettings.d b/src/dlangide/workspace/projectsettings.d index c52a54c..f773ead 100644 --- a/src/dlangide/workspace/projectsettings.d +++ b/src/dlangide/workspace/projectsettings.d @@ -69,7 +69,7 @@ class ProjectSettings : SettingsFile { } /// join parameter lists separating with space -string joinParams(string[] params...) { +string joinParams(string[] params...) pure { char[] res; foreach(param; params) { string s = param.strip; diff --git a/src/dlangide/workspace/workspace.d b/src/dlangide/workspace/workspace.d index 452944e..4a6cf6c 100644 --- a/src/dlangide/workspace/workspace.d +++ b/src/dlangide/workspace/workspace.d @@ -19,7 +19,8 @@ enum BuildOperation { Clean, Rebuild, Run, - Upgrade + Upgrade, + RunWithRdmd } enum BuildConfiguration { diff --git a/views/res/i18n/en.ini b/views/res/i18n/en.ini index e6529c6..2a4a0ce 100644 --- a/views/res/i18n/en.ini +++ b/views/res/i18n/en.ini @@ -49,6 +49,7 @@ MENU_BUILD_WORKSPACE_CLEAN=Clean workspace MENU_BUILD_PROJECT_BUILD=Build project MENU_BUILD_PROJECT_REBUILD=Rebuild project MENU_BUILD_PROJECT_CLEAN=Clean project +MENU_BUILD_RUN_WITH_RDMD=Run with rdmd MENU_DEBUG=&Debug MENU_DEBUG_START_DEBUGGING=Start debugging diff --git a/views/res/i18n/ru.ini b/views/res/i18n/ru.ini index 407615d..3aef15d 100644 --- a/views/res/i18n/ru.ini +++ b/views/res/i18n/ru.ini @@ -45,6 +45,7 @@ MENU_BUILD_WORKSPACE_CLEAN=Очистить workspace MENU_BUILD_PROJECT_BUILD=Собрать проект MENU_BUILD_PROJECT_REBUILD=Пересобрать проект MENU_BUILD_PROJECT_CLEAN=Очистить проект +MENU_BUILD_RUN_WITH_RDMD=Запустить с rdmd MENU_DEBUG=&Отладка diff --git a/views/res/mdpi/run-rdmd.png b/views/res/mdpi/run-rdmd.png new file mode 100644 index 0000000..a02d551 Binary files /dev/null and b/views/res/mdpi/run-rdmd.png differ diff --git a/views/resources.list b/views/resources.list index ffb67ad..29ee5af 100644 --- a/views/resources.list +++ b/views/resources.list @@ -62,6 +62,7 @@ res/mdpi/project-open.png res/mdpi/run-build.png res/mdpi/run-build-clean.png res/mdpi/run-build-configure.png +res/mdpi/run-rdmd.png res/mdpi/text-d.png res/mdpi/text-dml.png res/mdpi/text-json.png diff --git a/workspaces/for_rdmd_test.d b/workspaces/for_rdmd_test.d new file mode 100644 index 0000000..f040ee1 --- /dev/null +++ b/workspaces/for_rdmd_test.d @@ -0,0 +1,7 @@ +module for_rdmd_test; + +int inc(int x) +{ + return x + 1; +} + diff --git a/workspaces/rdmd_test.d b/workspaces/rdmd_test.d new file mode 100644 index 0000000..25fc788 --- /dev/null +++ b/workspaces/rdmd_test.d @@ -0,0 +1,22 @@ +import std.stdio; +import for_rdmd_test; + +void main() +{ + writeln("test!"); + debug writeln("I am in debug mode"); + writeln(inc(10)); +} + +int f(int x) +{ + return x*x; +} + +unittest { + writeln("unittest!"); + assert(f(0) == 0); + assert(f(5) == 25); + assert(f(-5) == 25); +} +