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.Debugging.Experimental;
using SharpIDE.Application.Features.SolutionDiscovery;
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
namespace SharpIDE.Application.Features.Debugging; namespace SharpIDE.Application.Features.Debugging;
@@ -8,8 +9,8 @@ public class Debugger
public required SharpIdeProjectModel Project { get; init; } public required SharpIdeProjectModel Project { get; init; }
public required int ProcessId { get; init; } public required int ProcessId { get; init; }
private DebuggingService _debuggingService = new DebuggingService(); 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 Newtonsoft.Json.Linq;
using SharpIDE.Application.Features.Debugging.Experimental; using SharpIDE.Application.Features.Debugging.Experimental;
using SharpIDE.Application.Features.Debugging.Experimental.VsDbg; using SharpIDE.Application.Features.Debugging.Experimental.VsDbg;
using SharpIDE.Application.Features.SolutionDiscovery;
namespace SharpIDE.Application.Features.Debugging; namespace SharpIDE.Application.Features.Debugging;
public class DebuggingService public class DebuggingService
{ {
private DebugProtocolHost _debugProtocolHost = null!; 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."); Guard.Against.NegativeOrZero(debuggeeProcessId, nameof(debuggeeProcessId), "Process ID must be a positive integer.");
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding); await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
@@ -100,12 +101,16 @@ public class DebuggingService
}; };
debugProtocolHost.SendRequestSync(attachRequest); debugProtocolHost.SendRequestSync(attachRequest);
// var breakpointRequest = new SetBreakpointsRequest foreach (var breakpoint in breakpointsByFile)
// { {
// Source = new Source { Path = @"C:\Users\Matthew\Documents\Git\BlazorCodeBreaker\src\WebApi\Program.cs" }, var setBreakpointsRequest = new SetBreakpointsRequest
// Breakpoints = [new SourceBreakpoint { Line = 7 }] {
// }; Source = new Source { Path = breakpoint.Key.Path },
// var breakpointsResponse = debugProtocolHost.SendRequestSync(breakpointRequest); Breakpoints = breakpoint.Value.Select(b => new SourceBreakpoint { Line = b.Line }).ToList()
};
var breakpointsResponse = debugProtocolHost.SendRequestSync(setBreakpointsRequest);
}
new DiagnosticsClient(debuggeeProcessId).ResumeRuntime(); new DiagnosticsClient(debuggeeProcessId).ResumeRuntime();
var configurationDoneRequest = new ConfigurationDoneRequest(); var configurationDoneRequest = new ConfigurationDoneRequest();
debugProtocolHost.SendRequestSync(configurationDoneRequest); debugProtocolHost.SendRequestSync(configurationDoneRequest);

View File

@@ -5,6 +5,7 @@ using AsyncReadProcess;
using SharpIDE.Application.Features.Debugging; using SharpIDE.Application.Features.Debugging;
using SharpIDE.Application.Features.Evaluation; using SharpIDE.Application.Features.Evaluation;
using SharpIDE.Application.Features.Events; using SharpIDE.Application.Features.Events;
using SharpIDE.Application.Features.SolutionDiscovery;
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
namespace SharpIDE.Application.Features.Run; namespace SharpIDE.Application.Features.Run;
@@ -12,6 +13,7 @@ namespace SharpIDE.Application.Features.Run;
public class RunService public class RunService
{ {
private readonly ConcurrentDictionary<SharpIdeProjectModel, SemaphoreSlim> _projectLocks = []; private readonly ConcurrentDictionary<SharpIdeProjectModel, SemaphoreSlim> _projectLocks = [];
public ConcurrentDictionary<SharpIdeFile, List<Breakpoint>> Breakpoints { get; } = [];
public async Task RunProject(SharpIdeProjectModel project) public async Task RunProject(SharpIdeProjectModel project)
{ {
var isDebug = true; var isDebug = true;
@@ -83,7 +85,7 @@ public class RunService
{ {
// 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 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; project.Running = true;

View File

@@ -4,12 +4,14 @@ using System.Collections.Immutable;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Ardalis.GuardClauses;
using Godot; using Godot;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using SharpIDE.Application.Features.Analysis; using SharpIDE.Application.Features.Analysis;
using SharpIDE.Application.Features.Debugging;
using SharpIDE.Application.Features.SolutionDiscovery; using SharpIDE.Application.Features.SolutionDiscovery;
using Task = System.Threading.Tasks.Task; using Task = System.Threading.Tasks.Task;
@@ -34,11 +36,13 @@ public partial class SharpIdeCodeEdit : CodeEdit
public override void _Ready() public override void _Ready()
{ {
SyntaxHighlighter = _syntaxHighlighter; SyntaxHighlighter = _syntaxHighlighter;
_popupMenu = GetNode<PopupMenu>("CodeFixesMenu"); _popupMenu = GetNode<PopupMenu>("CodeFixesMenu");
_popupMenu.IdPressed += OnCodeFixSelected; _popupMenu.IdPressed += OnCodeFixSelected;
CodeCompletionRequested += OnCodeCompletionRequested; CodeCompletionRequested += OnCodeCompletionRequested;
CodeFixesRequested += OnCodeFixesRequested; CodeFixesRequested += OnCodeFixesRequested;
BreakpointToggled += OnBreakpointToggled;
CaretChanged += OnCaretChanged; CaretChanged += OnCaretChanged;
TextChanged += OnTextChanged; TextChanged += OnTextChanged;
SymbolHovered += OnSymbolHovered; SymbolHovered += OnSymbolHovered;
@@ -46,6 +50,25 @@ public partial class SharpIdeCodeEdit : CodeEdit
SymbolLookup += OnSymbolLookup; 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) private void OnSymbolLookup(string symbol, long line, long column)
{ {
GD.Print($"Symbol lookup requested: {symbol} at line {line}, column {column}"); GD.Print($"Symbol lookup requested: {symbol} at line {line}, column {column}");