mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-09 03:52:19 +02:00
Embedded console / terminal support
This commit is contained in:
parent
60817eec48
commit
20a8e3327c
28 changed files with 2317 additions and 690 deletions
|
@ -10,6 +10,7 @@ namespace System.Diagnostics
|
||||||
bool mRedirectStandardOutput = false;
|
bool mRedirectStandardOutput = false;
|
||||||
bool mRedirectStandardError = false;
|
bool mRedirectStandardError = false;
|
||||||
bool mCreateNoWindow = false;
|
bool mCreateNoWindow = false;
|
||||||
|
bool mActivateWindow = false;
|
||||||
public bool ErrorDialog;
|
public bool ErrorDialog;
|
||||||
//public Windows.Handle ErrorDialogParentHandle;
|
//public Windows.Handle ErrorDialogParentHandle;
|
||||||
//public ProcessWindowStyle WindowStyle;
|
//public ProcessWindowStyle WindowStyle;
|
||||||
|
@ -26,6 +27,7 @@ namespace System.Diagnostics
|
||||||
public bool RedirectStandardOutput { get { return mRedirectStandardOutput; } set { mRedirectStandardOutput = value; } };
|
public bool RedirectStandardOutput { get { return mRedirectStandardOutput; } set { mRedirectStandardOutput = value; } };
|
||||||
public bool RedirectStandardError { get { return mRedirectStandardError; } set { mRedirectStandardError = value; } };
|
public bool RedirectStandardError { get { return mRedirectStandardError; } set { mRedirectStandardError = value; } };
|
||||||
public bool CreateNoWindow { get { return mCreateNoWindow; } set { mCreateNoWindow = value; } };
|
public bool CreateNoWindow { get { return mCreateNoWindow; } set { mCreateNoWindow = value; } };
|
||||||
|
public bool ActivateWindow { get { return mActivateWindow; } set { mActivateWindow = value; } };
|
||||||
|
|
||||||
Encoding StandardOutputEncoding;
|
Encoding StandardOutputEncoding;
|
||||||
Encoding StandardErrorEncoding;
|
Encoding StandardErrorEncoding;
|
||||||
|
|
|
@ -70,6 +70,8 @@ namespace System.Diagnostics
|
||||||
}
|
}
|
||||||
if (startInfo.CreateNoWindow)
|
if (startInfo.CreateNoWindow)
|
||||||
spawnFlags |= .NoWindow;
|
spawnFlags |= .NoWindow;
|
||||||
|
if (!startInfo.ActivateWindow)
|
||||||
|
spawnFlags |= .NoActivateWindow;
|
||||||
if (startInfo.RedirectStandardInput)
|
if (startInfo.RedirectStandardInput)
|
||||||
spawnFlags |= .RedirectStdInput;
|
spawnFlags |= .RedirectStdInput;
|
||||||
if (startInfo.RedirectStandardOutput)
|
if (startInfo.RedirectStandardOutput)
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace System.IO
|
||||||
case OpenError(FileOpenError);
|
case OpenError(FileOpenError);
|
||||||
case ReadError(FileReadError);
|
case ReadError(FileReadError);
|
||||||
case SeekError;
|
case SeekError;
|
||||||
|
case PipeListening;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class File
|
static class File
|
||||||
|
|
|
@ -72,6 +72,8 @@ namespace System.IO
|
||||||
{
|
{
|
||||||
case .Timeout:
|
case .Timeout:
|
||||||
return .Err(.ReadError(.Timeout));
|
return .Err(.ReadError(.Timeout));
|
||||||
|
case .PipeListening:
|
||||||
|
return .Err(.PipeListening);
|
||||||
default:
|
default:
|
||||||
return .Err(.ReadError(.Unknown));
|
return .Err(.ReadError(.Unknown));
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,5 +109,11 @@ namespace System.IO
|
||||||
|
|
||||||
return .Ok;
|
return .Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
mMemory.Clear();
|
||||||
|
mPosition = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace System.IO
|
||||||
|
|
||||||
public Result<void, FileOpenError> Create(StringView machineName, StringView pipeName, PipeOptions options)
|
public Result<void, FileOpenError> Create(StringView machineName, StringView pipeName, PipeOptions options)
|
||||||
{
|
{
|
||||||
|
Close();
|
||||||
|
|
||||||
Runtime.Assert(mBfpFile == null);
|
Runtime.Assert(mBfpFile == null);
|
||||||
|
|
||||||
String path = scope String();
|
String path = scope String();
|
||||||
|
@ -64,6 +66,8 @@ namespace System.IO
|
||||||
|
|
||||||
public Result<void, FileOpenError> Open(StringView machineName, StringView pipeName, PipeOptions options)
|
public Result<void, FileOpenError> Open(StringView machineName, StringView pipeName, PipeOptions options)
|
||||||
{
|
{
|
||||||
|
Close();
|
||||||
|
|
||||||
Runtime.Assert(mBfpFile == null);
|
Runtime.Assert(mBfpFile == null);
|
||||||
|
|
||||||
String path = scope String();
|
String path = scope String();
|
||||||
|
|
|
@ -31,7 +31,8 @@ namespace System
|
||||||
PartialData,
|
PartialData,
|
||||||
TempFileError,
|
TempFileError,
|
||||||
Timeout,
|
Timeout,
|
||||||
NotEmpty
|
NotEmpty,
|
||||||
|
PipeListening
|
||||||
};
|
};
|
||||||
|
|
||||||
public struct BfpSpawn {}
|
public struct BfpSpawn {}
|
||||||
|
@ -263,6 +264,7 @@ namespace System
|
||||||
ErrorDialog = 0x400,
|
ErrorDialog = 0x400,
|
||||||
Window_Hide = 0x800,
|
Window_Hide = 0x800,
|
||||||
Window_Maximized = 0x1000,
|
Window_Maximized = 0x1000,
|
||||||
|
NoActivateWindow = 0x2000
|
||||||
};
|
};
|
||||||
|
|
||||||
public enum BfpKillFlags : int32
|
public enum BfpKillFlags : int32
|
||||||
|
@ -455,6 +457,7 @@ namespace System
|
||||||
InsufficientBuffer = (int)Result.InsufficientBuffer,
|
InsufficientBuffer = (int)Result.InsufficientBuffer,
|
||||||
Timeout = (int)Result.Timeout,
|
Timeout = (int)Result.Timeout,
|
||||||
NotEmpty = (int)Result.NotEmpty,
|
NotEmpty = (int)Result.NotEmpty,
|
||||||
|
PipeListening = (int)Result.PipeListening,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !BF_RUNTIME_DISABLE
|
#if !BF_RUNTIME_DISABLE
|
||||||
|
|
21
BeefTools/BeefCon/BeefProj.toml
Normal file
21
BeefTools/BeefCon/BeefProj.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
FileVersion = 1
|
||||||
|
Dependencies = {corlib = "*", Beefy2D = "*"}
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
Name = "BeefCon"
|
||||||
|
TargetType = "BeefGUIApplication"
|
||||||
|
StartupObject = "BeefCon.Program"
|
||||||
|
|
||||||
|
[Configs.Debug.Win64]
|
||||||
|
TargetDirectory = "$(WorkspaceDir)\\..\\..\\IDE\\dist"
|
||||||
|
TargetName = "$(ProjectName)_d"
|
||||||
|
BeefLibType = "DynamicDebug"
|
||||||
|
DebugCommandArguments = "123 1 Powershell"
|
||||||
|
|
||||||
|
[Configs.Release.Win64]
|
||||||
|
TargetDirectory = "$(WorkspaceDir)\\..\\..\\IDE\\dist"
|
||||||
|
DebugCommandArguments = "123 1 Powershell"
|
||||||
|
|
||||||
|
[[ProjectFolder.Items]]
|
||||||
|
Type = "Source"
|
||||||
|
Path = "../../IDE/src/util/ConsoleProvider.bf"
|
8
BeefTools/BeefCon/BeefSpace.toml
Normal file
8
BeefTools/BeefCon/BeefSpace.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
FileVersion = 1
|
||||||
|
Projects = {BeefCon = {Path = "."}, Beefy2D = "*"}
|
||||||
|
|
||||||
|
[Workspace]
|
||||||
|
StartupProject = "BeefCon"
|
||||||
|
|
||||||
|
[Configs.Release.Win64]
|
||||||
|
BfOptimizationLevel = "OgPlus"
|
167
BeefTools/BeefCon/src/Program.bf
Normal file
167
BeefTools/BeefCon/src/Program.bf
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.IO;
|
||||||
|
using IDE.util;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Beefy.widgets;
|
||||||
|
|
||||||
|
namespace BeefCon;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
BeefConConsoleProvider.Pipe mPipe ~ delete _;
|
||||||
|
WinNativeConsoleProvider mProvider ~ delete _;
|
||||||
|
int32 mPid;
|
||||||
|
int32 mConid;
|
||||||
|
String mExecStr = new .() ~ delete _;
|
||||||
|
SpawnedProcess mSpawnedProcess ~ delete _;
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
mSpawnedProcess.Kill();
|
||||||
|
mSpawnedProcess.WaitFor();
|
||||||
|
}
|
||||||
|
|
||||||
|
static mixin GET<T>(var ptr)
|
||||||
|
{
|
||||||
|
*((T*)(ptr += sizeof(T)) - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MessageLoop()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
switch (mPipe.ReadMessage(-1))
|
||||||
|
{
|
||||||
|
case .Ok(let msg):
|
||||||
|
uint8* ptr = msg.Ptr + 1;
|
||||||
|
switch (*(BeefConConsoleProvider.Message*)msg.Ptr)
|
||||||
|
{
|
||||||
|
case .GetData:
|
||||||
|
mPipe.StartMessage(BeefConConsoleProvider.Message.Data);
|
||||||
|
mPipe.Stream.Write((int32)mProvider.Width);
|
||||||
|
mPipe.Stream.Write((int32)mProvider.Height);
|
||||||
|
mPipe.Stream.Write((int32)mProvider.BufferHeight);
|
||||||
|
mPipe.Stream.Write((int32)mProvider.ScrollTop);
|
||||||
|
mPipe.Stream.Write(mProvider.CursorVisible);
|
||||||
|
mPipe.Stream.Write(mProvider.CursorHeight);
|
||||||
|
mPipe.Stream.Write(mProvider.CursorPos);
|
||||||
|
for (int i < 16)
|
||||||
|
mPipe.Stream.Write(mProvider.GetColor(i));
|
||||||
|
|
||||||
|
for (int row < mProvider.Height)
|
||||||
|
{
|
||||||
|
for (int col < mProvider.Width)
|
||||||
|
{
|
||||||
|
var cell = mProvider.GetCell(col, row);
|
||||||
|
mPipe.Stream.Write(cell.mChar);
|
||||||
|
mPipe.Stream.Write(cell.mAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mPipe.EndMessage();
|
||||||
|
case .Resize:
|
||||||
|
int32 cols = GET!<int32>(ptr);
|
||||||
|
int32 rows = GET!<int32>(ptr);
|
||||||
|
bool resizeContent = GET!<bool>(ptr);
|
||||||
|
mProvider.Resize(cols, rows, resizeContent);
|
||||||
|
case .KeyDown:
|
||||||
|
KeyCode keyCode = GET!<KeyCode>(ptr);
|
||||||
|
KeyFlags keyFlags = GET!<KeyFlags>(ptr);
|
||||||
|
mProvider.KeyDown(keyCode, keyFlags);
|
||||||
|
case .KeyUp:
|
||||||
|
KeyCode keyCode = GET!<KeyCode>(ptr);
|
||||||
|
mProvider.KeyUp(keyCode);
|
||||||
|
case .InputString:
|
||||||
|
int32 strLen = GET!<int32>(ptr);
|
||||||
|
StringView str = .((.)ptr, strLen);
|
||||||
|
mProvider.SendInput(str);
|
||||||
|
case .MouseDown:
|
||||||
|
int32 col = GET!<int32>(ptr);
|
||||||
|
int32 row = GET!<int32>(ptr);
|
||||||
|
int32 btnState = GET!<int32>(ptr);
|
||||||
|
int32 btnCount = GET!<int32>(ptr);
|
||||||
|
KeyFlags keyFlags = GET!<KeyFlags>(ptr);
|
||||||
|
mProvider.MouseDown(col, row, btnState, btnCount, keyFlags);
|
||||||
|
case .MouseMove:
|
||||||
|
int32 col = GET!<int32>(ptr);
|
||||||
|
int32 row = GET!<int32>(ptr);
|
||||||
|
int32 btnState = GET!<int32>(ptr);
|
||||||
|
KeyFlags keyFlags = GET!<KeyFlags>(ptr);
|
||||||
|
mProvider.MouseMove(col, row, btnState, keyFlags);
|
||||||
|
case .MouseUp:
|
||||||
|
int32 col = GET!<int32>(ptr);
|
||||||
|
int32 row = GET!<int32>(ptr);
|
||||||
|
int32 btnState = GET!<int32>(ptr);
|
||||||
|
KeyFlags keyFlags = GET!<KeyFlags>(ptr);
|
||||||
|
mProvider.MouseUp(col, row, btnState, keyFlags);
|
||||||
|
case .MouseWheel:
|
||||||
|
int32 col = GET!<int32>(ptr);
|
||||||
|
int32 row = GET!<int32>(ptr);
|
||||||
|
int32 dy = GET!<int32>(ptr);
|
||||||
|
mProvider.MouseWheel(col, row, dy);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
case .Err(let err):
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
mPipe = new .();
|
||||||
|
mPipe.Listen(mPid, mConid);
|
||||||
|
|
||||||
|
mProvider = new .();
|
||||||
|
//mProvider.mHideNativeConsole = false;
|
||||||
|
mProvider.Attach();
|
||||||
|
|
||||||
|
ProcessStartInfo procInfo = scope ProcessStartInfo();
|
||||||
|
procInfo.UseShellExecute = false;
|
||||||
|
procInfo.SetFileName(mExecStr);
|
||||||
|
|
||||||
|
mSpawnedProcess = new SpawnedProcess();
|
||||||
|
if (mSpawnedProcess.Start(procInfo) case .Err)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
mProvider.Update();
|
||||||
|
|
||||||
|
var process = Platform.BfpProcess_GetById(null, mPid, null);
|
||||||
|
if (process == null)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Process closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Platform.BfpProcess_Release(process);
|
||||||
|
MessageLoop();
|
||||||
|
|
||||||
|
if (mPipe.mFailed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mPipe.mConnected)
|
||||||
|
Thread.Sleep(20);
|
||||||
|
|
||||||
|
if (mSpawnedProcess.WaitFor(0))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Main(String[] args)
|
||||||
|
{
|
||||||
|
if (args.Count < 2)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Usage: BeefCon <pid> <conid> <exe>");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Program pg = scope .();
|
||||||
|
pg.mPid = int32.Parse(args[0]);
|
||||||
|
pg.mConid = int32.Parse(args[1]);
|
||||||
|
pg.mExecStr.Set(args[2]);
|
||||||
|
pg.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,7 +54,8 @@ enum BfpResult
|
||||||
BfpResult_PartialData,
|
BfpResult_PartialData,
|
||||||
BfpResult_TempFileError,
|
BfpResult_TempFileError,
|
||||||
BfpResult_Timeout,
|
BfpResult_Timeout,
|
||||||
BfpResult_NotEmpty
|
BfpResult_NotEmpty,
|
||||||
|
BfpResult_PipeListening
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BfpSystemResult
|
enum BfpSystemResult
|
||||||
|
@ -77,7 +78,8 @@ enum BfpFileResult
|
||||||
BfpFileResult_PartialData = BfpResult_PartialData,
|
BfpFileResult_PartialData = BfpResult_PartialData,
|
||||||
BfpFileResult_InsufficientBuffer = BfpResult_InsufficientBuffer,
|
BfpFileResult_InsufficientBuffer = BfpResult_InsufficientBuffer,
|
||||||
BfpFileResult_Timeout = BfpResult_Timeout,
|
BfpFileResult_Timeout = BfpResult_Timeout,
|
||||||
BfpFileResult_NotEmpty = BfpResult_NotEmpty
|
BfpFileResult_NotEmpty = BfpResult_NotEmpty,
|
||||||
|
BfpFileResult_PipeListening = BfpResult_PipeListening
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void(*BfpCrashInfoFunc)();
|
typedef void(*BfpCrashInfoFunc)();
|
||||||
|
@ -197,6 +199,7 @@ enum BfpSpawnFlags
|
||||||
BfpSpawnFlag_ErrorDialog = 0x400,
|
BfpSpawnFlag_ErrorDialog = 0x400,
|
||||||
BfpSpawnFlag_Window_Hide = 0x800,
|
BfpSpawnFlag_Window_Hide = 0x800,
|
||||||
BfpSpawnFlag_Window_Maximized = 0x1000,
|
BfpSpawnFlag_Window_Maximized = 0x1000,
|
||||||
|
BfpSpawnFlag_NoActivateWindow = 0x2000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BfpSpawnResult
|
enum BfpSpawnResult
|
||||||
|
@ -420,7 +423,7 @@ enum BfpFileStdKind
|
||||||
|
|
||||||
BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* name, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttr, BfpFileResult* outResult);
|
BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* name, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttr, BfpFileResult* outResult);
|
||||||
BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult);
|
BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult);
|
||||||
BFP_EXPORT intptr BFP_CALLTYPE BfpFile_GetSystemHandle(BfpFile* file);
|
BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetFromHandle(intptr handle, BfpFileResult* outResult);
|
||||||
BFP_EXPORT void BFP_CALLTYPE BfpFile_Release(BfpFile* file);
|
BFP_EXPORT void BFP_CALLTYPE BfpFile_Release(BfpFile* file);
|
||||||
BFP_EXPORT void BFP_CALLTYPE BfpFile_Close(BfpFile* file, BfpFileResult* outResult);
|
BFP_EXPORT void BFP_CALLTYPE BfpFile_Close(BfpFile* file, BfpFileResult* outResult);
|
||||||
BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Write(BfpFile* file, const void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult);
|
BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Write(BfpFile* file, const void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult);
|
||||||
|
|
|
@ -1689,6 +1689,13 @@ public:
|
||||||
creationFlags |= CREATE_NO_WINDOW;
|
creationFlags |= CREATE_NO_WINDOW;
|
||||||
// set up the environment block parameter
|
// set up the environment block parameter
|
||||||
|
|
||||||
|
if ((flags & BfpSpawnFlag_NoActivateWindow) != 0)
|
||||||
|
{
|
||||||
|
startupInfo.dwFlags |= STARTF_USESHOWWINDOW;
|
||||||
|
startupInfo.wShowWindow = SW_SHOWNOACTIVATE;
|
||||||
|
}
|
||||||
|
// set up the environment block parameter
|
||||||
|
|
||||||
WCHAR* targetStrPtr = NULL;
|
WCHAR* targetStrPtr = NULL;
|
||||||
UTF16String targetStrW;
|
UTF16String targetStrW;
|
||||||
if ((flags & BfpSpawnFlag_ArgsIncludesTarget) != 0)
|
if ((flags & BfpSpawnFlag_ArgsIncludesTarget) != 0)
|
||||||
|
@ -1726,7 +1733,7 @@ public:
|
||||||
String str8(env, envSize);
|
String str8(env, envSize);
|
||||||
envW = UTF8Decode(str8);
|
envW = UTF8Decode(str8);
|
||||||
envVoidPtr = (void*)envW.c_str();
|
envVoidPtr = (void*)envW.c_str();
|
||||||
startupInfo.dwFlags |= CREATE_UNICODE_ENVIRONMENT;
|
creationFlags |= CREATE_UNICODE_ENVIRONMENT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2998,6 +3005,11 @@ BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* path, BfpFileCreateK
|
||||||
return bfpFile;
|
return bfpFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetFromHandle(intptr handle, BfpFileResult* outResult)
|
||||||
|
{
|
||||||
|
return new BfpFile((HANDLE)handle);
|
||||||
|
}
|
||||||
|
|
||||||
BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult)
|
BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult)
|
||||||
{
|
{
|
||||||
HANDLE h = INVALID_HANDLE_VALUE;
|
HANDLE h = INVALID_HANDLE_VALUE;
|
||||||
|
@ -3235,6 +3247,9 @@ BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr
|
||||||
int lastError = ::GetLastError();
|
int lastError = ::GetLastError();
|
||||||
switch (lastError)
|
switch (lastError)
|
||||||
{
|
{
|
||||||
|
case ERROR_PIPE_LISTENING:
|
||||||
|
OUTRESULT(BfpFileResult_PipeListening);
|
||||||
|
break;
|
||||||
case ERROR_BROKEN_PIPE: // Just an EOF
|
case ERROR_BROKEN_PIPE: // Just an EOF
|
||||||
OUTRESULT(BfpFileResult_Ok);
|
OUTRESULT(BfpFileResult_Ok);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -138,6 +138,14 @@ namespace IDE.Debugger
|
||||||
Allocations = 2
|
Allocations = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum OpenFileFlags
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RedirectStdInput = 1,
|
||||||
|
RedirectStdOutput = 2,
|
||||||
|
RedirectStdError = 4
|
||||||
|
}
|
||||||
|
|
||||||
public List<Breakpoint> mBreakpointList = new List<Breakpoint>();
|
public List<Breakpoint> mBreakpointList = new List<Breakpoint>();
|
||||||
public Dictionary<String, StepFilter> mStepFilterList = new Dictionary<String, StepFilter>();
|
public Dictionary<String, StepFilter> mStepFilterList = new Dictionary<String, StepFilter>();
|
||||||
|
|
||||||
|
@ -157,7 +165,7 @@ namespace IDE.Debugger
|
||||||
static extern bool Debugger_OpenMiniDump(char8* filename);
|
static extern bool Debugger_OpenMiniDump(char8* filename);
|
||||||
|
|
||||||
[CallingConvention(.Stdcall),CLink]
|
[CallingConvention(.Stdcall),CLink]
|
||||||
static extern bool Debugger_OpenFile(char8* launchPath, char8* targetPath, char8* args, char8* workingDir, void* envBlockPtr, int32 envBlockLen, bool hotSwapEnabled);
|
static extern bool Debugger_OpenFile(char8* launchPath, char8* targetPath, char8* args, char8* workingDir, void* envBlockPtr, int32 envBlockLen, bool hotSwapEnabled, OpenFileFlags openFileFlags);
|
||||||
|
|
||||||
[CallingConvention(.Stdcall),CLink]
|
[CallingConvention(.Stdcall),CLink]
|
||||||
static extern bool Debugger_ComptimeAttach(void* bfCompiler);
|
static extern bool Debugger_ComptimeAttach(void* bfCompiler);
|
||||||
|
@ -165,6 +173,9 @@ namespace IDE.Debugger
|
||||||
[CallingConvention(.Stdcall),CLink]
|
[CallingConvention(.Stdcall),CLink]
|
||||||
static extern bool Debugger_Attach(int32 processId, AttachFlags attachFlags);
|
static extern bool Debugger_Attach(int32 processId, AttachFlags attachFlags);
|
||||||
|
|
||||||
|
[CallingConvention(.Stdcall),CLink]
|
||||||
|
public static extern void Debugger_GetStdHandles(Platform.BfpFile** outStdIn, Platform.BfpFile** outStdOut, Platform.BfpFile** outStdErr);
|
||||||
|
|
||||||
[CallingConvention(.Stdcall),CLink]
|
[CallingConvention(.Stdcall),CLink]
|
||||||
static extern void Debugger_Run();
|
static extern void Debugger_Run();
|
||||||
|
|
||||||
|
@ -473,7 +484,7 @@ namespace IDE.Debugger
|
||||||
Debugger_FullReportMemory();
|
Debugger_FullReportMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OpenFile(String launchPath, String targetPath, String args, String workingDir, Span<char8> envBlock, bool isCompiled, bool hotSwapEnabled)
|
public bool OpenFile(String launchPath, String targetPath, String args, String workingDir, Span<char8> envBlock, bool isCompiled, bool hotSwapEnabled, OpenFileFlags openFileFlags)
|
||||||
{
|
{
|
||||||
DeleteAndNullify!(mRunningPath);
|
DeleteAndNullify!(mRunningPath);
|
||||||
mRunningPath = new String(launchPath);
|
mRunningPath = new String(launchPath);
|
||||||
|
@ -481,7 +492,7 @@ namespace IDE.Debugger
|
||||||
mIsComptimeDebug = false;
|
mIsComptimeDebug = false;
|
||||||
mIsRunningCompiled = isCompiled;
|
mIsRunningCompiled = isCompiled;
|
||||||
mIsRunningWithHotSwap = hotSwapEnabled;
|
mIsRunningWithHotSwap = hotSwapEnabled;
|
||||||
return Debugger_OpenFile(launchPath, targetPath, args, workingDir, envBlock.Ptr, (int32)envBlock.Length, hotSwapEnabled);
|
return Debugger_OpenFile(launchPath, targetPath, args, workingDir, envBlock.Ptr, (int32)envBlock.Length, hotSwapEnabled, openFileFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ComptimeAttach(BfCompiler compiler)
|
public bool ComptimeAttach(BfCompiler compiler)
|
||||||
|
@ -1175,6 +1186,11 @@ namespace IDE.Debugger
|
||||||
return Debugger_Attach(process.Id, attachFlags);
|
return Debugger_Attach(process.Id, attachFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void GetStdHandles(Platform.BfpFile** outStdIn, Platform.BfpFile** outStdOut, Platform.BfpFile** outStdErr)
|
||||||
|
{
|
||||||
|
Debugger_GetStdHandles(outStdIn, outStdOut, outStdErr);
|
||||||
|
}
|
||||||
|
|
||||||
public DbgProfiler StartProfiling(int threadId, String desc, int sampleRate)
|
public DbgProfiler StartProfiling(int threadId, String desc, int sampleRate)
|
||||||
{
|
{
|
||||||
DbgProfiler profiler = new DbgProfiler(Debugger_StartProfiling(threadId, desc, (.)sampleRate));
|
DbgProfiler profiler = new DbgProfiler(Debugger_StartProfiling(threadId, desc, (.)sampleRate));
|
||||||
|
|
|
@ -345,6 +345,9 @@ namespace IDE
|
||||||
bool mProfileCompile = false;
|
bool mProfileCompile = false;
|
||||||
ProfileInstance mProfileCompileProfileId;
|
ProfileInstance mProfileCompileProfileId;
|
||||||
|
|
||||||
|
Monitor mDebugOutputMonitor = new .() ~ delete _;
|
||||||
|
String mDebugOutput = new .() ~ delete _;
|
||||||
|
|
||||||
#if !CLI
|
#if !CLI
|
||||||
public IPCHelper mIPCHelper ~ delete _;
|
public IPCHelper mIPCHelper ~ delete _;
|
||||||
public bool mIPCHadFocus;
|
public bool mIPCHadFocus;
|
||||||
|
@ -3779,7 +3782,7 @@ namespace IDE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always write to STDOUT even if we're running as a GUI, allowing cases like RunAndWait to pass us a stdout handle
|
// Always write to STDOUT even if we're running as a GUI, allowing cases like RunAndWait to pass us a stdout handle
|
||||||
Console.Error.WriteLine("ERROR: {0}", text);
|
Console.Error.WriteLine("ERROR: {0}", text).IgnoreError();
|
||||||
|
|
||||||
#if CLI
|
#if CLI
|
||||||
mFailed = true;
|
mFailed = true;
|
||||||
|
@ -3806,7 +3809,7 @@ namespace IDE
|
||||||
|
|
||||||
mFailed = true;
|
mFailed = true;
|
||||||
OutputLineSmart("ERROR: {0}", text);
|
OutputLineSmart("ERROR: {0}", text);
|
||||||
Console.Error.WriteLine("ERROR: {0}", text);
|
Console.Error.WriteLine("ERROR: {0}", text).IgnoreError();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -8250,8 +8253,11 @@ namespace IDE
|
||||||
NOP!();
|
NOP!();
|
||||||
}
|
}
|
||||||
|
|
||||||
mConsolePanel.SysKeyDown(evt);
|
if (!evt.mKeyFlags.HeldKeys.HasFlag(.Alt))
|
||||||
//mTerminalPanel.SysKeyDown(evt);
|
{
|
||||||
|
mConsolePanel.SysKeyDown(evt);
|
||||||
|
mTerminalPanel.SysKeyDown(evt);
|
||||||
|
}
|
||||||
|
|
||||||
if (evt.mHandled)
|
if (evt.mHandled)
|
||||||
return;
|
return;
|
||||||
|
@ -8426,8 +8432,8 @@ namespace IDE
|
||||||
|
|
||||||
void SysKeyUp(KeyCode keyCode)
|
void SysKeyUp(KeyCode keyCode)
|
||||||
{
|
{
|
||||||
//mTerminalPanel.SysKeyUp(keyCode);
|
|
||||||
mConsolePanel.SysKeyUp(keyCode);
|
mConsolePanel.SysKeyUp(keyCode);
|
||||||
|
mTerminalPanel.SysKeyUp(keyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowOpenFileInSolutionDialog()
|
void ShowOpenFileInSolutionDialog()
|
||||||
|
@ -8786,8 +8792,10 @@ namespace IDE
|
||||||
return;
|
return;
|
||||||
StreamReader streamReader = scope StreamReader(fileStream, null, false, 4096);
|
StreamReader streamReader = scope StreamReader(fileStream, null, false, 4096);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
var buffer = scope String();
|
var buffer = scope String();
|
||||||
if (streamReader.ReadLine(buffer) case .Err)
|
if (streamReader.ReadLine(buffer) case .Err)
|
||||||
break;
|
break;
|
||||||
|
@ -8816,6 +8824,60 @@ namespace IDE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReadDebugOutputThread(Object obj)
|
||||||
|
{
|
||||||
|
FileStream fileStream = (.)obj;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
Loop: while (true)
|
||||||
|
{
|
||||||
|
uint8[4096] data = ?;
|
||||||
|
switch (fileStream.TryRead(data, -1))
|
||||||
|
{
|
||||||
|
case .Ok(let len):
|
||||||
|
if (len == 0)
|
||||||
|
break Loop;
|
||||||
|
using (mDebugOutputMonitor.Enter())
|
||||||
|
{
|
||||||
|
for (int i < len)
|
||||||
|
mDebugOutput.Append((char8)data[i]);
|
||||||
|
}
|
||||||
|
case .Err:
|
||||||
|
break Loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*var buffer = scope String();
|
||||||
|
if (streamReader.Read(buffer) case .Err)
|
||||||
|
break;
|
||||||
|
using (mDebugOutputMonitor.Enter())
|
||||||
|
mDebugOutput.Add(new String(buffer));*/
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete fileStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static void ReadDebugErrorThread(Object obj)
|
||||||
|
{
|
||||||
|
ExecutionInstance executionInstance = (ExecutionInstance)obj;
|
||||||
|
|
||||||
|
FileStream fileStream = scope FileStream();
|
||||||
|
if (executionInstance.mProcess.AttachStandardError(fileStream) case .Err)
|
||||||
|
return;
|
||||||
|
StreamReader streamReader = scope StreamReader(fileStream, null, false, 4096);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var buffer = scope String();
|
||||||
|
if (streamReader.ReadLine(buffer) case .Err)
|
||||||
|
break;
|
||||||
|
|
||||||
|
using (IDEApp.sApp.mMonitor.Enter())
|
||||||
|
executionInstance.mDeferredOutput.Add(new String(buffer));
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
public enum RunFlags
|
public enum RunFlags
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
@ -11943,8 +12005,26 @@ namespace IDE
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mDebugger.OpenFile(launchPath, targetPath, arguments, workingDir, envBlock, wasCompiled, workspaceOptions.mAllowHotSwapping))
|
if (mSettings.mDebugConsoleKind == .Embedded)
|
||||||
|
{
|
||||||
|
ShowConsole();
|
||||||
|
mConsolePanel.Attach();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSettings.mDebugConsoleKind == .RedirectToImmediate)
|
||||||
|
{
|
||||||
|
ShowImmediatePanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugManager.OpenFileFlags openFileFlags = .None;
|
||||||
|
|
||||||
|
if ((mSettings.mDebugConsoleKind == .RedirectToImmediate) || (mSettings.mDebugConsoleKind == .RedirectToOutput))
|
||||||
|
openFileFlags |= .RedirectStdOutput | .RedirectStdError;
|
||||||
|
|
||||||
|
if (!mDebugger.OpenFile(launchPath, targetPath, arguments, workingDir, envBlock, wasCompiled, workspaceOptions.mAllowHotSwapping, openFileFlags))
|
||||||
{
|
{
|
||||||
|
if (!mSettings.mAlwaysEnableConsole)
|
||||||
|
mConsolePanel.Detach();
|
||||||
DeleteAndNullify!(mCompileAndRunStopwatch);
|
DeleteAndNullify!(mCompileAndRunStopwatch);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -12301,8 +12381,10 @@ namespace IDE
|
||||||
mOutputPanel = new OutputPanel(true);
|
mOutputPanel = new OutputPanel(true);
|
||||||
mOutputPanel.mAutoDelete = false;
|
mOutputPanel.mAutoDelete = false;
|
||||||
mTerminalPanel = new TerminalPanel();
|
mTerminalPanel = new TerminalPanel();
|
||||||
|
mTerminalPanel .Init();
|
||||||
mTerminalPanel.mAutoDelete = false;
|
mTerminalPanel.mAutoDelete = false;
|
||||||
mConsolePanel = new ConsolePanel();
|
mConsolePanel = new ConsolePanel();
|
||||||
|
mConsolePanel.Init();
|
||||||
mConsolePanel.mAutoDelete = false;
|
mConsolePanel.mAutoDelete = false;
|
||||||
mImmediatePanel = new ImmediatePanel();
|
mImmediatePanel = new ImmediatePanel();
|
||||||
mImmediatePanel.mAutoDelete = false;
|
mImmediatePanel.mAutoDelete = false;
|
||||||
|
@ -12963,6 +13045,37 @@ namespace IDE
|
||||||
{
|
{
|
||||||
mDebugger.Update();
|
mDebugger.Update();
|
||||||
|
|
||||||
|
Platform.BfpFile* stdOut = null;
|
||||||
|
Platform.BfpFile* stdError = null;
|
||||||
|
mDebugger.GetStdHandles(null, &stdOut, &stdError);
|
||||||
|
if (stdOut != null)
|
||||||
|
{
|
||||||
|
FileStream fileStream = new FileStream();
|
||||||
|
fileStream.Attach(stdOut);
|
||||||
|
Thread thread = new Thread(new => ReadDebugOutputThread);
|
||||||
|
thread.Start(fileStream, true);
|
||||||
|
}
|
||||||
|
if (stdError != null)
|
||||||
|
{
|
||||||
|
FileStream fileStream = new FileStream();
|
||||||
|
fileStream.Attach(stdError);
|
||||||
|
Thread thread = new Thread(new => ReadDebugOutputThread);
|
||||||
|
thread.Start(fileStream, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (mDebugOutputMonitor.Enter())
|
||||||
|
{
|
||||||
|
if (!mDebugOutput.IsEmpty)
|
||||||
|
{
|
||||||
|
mDebugOutput.Replace("\r", "");
|
||||||
|
if (mSettings.mDebugConsoleKind == .RedirectToOutput)
|
||||||
|
mOutputPanel.Write(mDebugOutput);
|
||||||
|
if (mSettings.mDebugConsoleKind == .RedirectToImmediate)
|
||||||
|
mImmediatePanel.Write(mDebugOutput);
|
||||||
|
mDebugOutput.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
runState = mDebugger.GetRunState();
|
runState = mDebugger.GetRunState();
|
||||||
mDebuggerPerformingTask = (runState == .DebugEval) || (runState == .DebugEval_Done) || (runState == .SearchingSymSrv);
|
mDebuggerPerformingTask = (runState == .DebugEval) || (runState == .DebugEval_Done) || (runState == .SearchingSymSrv);
|
||||||
|
|
||||||
|
@ -13514,6 +13627,8 @@ namespace IDE
|
||||||
var disassemblyPanel = TryGetDisassemblyPanel(false);
|
var disassemblyPanel = TryGetDisassemblyPanel(false);
|
||||||
if (disassemblyPanel != null)
|
if (disassemblyPanel != null)
|
||||||
disassemblyPanel.Disable();
|
disassemblyPanel.Disable();
|
||||||
|
if (!mSettings.mAlwaysEnableConsole)
|
||||||
|
mConsolePanel.Detach();
|
||||||
mDebugger.DisposeNativeBreakpoints();
|
mDebugger.DisposeNativeBreakpoints();
|
||||||
mDebugger.Detach();
|
mDebugger.Detach();
|
||||||
mDebugger.mIsRunning = false;
|
mDebugger.mIsRunning = false;
|
||||||
|
@ -14539,6 +14654,16 @@ namespace IDE
|
||||||
RefreshRate = 60;
|
RefreshRate = 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mTerminalPanel != null)
|
||||||
|
{
|
||||||
|
// Detach terminal if the panel is closed
|
||||||
|
var terminalTabButton = GetTab(mTerminalPanel);
|
||||||
|
if (terminalTabButton == null)
|
||||||
|
{
|
||||||
|
mTerminalPanel.Detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool hasFocus = false;
|
bool hasFocus = false;
|
||||||
for (let window in mWindows)
|
for (let window in mWindows)
|
||||||
{
|
{
|
||||||
|
@ -14622,6 +14747,15 @@ namespace IDE
|
||||||
if (mScriptManager != null)
|
if (mScriptManager != null)
|
||||||
mScriptManager.Update();
|
mScriptManager.Update();
|
||||||
|
|
||||||
|
if (mConsolePanel != null)
|
||||||
|
{
|
||||||
|
if ((mSettings.mAlwaysEnableConsole) ||
|
||||||
|
((mSettings.mDebugConsoleKind == .Embedded) && (mDebugger.mIsRunning)))
|
||||||
|
mConsolePanel.Attach();
|
||||||
|
else
|
||||||
|
mConsolePanel.Detach();
|
||||||
|
}
|
||||||
|
|
||||||
if (mTestManager != null)
|
if (mTestManager != null)
|
||||||
{
|
{
|
||||||
mTestManager.Update();
|
mTestManager.Update();
|
||||||
|
|
|
@ -898,8 +898,10 @@ namespace IDE
|
||||||
Add("Show Output", "Ctrl+Alt+O");
|
Add("Show Output", "Ctrl+Alt+O");
|
||||||
Add("Show Profiler", "Ctrl+Alt+P");
|
Add("Show Profiler", "Ctrl+Alt+P");
|
||||||
Add("Show QuickWatch", "Shift+Alt+W");
|
Add("Show QuickWatch", "Shift+Alt+W");
|
||||||
Add("Show Threads", "Ctrl+Alt+T");
|
Add("Show Threads", "Ctrl+Alt+H");
|
||||||
Add("Show Watches", "Ctrl+Alt+W");
|
Add("Show Watches", "Ctrl+Alt+W");
|
||||||
|
Add("Show Console", "Ctrl+Alt+N");
|
||||||
|
Add("Show Terminal", "Ctrl+Alt+T");
|
||||||
Add("Show Workspace Explorer", "Ctrl+Alt+S");
|
Add("Show Workspace Explorer", "Ctrl+Alt+S");
|
||||||
Add("Start Debugging", "F5");
|
Add("Start Debugging", "F5");
|
||||||
Add("Start Without Debugging", "Ctrl+F5");
|
Add("Start Without Debugging", "Ctrl+F5");
|
||||||
|
@ -1097,6 +1099,14 @@ namespace IDE
|
||||||
public bool mDependencies;
|
public bool mDependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ConsoleKind
|
||||||
|
{
|
||||||
|
Native,
|
||||||
|
Embedded,
|
||||||
|
RedirectToOutput,
|
||||||
|
RedirectToImmediate,
|
||||||
|
}
|
||||||
|
|
||||||
public bool mLoadedSettings;
|
public bool mLoadedSettings;
|
||||||
public String mSettingFileText ~ delete _;
|
public String mSettingFileText ~ delete _;
|
||||||
public DateTime mSettingFileDateTime;
|
public DateTime mSettingFileDateTime;
|
||||||
|
@ -1110,6 +1120,8 @@ namespace IDE
|
||||||
public RecentFiles mRecentFiles = new RecentFiles() ~ delete _;
|
public RecentFiles mRecentFiles = new RecentFiles() ~ delete _;
|
||||||
public String mWakaTimeKey = new .() ~ delete _;
|
public String mWakaTimeKey = new .() ~ delete _;
|
||||||
public String mWindowsTerminal = new .("Powershell") ~ delete _;
|
public String mWindowsTerminal = new .("Powershell") ~ delete _;
|
||||||
|
public ConsoleKind mDebugConsoleKind;
|
||||||
|
public bool mAlwaysEnableConsole;
|
||||||
public String mEmscriptenPath = new .() ~ delete _;
|
public String mEmscriptenPath = new .() ~ delete _;
|
||||||
public bool mEnableDevMode;
|
public bool mEnableDevMode;
|
||||||
public TutorialsFinished mTutorialsFinished = .();
|
public TutorialsFinished mTutorialsFinished = .();
|
||||||
|
@ -1167,8 +1179,12 @@ namespace IDE
|
||||||
mDebuggerSettings.Serialize(sd);
|
mDebuggerSettings.Serialize(sd);
|
||||||
using (sd.CreateObject("VisualStudio"))
|
using (sd.CreateObject("VisualStudio"))
|
||||||
mVSSettings.Serialize(sd);
|
mVSSettings.Serialize(sd);
|
||||||
using (sd.CreateObject("Terminal"))
|
using (sd.CreateObject("Console"))
|
||||||
|
{
|
||||||
sd.Add("WindowsTerminal", mWindowsTerminal);
|
sd.Add("WindowsTerminal", mWindowsTerminal);
|
||||||
|
sd.Add("DebugConsole", mDebugConsoleKind);
|
||||||
|
sd.Add("AlwaysEnableConsole", mAlwaysEnableConsole);
|
||||||
|
}
|
||||||
using (sd.CreateObject("Wasm"))
|
using (sd.CreateObject("Wasm"))
|
||||||
sd.Add("EmscriptenPath", mEmscriptenPath);
|
sd.Add("EmscriptenPath", mEmscriptenPath);
|
||||||
|
|
||||||
|
@ -1258,8 +1274,12 @@ namespace IDE
|
||||||
mDebuggerSettings.Deserialize(sd);
|
mDebuggerSettings.Deserialize(sd);
|
||||||
using (sd.Open("VisualStudio"))
|
using (sd.Open("VisualStudio"))
|
||||||
mVSSettings.Deserialize(sd);
|
mVSSettings.Deserialize(sd);
|
||||||
using (sd.Open("Terminal"))
|
using (sd.Open("Console"))
|
||||||
|
{
|
||||||
sd.Get("WindowsTerminal", mWindowsTerminal);
|
sd.Get("WindowsTerminal", mWindowsTerminal);
|
||||||
|
mDebugConsoleKind = sd.GetEnum<ConsoleKind>("DebugConsole", .Native);
|
||||||
|
mAlwaysEnableConsole = sd.GetBool("AlwaysEnableConsole");
|
||||||
|
}
|
||||||
using (sd.Open("Wasm"))
|
using (sd.Open("Wasm"))
|
||||||
sd.Get("EmscriptenPath", mEmscriptenPath);
|
sd.Get("EmscriptenPath", mEmscriptenPath);
|
||||||
|
|
||||||
|
|
|
@ -614,7 +614,7 @@ namespace IDE
|
||||||
|
|
||||||
var envBlock = scope List<char8>();
|
var envBlock = scope List<char8>();
|
||||||
Environment.EncodeEnvironmentVariables(envVars, envBlock);
|
Environment.EncodeEnvironmentVariables(envVars, envBlock);
|
||||||
if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true, false))
|
if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true, false, .None))
|
||||||
{
|
{
|
||||||
QueueOutputLine("ERROR: Failed debug '{0}'", curProjectInfo.mTestExePath);
|
QueueOutputLine("ERROR: Failed debug '{0}'", curProjectInfo.mTestExePath);
|
||||||
TestFailed();
|
TestFailed();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -332,7 +332,7 @@ namespace IDE.ui
|
||||||
var envBlock = scope List<char8>();
|
var envBlock = scope List<char8>();
|
||||||
Environment.EncodeEnvironmentVariables(envVars, envBlock);
|
Environment.EncodeEnvironmentVariables(envVars, envBlock);
|
||||||
|
|
||||||
if (!gApp.mDebugger.OpenFile(targetPath, targetPath, arguments, workingDir, envBlock, false, false))
|
if (!gApp.mDebugger.OpenFile(targetPath, targetPath, arguments, workingDir, envBlock, false, false, .None))
|
||||||
{
|
{
|
||||||
gApp.Fail(scope String()..AppendF("Unable to open executable for debugging: {0}", targetPath));
|
gApp.Fail(scope String()..AppendF("Unable to open executable for debugging: {0}", targetPath));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2991,7 +2991,7 @@ namespace IDE.ui
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
item = folderItem.AddItem("Terminal");
|
item = folderItem.AddItem("External Terminal");
|
||||||
item.mOnMenuItemSelected.Add(new (menu) =>
|
item.mOnMenuItemSelected.Add(new (menu) =>
|
||||||
{
|
{
|
||||||
let projectItem = GetSelectedProjectItem();
|
let projectItem = GetSelectedProjectItem();
|
||||||
|
@ -3023,6 +3023,34 @@ namespace IDE.ui
|
||||||
process.Start(psi).IgnoreError();
|
process.Start(psi).IgnoreError();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
item = folderItem.AddItem("Embedded Terminal");
|
||||||
|
item.mOnMenuItemSelected.Add(new (menu) =>
|
||||||
|
{
|
||||||
|
let projectItem = GetSelectedProjectItem();
|
||||||
|
String path = scope String();
|
||||||
|
if (projectItem == null)
|
||||||
|
{
|
||||||
|
path.Set(gApp.mWorkspace.mDir);
|
||||||
|
}
|
||||||
|
else if (let projectFolder = projectItem as ProjectFolder)
|
||||||
|
{
|
||||||
|
if (projectFolder.mParentFolder == null)
|
||||||
|
{
|
||||||
|
path.Set(projectFolder.mProject.mProjectDir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
projectFolder.GetFullImportPath(path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
projectItem.mParentFolder.GetFullImportPath(path);
|
||||||
|
|
||||||
|
if (!path.IsWhiteSpace)
|
||||||
|
{
|
||||||
|
gApp.ShowTerminal();
|
||||||
|
gApp.mTerminalPanel.OpenDirectory(path);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectItem == null)
|
if (projectItem == null)
|
||||||
|
|
|
@ -62,7 +62,7 @@ namespace IDE.ui
|
||||||
AddCategoryItem(root, "Compiler");
|
AddCategoryItem(root, "Compiler");
|
||||||
AddCategoryItem(root, "Debugger");
|
AddCategoryItem(root, "Debugger");
|
||||||
AddCategoryItem(root, "Visual Studio");
|
AddCategoryItem(root, "Visual Studio");
|
||||||
AddCategoryItem(root, "Terminal");
|
AddCategoryItem(root, "Console");
|
||||||
AddCategoryItem(root, "Wasm");
|
AddCategoryItem(root, "Wasm");
|
||||||
|
|
||||||
if (!gApp.mSettings.mVSSettings.IsConfigured())
|
if (!gApp.mSettings.mVSSettings.IsConfigured())
|
||||||
|
@ -170,7 +170,7 @@ namespace IDE.ui
|
||||||
category.Open(true, true);
|
category.Open(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PopulateTerminalOptions()
|
void PopulateConsoleOptions()
|
||||||
{
|
{
|
||||||
mCurPropertiesTarget = gApp.mSettings;
|
mCurPropertiesTarget = gApp.mSettings;
|
||||||
|
|
||||||
|
@ -179,6 +179,8 @@ namespace IDE.ui
|
||||||
category.mIsBold = true;
|
category.mIsBold = true;
|
||||||
category.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, cHeaderColor);
|
category.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, cHeaderColor);
|
||||||
AddPropertiesItem(category, "Windows Terminal", "mWindowsTerminal");
|
AddPropertiesItem(category, "Windows Terminal", "mWindowsTerminal");
|
||||||
|
AddPropertiesItem(category, "Debug Console", "mDebugConsoleKind");
|
||||||
|
AddPropertiesItem(category, "Always Enable Console", "mAlwaysEnableConsole");
|
||||||
category.Open(true, true);
|
category.Open(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,7 +440,7 @@ namespace IDE.ui
|
||||||
case .VisualStudio:
|
case .VisualStudio:
|
||||||
PopulateVSOptions();
|
PopulateVSOptions();
|
||||||
case .Terminal:
|
case .Terminal:
|
||||||
PopulateTerminalOptions();
|
PopulateConsoleOptions();
|
||||||
case .Wasm:
|
case .Wasm:
|
||||||
PopulateWasmOptions();
|
PopulateWasmOptions();
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -10,15 +10,51 @@ using Beefy.widgets;
|
||||||
using Beefy.events;
|
using Beefy.events;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Beefy.utils;
|
using Beefy.utils;
|
||||||
|
using IDE.util;
|
||||||
|
|
||||||
namespace IDE.ui;
|
namespace IDE.ui;
|
||||||
|
|
||||||
class TerminalPanel : Panel
|
class TerminalPanel : ConsolePanel
|
||||||
{
|
{
|
||||||
public override void Serialize(StructuredData data)
|
public override void Serialize(StructuredData data)
|
||||||
{
|
{
|
||||||
base.Serialize(data);
|
|
||||||
|
|
||||||
data.Add("Type", "TerminalPanel");
|
data.Add("Type", "TerminalPanel");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
var consoleProvider = new BeefConConsoleProvider();
|
||||||
|
consoleProvider.mBeefConExePath = new $"{gApp.mInstallDir}/BeefCon.exe";
|
||||||
|
consoleProvider.mTerminalExe = new .(gApp.mSettings.mWindowsTerminal);
|
||||||
|
|
||||||
|
mConsoleProvider = consoleProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddedToParent()
|
||||||
|
{
|
||||||
|
var consoleProvider = (BeefConConsoleProvider)mConsoleProvider;
|
||||||
|
consoleProvider.mTerminalExe.Set(gApp.mSettings.mWindowsTerminal);
|
||||||
|
consoleProvider.mWorkingDir.Set(gApp.mWorkspace.mDir);
|
||||||
|
mConsoleProvider.Attach();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemovedFromParent(Widget previousParent, WidgetWindow window)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenDirectory(StringView path)
|
||||||
|
{
|
||||||
|
var consoleProvider = (BeefConConsoleProvider)mConsoleProvider;
|
||||||
|
consoleProvider.mWorkingDir.Set(path);
|
||||||
|
consoleProvider.Detach();
|
||||||
|
consoleProvider.Attach();
|
||||||
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -328,7 +328,7 @@ bool CeDebugger::CanOpen(const StringImpl& fileName, DebuggerResult* outResult)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CeDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled)
|
void CeDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,6 +337,10 @@ bool CeDebugger::Attach(int processId, BfDbgAttachFlags attachFlags)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CeDebugger::GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void CeDebugger::Run()
|
void CeDebugger::Run()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,8 +314,9 @@ public:
|
||||||
virtual void OutputRawMessage(const StringImpl& msg) override;
|
virtual void OutputRawMessage(const StringImpl& msg) override;
|
||||||
virtual int GetAddrSize() override;
|
virtual int GetAddrSize() override;
|
||||||
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) override;
|
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) override;
|
||||||
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled) override;
|
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags) override;
|
||||||
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) override;
|
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) override;
|
||||||
|
virtual void GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) override;
|
||||||
virtual void Run() override;
|
virtual void Run() override;
|
||||||
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;
|
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;
|
||||||
virtual void InitiateHotResolve(DbgHotResolveFlags flags) override;
|
virtual void InitiateHotResolve(DbgHotResolveFlags flags) override;
|
||||||
|
|
|
@ -754,7 +754,7 @@ BF_EXPORT int BF_CALLTYPE Debugger_GetAddrSize()
|
||||||
return gDebugger->GetAddrSize();
|
return gDebugger->GetAddrSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char* targetPath, const char* args, const char* workingDir, void* envBlockPtr, int envBlockSize, bool hotSwapEnabled)
|
BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char* targetPath, const char* args, const char* workingDir, void* envBlockPtr, int envBlockSize, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags)
|
||||||
{
|
{
|
||||||
BF_ASSERT(gDebugger == NULL);
|
BF_ASSERT(gDebugger == NULL);
|
||||||
|
|
||||||
|
@ -784,7 +784,7 @@ BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char*
|
||||||
envBlock.Insert(0, (uint8*)envBlockPtr, envBlockSize);
|
envBlock.Insert(0, (uint8*)envBlockPtr, envBlockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
gDebugger->OpenFile(launchPath, targetPath, args, workingDir, envBlock, hotSwapEnabled);
|
gDebugger->OpenFile(launchPath, targetPath, args, workingDir, envBlock, hotSwapEnabled, openFileFlags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,6 +911,12 @@ BF_EXPORT bool BF_CALLTYPE Debugger_Attach(int processId, BfDbgAttachFlags attac
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BF_EXPORT void Debugger_GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr)
|
||||||
|
{
|
||||||
|
if (gDebugger != NULL)
|
||||||
|
gDebugger->GetStdHandles(outStdIn, outStdOut, outStdErr);
|
||||||
|
}
|
||||||
|
|
||||||
BF_EXPORT void BF_CALLTYPE Debugger_Run()
|
BF_EXPORT void BF_CALLTYPE Debugger_Run()
|
||||||
{
|
{
|
||||||
gDebugger->Run();
|
gDebugger->Run();
|
||||||
|
|
|
@ -200,6 +200,14 @@ enum DbgMemoryFlags : uint8
|
||||||
DbgMemoryFlags_Execute = 4
|
DbgMemoryFlags_Execute = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum DbgOpenFileFlags : uint8
|
||||||
|
{
|
||||||
|
DbgOpenFileFlag_None = 0,
|
||||||
|
DbgOpenFileFlag_RedirectStdInput = 1,
|
||||||
|
DbgOpenFileFlag_RedirectStdOutput = 2,
|
||||||
|
DbgOpenFileFlag_RedirectStdError = 4
|
||||||
|
};
|
||||||
|
|
||||||
class DbgModuleMemoryCache
|
class DbgModuleMemoryCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -266,8 +274,9 @@ public:
|
||||||
virtual void OutputRawMessage(const StringImpl& msg) = 0;
|
virtual void OutputRawMessage(const StringImpl& msg) = 0;
|
||||||
virtual int GetAddrSize() = 0;
|
virtual int GetAddrSize() = 0;
|
||||||
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) = 0;
|
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) = 0;
|
||||||
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled) = 0;
|
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags) = 0;
|
||||||
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) = 0;
|
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) = 0;
|
||||||
|
virtual void GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) = 0;
|
||||||
virtual void Run() = 0;
|
virtual void Run() = 0;
|
||||||
virtual bool HasLoadedTargetBinary() { return true; }
|
virtual bool HasLoadedTargetBinary() { return true; }
|
||||||
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) = 0;
|
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) = 0;
|
||||||
|
|
|
@ -79,6 +79,11 @@ static void FilterThreadName(String& name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsHandleValid(HANDLE handle)
|
||||||
|
{
|
||||||
|
return (handle != NULL) && (handle != INVALID_HANDLE_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
WdBreakpointCondition::~WdBreakpointCondition()
|
WdBreakpointCondition::~WdBreakpointCondition()
|
||||||
|
@ -508,6 +513,9 @@ WinDebugger::WinDebugger(DebugManager* debugManager) : mDbgSymSrv(this)
|
||||||
mOrigStepType = StepType_None;
|
mOrigStepType = StepType_None;
|
||||||
mLastValidStepIntoPC = 0;
|
mLastValidStepIntoPC = 0;
|
||||||
mActiveSymSrvRequest = NULL;
|
mActiveSymSrvRequest = NULL;
|
||||||
|
mStdInputPipe = INVALID_HANDLE_VALUE;
|
||||||
|
mStdOutputPipe = INVALID_HANDLE_VALUE;
|
||||||
|
mStdErrorPipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
mStoredReturnValueAddr = 0;
|
mStoredReturnValueAddr = 0;
|
||||||
#ifdef BF_DBG_32
|
#ifdef BF_DBG_32
|
||||||
|
@ -528,6 +536,8 @@ WinDebugger::WinDebugger(DebugManager* debugManager) : mDbgSymSrv(this)
|
||||||
mDbgProcessId = 0;
|
mDbgProcessId = 0;
|
||||||
mDbgHeapData = NULL;
|
mDbgHeapData = NULL;
|
||||||
mIsPartialCallStack = true;
|
mIsPartialCallStack = true;
|
||||||
|
mHotSwapEnabled = false;
|
||||||
|
mOpenFileFlags = DbgOpenFileFlag_None;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
|
@ -919,7 +929,7 @@ void WinDebugger::DebugThreadProc()
|
||||||
|
|
||||||
if (!IsMiniDumpDebugger())
|
if (!IsMiniDumpDebugger())
|
||||||
{
|
{
|
||||||
if (!DoOpenFile(mLaunchPath, mArgs, mWorkingDir, mEnvBlock))
|
if (!DoOpenFile(mLaunchPath, mArgs, mWorkingDir, mEnvBlock, mOpenFileFlags))
|
||||||
{
|
{
|
||||||
if (mDbgProcessId != 0)
|
if (mDbgProcessId != 0)
|
||||||
OutputRawMessage("error Unable to attach to process");
|
OutputRawMessage("error Unable to attach to process");
|
||||||
|
@ -1005,7 +1015,7 @@ bool WinDebugger::CanOpen(const StringImpl& fileName, DebuggerResult* outResult)
|
||||||
return canRead;
|
return canRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled)
|
void WinDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags)
|
||||||
{
|
{
|
||||||
BF_ASSERT(!mIsRunning);
|
BF_ASSERT(!mIsRunning);
|
||||||
mLaunchPath = launchPath;
|
mLaunchPath = launchPath;
|
||||||
|
@ -1014,6 +1024,7 @@ void WinDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targe
|
||||||
mWorkingDir = workingDir;
|
mWorkingDir = workingDir;
|
||||||
mEnvBlock = envBlock;
|
mEnvBlock = envBlock;
|
||||||
mHotSwapEnabled = hotSwapEnabled;
|
mHotSwapEnabled = hotSwapEnabled;
|
||||||
|
mOpenFileFlags = openFileFlags;
|
||||||
mDebugTarget = new DebugTarget(this);
|
mDebugTarget = new DebugTarget(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1059,6 +1070,29 @@ bool WinDebugger::Attach(int processId, BfDbgAttachFlags attachFlags)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WinDebugger::GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr)
|
||||||
|
{
|
||||||
|
AutoCrit autoCrit(mDebugManager->mCritSect);
|
||||||
|
|
||||||
|
if ((outStdIn != NULL) && (IsHandleValid(mStdInputPipe)))
|
||||||
|
{
|
||||||
|
*outStdIn = BfpFile_GetFromHandle((intptr)mStdInputPipe, NULL);
|
||||||
|
mStdInputPipe = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((outStdOut != NULL) && (IsHandleValid(mStdOutputPipe)))
|
||||||
|
{
|
||||||
|
*outStdOut = BfpFile_GetFromHandle((intptr)mStdOutputPipe, NULL);
|
||||||
|
mStdOutputPipe = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((outStdErr != NULL) && (IsHandleValid(mStdErrorPipe)))
|
||||||
|
{
|
||||||
|
*outStdErr = BfpFile_GetFromHandle((intptr)mStdErrorPipe, NULL);
|
||||||
|
mStdErrorPipe = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WinDebugger::Run()
|
void WinDebugger::Run()
|
||||||
{
|
{
|
||||||
mIsRunning = true;
|
mIsRunning = true;
|
||||||
|
@ -1262,7 +1296,50 @@ String WinDebugger::GetDbgAllocInfo()
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock)
|
static bool CreatePipeWithSecurityAttributes(HANDLE& hReadPipe, HANDLE& hWritePipe, SECURITY_ATTRIBUTES* lpPipeAttributes, int32 nSize)
|
||||||
|
{
|
||||||
|
hReadPipe = 0;
|
||||||
|
hWritePipe = 0;
|
||||||
|
bool ret = ::CreatePipe(&hReadPipe, &hWritePipe, lpPipeAttributes, nSize);
|
||||||
|
if (!ret || (hReadPipe == INVALID_HANDLE_VALUE) || (hWritePipe == INVALID_HANDLE_VALUE))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CreatePipe(HANDLE& parentHandle, HANDLE& childHandle, bool parentInputs)
|
||||||
|
{
|
||||||
|
SECURITY_ATTRIBUTES securityAttributesParent = { 0 };
|
||||||
|
securityAttributesParent.bInheritHandle = 1;
|
||||||
|
|
||||||
|
HANDLE hTmp = INVALID_HANDLE_VALUE;
|
||||||
|
if (parentInputs)
|
||||||
|
CreatePipeWithSecurityAttributes(childHandle, hTmp, &securityAttributesParent, 0);
|
||||||
|
else
|
||||||
|
CreatePipeWithSecurityAttributes(hTmp, childHandle, &securityAttributesParent, 0);
|
||||||
|
|
||||||
|
HANDLE dupHandle = 0;
|
||||||
|
|
||||||
|
// Duplicate the parent handle to be non-inheritable so that the child process
|
||||||
|
// doesn't have access. This is done for correctness sake, exact reason is unclear.
|
||||||
|
// One potential theory is that child process can do something brain dead like
|
||||||
|
// closing the parent end of the pipe and there by getting into a blocking situation
|
||||||
|
// as parent will not be draining the pipe at the other end anymore.
|
||||||
|
if (!::DuplicateHandle(GetCurrentProcess(), hTmp,
|
||||||
|
GetCurrentProcess(), &dupHandle,
|
||||||
|
0, false, DUPLICATE_SAME_ACCESS))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentHandle = dupHandle;
|
||||||
|
|
||||||
|
if (hTmp != INVALID_HANDLE_VALUE)
|
||||||
|
::CloseHandle(hTmp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, DbgOpenFileFlags openFileFlags)
|
||||||
{
|
{
|
||||||
BP_ZONE("WinDebugger::DoOpenFile");
|
BP_ZONE("WinDebugger::DoOpenFile");
|
||||||
|
|
||||||
|
@ -1274,6 +1351,33 @@ bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args,
|
||||||
si.cb = sizeof(si);
|
si.cb = sizeof(si);
|
||||||
ZeroMemory(&mProcessInfo, sizeof(mProcessInfo));
|
ZeroMemory(&mProcessInfo, sizeof(mProcessInfo));
|
||||||
|
|
||||||
|
DWORD flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | CREATE_DEFAULT_ERROR_MODE;
|
||||||
|
BOOL inheritHandles = false;
|
||||||
|
|
||||||
|
// set up the streams
|
||||||
|
if ((openFileFlags & (DbgOpenFileFlag_RedirectStdInput | DbgOpenFileFlag_RedirectStdOutput | DbgOpenFileFlag_RedirectStdError)) != 0)
|
||||||
|
{
|
||||||
|
if ((openFileFlags & DbgOpenFileFlag_RedirectStdInput) != 0)
|
||||||
|
CreatePipe(mStdInputPipe, si.hStdInput, true);
|
||||||
|
else if (::GetConsoleWindow() != NULL)
|
||||||
|
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
else
|
||||||
|
si.hStdInput = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
if ((openFileFlags & DbgOpenFileFlag_RedirectStdOutput) != 0)
|
||||||
|
CreatePipe(mStdOutputPipe, si.hStdOutput, false);
|
||||||
|
else
|
||||||
|
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
|
if ((openFileFlags & DbgOpenFileFlag_RedirectStdError) != 0)
|
||||||
|
CreatePipe(mStdErrorPipe, si.hStdError, false);
|
||||||
|
else
|
||||||
|
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
flags |= CREATE_NO_WINDOW;
|
||||||
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
inheritHandles = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mDbgProcessId != 0)
|
if (mDbgProcessId != 0)
|
||||||
{
|
{
|
||||||
BOOL success = ::DebugActiveProcess(mDbgProcessId);
|
BOOL success = ::DebugActiveProcess(mDbgProcessId);
|
||||||
|
@ -1288,7 +1392,6 @@ bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args,
|
||||||
|
|
||||||
UTF16String envW;
|
UTF16String envW;
|
||||||
|
|
||||||
DWORD flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | CREATE_DEFAULT_ERROR_MODE;
|
|
||||||
void* envPtr = NULL;
|
void* envPtr = NULL;
|
||||||
if (!envBlock.IsEmpty())
|
if (!envBlock.IsEmpty())
|
||||||
{
|
{
|
||||||
|
@ -1318,11 +1421,34 @@ bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args,
|
||||||
cmdLine += args;
|
cmdLine += args;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL worked = CreateProcessW(NULL, (WCHAR*)UTF8Decode(cmdLine).c_str(), NULL, NULL, FALSE,
|
BOOL worked = CreateProcessW(NULL, (WCHAR*)UTF8Decode(cmdLine).c_str(), NULL, NULL, inheritHandles,
|
||||||
flags, envPtr, (WCHAR*)UTF8Decode(workingDir).c_str(), &si, &mProcessInfo);
|
flags, envPtr, (WCHAR*)UTF8Decode(workingDir).c_str(), &si, &mProcessInfo);
|
||||||
|
|
||||||
|
if ((openFileFlags & DbgOpenFileFlag_RedirectStdInput) != 0)
|
||||||
|
::CloseHandle(si.hStdInput);
|
||||||
|
if ((openFileFlags & DbgOpenFileFlag_RedirectStdOutput) != 0)
|
||||||
|
::CloseHandle(si.hStdOutput);
|
||||||
|
if ((openFileFlags & DbgOpenFileFlag_RedirectStdError) != 0)
|
||||||
|
::CloseHandle(si.hStdError);
|
||||||
|
|
||||||
if (!worked)
|
if (!worked)
|
||||||
{
|
{
|
||||||
|
if (IsHandleValid(mStdInputPipe))
|
||||||
|
{
|
||||||
|
::CloseHandle(mStdInputPipe);
|
||||||
|
mStdInputPipe = 0;
|
||||||
|
}
|
||||||
|
if (IsHandleValid(mStdOutputPipe))
|
||||||
|
{
|
||||||
|
::CloseHandle(mStdOutputPipe);
|
||||||
|
mStdOutputPipe = 0;
|
||||||
|
}
|
||||||
|
if (IsHandleValid(mStdErrorPipe))
|
||||||
|
{
|
||||||
|
::CloseHandle(mStdErrorPipe);
|
||||||
|
mStdErrorPipe = 0;
|
||||||
|
}
|
||||||
|
|
||||||
auto lastError = ::GetLastError();
|
auto lastError = ::GetLastError();
|
||||||
if (lastError == ERROR_DIRECTORY)
|
if (lastError == ERROR_DIRECTORY)
|
||||||
{
|
{
|
||||||
|
@ -1503,6 +1629,18 @@ void WinDebugger::Detach()
|
||||||
mBreakpointAddrMap.Clear();
|
mBreakpointAddrMap.Clear();
|
||||||
|
|
||||||
gDebugUpdateCnt = 0;
|
gDebugUpdateCnt = 0;
|
||||||
|
|
||||||
|
if (IsHandleValid(mStdInputPipe))
|
||||||
|
::CloseHandle(mStdInputPipe);
|
||||||
|
mStdInputPipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
if (IsHandleValid(mStdOutputPipe))
|
||||||
|
::CloseHandle(mStdOutputPipe);
|
||||||
|
mStdOutputPipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
if (IsHandleValid(mStdErrorPipe))
|
||||||
|
::CloseHandle(mStdErrorPipe);
|
||||||
|
mStdErrorPipe = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler* WinDebugger::StartProfiling()
|
Profiler* WinDebugger::StartProfiling()
|
||||||
|
@ -2927,12 +3065,32 @@ static BOOL CALLBACK WdEnumWindowsProc(HWND hwnd, LPARAM lParam)
|
||||||
if (processId != ((WinDebugger*)gDebugger)->mProcessInfo.dwProcessId)
|
if (processId != ((WinDebugger*)gDebugger)->mProcessInfo.dwProcessId)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
SetForegroundWindow(hwnd);
|
while (true)
|
||||||
|
{
|
||||||
|
HWND parentHWnd = GetParent(hwnd);
|
||||||
|
if (parentHWnd != NULL)
|
||||||
|
{
|
||||||
|
hwnd = parentHWnd;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SetForegroundWindow(hwnd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinDebugger::ForegroundTarget()
|
void WinDebugger::ForegroundTarget()
|
||||||
{
|
{
|
||||||
|
HWND hwnd = ::GetForegroundWindow();
|
||||||
|
if (hwnd != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
DWORD processId = 0;
|
||||||
|
GetWindowThreadProcessId(hwnd, &processId);
|
||||||
|
if (processId == ((WinDebugger*)gDebugger)->mProcessInfo.dwProcessId)
|
||||||
|
return; // Already good
|
||||||
|
}
|
||||||
|
|
||||||
EnumWindows(WdEnumWindowsProc, 0);
|
EnumWindows(WdEnumWindowsProc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -389,6 +389,7 @@ public:
|
||||||
String mArgs;
|
String mArgs;
|
||||||
String mWorkingDir;
|
String mWorkingDir;
|
||||||
bool mHotSwapEnabled;
|
bool mHotSwapEnabled;
|
||||||
|
DbgOpenFileFlags mOpenFileFlags;
|
||||||
Array<uint8> mEnvBlock;
|
Array<uint8> mEnvBlock;
|
||||||
DebugTarget* mEmptyDebugTarget;
|
DebugTarget* mEmptyDebugTarget;
|
||||||
DebugTarget* mDebugTarget;
|
DebugTarget* mDebugTarget;
|
||||||
|
@ -400,6 +401,11 @@ public:
|
||||||
DWORD mDbgProcessId;
|
DWORD mDbgProcessId;
|
||||||
HANDLE mDbgProcessHandle;
|
HANDLE mDbgProcessHandle;
|
||||||
HANDLE mDbgThreadHandle;
|
HANDLE mDbgThreadHandle;
|
||||||
|
|
||||||
|
HANDLE mStdInputPipe;
|
||||||
|
HANDLE mStdOutputPipe;
|
||||||
|
HANDLE mStdErrorPipe;
|
||||||
|
|
||||||
bool mIsDebuggerWaiting;
|
bool mIsDebuggerWaiting;
|
||||||
bool mWantsDebugContinue;
|
bool mWantsDebugContinue;
|
||||||
bool mNeedsRehupBreakpoints;
|
bool mNeedsRehupBreakpoints;
|
||||||
|
@ -553,7 +559,7 @@ public:
|
||||||
void ModuleChanged(DbgModule* dbgModule);
|
void ModuleChanged(DbgModule* dbgModule);
|
||||||
bool DoUpdate();
|
bool DoUpdate();
|
||||||
void DebugThreadProc();
|
void DebugThreadProc();
|
||||||
bool DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock);
|
bool DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, DbgOpenFileFlags openFileFlags);
|
||||||
|
|
||||||
DbgTypedValue GetRegister(const StringImpl& regName, DbgLanguage language, CPURegisters* registers, Array<RegForm>* regForms = NULL);
|
DbgTypedValue GetRegister(const StringImpl& regName, DbgLanguage language, CPURegisters* registers, Array<RegForm>* regForms = NULL);
|
||||||
void FixupLineData(DbgCompileUnit* compileUnit);
|
void FixupLineData(DbgCompileUnit* compileUnit);
|
||||||
|
@ -581,8 +587,9 @@ public:
|
||||||
virtual void OutputRawMessage(const StringImpl& msg) override;
|
virtual void OutputRawMessage(const StringImpl& msg) override;
|
||||||
virtual int GetAddrSize() override;
|
virtual int GetAddrSize() override;
|
||||||
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) override;
|
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) override;
|
||||||
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled) override;
|
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags) override;
|
||||||
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) override;
|
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) override;
|
||||||
|
virtual void GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) override;
|
||||||
virtual void Run() override;
|
virtual void Run() override;
|
||||||
virtual bool HasLoadedTargetBinary() override;
|
virtual bool HasLoadedTargetBinary() override;
|
||||||
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;
|
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue