diff --git a/BeefySysLib/util/Array.h b/BeefySysLib/util/Array.h index fd2bbd05..e1020cdf 100644 --- a/BeefySysLib/util/Array.h +++ b/BeefySysLib/util/Array.h @@ -958,8 +958,7 @@ public: intptr moveCount = this->mSize - idx; memmove(this->mVals + idx + size, this->mVals + idx, moveCount * sizeof(T)); } - for (intptr i = 0; i < size; i++) - this->mVals[idx + i] = vals[i]; + memcpy(&this->mVals[idx], vals, size * sizeof(T)); this->mSize += (int_cosize)size; } diff --git a/IDE/BeefProj.toml b/IDE/BeefProj.toml index 98e11371..24da142b 100644 --- a/IDE/BeefProj.toml +++ b/IDE/BeefProj.toml @@ -25,7 +25,7 @@ OtherLinkFlags = "" TargetDirectory = "$(WorkspaceDir)/dist" TargetName = "BeefIDE_d" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib" -DebugCommandArguments = "-proddir=C:\\_Beef\\TestApp" +DebugCommandArguments = "-proddir=C:\\Beef\\IDEHelper\\Tests" DebugWorkingDirectory = "c:\\Beef\\IDE\\Tests\\EmptyTest" EnvironmentVars = ["_NO_DEBUG_HEAP=1"] diff --git a/IDE/mintest/BeefSpace.toml b/IDE/mintest/BeefSpace.toml index 38bb6c23..3e5cadb7 100644 --- a/IDE/mintest/BeefSpace.toml +++ b/IDE/mintest/BeefSpace.toml @@ -1,5 +1,6 @@ FileVersion = 1 Projects = {mintest = {Path = "."}, minlib = {Path = "minlib"}, LibA = {Path = "LibA"}, LibB = {Path = "LibB"}, mintest2 = {Path = "mintest2"}} +Locked = ["mintest2"] [Workspace] StartupProject = "mintest" diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index ee3fa102..98ba757c 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -321,7 +321,7 @@ namespace IDE class LaunchData { - public String mTargetPath = new .() ~ delete _; + public String mTargetPath ~ delete _; public String mArgs ~ delete _; public String mWorkingDir ~ delete _; public bool mPaused = false; @@ -6358,6 +6358,9 @@ namespace IDE mWantsClean = true; case "-dbgCompileDump": mDbgCompileDump = true; + case "-launch": + if (mLaunchData == null) + mLaunchData = new .(); case "-launchPaused": if (mLaunchData != null) mLaunchData.mPaused = true; @@ -6385,7 +6388,12 @@ namespace IDE case "-launch": if (mLaunchData == null) mLaunchData = new .(); - mLaunchData.mTargetPath.Set(value); + String.NewOrSet!(mLaunchData.mTargetPath, value); + case "-launchDir": + if (mLaunchData != null) + String.NewOrSet!(mLaunchData.mWorkingDir, value); + else + Fail("'-launchDir' can only be used after '-launch'"); #if BF_PLATFORM_WINDOWS case "-minidump": String.NewOrSet!(mCrashDumpPath, value); @@ -8404,9 +8412,15 @@ namespace IDE switch (replaceStr) { case "Arguments": - newString = options.mDebugOptions.mCommandArguments; + if (mLaunchData?.mArgs != null) + newString = mLaunchData.mArgs; + else + newString = options.mDebugOptions.mCommandArguments; case "WorkingDir": - newString = options.mDebugOptions.mWorkingDirectory; + if (mLaunchData?.mWorkingDir != null) + newString = mLaunchData.mWorkingDir; + else + newString = options.mDebugOptions.mWorkingDirectory; case "TargetDir": { if (project.IsDebugSession) @@ -9308,6 +9322,9 @@ namespace IDE return false; } + if (mInitialized) + DeleteAndNullify!(mLaunchData); + mOutputPanel.Clear(); OutputLine("Compiling..."); if (!Compile(.RunAfter)) @@ -9357,10 +9374,89 @@ namespace IDE Test } + public void AutoGenerateStartupCode(Project project) + { + String namespaceName = scope .(); + String className = scope .(); + String startupStr = project.mBeefGlobalOptions.mStartupObject; + + int dotPos = startupStr.LastIndexOf('.'); + if (dotPos != -1) + { + namespaceName.Append(startupStr, 0, dotPos); + className.Append(startupStr, dotPos + 1); + } + else + { + namespaceName.Append(project.mProjectName); + className.Append(startupStr); + } + + String startupCode = scope .(); + startupCode.AppendF( + """ + using System; + + namespace {} + {{ + class {} + {{ + public static int Main(String[] args) + {{ + return 0; + }} + }} + }} + """, namespaceName, className); + + String srcPath = scope .(); + project.mRootFolder.GetFullImportPath(srcPath); + srcPath.Append(Path.DirectorySeparatorChar); + srcPath.Append("Program.bf"); + + if (!SafeWriteTextFile(srcPath, startupCode)) + return; + + OnWatchedFileChanged(project.mRootFolder, .FileCreated, srcPath); + if (project.IsEmpty) + return; + + let projectSource = project.mRootFolder.mChildItems[0] as ProjectSource; + if (projectSource == null) + return; + + ShowSourceFile(srcPath); + } + protected bool Compile(CompileKind compileKind = .Normal, Project hotProject = null) { Debug.Assert(mBuildContext == null); + if (mWorkspace.mStartupProject != null) + { + if (mWorkspace.mStartupProject.IsEmpty) + { + DarkDialog dlg = new DarkDialog("Initialize Project?", + """ + This project does not contain any source code. Do you want to auto-generate some startup code? + """ + , DarkTheme.sDarkTheme.mIconError); + dlg.mWindowFlags |= .Modal; + dlg.AddYesNoButtons(new (dlg) => + { + AutoGenerateStartupCode(mWorkspace.mStartupProject); + }, + new (dlg) => + { + + }); + dlg.PopupWindow(GetActiveWindow()); + + OutputLine("Aborted - no startup project code found."); + return false; + } + } + let platform = Workspace.PlatformType.GetFromName(mPlatformName); let hostPlatform = Workspace.PlatformType.GetHostPlatform(); if (platform == .Unknown) @@ -10230,7 +10326,15 @@ namespace IDE } else if (mLaunchData != null) { - LaunchDialog.DoLaunch(null, mLaunchData.mTargetPath, mLaunchData.mArgs ?? "", mLaunchData.mWorkingDir ?? "", "", mLaunchData.mPaused, true); + if (mLaunchData.mTargetPath == null) + { + if (mLaunchData.mPaused) + RunWithStep(); + else + CompileAndRun(); + } + else + LaunchDialog.DoLaunch(null, mLaunchData.mTargetPath, mLaunchData.mArgs ?? "", mLaunchData.mWorkingDir ?? "", "", mLaunchData.mPaused, true); } mInitialized = true; @@ -11357,6 +11461,9 @@ namespace IDE DeleteAndNullify!(mBuildContext); } } + + if ((mBuildContext == null) && (!IsCompiling)) + DeleteAndNullify!(mLaunchData); } public void ShowPassOutput(BfPassInstance bfPassInstance) diff --git a/IDE/src/Project.bf b/IDE/src/Project.bf index 1e5bf919..46368e15 100644 --- a/IDE/src/Project.bf +++ b/IDE/src/Project.bf @@ -1250,6 +1250,14 @@ namespace IDE } } + public bool IsEmpty + { + get + { + return mRootFolder.mChildItems.IsEmpty; + } + } + void SetupDefaultOptions(Options options) { options.mBuildOptions.mOtherLinkFlags.Set("$(LinkFlags)"); diff --git a/IDE/src/ui/ProjectPanel.bf b/IDE/src/ui/ProjectPanel.bf index 9fcb90e7..537873a8 100644 --- a/IDE/src/ui/ProjectPanel.bf +++ b/IDE/src/ui/ProjectPanel.bf @@ -807,6 +807,22 @@ namespace IDE.ui }); } + bool CheckProjectModify(Project project) + { + if (!project.mLocked) + return true; + + let dialog = gApp.Fail( + """ + This project is locked because it may be a shared library, and editing shared libraries may have unwanted effects on other programs that use it. + + If you are sure you want to edit this project then you can unlock it by right clicking on the project and deselecting 'Lock Project' + """, + null, mWidgetWindow); + dialog.mWindowFlags |= .Modal; + return false; + } + public void ImportFile(ProjectFolder folder) { #if !CLI @@ -827,6 +843,9 @@ namespace IDE.ui fullDir = scope String(); folder.mProject.GetProjectFullPath(oldStr, fullDir);*/ + if (!CheckProjectModify(folder.mProject)) + return; + String fullDir = scope String(); folder.GetFullImportPath(fullDir); //fullDir.Replace('/', '\\'); @@ -960,6 +979,9 @@ namespace IDE.ui public void ImportFolder(ProjectFolder folder) { #if !CLI + if (!CheckProjectModify(folder.mProject)) + return; + //ThrowUnimplemented(); String relDir = scope String(""); var checkFolder = folder; @@ -2113,7 +2135,10 @@ namespace IDE.ui { var projectFolder = GetSelectedProjectItem() as ProjectFolder; if (projectFolder != null) - NewFolder(projectFolder); + { + if (CheckProjectModify(projectFolder.mProject)) + NewFolder(projectFolder); + } }); item = menu.AddItem("New Class..."); @@ -2121,7 +2146,10 @@ namespace IDE.ui { var projectFolder = GetSelectedProjectItem() as ProjectFolder; if (projectFolder != null) - NewClass(projectFolder); + { + if (CheckProjectModify(projectFolder.mProject)) + NewClass(projectFolder); + } }); item = menu.AddItem("Import File...");