[WIP] DAP

This commit is contained in:
Joshua "Yoshi" Askharoun
2025-12-01 00:45:01 -06:00
parent 22e78658ce
commit 27ee87c8f0
9 changed files with 128 additions and 111 deletions
@@ -60,7 +60,7 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi
{ {
if (ConnectionString is not null) if (ConnectionString is not null)
{ {
ConnectionStringHelper.CreateFromString(ConnectionString, out _inputStream, out _outputStream); ConnectionStringHelper.ConnectToString(ConnectionString, out _inputStream, out _outputStream);
} }
_debugAdapter = await DebugAdapterClient.From(options => _debugAdapter = await DebugAdapterClient.From(options =>
@@ -70,10 +70,12 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi
.WithOutput(_outputStream) .WithOutput(_outputStream)
.OnInitialize((server, _, cancellationToken) => .OnInitialize((server, _, cancellationToken) =>
{ {
var __ = server.RequestDebugAdapterInitialize(new());
return Task.CompletedTask; return Task.CompletedTask;
}) })
.OnInitialized((_, _, response, _) => .OnInitialized((_, _, response, _) =>
{ {
Connected?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask; return Task.CompletedTask;
}) })
.OnContinued(args => .OnContinued(args =>
@@ -141,7 +143,16 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi
public void Start() public void Start()
{ {
StartAsync().RunSynchronously(); System.Threading.Thread clientThread = new(() =>
Connected?.Invoke(this, EventArgs.Empty); {
_ = StartAsync();
//.ContinueWith(t =>
//{
// if (t.Exception is not null)
// System.Diagnostics.Debug.WriteLine(t.Exception);
//});
});
clientThread.IsBackground = true;
clientThread.Start();
} }
} }
@@ -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<IDebuggerState, object>? 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) ;
}
}
@@ -1,42 +1,73 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Iris.Debug; using Microsoft.Iris.Debug;
using Microsoft.Iris.Debug.Data;
using Microsoft.Iris.DebugAdapter.Server.Handlers; using Microsoft.Iris.DebugAdapter.Server.Handlers;
using OmniSharp.Extensions.DebugAdapter.Protocol.Events;
using OmniSharp.Extensions.DebugAdapter.Server; using OmniSharp.Extensions.DebugAdapter.Server;
using System; using System;
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.Iris.DebugAdapter.Server; 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<bool> _serverStopped; private readonly TaskCompletionSource<bool> _serverStopped;
private Stream _inputStream, _outputStream;
private InterpreterCommand _debuggerCommand;
public IrisDebugAdapterServer( public IrisDebugAdapterServer(IrisDebugServerOptions options)
Stream inputStream,
Stream outputStream,
IrisDebugServerOptions options)
{ {
_inputStream = inputStream;
_outputStream = outputStream;
_serverStopped = new(); _serverStopped = new();
Options = options; Options = options;
ConnectionString = options.ConnectionString;
} }
internal IrisDebugServerOptions Options { get; } internal IrisDebugServerOptions Options { get; }
internal DebugAdapterServer? Server { get; private set; } 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; }
/// <summary> /// <summary>
/// Start the debug server listening. /// Start the debug server listening.
/// </summary> /// </summary>
/// <returns>A task that completes when the server is ready.</returns> /// <returns>A task that completes when the server is ready.</returns>
public async Task StartAsync() 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 // 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. // so that it doesn't send the powerShell/startDebugger message.
@@ -49,7 +80,7 @@ public class IrisDebugAdapterServer : IDisposable
.WithServices(serviceCollection => .WithServices(serviceCollection =>
serviceCollection serviceCollection
.AddOptions() .AddOptions()
.AddIrisDebugServices(Options.SymbolDir, Options.SourceDir) .AddIrisDebugServices(this, Options.SymbolDir, Options.SourceDir)
) )
// TODO: Consider replacing all WithHandler with AddSingleton // TODO: Consider replacing all WithHandler with AddSingleton
//.WithHandler<AttachHandler>() //.WithHandler<AttachHandler>()
@@ -98,7 +129,11 @@ public class IrisDebugAdapterServer : IDisposable
return Task.CompletedTask; return Task.CompletedTask;
}) })
; ;
}).ConfigureAwait(false); });
await Server.Initialize(default).ConfigureAwait(false);
Connected?.Invoke(this, EventArgs.Empty);
} }
public void Dispose() public void Dispose()
@@ -116,6 +151,44 @@ public class IrisDebugAdapterServer : IDisposable
public async Task WaitForShutdownAsync() => await _serverStopped.Task.ConfigureAwait(false); public async Task WaitForShutdownAsync() => await _serverStopped.Task.ConfigureAwait(false);
public event EventHandler? SessionEnded; public event EventHandler? SessionEnded;
public event Action<IDebuggerState, object> Connected;
internal void OnSessionEnded() => SessionEnded?.Invoke(this, EventArgs.Empty); 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();
}
} }
@@ -2,7 +2,9 @@
public class IrisDebugServerOptions 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; } public string? SourceDir { get; set; }
} }
@@ -1,14 +1,16 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Iris.Debug;
namespace Microsoft.Iris.DebugAdapter.Server; namespace Microsoft.Iris.DebugAdapter.Server;
internal static class ServiceCollectionExtensions 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); DebugSymbolResolver symbolResolver = new(symbolDir, sourceDir);
return services return services
.AddSingleton(symbolResolver); .AddSingleton(symbolResolver)
.AddSingleton(debuggerServer);
} }
} }
@@ -14,7 +14,20 @@ public static class ConnectionStringHelper
? connectionString ? connectionString
: NamedPipeUtils.GenerateValidNamedPipeName(); : NamedPipeUtils.GenerateValidNamedPipeName();
input = NamedPipeUtils.CreateNamedPipe(pipeName, PipeDirection.InOut); var pipe = NamedPipeUtils.CreateNamedPipe(pipeName, PipeDirection.InOut);
output = input; 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;
} }
} }
@@ -147,5 +147,5 @@ public static class NamedPipeUtils
#endif #endif
return $@"\\.\pipe\{pipeName}"; return $@"\\.\pipe\{pipeName}";
} }
}
#pragma warning restore IDE0022 #pragma warning restore IDE0022
}
+5 -5
View File
@@ -9,11 +9,11 @@ using System.Globalization;
namespace UIXC.Commands; namespace UIXC.Commands;
public class DebugCommand : Command<DebugCommand.Settings> public class DebugCommand : AsyncCommand<DebugCommand.Settings>
{ {
private bool isRunning = true; private readonly TaskCompletionSource _exit = new();
public override int Execute(CommandContext context, Settings settings) public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
{ {
if (settings.ConnectionString is null) if (settings.ConnectionString is null)
{ {
@@ -58,7 +58,7 @@ public class DebugCommand : Command<DebugCommand.Settings>
c.Start(); c.Start();
while (isRunning) ; await _exit.Task.ConfigureAwait(false);
return 0; return 0;
} }
@@ -148,7 +148,7 @@ public class DebugCommand : Command<DebugCommand.Settings>
break; break;
case "EXIT" or "QUIT": case "EXIT" or "QUIT":
isRunning = false; _exit.SetResult();
return 0; return 0;
} }
} }
+1 -1
View File
@@ -3,7 +3,7 @@
"UIXC": { "UIXC": {
"commandName": "Project", "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\\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", //"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",