diff --git a/GodotDebugSession/ActionTextWriter.cs b/GodotDebugSession/ActionTextWriter.cs new file mode 100644 index 0000000..9402741 --- /dev/null +++ b/GodotDebugSession/ActionTextWriter.cs @@ -0,0 +1,32 @@ +using System; +using System.IO; +using System.Text; + +namespace GodotDebugSession +{ + public class ActionTextWriter : TextWriter + { + private readonly StringBuilder buffer = new StringBuilder(); + + private Action Writer { get; } + + public ActionTextWriter(Action writer) + { + Writer = writer; + } + + public override Encoding Encoding => Encoding.UTF8; + + public override void Write(char value) + { + if (value == '\n') + { + Writer(buffer.ToString()); + buffer.Clear(); + return; + } + + buffer.Append(value); + } + } +} diff --git a/GodotDebugSession/GodotDebugSession.cs b/GodotDebugSession/GodotDebugSession.cs index 3fd144f..2d2bfb5 100644 --- a/GodotDebugSession/GodotDebugSession.cs +++ b/GodotDebugSession/GodotDebugSession.cs @@ -69,7 +69,7 @@ namespace GodotDebugSession IPAddress address = Utilities.ResolveIPAddress(host); if (address == null) { - SendErrorResponse(response, 3013, "Invalid address '{host}'.", new {host}); + SendErrorResponse(response, 3013, "Invalid address '{host}'.", new { host }); return; } @@ -85,11 +85,13 @@ namespace GodotDebugSession _debuggeeKilled = false; string godotExecutablePath = (string)args.executable; + string[] executableArguments = args.executableArguments?.ToObject() ?? Array.Empty(); string godotProjectDir = (string)args.godotProjectDir; - var startInfo = new GodotDebuggerStartInfo(executionType, godotExecutablePath, - processOutputListener: this, listenArgs) {WorkingDirectory = godotProjectDir}; + var startInfo = new GodotDebuggerStartInfo(executionType, + godotExecutablePath, executableArguments, processOutputListener: this, listenArgs) + { WorkingDirectory = godotProjectDir }; _session.Run(startInfo, _debuggerSessionOptions); diff --git a/GodotDebugSession/GodotDebugSession.csproj b/GodotDebugSession/GodotDebugSession.csproj index 22f2d75..1275f3b 100644 --- a/GodotDebugSession/GodotDebugSession.csproj +++ b/GodotDebugSession/GodotDebugSession.csproj @@ -53,6 +53,7 @@ Utilities.cs + @@ -79,6 +80,7 @@ + diff --git a/GodotDebugSession/GodotDebuggerSession.cs b/GodotDebugSession/GodotDebuggerSession.cs index dd4596f..a8fe60c 100644 --- a/GodotDebugSession/GodotDebuggerSession.cs +++ b/GodotDebugSession/GodotDebuggerSession.cs @@ -4,8 +4,10 @@ using System.Net.Sockets; using System.Net; using System.Threading.Tasks; using GodotTools.IdeMessaging.Requests; +using Medallion.Shell; using Mono.Debugging.Client; using Mono.Debugging.Soft; +using System.Collections.Generic; namespace GodotDebugSession { @@ -50,7 +52,7 @@ namespace GodotDebugSession messagingClient.Start(); await messagingClient.AwaitConnected(); var response = await messagingClient.SendRequest( - new DebugPlayRequest {DebuggerHost = host, DebuggerPort = assignedDebugPort}); + new DebugPlayRequest { DebuggerHost = host, DebuggerPort = assignedDebugPort }); if (response.Status != GodotTools.IdeMessaging.MessageStatus.Ok) { @@ -89,33 +91,30 @@ namespace GodotDebugSession // Launch Godot to run the game and connect to our remote debugger - var processStartInfo = new ProcessStartInfo(godotStartInfo.GodotExecutablePath) + var args = new List() { - Arguments = $"--path {workingDir} --remote-debug {host}:{remoteDebugPort}", - WorkingDirectory = workingDir, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false, - CreateNoWindow = true + "--path", workingDir, + "--remote-debug", $"{host}:{remoteDebugPort}", }; + args.AddRange(godotStartInfo.ExecutableArguments); - // Tells Godot to connect to the mono debugger we just started - processStartInfo.EnvironmentVariables["GODOT_MONO_DEBUGGER_AGENT"] = - "--debugger-agent=transport=dt_socket" + - $",address={host}:{assignedDebugPort}" + - ",server=n"; + var process = Command.Run(godotStartInfo.GodotExecutablePath, args, options => + { + options.WorkingDirectory(workingDir); + options.ThrowOnError(true); - var process = new Process {StartInfo = processStartInfo, EnableRaisingEvents = true}; - process.OutputDataReceived += (sender, e) => - godotStartInfo.ProcessOutputListener.ReceiveStdOut(e.Data); - process.ErrorDataReceived += (sender, e) => - godotStartInfo.ProcessOutputListener.ReceiveStdErr(e.Data); + // Tells Godot to connect to the mono debugger we just started + options.EnvironmentVariable("GODOT_MONO_DEBUGGER_AGENT", + "--debugger-agent=transport=dt_socket" + + $",address={host}:{assignedDebugPort}" + + ",server=n"); + }) + .RedirectTo(godotStartInfo.ProcessOutputListener.GetStdOutTextWriter()) + .RedirectStandardErrorTo(godotStartInfo.ProcessOutputListener.GetStdErrTextWriter()); try { - process.Start(); - process.BeginOutputReadLine(); - process.BeginErrorReadLine(); + await process.Task; } catch (Exception e) { @@ -124,7 +123,7 @@ namespace GodotDebugSession return; } - OnDebuggerOutput(false, $"Godot PID:{process.Id}{Environment.NewLine}"); + OnDebuggerOutput(false, $"Godot PID:{process.ProcessId}{Environment.NewLine}"); } catch (Exception e) { diff --git a/GodotDebugSession/GodotDebuggerStartInfo.cs b/GodotDebugSession/GodotDebuggerStartInfo.cs index d563c10..d688222 100644 --- a/GodotDebugSession/GodotDebuggerStartInfo.cs +++ b/GodotDebugSession/GodotDebuggerStartInfo.cs @@ -1,3 +1,4 @@ +using System.IO; using Mono.Debugging.Soft; namespace GodotDebugSession @@ -5,15 +6,18 @@ namespace GodotDebugSession public class GodotDebuggerStartInfo : SoftDebuggerStartInfo { public string GodotExecutablePath { get; } + public string[] ExecutableArguments { get; } public ExecutionType ExecutionType { get; } public IProcessOutputListener ProcessOutputListener { get; } public GodotDebuggerStartInfo(ExecutionType executionType, string godotExecutablePath, - IProcessOutputListener processOutputListener, SoftDebuggerRemoteArgs softDebuggerConnectArgs) : + string[] executableArguments, IProcessOutputListener processOutputListener, + SoftDebuggerRemoteArgs softDebuggerConnectArgs) : base(softDebuggerConnectArgs) { ExecutionType = executionType; GodotExecutablePath = godotExecutablePath; + ExecutableArguments = executableArguments; ProcessOutputListener = processOutputListener; } } @@ -30,4 +34,17 @@ namespace GodotDebugSession void ReceiveStdOut(string data); void ReceiveStdErr(string data); } + + public static class IProcessOutputListenerExtensions + { + public static TextWriter GetStdOutTextWriter(this IProcessOutputListener processOutputListener) + { + return new ActionTextWriter(processOutputListener.ReceiveStdOut); + } + + public static TextWriter GetStdErrTextWriter(this IProcessOutputListener processOutputListener) + { + return new ActionTextWriter(processOutputListener.ReceiveStdErr); + } + } }