set initial breakpoints

This commit is contained in:
Matt Parker
2025-08-25 21:26:53 +10:00
parent 97dcfd2d4c
commit ef46c94b30
5 changed files with 47 additions and 10 deletions

View File

@@ -0,0 +1,6 @@
namespace SharpIDE.Application.Features.Debugging;
public class Breakpoint
{
public required int Line { get; init; }
}

View File

@@ -1,4 +1,5 @@
using SharpIDE.Application.Features.Debugging.Experimental;
using SharpIDE.Application.Features.SolutionDiscovery;
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
namespace SharpIDE.Application.Features.Debugging;
@@ -8,8 +9,8 @@ public class Debugger
public required SharpIdeProjectModel Project { get; init; }
public required int ProcessId { get; init; }
private DebuggingService _debuggingService = new DebuggingService();
public async Task Attach(CancellationToken cancellationToken)
public async Task Attach(CancellationToken cancellationToken, Dictionary<SharpIdeFile, List<Breakpoint>> breakpointsByFile)
{
await _debuggingService.Attach(ProcessId, cancellationToken);
await _debuggingService.Attach(ProcessId, breakpointsByFile, cancellationToken);
}
}

View File

@@ -6,13 +6,14 @@ using Microsoft.VisualStudio.Shared.VSCodeDebugProtocol.Messages;
using Newtonsoft.Json.Linq;
using SharpIDE.Application.Features.Debugging.Experimental;
using SharpIDE.Application.Features.Debugging.Experimental.VsDbg;
using SharpIDE.Application.Features.SolutionDiscovery;
namespace SharpIDE.Application.Features.Debugging;
public class DebuggingService
{
private DebugProtocolHost _debugProtocolHost = null!;
public async Task Attach(int debuggeeProcessId, CancellationToken cancellationToken = default)
public async Task Attach(int debuggeeProcessId, Dictionary<SharpIdeFile, List<Breakpoint>> breakpointsByFile, CancellationToken cancellationToken = default)
{
Guard.Against.NegativeOrZero(debuggeeProcessId, nameof(debuggeeProcessId), "Process ID must be a positive integer.");
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
@@ -100,12 +101,16 @@ public class DebuggingService
};
debugProtocolHost.SendRequestSync(attachRequest);
// var breakpointRequest = new SetBreakpointsRequest
// {
// Source = new Source { Path = @"C:\Users\Matthew\Documents\Git\BlazorCodeBreaker\src\WebApi\Program.cs" },
// Breakpoints = [new SourceBreakpoint { Line = 7 }]
// };
// var breakpointsResponse = debugProtocolHost.SendRequestSync(breakpointRequest);
foreach (var breakpoint in breakpointsByFile)
{
var setBreakpointsRequest = new SetBreakpointsRequest
{
Source = new Source { Path = breakpoint.Key.Path },
Breakpoints = breakpoint.Value.Select(b => new SourceBreakpoint { Line = b.Line }).ToList()
};
var breakpointsResponse = debugProtocolHost.SendRequestSync(setBreakpointsRequest);
}
new DiagnosticsClient(debuggeeProcessId).ResumeRuntime();
var configurationDoneRequest = new ConfigurationDoneRequest();
debugProtocolHost.SendRequestSync(configurationDoneRequest);

View File

@@ -5,6 +5,7 @@ using AsyncReadProcess;
using SharpIDE.Application.Features.Debugging;
using SharpIDE.Application.Features.Evaluation;
using SharpIDE.Application.Features.Events;
using SharpIDE.Application.Features.SolutionDiscovery;
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
namespace SharpIDE.Application.Features.Run;
@@ -12,6 +13,7 @@ namespace SharpIDE.Application.Features.Run;
public class RunService
{
private readonly ConcurrentDictionary<SharpIdeProjectModel, SemaphoreSlim> _projectLocks = [];
public ConcurrentDictionary<SharpIdeFile, List<Breakpoint>> Breakpoints { get; } = [];
public async Task RunProject(SharpIdeProjectModel project)
{
var isDebug = true;
@@ -83,7 +85,7 @@ public class RunService
{
// Attach debugger (which internally uses a DiagnosticClient to resume startup)
var debuggingService = new Debugger { Project = project, ProcessId = process.ProcessId };
await debuggingService.Attach(project.RunningCancellationTokenSource.Token).ConfigureAwait(false);
await debuggingService.Attach(project.RunningCancellationTokenSource.Token, Breakpoints.ToDictionary()).ConfigureAwait(false);
}
project.Running = true;

View File

@@ -4,12 +4,14 @@ using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Threading;
using Ardalis.GuardClauses;
using Godot;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
using SharpIDE.Application.Features.Analysis;
using SharpIDE.Application.Features.Debugging;
using SharpIDE.Application.Features.SolutionDiscovery;
using Task = System.Threading.Tasks.Task;
@@ -34,11 +36,13 @@ public partial class SharpIdeCodeEdit : CodeEdit
public override void _Ready()
{
SyntaxHighlighter = _syntaxHighlighter;
_popupMenu = GetNode<PopupMenu>("CodeFixesMenu");
_popupMenu.IdPressed += OnCodeFixSelected;
CodeCompletionRequested += OnCodeCompletionRequested;
CodeFixesRequested += OnCodeFixesRequested;
BreakpointToggled += OnBreakpointToggled;
CaretChanged += OnCaretChanged;
TextChanged += OnTextChanged;
SymbolHovered += OnSymbolHovered;
@@ -46,6 +50,25 @@ public partial class SharpIdeCodeEdit : CodeEdit
SymbolLookup += OnSymbolLookup;
}
private void OnBreakpointToggled(long line)
{
var lineInt = (int)line;
var breakpointAdded = IsLineBreakpointed(lineInt);
lineInt++; // Godot is 0-indexed, Debugging is 1-indexed
Guard.Against.Negative(lineInt, nameof(lineInt));
var breakpoints = Singletons.RunService.Breakpoints.GetOrAdd(_currentFile, []);
if (breakpointAdded)
{
breakpoints.Add(new Breakpoint { Line = lineInt } );
}
else
{
var breakpoint = breakpoints.Single(b => b.Line == lineInt);
breakpoints.Remove(breakpoint);
}
GD.Print($"Breakpoint {(breakpointAdded ? "added" : "removed")} at line {lineInt}");
}
private void OnSymbolLookup(string symbol, long line, long column)
{
GD.Print($"Symbol lookup requested: {symbol} at line {line}, column {column}");