send step over
This commit is contained in:
@@ -13,4 +13,6 @@ public class Debugger
|
|||||||
{
|
{
|
||||||
await _debuggingService.Attach(ProcessId, breakpointsByFile, cancellationToken);
|
await _debuggingService.Attach(ProcessId, breakpointsByFile, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task StepOver(int threadId, CancellationToken cancellationToken = default) => await _debuggingService.StepOver(threadId, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ public class DebuggingService
|
|||||||
var dict = prop?.GetValue(@event) as Dictionary<string, JToken>;
|
var dict = prop?.GetValue(@event) as Dictionary<string, JToken>;
|
||||||
var filePath = dict?["source"]?["path"]!.Value<string>()!;
|
var filePath = dict?["source"]?["path"]!.Value<string>()!;
|
||||||
var line = (dict?["line"]?.Value<int>()!).Value;
|
var line = (dict?["line"]?.Value<int>()!).Value;
|
||||||
GlobalEvents.InvokeDebuggerExecutionStopped(filePath, line);
|
var executionStopInfo = new ExecutionStopInfo { FilePath = filePath, Line = line, ThreadId = @event.ThreadId!.Value };
|
||||||
|
GlobalEvents.InvokeDebuggerExecutionStopped(executionStopInfo);
|
||||||
if (@event.Reason is StoppedEvent.ReasonValue.Exception)
|
if (@event.Reason is StoppedEvent.ReasonValue.Exception)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Stopped due to exception, continuing");
|
Console.WriteLine("Stopped due to exception, continuing");
|
||||||
@@ -125,4 +126,11 @@ public class DebuggingService
|
|||||||
debugProtocolHost.SendRequestSync(configurationDoneRequest);
|
debugProtocolHost.SendRequestSync(configurationDoneRequest);
|
||||||
}
|
}
|
||||||
// Typically you would do attachRequest, configurationDoneRequest, setBreakpointsRequest, then ResumeRuntime. But netcoredbg blows up on configurationDoneRequuest if ResumeRuntime hasn't been called yet.
|
// Typically you would do attachRequest, configurationDoneRequest, setBreakpointsRequest, then ResumeRuntime. But netcoredbg blows up on configurationDoneRequuest if ResumeRuntime hasn't been called yet.
|
||||||
|
|
||||||
|
public async Task StepOver(int threadId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
|
||||||
|
var nextRequest = new NextRequest(threadId);
|
||||||
|
_debugProtocolHost.SendRequestSync(nextRequest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace SharpIDE.Application.Features.Debugging;
|
||||||
|
|
||||||
|
public class ExecutionStopInfo
|
||||||
|
{
|
||||||
|
public required string FilePath { get; init; }
|
||||||
|
public required int Line { get; init; }
|
||||||
|
public required int ThreadId { get; init; }
|
||||||
|
}
|
||||||
@@ -18,6 +18,6 @@ public static class GlobalEvents
|
|||||||
public static event Func<SharpIdeProjectModel, Task> ProjectStoppedRunning = _ => Task.CompletedTask;
|
public static event Func<SharpIdeProjectModel, Task> ProjectStoppedRunning = _ => Task.CompletedTask;
|
||||||
public static void InvokeProjectStoppedRunning(SharpIdeProjectModel project) => ProjectStoppedRunning?.Invoke(project);
|
public static void InvokeProjectStoppedRunning(SharpIdeProjectModel project) => ProjectStoppedRunning?.Invoke(project);
|
||||||
|
|
||||||
public static event Func<string, int, Task> DebuggerExecutionStopped = (_, _) => Task.CompletedTask;
|
public static event Func<ExecutionStopInfo, Task> DebuggerExecutionStopped = _ => Task.CompletedTask;
|
||||||
public static void InvokeDebuggerExecutionStopped(string filePath, int line) => DebuggerExecutionStopped?.Invoke(filePath, line);
|
public static void InvokeDebuggerExecutionStopped(ExecutionStopInfo executionStopInfo) => DebuggerExecutionStopped?.Invoke(executionStopInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public class RunService
|
|||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<SharpIdeProjectModel, SemaphoreSlim> _projectLocks = [];
|
private readonly ConcurrentDictionary<SharpIdeProjectModel, SemaphoreSlim> _projectLocks = [];
|
||||||
public ConcurrentDictionary<SharpIdeFile, List<Breakpoint>> Breakpoints { get; } = [];
|
public ConcurrentDictionary<SharpIdeFile, List<Breakpoint>> Breakpoints { get; } = [];
|
||||||
|
private Debugger? _debugger; // TODO: Support multiple debuggers for multiple running projects
|
||||||
public async Task RunProject(SharpIdeProjectModel project)
|
public async Task RunProject(SharpIdeProjectModel project)
|
||||||
{
|
{
|
||||||
var isDebug = true;
|
var isDebug = true;
|
||||||
@@ -84,8 +85,9 @@ public class RunService
|
|||||||
if (isDebug)
|
if (isDebug)
|
||||||
{
|
{
|
||||||
// Attach debugger (which internally uses a DiagnosticClient to resume startup)
|
// Attach debugger (which internally uses a DiagnosticClient to resume startup)
|
||||||
var debuggingService = new Debugger { Project = project, ProcessId = process.ProcessId };
|
var debugger = new Debugger { Project = project, ProcessId = process.ProcessId };
|
||||||
await debuggingService.Attach(project.RunningCancellationTokenSource.Token, Breakpoints.ToDictionary()).ConfigureAwait(false);
|
_debugger = debugger;
|
||||||
|
await debugger.Attach(project.RunningCancellationTokenSource.Token, Breakpoints.ToDictionary()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
project.Running = true;
|
project.Running = true;
|
||||||
@@ -126,6 +128,11 @@ public class RunService
|
|||||||
await project.RunningCancellationTokenSource.CancelAsync().ConfigureAwait(false);
|
await project.RunningCancellationTokenSource.CancelAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SendDebuggerStepOver(int threadId)
|
||||||
|
{
|
||||||
|
await _debugger!.StepOver(threadId);
|
||||||
|
}
|
||||||
|
|
||||||
private string GetRunArguments(SharpIdeProjectModel project)
|
private string GetRunArguments(SharpIdeProjectModel project)
|
||||||
{
|
{
|
||||||
var dllFullPath = ProjectEvaluation.GetOutputDllFullPath(project);
|
var dllFullPath = ProjectEvaluation.GetOutputDllFullPath(project);
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ namespace SharpIDE.Godot;
|
|||||||
public static class InputStringNames
|
public static class InputStringNames
|
||||||
{
|
{
|
||||||
public static readonly StringName CodeFixes = "CodeFixes";
|
public static readonly StringName CodeFixes = "CodeFixes";
|
||||||
|
public static readonly StringName StepOver = "StepOver";
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@ using SharpIDE.Application.Features.Analysis;
|
|||||||
using SharpIDE.Application.Features.Debugging;
|
using SharpIDE.Application.Features.Debugging;
|
||||||
using SharpIDE.Application.Features.Events;
|
using SharpIDE.Application.Features.Events;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||||
|
using SharpIDE.Godot.Features.Run;
|
||||||
using Task = System.Threading.Tasks.Task;
|
using Task = System.Threading.Tasks.Task;
|
||||||
|
|
||||||
namespace SharpIDE.Godot;
|
namespace SharpIDE.Godot;
|
||||||
@@ -34,6 +35,7 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
|
|
||||||
private ImmutableArray<(FileLinePositionSpan fileSpan, Diagnostic diagnostic)> _diagnostics = [];
|
private ImmutableArray<(FileLinePositionSpan fileSpan, Diagnostic diagnostic)> _diagnostics = [];
|
||||||
private ImmutableArray<CodeAction> _currentCodeActionsInPopup = [];
|
private ImmutableArray<CodeAction> _currentCodeActionsInPopup = [];
|
||||||
|
private ExecutionStopInfo? _executionStopInfo;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
@@ -51,11 +53,12 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
GlobalEvents.DebuggerExecutionStopped += OnDebuggerExecutionStopped;
|
GlobalEvents.DebuggerExecutionStopped += OnDebuggerExecutionStopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnDebuggerExecutionStopped(string filePath, int line)
|
private async Task OnDebuggerExecutionStopped(ExecutionStopInfo executionStopInfo)
|
||||||
{
|
{
|
||||||
if (filePath != _currentFile.Path) return; // TODO: handle file switching
|
if (executionStopInfo.FilePath != _currentFile.Path) return; // TODO: handle file switching
|
||||||
var lineInt = line - 1; // Debugging is 1-indexed, Godot is 0-indexed
|
var lineInt = executionStopInfo.Line - 1; // Debugging is 1-indexed, Godot is 0-indexed
|
||||||
Guard.Against.Negative(lineInt, nameof(lineInt));
|
Guard.Against.Negative(lineInt, nameof(lineInt));
|
||||||
|
_executionStopInfo = executionStopInfo;
|
||||||
|
|
||||||
await this.InvokeAsync(() =>
|
await this.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
@@ -237,6 +240,19 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
{
|
{
|
||||||
EmitSignalCodeFixesRequested();
|
EmitSignalCodeFixesRequested();
|
||||||
}
|
}
|
||||||
|
else if (@event.IsActionPressed(InputStringNames.StepOver))
|
||||||
|
{
|
||||||
|
SendDebuggerStepOver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendDebuggerStepOver()
|
||||||
|
{
|
||||||
|
if (_executionStopInfo is null) return;
|
||||||
|
_ = GodotTask.Run(async () =>
|
||||||
|
{
|
||||||
|
await Singletons.RunService.SendDebuggerStepOver(_executionStopInfo.ThreadId);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetDiagnosticsModel(ImmutableArray<(FileLinePositionSpan fileSpan, Diagnostic diagnostic)> diagnostics)
|
private void SetDiagnosticsModel(ImmutableArray<(FileLinePositionSpan fileSpan, Diagnostic diagnostic)> diagnostics)
|
||||||
|
|||||||
@@ -32,3 +32,8 @@ CodeFixes={
|
|||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194309,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194309,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
StepOver={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194341,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user