From 27ee87c8f04b782c400e55291b9366428edadb2c Mon Sep 17 00:00:00 2001 From: "Joshua \"Yoshi\" Askharoun" Date: Mon, 1 Dec 2025 00:45:01 -0600 Subject: [PATCH] [WIP] DAP --- .../IrisDebugAdapterClient.cs | 17 +++- .../DapDebuggerServer.cs | 84 ---------------- .../IrisDebugAdapterServer.cs | 97 ++++++++++++++++--- .../IrisDebugServerOptions.cs | 4 +- .../ServiceCollectionExtensions.cs | 6 +- .../ConnectionStringHelper.cs | 17 +++- .../UIX.DebugAdapter.Shared/NamedPipeUtils.cs | 2 +- UIXC/Commands/DebugCommand.cs | 10 +- UIXC/Properties/launchSettings.json | 2 +- 9 files changed, 128 insertions(+), 111 deletions(-) delete mode 100644 DebugAdapter/UIX.DebugAdapter.Server/DapDebuggerServer.cs diff --git a/DebugAdapter/UIX.DebugAdapter.Client/IrisDebugAdapterClient.cs b/DebugAdapter/UIX.DebugAdapter.Client/IrisDebugAdapterClient.cs index 28d0b4b..4ab1a01 100644 --- a/DebugAdapter/UIX.DebugAdapter.Client/IrisDebugAdapterClient.cs +++ b/DebugAdapter/UIX.DebugAdapter.Client/IrisDebugAdapterClient.cs @@ -60,7 +60,7 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi { if (ConnectionString is not null) { - ConnectionStringHelper.CreateFromString(ConnectionString, out _inputStream, out _outputStream); + ConnectionStringHelper.ConnectToString(ConnectionString, out _inputStream, out _outputStream); } _debugAdapter = await DebugAdapterClient.From(options => @@ -70,10 +70,12 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi .WithOutput(_outputStream) .OnInitialize((server, _, cancellationToken) => { + var __ = server.RequestDebugAdapterInitialize(new()); return Task.CompletedTask; }) .OnInitialized((_, _, response, _) => { + Connected?.Invoke(this, EventArgs.Empty); return Task.CompletedTask; }) .OnContinued(args => @@ -141,7 +143,16 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi public void Start() { - StartAsync().RunSynchronously(); - Connected?.Invoke(this, EventArgs.Empty); + System.Threading.Thread clientThread = new(() => + { + _ = StartAsync(); + //.ContinueWith(t => + //{ + // if (t.Exception is not null) + // System.Diagnostics.Debug.WriteLine(t.Exception); + //}); + }); + clientThread.IsBackground = true; + clientThread.Start(); } } diff --git a/DebugAdapter/UIX.DebugAdapter.Server/DapDebuggerServer.cs b/DebugAdapter/UIX.DebugAdapter.Server/DapDebuggerServer.cs deleted file mode 100644 index c9d72d8..0000000 --- a/DebugAdapter/UIX.DebugAdapter.Server/DapDebuggerServer.cs +++ /dev/null @@ -1,84 +0,0 @@ -using Microsoft.Iris.Debug; -using Microsoft.Iris.Debug.Data; -using OmniSharp.Extensions.DebugAdapter.Protocol.Events; -using System; - -namespace Microsoft.Iris.DebugAdapter.Server; - -public class DapDebuggerServer : IDebuggerServer, IRemoteDebuggerState -{ - private readonly IrisDebugServerOptions _debugAdapterOptions; - private IrisDebugAdapterServer? _debugAdapter; - private InterpreterCommand _debuggerCommand; - - public InterpreterCommand DebuggerCommand - { - get => _debuggerCommand; - set - { - _debuggerCommand = value; - - if (_debugAdapter?.Server is null) - return; - - if (value is InterpreterCommand.Continue) - { - _debugAdapter.Server.SendContinued(new() - { - ThreadId = Environment.CurrentManagedThreadId, - }); - } - else if (value is InterpreterCommand.Break) - { - _debugAdapter.Server.SendStopped(new() - { - Reason = new("unknown"), - ThreadId = Environment.CurrentManagedThreadId, - }); - } - } - } - - public string ConnectionString { get; } - - public event Action? Connected; - - public DapDebuggerServer(string connectionString, IrisDebugServerOptions options) - { - ConnectionString = connectionString; - - _debugAdapterOptions = options; - } - - public void LogDispatcher(string message) - { - } - - public void LogInterpreterDecode(object context, InterpreterInstruction instruction) - { - } - - public void LogInterpreterExecute(object context, InterpreterEntry entry) - { - } - - public MarkupLineNumberEntry[] OnLineNumberTableRequested(string uri) - { - return []; - } - - public void Start() - { - ConnectionStringHelper.CreateFromString(ConnectionString, out var input, out var output); - - _debugAdapter = new(input, output, _debugAdapterOptions); - _debugAdapter.StartAsync().RunSynchronously(); - - Connected?.Invoke(this, EventArgs.Empty); - } - - public void WaitForContinue() - { - while (DebuggerCommand is InterpreterCommand.Break) ; - } -} diff --git a/DebugAdapter/UIX.DebugAdapter.Server/IrisDebugAdapterServer.cs b/DebugAdapter/UIX.DebugAdapter.Server/IrisDebugAdapterServer.cs index 26d4875..9a5c5d8 100644 --- a/DebugAdapter/UIX.DebugAdapter.Server/IrisDebugAdapterServer.cs +++ b/DebugAdapter/UIX.DebugAdapter.Server/IrisDebugAdapterServer.cs @@ -1,42 +1,73 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Iris.Debug; +using Microsoft.Iris.Debug.Data; using Microsoft.Iris.DebugAdapter.Server.Handlers; +using OmniSharp.Extensions.DebugAdapter.Protocol.Events; using OmniSharp.Extensions.DebugAdapter.Server; using System; using System.IO; +using System.Threading; using System.Threading.Tasks; namespace Microsoft.Iris.DebugAdapter.Server; -public class IrisDebugAdapterServer : IDisposable +public class IrisDebugAdapterServer : IDebuggerServer, IRemoteDebuggerState, IDisposable { - private readonly Stream _inputStream; - private readonly Stream _outputStream; private readonly TaskCompletionSource _serverStopped; + private Stream _inputStream, _outputStream; + private InterpreterCommand _debuggerCommand; - public IrisDebugAdapterServer( - Stream inputStream, - Stream outputStream, - IrisDebugServerOptions options) + public IrisDebugAdapterServer(IrisDebugServerOptions options) { - _inputStream = inputStream; - _outputStream = outputStream; _serverStopped = new(); Options = options; + ConnectionString = options.ConnectionString; } internal IrisDebugServerOptions Options { get; } internal DebugAdapterServer? Server { get; private set; } + public InterpreterCommand DebuggerCommand + { + get => _debuggerCommand; + set + { + _debuggerCommand = value; + + if (Server is null) + return; + + if (value is InterpreterCommand.Continue) + { + Server.SendContinued(new() + { + ThreadId = Environment.CurrentManagedThreadId, + }); + } + else if (value is InterpreterCommand.Break) + { + Server.SendStopped(new() + { + Reason = new("unknown"), + ThreadId = Environment.CurrentManagedThreadId, + }); + } + } + } + + public string ConnectionString { get; } + /// /// Start the debug server listening. /// /// A task that completes when the server is ready. public async Task StartAsync() { - Server = await DebugAdapterServer.From(options => + ConnectionStringHelper.CreateFromString(ConnectionString, out _inputStream, out _outputStream); + + Server = DebugAdapterServer.Create(options => { // We need to let the PowerShell Context Service know that we are in a debug session // so that it doesn't send the powerShell/startDebugger message. @@ -49,7 +80,7 @@ public class IrisDebugAdapterServer : IDisposable .WithServices(serviceCollection => serviceCollection .AddOptions() - .AddIrisDebugServices(Options.SymbolDir, Options.SourceDir) + .AddIrisDebugServices(this, Options.SymbolDir, Options.SourceDir) ) // TODO: Consider replacing all WithHandler with AddSingleton //.WithHandler() @@ -98,7 +129,11 @@ public class IrisDebugAdapterServer : IDisposable return Task.CompletedTask; }) ; - }).ConfigureAwait(false); + }); + + await Server.Initialize(default).ConfigureAwait(false); + + Connected?.Invoke(this, EventArgs.Empty); } public void Dispose() @@ -116,6 +151,44 @@ public class IrisDebugAdapterServer : IDisposable public async Task WaitForShutdownAsync() => await _serverStopped.Task.ConfigureAwait(false); public event EventHandler? SessionEnded; + public event Action Connected; internal void OnSessionEnded() => SessionEnded?.Invoke(this, EventArgs.Empty); + + public MarkupLineNumberEntry[] OnLineNumberTableRequested(string uri) + { + return []; + } + + public void LogInterpreterDecode(object context, InterpreterInstruction instruction) + { + } + + public void LogInterpreterExecute(object context, InterpreterEntry entry) + { + } + + public void LogDispatcher(string message) + { + } + + public void WaitForContinue() + { + while (DebuggerCommand is InterpreterCommand.Break) ; + } + + public void Start() + { + Thread serverThread = new(() => + { + _ = StartAsync(); + //.ContinueWith(t => + //{ + // if (t.Exception is not null) + // System.Diagnostics.Debug.WriteLine(t.Exception); + //}); + }); + serverThread.IsBackground = true; + serverThread.Start(); + } } diff --git a/DebugAdapter/UIX.DebugAdapter.Server/IrisDebugServerOptions.cs b/DebugAdapter/UIX.DebugAdapter.Server/IrisDebugServerOptions.cs index 2fe2d21..a50dcd6 100644 --- a/DebugAdapter/UIX.DebugAdapter.Server/IrisDebugServerOptions.cs +++ b/DebugAdapter/UIX.DebugAdapter.Server/IrisDebugServerOptions.cs @@ -2,7 +2,9 @@ public class IrisDebugServerOptions { - public string SymbolDir { get; set; } + public required string ConnectionString { get; set; } + + public required string SymbolDir { get; set; } public string? SourceDir { get; set; } } diff --git a/DebugAdapter/UIX.DebugAdapter.Server/ServiceCollectionExtensions.cs b/DebugAdapter/UIX.DebugAdapter.Server/ServiceCollectionExtensions.cs index 76193a9..6024684 100644 --- a/DebugAdapter/UIX.DebugAdapter.Server/ServiceCollectionExtensions.cs +++ b/DebugAdapter/UIX.DebugAdapter.Server/ServiceCollectionExtensions.cs @@ -1,14 +1,16 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Iris.Debug; namespace Microsoft.Iris.DebugAdapter.Server; internal static class ServiceCollectionExtensions { - public static IServiceCollection AddIrisDebugServices(this IServiceCollection services, string symbolDir, string? sourceDir) + public static IServiceCollection AddIrisDebugServices(this IServiceCollection services, IDebuggerServer debuggerServer, string symbolDir, string? sourceDir) { DebugSymbolResolver symbolResolver = new(symbolDir, sourceDir); return services - .AddSingleton(symbolResolver); + .AddSingleton(symbolResolver) + .AddSingleton(debuggerServer); } } diff --git a/DebugAdapter/UIX.DebugAdapter.Shared/ConnectionStringHelper.cs b/DebugAdapter/UIX.DebugAdapter.Shared/ConnectionStringHelper.cs index c7e4514..a600895 100644 --- a/DebugAdapter/UIX.DebugAdapter.Shared/ConnectionStringHelper.cs +++ b/DebugAdapter/UIX.DebugAdapter.Shared/ConnectionStringHelper.cs @@ -14,7 +14,20 @@ public static class ConnectionStringHelper ? connectionString : NamedPipeUtils.GenerateValidNamedPipeName(); - input = NamedPipeUtils.CreateNamedPipe(pipeName, PipeDirection.InOut); - output = input; + var pipe = NamedPipeUtils.CreateNamedPipe(pipeName, PipeDirection.InOut); + pipe.WaitForConnection(); + + output = input = pipe; + } + + public static void ConnectToString(string connectionString, out Stream input, out Stream output) + { + if (!connectionString.StartsWith(PIPE_PREFIX)) + throw new System.NotSupportedException(); + + var pipe = new NamedPipeClientStream(connectionString); + pipe.Connect(); + + output = input = pipe; } } diff --git a/DebugAdapter/UIX.DebugAdapter.Shared/NamedPipeUtils.cs b/DebugAdapter/UIX.DebugAdapter.Shared/NamedPipeUtils.cs index 27ecb49..75569f9 100644 --- a/DebugAdapter/UIX.DebugAdapter.Shared/NamedPipeUtils.cs +++ b/DebugAdapter/UIX.DebugAdapter.Shared/NamedPipeUtils.cs @@ -147,5 +147,5 @@ public static class NamedPipeUtils #endif return $@"\\.\pipe\{pipeName}"; } -} #pragma warning restore IDE0022 +} diff --git a/UIXC/Commands/DebugCommand.cs b/UIXC/Commands/DebugCommand.cs index c695674..befe2a8 100644 --- a/UIXC/Commands/DebugCommand.cs +++ b/UIXC/Commands/DebugCommand.cs @@ -9,11 +9,11 @@ using System.Globalization; namespace UIXC.Commands; -public class DebugCommand : Command +public class DebugCommand : AsyncCommand { - private bool isRunning = true; + private readonly TaskCompletionSource _exit = new(); - public override int Execute(CommandContext context, Settings settings) + public override async Task ExecuteAsync(CommandContext context, Settings settings) { if (settings.ConnectionString is null) { @@ -58,7 +58,7 @@ public class DebugCommand : Command c.Start(); - while (isRunning) ; + await _exit.Task.ConfigureAwait(false); return 0; } @@ -148,7 +148,7 @@ public class DebugCommand : Command break; case "EXIT" or "QUIT": - isRunning = false; + _exit.SetResult(); return 0; } } diff --git a/UIXC/Properties/launchSettings.json b/UIXC/Properties/launchSettings.json index 9a45604..b71f31f 100644 --- a/UIXC/Properties/launchSettings.json +++ b/UIXC/Properties/launchSettings.json @@ -3,7 +3,7 @@ "UIXC": { "commandName": "Project", - "commandLineArgs": "debug --symbols E:\\Repos\\ZuneDev\\ZuneUIXTools\\test\\syms --sources E:\\Repos\\ZuneDev\\ZuneUIXTools\\test", + "commandLineArgs": "debug -u \\\\.\\pipe\\IrisUIX_OpenZune_WPFHost --symbols E:\\Repos\\ZuneDev\\ZuneUIXTools\\test\\syms --sources E:\\Repos\\ZuneDev\\ZuneUIXTools\\test", //"commandLineArgs": "decompile E:\\Documents\\REProj\\Zune\\Resources\\ZuneShellResources48\\NOWPLAYINGMUSICBACKGROUND.UIX -l xml -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o E:\\Repos\\ZuneDev\\ZuneUIXTools\\test --symbols E:\\Repos\\ZuneDev\\ZuneUIXTools\\test\\syms", //"commandLineArgs": "decompile E:\\Documents\\REProj\\Zune\\Resources\\ZuneMarketplaceResources48\\MarketplaceData.schema.xml -l xml -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o E:\\Repos\\ZuneDev\\ZuneUIXTools\\test",