mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-22 17:48:01 +02:00
454 lines
13 KiB
Beef
454 lines
13 KiB
Beef
using System;
|
|
using System.Collections;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Beefy;
|
|
using Beefy.gfx;
|
|
using Beefy.theme.dark;
|
|
using Beefy.widgets;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
|
|
namespace IDE.ui
|
|
{
|
|
public class LaunchDialog : IDEDialog
|
|
{
|
|
const String cBrowseCmd = "< Browse ... >";
|
|
const String cCurProjectCmd = "< Current Debug Setting >";
|
|
|
|
PathComboBox mTargetCombo;
|
|
DarkComboBox mArgumentsCombo;
|
|
DarkComboBox mWorkingDirCombo;
|
|
DarkComboBox mEnvironmentCombo;
|
|
|
|
DarkCheckBox mDebugCheckbox;
|
|
DarkCheckBox mPausedCheckbox;
|
|
DarkCheckBox mProfileCheckbox;
|
|
bool mIgnoreContentChanged;
|
|
|
|
public this()
|
|
{
|
|
mSettingHistoryManager = gApp.mLaunchHistoryManager;
|
|
|
|
mTitle = new .("Launch Executable");
|
|
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable | .PopupPosition;
|
|
|
|
AddOkCancelButtons(new (evt) => { evt.mCloseDialog = false; Launch(); }, null, 0, 1);
|
|
|
|
mButtonBottomMargin = GS!(6);
|
|
mButtonRightMargin = GS!(6);
|
|
|
|
mTargetCombo = new PathComboBox();
|
|
mTargetCombo.MakeEditable(new PathEditWidget());
|
|
mTargetCombo.Label = "";
|
|
mTargetCombo.mPopulateMenuAction.Add(new => PopulateTargetMenu);
|
|
AddWidget(mTargetCombo);
|
|
AddEdit(mTargetCombo.mEditWidget);
|
|
|
|
mArgumentsCombo = new DarkComboBox();
|
|
mArgumentsCombo.MakeEditable();
|
|
mArgumentsCombo.Label = "";
|
|
mArgumentsCombo.mPopulateMenuAction.Add(new => PopulateArgumentsMenu);
|
|
AddWidget(mArgumentsCombo);
|
|
AddEdit(mArgumentsCombo.mEditWidget);
|
|
|
|
mWorkingDirCombo = new PathComboBox();
|
|
mWorkingDirCombo.MakeEditable(new PathEditWidget());
|
|
mWorkingDirCombo.Label = "";
|
|
mWorkingDirCombo.mPopulateMenuAction.Add(new => PopulateWorkingDirMenu);
|
|
AddWidget(mWorkingDirCombo);
|
|
AddEdit(mWorkingDirCombo.mEditWidget);
|
|
|
|
mEnvironmentCombo = new DarkComboBox();
|
|
mEnvironmentCombo.MakeEditable();
|
|
mEnvironmentCombo.Label = "";
|
|
mEnvironmentCombo.mPopulateMenuAction.Add(new => PopulateEnvironmentMenu);
|
|
AddWidget(mEnvironmentCombo);
|
|
AddEdit(mEnvironmentCombo.mEditWidget);
|
|
|
|
mDebugCheckbox = new DarkCheckBox();
|
|
mDebugCheckbox.Label = "&Debug";
|
|
mDebugCheckbox.Checked = true;
|
|
AddDialogComponent(mDebugCheckbox);
|
|
|
|
mPausedCheckbox = new DarkCheckBox();
|
|
mPausedCheckbox.Label = "&Start Paused";
|
|
mPausedCheckbox.Checked = false;
|
|
AddDialogComponent(mPausedCheckbox);
|
|
|
|
mProfileCheckbox = new DarkCheckBox();
|
|
mProfileCheckbox.Label = "P&rofile";
|
|
mProfileCheckbox.Checked = false;
|
|
AddDialogComponent(mProfileCheckbox);
|
|
|
|
//mPrevButton = new DarkButton();
|
|
//mPrevButton.Label = "< Prev";
|
|
|
|
CreatePrevNextButtons();
|
|
}
|
|
|
|
protected override void UseProps(PropertyBag propBag)
|
|
{
|
|
mTargetCombo.Label = propBag.Get<String>("Target") ?? "";
|
|
mArgumentsCombo.Label = propBag.Get<String>("Arguments") ?? "";
|
|
mWorkingDirCombo.Label = propBag.Get<String>("WorkingDir") ?? "";
|
|
mEnvironmentCombo.Label = propBag.Get<String>("EnvVars") ?? "";
|
|
mDebugCheckbox.Checked = propBag.Get<bool>("Debug", true);
|
|
mPausedCheckbox.Checked = propBag.Get<bool>("StartPaused");
|
|
mProfileCheckbox.Checked = propBag.Get<bool>("Profile");
|
|
}
|
|
|
|
void SaveProps()
|
|
{
|
|
PropertyBag propBag = new PropertyBag();
|
|
propBag.Add("Target", mTargetCombo.Label);
|
|
propBag.Add("Arguments", mArgumentsCombo.Label);
|
|
propBag.Add("WorkingDir", mWorkingDirCombo.Label);
|
|
propBag.Add("EnvVars", mEnvironmentCombo.Label);
|
|
propBag.Add("Debug", mDebugCheckbox.Checked);
|
|
propBag.Add("StartPaused", mPausedCheckbox.Checked);
|
|
propBag.Add("Profile", mProfileCheckbox.Checked);
|
|
|
|
mSettingHistoryManager.Add(propBag);
|
|
}
|
|
|
|
bool GetStartupOption(delegate String (Project.Options options) dlg, String outString)
|
|
{
|
|
if (gApp.mWorkspace.mStartupProject != null)
|
|
{
|
|
let options = gApp.GetCurProjectOptions(gApp.mWorkspace.mStartupProject);
|
|
let workspaceOptions = gApp.GetCurWorkspaceOptions();
|
|
|
|
var inStr = dlg(options);
|
|
if (inStr == null)
|
|
return false;
|
|
|
|
gApp.ResolveConfigString(gApp.mPlatformName, workspaceOptions, gApp.mWorkspace.mStartupProject, options, inStr, "", outString);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void DoBrowse()
|
|
{
|
|
#if !CLI
|
|
String str = scope String();
|
|
GetStartupOption(scope (options) => options.mDebugOptions.mCommand, str);
|
|
|
|
String dir = scope String();
|
|
Path.GetDirectoryPath(str, dir).IgnoreError();
|
|
IDEUtils.FixFilePath(dir);
|
|
|
|
var fileDialog = scope System.IO.OpenFileDialog();
|
|
fileDialog.ShowReadOnly = false;
|
|
fileDialog.Title = "Select Executable";
|
|
fileDialog.Multiselect = true;
|
|
if (!dir.IsEmpty)
|
|
fileDialog.InitialDirectory = dir;
|
|
fileDialog.ValidateNames = true;
|
|
fileDialog.DefaultExt = ".exe";
|
|
fileDialog.SetFilter("Executables (*.exe)|*.exe|All files (*.*)|*.*");
|
|
mWidgetWindow.PreModalChild();
|
|
if (fileDialog.ShowDialog(gApp.GetActiveWindow()) case .Ok)
|
|
{
|
|
var fileNames = fileDialog.FileNames;
|
|
if (!fileNames.IsEmpty)
|
|
mTargetCombo.Label = fileNames[0];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void PopulateTargetMenu(Menu menu)
|
|
{
|
|
var item = menu.AddItem(cBrowseCmd);
|
|
item.mOnMenuItemSelected.Add(new (dlg) =>
|
|
{
|
|
DoBrowse();
|
|
});
|
|
|
|
item = menu.AddItem(cCurProjectCmd);
|
|
item.mOnMenuItemSelected.Add(new (dlg) =>
|
|
{
|
|
mIgnoreContentChanged = true;
|
|
String str = scope String();
|
|
GetStartupOption(scope (options) => options.mDebugOptions.mCommand, str);
|
|
mTargetCombo.Label = str;
|
|
mIgnoreContentChanged = false;
|
|
});
|
|
}
|
|
|
|
void PopulateArgumentsMenu(Menu menu)
|
|
{
|
|
var item = menu.AddItem(cCurProjectCmd);
|
|
item.mOnMenuItemSelected.Add(new (dlg) =>
|
|
{
|
|
mIgnoreContentChanged = true;
|
|
String str = scope String();
|
|
GetStartupOption(scope (options) => options.mDebugOptions.mCommandArguments, str);
|
|
mArgumentsCombo.Label = str;
|
|
mIgnoreContentChanged = false;
|
|
});
|
|
}
|
|
|
|
void PopulateWorkingDirMenu(Menu menu)
|
|
{
|
|
var item = menu.AddItem(cCurProjectCmd);
|
|
item.mOnMenuItemSelected.Add(new (dlg) =>
|
|
{
|
|
mIgnoreContentChanged = true;
|
|
String str = scope String();
|
|
GetStartupOption(scope (options) => options.mDebugOptions.mWorkingDirectory, str);
|
|
mWorkingDirCombo.Label = str;
|
|
mIgnoreContentChanged = false;
|
|
});
|
|
}
|
|
|
|
void PopulateEnvironmentMenu(Menu menu)
|
|
{
|
|
var item = menu.AddItem(cCurProjectCmd);
|
|
item.mOnMenuItemSelected.Add(new (dlg) =>
|
|
{
|
|
mIgnoreContentChanged = true;
|
|
String str = scope String();
|
|
|
|
for (int i = 0; true; i++)
|
|
{
|
|
var curStr = scope String();
|
|
|
|
if (!GetStartupOption(scope (options) =>
|
|
{
|
|
if (i < options.mDebugOptions.mEnvironmentVars.Count)
|
|
return options.mDebugOptions.mEnvironmentVars[i];
|
|
return null;
|
|
}, curStr))
|
|
break;
|
|
|
|
if (!str.IsEmpty)
|
|
str.Append(";");
|
|
str.Append(curStr);
|
|
}
|
|
mEnvironmentCombo.Label = str;
|
|
mIgnoreContentChanged = false;
|
|
});
|
|
}
|
|
|
|
public static void DoLaunch(LaunchDialog dialog, String targetPath, String arguments, String workingDir, String envVarStr, bool startPaused, bool debug)
|
|
{
|
|
var workingDir;
|
|
|
|
if (!File.Exists(targetPath))
|
|
{
|
|
dialog?.mTargetCombo.SetFocus();
|
|
gApp.Fail(scope String()..AppendF("Unable to locate target file '{0}'", targetPath));
|
|
return;
|
|
}
|
|
|
|
if (workingDir.IsWhiteSpace)
|
|
{
|
|
workingDir = scope:: .(@workingDir);
|
|
Path.GetDirectoryPath(targetPath, workingDir);
|
|
}
|
|
if (workingDir.EndsWith('\\') || workingDir.EndsWith('/'))
|
|
workingDir.RemoveFromEnd(1);
|
|
|
|
if (!Directory.Exists(workingDir))
|
|
{
|
|
dialog?.mWorkingDirCombo.SetFocus();
|
|
gApp.Fail(scope String()..AppendF("Unable to locate working directory '{0}'", workingDir));
|
|
return;
|
|
}
|
|
|
|
if (gApp.mDebugger.mIsRunning)
|
|
{
|
|
gApp.Fail("An executable is already being debugged");
|
|
return;
|
|
}
|
|
|
|
gApp.mProfilePanel.Clear();
|
|
gApp.mDebugger.ClearInvalidBreakpoints();
|
|
|
|
gApp.mExecutionPaused = false;
|
|
gApp.mTargetDidInitBreak = false;
|
|
gApp.mTargetHadFirstBreak = false;
|
|
|
|
if (!debug)
|
|
{
|
|
ProcessStartInfo procInfo = scope ProcessStartInfo();
|
|
procInfo.UseShellExecute = false;
|
|
procInfo.SetWorkingDirectory(workingDir);
|
|
procInfo.SetArguments(arguments);
|
|
for (var envVar in envVarStr.Split(';'))
|
|
{
|
|
envVar.Trim();
|
|
if (envVar.IsEmpty)
|
|
continue;
|
|
int eqPos = envVar.IndexOf('=', 1);
|
|
if (eqPos == -1)
|
|
{
|
|
gApp.OutputErrorLine("Invalid environment variable: {0}", envVar);
|
|
}
|
|
else
|
|
{
|
|
procInfo.AddEnvironmentVariable(StringView(envVar, 0, eqPos), StringView(envVar, eqPos + 1));
|
|
}
|
|
}
|
|
|
|
procInfo.SetFileName(targetPath);
|
|
|
|
var spawnedProcess = scope SpawnedProcess();
|
|
if (spawnedProcess.Start(procInfo) case .Err)
|
|
{
|
|
gApp.Fail(scope String()..AppendF("Unable to start executable: {0}", targetPath));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (startPaused)
|
|
{
|
|
gApp.mTargetDidInitBreak = true;
|
|
gApp.mTargetHadFirstBreak = true;
|
|
}
|
|
|
|
var envVars = scope Dictionary<String, String>();
|
|
defer { for (var kv in envVars) { delete kv.key; delete kv.value; } }
|
|
Environment.GetEnvironmentVariables(envVars);
|
|
|
|
for (var envVar in envVarStr.Split(';'))
|
|
{
|
|
envVar.Trim();
|
|
if (envVar.IsEmpty)
|
|
continue;
|
|
int eqPos = envVar.IndexOf('=', 1);
|
|
if (eqPos == -1)
|
|
{
|
|
gApp.OutputErrorLine("Invalid environment variable: {0}", envVar);
|
|
}
|
|
else
|
|
{
|
|
Environment.SetEnvironmentVariable(envVars, StringView(envVar, 0, eqPos), StringView(envVar, eqPos + 1));
|
|
}
|
|
}
|
|
|
|
var envBlock = scope List<char8>();
|
|
Environment.EncodeEnvironmentVariables(envVars, envBlock);
|
|
|
|
if (!gApp.mDebugger.OpenFile(targetPath, targetPath, arguments, workingDir, envBlock, false, false))
|
|
{
|
|
gApp.Fail(scope String()..AppendF("Unable to open executable for debugging: {0}", targetPath));
|
|
return;
|
|
}
|
|
|
|
gApp.[Friend]CheckDebugVisualizers();
|
|
gApp.mDebugger.mIsRunning = true;
|
|
gApp.mDebugger.RehupBreakpoints(true);
|
|
gApp.mDebugger.Run();
|
|
}
|
|
|
|
void Launch()
|
|
{
|
|
var targetPath = scope String();
|
|
targetPath.Append(mTargetCombo.Label);
|
|
IDEUtils.FixFilePath(targetPath);
|
|
|
|
String workingDir = scope String();
|
|
|
|
workingDir.Append(mWorkingDirCombo.Label);
|
|
if (Path.IsPathRooted(workingDir))
|
|
{
|
|
defer targetPath.Remove(0, targetPath.Length);
|
|
Path.GetAbsolutePath(targetPath, workingDir, targetPath);
|
|
}
|
|
else
|
|
{
|
|
String targetDir = scope .();
|
|
Path.GetDirectoryPath(targetPath, targetDir);
|
|
if (!targetDir.IsWhiteSpace)
|
|
{
|
|
defer workingDir.Remove(0, workingDir.Length);
|
|
Path.GetAbsolutePath(workingDir, targetDir, workingDir);
|
|
}
|
|
}
|
|
|
|
String envVarStr = scope String();
|
|
envVarStr.Append(mEnvironmentCombo.Label);
|
|
|
|
String arguments = scope String();
|
|
arguments.Append(mArgumentsCombo.Label);
|
|
|
|
DoLaunch(this, targetPath, arguments, workingDir, envVarStr, mPausedCheckbox.Checked, mDebugCheckbox.Checked);
|
|
|
|
SaveProps();
|
|
|
|
Close();
|
|
}
|
|
|
|
public override void ResizeComponents()
|
|
{
|
|
base.ResizeComponents();
|
|
|
|
float curY = GS!(30);
|
|
|
|
mTargetCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
|
|
|
|
curY += GS!(42);
|
|
mArgumentsCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
|
|
|
|
curY += GS!(42);
|
|
mWorkingDirCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
|
|
|
|
curY += GS!(42);
|
|
mEnvironmentCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
|
|
|
|
curY += GS!(28);
|
|
mDebugCheckbox.Resize(GS!(6), curY, mProfileCheckbox.CalcWidth(), GS!(22));
|
|
curY += GS!(22);
|
|
mPausedCheckbox.Resize(GS!(6), curY, mPausedCheckbox.CalcWidth(), GS!(22));
|
|
curY += GS!(22);
|
|
mProfileCheckbox.Resize(GS!(6), curY, mProfileCheckbox.CalcWidth(), GS!(22));
|
|
}
|
|
|
|
public override void CalcSize()
|
|
{
|
|
mWidth = GS!(400);
|
|
mHeight = GS!(260);
|
|
}
|
|
|
|
public override void AddedToParent()
|
|
{
|
|
base.AddedToParent();
|
|
RehupMinSize();
|
|
}
|
|
|
|
void RehupMinSize()
|
|
{
|
|
mWidgetWindow.SetMinimumSize(GS!(280), GS!(280), true);
|
|
}
|
|
|
|
public override void RehupScale(float oldScale, float newScale)
|
|
{
|
|
base.RehupScale(oldScale, newScale);
|
|
RehupMinSize();
|
|
}
|
|
|
|
public override void Resize(float x, float y, float width, float height)
|
|
{
|
|
base.Resize(x, y, width, height);
|
|
ResizeComponents();
|
|
}
|
|
|
|
public override void Draw(Graphics g)
|
|
{
|
|
base.Draw(g);
|
|
|
|
g.DrawString("Target Path:", GS!(6), mTargetCombo.mY - GS!(18));
|
|
g.DrawString("Arguments:", GS!(6), mArgumentsCombo.mY - GS!(18));
|
|
g.DrawString("Working Directory:", GS!(6), mWorkingDirCombo.mY - GS!(18));
|
|
g.DrawString("Environment Variables:", GS!(6), mEnvironmentCombo.mY - GS!(18));
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
}
|
|
}
|
|
}
|