[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)
{
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();
}
}
@@ -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.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<bool> _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; }
/// <summary>
/// Start the debug server listening.
/// </summary>
/// <returns>A task that completes when the server is ready.</returns>
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<AttachHandler>()
@@ -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<IDebuggerState, object> 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();
}
}
@@ -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; }
}
@@ -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);
}
}
@@ -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;
}
}
@@ -147,5 +147,5 @@ public static class NamedPipeUtils
#endif
return $@"\\.\pipe\{pipeName}";
}
}
#pragma warning restore IDE0022
}