From c6f1f358a9eca0898c0d148720d270fe17e435b2 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 22 Jun 2020 08:49:23 -0700 Subject: [PATCH] Added multi-line custom build command --- BeefLibs/Beefy2D/src/widgets/EditWidget.bf | 3 ++ BeefLibs/corlib/src/Collections/List.bf | 6 +++ IDE/src/BuildContext.bf | 5 +- IDE/src/IDEApp.bf | 35 +++++++++--- IDE/src/ScriptManager.bf | 13 ++++- IDE/src/ui/BuildPropertiesDialog.bf | 2 +- IDE/src/ui/ProjectProperties.bf | 1 + IDE/src/ui/PropertiesDialog.bf | 62 +++++++++++++++++++--- 8 files changed, 110 insertions(+), 17 deletions(-) diff --git a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf index 91d86a5e..65325720 100644 --- a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf +++ b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf @@ -2159,7 +2159,10 @@ namespace Beefy.widgets Redo(); case .Return: if (mIsMultiline) + { mEditWidget.Submit(); + return; + } default: } } diff --git a/BeefLibs/corlib/src/Collections/List.bf b/BeefLibs/corlib/src/Collections/List.bf index 2645f617..19310d69 100644 --- a/BeefLibs/corlib/src/Collections/List.bf +++ b/BeefLibs/corlib/src/Collections/List.bf @@ -304,6 +304,12 @@ namespace System.Collections #endif } + public void AddRange(IEnumerator items) + { + for (let item in items) + Add(item); + } + /// Returns a pointer to the start of the added uninitialized section public T* GrowUnitialized(int addSize) { diff --git a/IDE/src/BuildContext.bf b/IDE/src/BuildContext.bf index f2865df2..684ec3e2 100644 --- a/IDE/src/BuildContext.bf +++ b/IDE/src/BuildContext.bf @@ -130,7 +130,7 @@ namespace IDE bool isCommand = false; for (let c in origCustomCmd.RawChars) { - if ((c == '\"') || (c == '$')) + if ((c == '\"') || (c == '$') || (c == '\n')) break; if (c == '(') isCommand = true; @@ -146,6 +146,9 @@ namespace IDE { customCmd.Append("%exec "); gApp.ResolveConfigString(gApp.mPlatformName, workspaceOptions, project, options, origCustomCmd, "custom command", customCmd); + + // For multi-line execs + customCmd.Replace('\n', '\v'); } if (customCmd.IsWhiteSpace) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 46c6d4ad..01a5fb57 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -7480,8 +7480,9 @@ namespace IDE { None, ShellCommand = 1, - NoRedirect = 2, - NoWait = 4, + BatchCommand = 2, + NoRedirect = 4, + NoWait = 8, } public ExecutionInstance DoRun(String inFileName, String args, String workingDir, ArgsFileKind useArgsFile, Dictionary envVars = null, String stdInData = null, RunFlags runFlags = .None) @@ -7506,8 +7507,31 @@ namespace IDE startInfo.CreateNoWindow = true; } + + var executionInstance = new ExecutionInstance(); + #if BF_PLATFORM_WINDOWS - if (runFlags.HasFlag(.ShellCommand)) + if (runFlags.HasFlag(.BatchCommand)) + { + String tempFileName = scope String(); + Path.GetTempFileName(tempFileName); + tempFileName.Append(".bat"); + + String shellArgs = scope .(); + IDEUtils.AppendWithOptionalQuotes(shellArgs, fileName); + shellArgs.Append(" "); + shellArgs.Append(args); + + var result = File.WriteAllText(tempFileName, shellArgs, Encoding.UTF8); + if (result case .Err) + OutputLine("Failed to create temporary batch file"); + + startInfo.SetFileName(tempFileName); + startInfo.SetArguments(""); + + executionInstance.mTempFileName = new String(tempFileName); + } + else if (runFlags.HasFlag(.ShellCommand)) { String shellArgs = scope .(); shellArgs.Append("/c "); @@ -7525,8 +7549,6 @@ namespace IDE startInfo.AddEnvironmentVariable(envKV.key, envKV.value); } - var executionInstance = new ExecutionInstance(); - if (useArgsFile != .None) { String tempFileName = scope String(); @@ -7542,7 +7564,8 @@ namespace IDE String arguments = scope String(); arguments.Concat("@", tempFileName); startInfo.SetArguments(arguments); - + + delete executionInstance.mTempFileName; executionInstance.mTempFileName = new String(tempFileName); } diff --git a/IDE/src/ScriptManager.bf b/IDE/src/ScriptManager.bf index 9e5a3970..76e3e891 100644 --- a/IDE/src/ScriptManager.bf +++ b/IDE/src/ScriptManager.bf @@ -1369,9 +1369,18 @@ namespace IDE { var exeArgs = scope String(); exeArgs.Append(cmd, spacePos + 1); + IDEApp.RunFlags runFlags = .None; + if (!exePath.EndsWith(".exe", .OrdinalIgnoreCase)) + runFlags = .ShellCommand; - bool wantsShellCommand = !exePath.EndsWith(".exe", .OrdinalIgnoreCase); - gApp.DoRun(exePath, exeArgs, gApp.mInstallDir, .None, null, null, wantsShellCommand ? .ShellCommand : .None); + // Hande re-encoded embedded newlines + if (exeArgs.Contains('\v')) + { + exeArgs.Replace('\v', '\n'); + runFlags = .BatchCommand; + } + + gApp.DoRun(exePath, exeArgs, gApp.mInstallDir, .None, null, null, runFlags); } } diff --git a/IDE/src/ui/BuildPropertiesDialog.bf b/IDE/src/ui/BuildPropertiesDialog.bf index b380c112..ee7203c2 100644 --- a/IDE/src/ui/BuildPropertiesDialog.bf +++ b/IDE/src/ui/BuildPropertiesDialog.bf @@ -282,7 +282,7 @@ namespace IDE.ui let valueItem = propEntry.mListViewItem.GetSubItem(1); if (!valueItem.Label.IsEmpty) { - let dialog = ThemeFactory.mDefault.CreateDialog("Remove?", "Are you sure you want to remove the selected custom build options?"); + let dialog = ThemeFactory.mDefault.CreateDialog("Remove?", "Are you sure you want to remove the selected distinct build options?"); dialog.AddYesNoButtons(new (evt) => { DeleteDistinctBuildOptions(propEntry.mListViewItem); diff --git a/IDE/src/ui/ProjectProperties.bf b/IDE/src/ui/ProjectProperties.bf index 0cbb7b6c..da9a6508 100644 --- a/IDE/src/ui/ProjectProperties.bf +++ b/IDE/src/ui/ProjectProperties.bf @@ -675,6 +675,7 @@ namespace IDE.ui (listViewItem, propEntry) = AddPropertiesItem(root, "Rebuild Dependencies", "mBuildOptions.mLinkDependencies"); (listViewItem, propEntry) = AddPropertiesItem(root, "Prebuild Commands", "mBuildOptions.mPreBuildCmds"); (listViewItem, propEntry) = AddPropertiesItem(root, "Postbuild Commands", "mBuildOptions.mPostBuildCmds"); + propEntry.mAllowMultiline = true; (listViewItem, propEntry) = AddPropertiesItem(root, "Clean Commands", "mBuildOptions.mCleanCmds"); (listViewItem, propEntry) = AddPropertiesItem(root, "Build Commands on Compile", "mBuildOptions.mBuildCommandsOnCompile"); (listViewItem, propEntry) = AddPropertiesItem(root, "Build Commands on Run", "mBuildOptions.mBuildCommandsOnRun"); diff --git a/IDE/src/ui/PropertiesDialog.bf b/IDE/src/ui/PropertiesDialog.bf index 1bd4bcc3..3ec0dd3d 100644 --- a/IDE/src/ui/PropertiesDialog.bf +++ b/IDE/src/ui/PropertiesDialog.bf @@ -188,6 +188,12 @@ namespace IDE.ui BrowseForFolder, } + public enum MultiEncodeKind + { + Semicolon, + Extended // Uses /v to split + } + public Flags mFlags; public DarkListViewItem mListViewItem; public Object mTarget; @@ -203,9 +209,11 @@ namespace IDE.ui public PropertyBag mProperties ~ delete _; public Event mOnUpdate ~ _.Dispose(); public bool mDisabled; + public bool mMultiRootReadOnly; public uint32? mColorOverride; public String mRelPath ~ delete _; public bool mIsTypeWildcard; + public bool mAllowMultiline; public Insets mEditInsets ~ delete _; public ~this() @@ -817,6 +825,9 @@ namespace IDE.ui Rect rect = .(xPos, yPos, GetValueEditWidth(editItem), GS!(20)); propEntry.mEditInsets?.ApplyTo(ref rect); + if (mPropEditWidget.mEditWidgetContent.mIsMultiline) + rect.mHeight *= 4; + mPropEditWidget.Resize(rect.Left, rect.Top, rect.Width, rect.mHeight); //mPropEditWidget.Resize(mPropEditWidget.mX, mPropEditWidget.mY, GetValueEditWidth(mEditingListViewItem.GetSubItem(1)), mPropEditWidget.mHeight); @@ -961,7 +972,8 @@ namespace IDE.ui } else if (curVariantType == typeof(List)) { - let entryViews = scope List(newValue.Split(';')); + let entryViews = scope List(); + entryViews.AddRange(newValue.Split(';')); let entries = new List(); for (int32 i = 0; i < entryViews.Count; i++) @@ -969,7 +981,9 @@ namespace IDE.ui String entry = scope String(entryViews[i]); entry.Trim(); if (entry.Length > 0) - entries.Add(new String(entry)); + { + entries.Add(new String(entry)); + } } editingProp.mCurValue = Variant.Create(entries, true); } @@ -1200,6 +1214,9 @@ namespace IDE.ui var propEntry = propEntries[0]; + if ((propEntry.mMultiRootReadOnly) && (subValueIdx == -1)) + return; + var valueItem = propEntry.mListViewItem.GetSubItem(1); let type = propEntry.mCurValue.VariantType; @@ -1219,6 +1236,12 @@ namespace IDE.ui } else editWidget = new DarkEditWidget(); + + let ewc = editWidget.mEditWidgetContent; + ewc.mIsMultiline = propEntry.mAllowMultiline; + if (ewc.mIsMultiline) + editWidget.InitScrollbars(false, true); + editWidget.mScrollContentInsets.Set(GS!(3), GS!(3), GS!(1), GS!(3)); editWidget.Content.mTextInsets.Set(GS!(-3), GS!(2), 0, GS!(2)); //editWidget.RehupSize(); @@ -1236,7 +1259,8 @@ namespace IDE.ui moveItemWidget.Resize(6, editWidget.mY - GS!(16), GS!(20), GS!(20)); moveItemWidget.mArrowDir = -1; moveItemWidget.mOnMouseDown.Add(new (evt) => { MoveEditingItem(subValueIdx, -1); }); - editWidget.mOnKeyDown.Add(new (evt) => { if (evt.mKeyCode == KeyCode.Up) MoveEditingItem(subValueIdx, -1); }); + if (!ewc.mIsMultiline) + editWidget.mOnKeyDown.Add(new (evt) => { if (evt.mKeyCode == KeyCode.Up) MoveEditingItem(subValueIdx, -1); }); } if (subValueIdx < stringList.Count - 1) @@ -1246,7 +1270,8 @@ namespace IDE.ui moveItemWidget.Resize(6, editWidget.mY + GS!(16), GS!(20), GS!(20)); moveItemWidget.mArrowDir = 1; moveItemWidget.mOnMouseDown.Add(new (evt) => { MoveEditingItem(subValueIdx, 1); }); - editWidget.mOnKeyDown.Add(new (evt) => { if (evt.mKeyCode == KeyCode.Down) MoveEditingItem(subValueIdx, 1); }); + if (!ewc.mIsMultiline) + editWidget.mOnKeyDown.Add(new (evt) => { if (evt.mKeyCode == KeyCode.Down) MoveEditingItem(subValueIdx, 1); }); } } else @@ -1260,7 +1285,20 @@ namespace IDE.ui if (label == "Not Set") label = ""; }*/ - if (editWidget is KeysEditWidget) + + if (propEntry.mCurValue.VariantType == typeof(List)) + { + List stringList = propEntry.mCurValue.Get>(); + String allValues = scope .(); + for (int i = 0; i < stringList.Count; i++) + { + if (i > 0) + allValues.Append(";"); + allValues.Append(stringList[i]); + } + editWidget.SetText(allValues); + } + else if (editWidget is KeysEditWidget) editWidget.SetText("< Press Key >"); else editWidget.SetText(label); @@ -1276,7 +1314,6 @@ namespace IDE.ui editWidget.SetFocus(); mWidgetWindow.mOnMouseWheel.Add(new => HandleMouseWheel); mWidgetWindow.mOnWindowMoved.Add(new => HandleWindowMoved); - editWidget.mEditWidgetContent.ClearUndoData(); mEditingListViewItem = item; @@ -1350,6 +1387,13 @@ namespace IDE.ui } } + void FixLabel(ListViewItem lvItem) + { + if (!lvItem.mLabel.Contains('\n')) + return; + lvItem.mLabel.Replace('\n', ' '); + } + if (handled) { if (curVariantType == typeof(String)) @@ -1410,9 +1454,11 @@ namespace IDE.ui if (i < strVals.Count) { if (i > 0) - allValues.Append(";"); + allValues.Append(";"); curValue = strVals[i]; allValues.Append(curValue); + if (curValue.Contains(';')) // Don't allow editing if the parsing will mess up + propEntry.mMultiRootReadOnly = true; } DarkListViewItem childItem; @@ -1456,12 +1502,14 @@ namespace IDE.ui childSubItem.mTextColor = 0xFFC0C0C0; } childSubItem.Label = curValue; + FixLabel(childSubItem); } while (propEntry.mListViewItem.GetChildCount() > strVals.Count + 1) propEntry.mListViewItem.RemoveChildItem(propEntry.mListViewItem.GetChildAtIndex(propEntry.mListViewItem.GetChildCount() - 1)); valueItem.Label = allValues; + FixLabel(valueItem); } else if (propEntry.mCheckBox != null) {