set breakpoints while running

This commit is contained in:
Matt Parker
2025-12-12 23:02:03 +10:00
parent b512bd16bd
commit e4cc15ef1b
5 changed files with 50 additions and 7 deletions

View File

@@ -14,6 +14,7 @@ public class Debugger
{
await _debuggingService.Attach(ProcessId, debuggerExecutablePath, breakpointsByFile, project, cancellationToken);
}
public async Task SetBreakpointsForFile(SharpIdeFile file, List<Breakpoint> breakpoints, CancellationToken cancellationToken = default) => await _debuggingService.SetBreakpointsForFile(file, breakpoints, cancellationToken);
public async Task StepOver(int threadId, CancellationToken cancellationToken = default) => await _debuggingService.StepOver(threadId, cancellationToken);
public async Task StepInto(int threadId, CancellationToken cancellationToken = default) => await _debuggingService.StepInto(threadId, cancellationToken);

View File

@@ -157,6 +157,16 @@ public class DebuggingService
}
// Typically you would do attachRequest, setBreakpointsRequest, configurationDoneRequest, then ResumeRuntime. But netcoredbg blows up on configurationDoneRequest if ResumeRuntime hasn't been called yet.
public async Task SetBreakpointsForFile(SharpIdeFile file, List<Breakpoint> breakpoints, CancellationToken cancellationToken = default)
{
var setBreakpointsRequest = new SetBreakpointsRequest
{
Source = new Source { Path = file.Path },
Breakpoints = breakpoints.Select(b => new SourceBreakpoint { Line = b.Line }).ToList()
};
var breakpointsResponse = _debugProtocolHost.SendRequestSync(setBreakpointsRequest);
}
public async Task StepOver(int threadId, CancellationToken cancellationToken)
{
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);

View File

@@ -14,10 +14,9 @@ using Breakpoint = SharpIDE.Application.Features.Debugging.Breakpoint;
namespace SharpIDE.Application.Features.Run;
public class RunService(ILogger<RunService> logger, RoslynAnalysis roslynAnalysis)
public partial class RunService(ILogger<RunService> logger, RoslynAnalysis roslynAnalysis)
{
private readonly ConcurrentDictionary<SharpIdeProjectModel, SemaphoreSlim> _projectLocks = [];
public ConcurrentDictionary<SharpIdeFile, List<Breakpoint>> Breakpoints { get; } = [];
private Debugger? _debugger; // TODO: Support multiple debuggers for multiple running projects
private readonly ILogger<RunService> _logger = logger;

View File

@@ -0,0 +1,35 @@
using System.Collections.Concurrent;
using Ardalis.GuardClauses;
using SharpIDE.Application.Features.Debugging;
using SharpIDE.Application.Features.SolutionDiscovery;
namespace SharpIDE.Application.Features.Run;
public partial class RunService
{
public ConcurrentDictionary<SharpIdeFile, List<Breakpoint>> Breakpoints { get; } = [];
public async Task AddBreakpointForFile(SharpIdeFile file, int line)
{
Guard.Against.Null(file);
var breakpoints = Breakpoints.GetOrAdd(file, []);
var breakpoint = new Breakpoint { Line = line };
breakpoints.Add(breakpoint);
if (_debugger is not null)
{
await _debugger.SetBreakpointsForFile(file, breakpoints);
}
}
public async Task RemoveBreakpointForFile(SharpIdeFile file, int line)
{
Guard.Against.Null(file);
var breakpoints = Breakpoints.GetOrAdd(file, []);
var breakpoint = breakpoints.Single(b => b.Line == line);
breakpoints.Remove(breakpoint);
if (_debugger is not null)
{
await _debugger.SetBreakpointsForFile(file, breakpoints);
}
}
}

View File

@@ -176,21 +176,19 @@ public partial class SharpIdeCodeEdit : CodeEdit
if (_currentFile is not null) _openTabsFileManager.CloseFile(_currentFile);
}
private void OnBreakpointToggled(long line)
private async void OnBreakpointToggled(long line)
{
if (_fileChangingSuppressBreakpointToggleEvent) return;
var lineInt = (int)line;
var breakpointAdded = IsLineBreakpointed(lineInt);
var lineForDebugger = lineInt + 1; // Godot is 0-indexed, Debugging is 1-indexed
var breakpoints = _runService.Breakpoints.GetOrAdd(_currentFile, []);
if (breakpointAdded)
{
breakpoints.Add(new Breakpoint { Line = lineForDebugger } );
await _runService.AddBreakpointForFile(_currentFile, lineForDebugger);
}
else
{
var breakpoint = breakpoints.Single(b => b.Line == lineForDebugger);
breakpoints.Remove(breakpoint);
await _runService.RemoveBreakpointForFile(_currentFile, lineForDebugger);
}
SetLineColour(lineInt);
GD.Print($"Breakpoint {(breakpointAdded ? "added" : "removed")} at line {lineForDebugger}");