wire up debug panel

This commit is contained in:
Matt Parker
2025-08-29 19:01:06 +10:00
parent 850be02a52
commit 5f9439c9aa
9 changed files with 116 additions and 28 deletions

View File

@@ -12,6 +12,12 @@ public static class GlobalEvents
public static event Func<Task> StartedRunningProject = () => Task.CompletedTask; public static event Func<Task> StartedRunningProject = () => Task.CompletedTask;
public static void InvokeStartedRunningProject() => StartedRunningProject?.InvokeParallelFireAndForget(); public static void InvokeStartedRunningProject() => StartedRunningProject?.InvokeParallelFireAndForget();
public static event Func<SharpIdeProjectModel, Task> ProjectStartedDebugging = _ => Task.CompletedTask;
public static void InvokeProjectStartedDebugging(SharpIdeProjectModel project) => ProjectStartedDebugging?.InvokeParallelFireAndForget(project);
public static event Func<SharpIdeProjectModel, Task> ProjectStoppedDebugging = _ => Task.CompletedTask;
public static void InvokeProjectStoppedDebugging(SharpIdeProjectModel project) => ProjectStoppedDebugging?.InvokeParallelFireAndForget(project);
public static event Func<SharpIdeProjectModel, Task> ProjectStartedRunning = _ => Task.CompletedTask; public static event Func<SharpIdeProjectModel, Task> ProjectStartedRunning = _ => Task.CompletedTask;
public static void InvokeProjectStartedRunning(SharpIdeProjectModel project) => ProjectStartedRunning?.InvokeParallelFireAndForget(project); public static void InvokeProjectStartedRunning(SharpIdeProjectModel project) => ProjectStartedRunning?.InvokeParallelFireAndForget(project);

View File

@@ -15,9 +15,8 @@ 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 private Debugger? _debugger; // TODO: Support multiple debuggers for multiple running projects
public async Task RunProject(SharpIdeProjectModel project) public async Task RunProject(SharpIdeProjectModel project, bool isDebug = false)
{ {
var isDebug = true;
Guard.Against.Null(project, nameof(project)); Guard.Against.Null(project, nameof(project));
Guard.Against.NullOrWhiteSpace(project.FilePath, nameof(project.FilePath), "Project file path cannot be null or empty."); Guard.Against.NullOrWhiteSpace(project.FilePath, nameof(project.FilePath), "Project file path cannot be null or empty.");
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding); await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
@@ -92,9 +91,16 @@ public class RunService
project.Running = true; project.Running = true;
project.OpenInRunPanel = true; project.OpenInRunPanel = true;
GlobalEvents.InvokeProjectsRunningChanged(); if (isDebug)
GlobalEvents.InvokeStartedRunningProject(); {
GlobalEvents.InvokeProjectStartedRunning(project); GlobalEvents.InvokeProjectStartedDebugging(project);
}
else
{
GlobalEvents.InvokeProjectsRunningChanged();
GlobalEvents.InvokeStartedRunningProject();
GlobalEvents.InvokeProjectStartedRunning(project);
}
project.InvokeProjectStartedRunning(); project.InvokeProjectStartedRunning();
await process.WaitForExitAsync().WaitAsync(project.RunningCancellationTokenSource.Token).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing); await process.WaitForExitAsync().WaitAsync(project.RunningCancellationTokenSource.Token).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
if (project.RunningCancellationTokenSource.IsCancellationRequested) if (project.RunningCancellationTokenSource.IsCancellationRequested)
@@ -107,8 +113,16 @@ public class RunService
project.RunningCancellationTokenSource.Dispose(); project.RunningCancellationTokenSource.Dispose();
project.RunningCancellationTokenSource = null; project.RunningCancellationTokenSource = null;
project.Running = false; project.Running = false;
GlobalEvents.InvokeProjectsRunningChanged(); if (isDebug)
GlobalEvents.InvokeProjectStoppedRunning(project); {
GlobalEvents.InvokeProjectStoppedDebugging(project);
}
else
{
GlobalEvents.InvokeProjectsRunningChanged();
GlobalEvents.InvokeProjectStoppedRunning(project);
}
project.InvokeProjectStoppedRunning(); project.InvokeProjectStoppedRunning();
Console.WriteLine("Project finished running"); Console.WriteLine("Project finished running");
@@ -133,6 +147,11 @@ public class RunService
await _debugger!.StepOver(threadId); await _debugger!.StepOver(threadId);
} }
public async Task GetInfoAtStopPoint()
{
await _debugger!.GetInfoAtStopPoint();
}
private string GetRunArguments(SharpIdeProjectModel project) private string GetRunArguments(SharpIdeProjectModel project)
{ {
var dllFullPath = ProjectEvaluation.GetOutputDllFullPath(project); var dllFullPath = ProjectEvaluation.GetOutputDllFullPath(project);

View File

@@ -13,27 +13,28 @@ public partial class DebugPanel : Control
[Export] [Export]
public Texture2D RunningIcon { get; set; } = null!; public Texture2D RunningIcon { get; set; } = null!;
private PackedScene _runPanelTabScene = GD.Load<PackedScene>("res://Features/Run/RunPanelTab.tscn"); private PackedScene _debugPanelTabScene = GD.Load<PackedScene>("res://Features/Debug_/DebugPanelTab.tscn");
public override void _Ready() public override void _Ready()
{ {
if (RunningIcon is null) throw new Exception("RunningIcon is null in DebugPanel");
_tabBar = GetNode<TabBar>("%TabBar"); _tabBar = GetNode<TabBar>("%TabBar");
_tabBar.ClearTabs(); _tabBar.ClearTabs();
//_tabBar.TabClosePressed //_tabBar.TabClosePressed
_tabBar.TabClicked += OnTabBarTabClicked; _tabBar.TabClicked += OnTabBarTabClicked;
_tabsPanel = GetNode<Panel>("%TabsPanel"); _tabsPanel = GetNode<Panel>("%TabsPanel");
GlobalEvents.ProjectStartedRunning += async projectModel => GlobalEvents.ProjectStartedDebugging += async projectModel =>
{ {
await this.InvokeAsync(() => ProjectStartedRunning(projectModel)); await this.InvokeAsync(() => ProjectStartedDebugging(projectModel));
}; };
GlobalEvents.ProjectStoppedRunning += async projectModel => GlobalEvents.ProjectStoppedDebugging += async projectModel =>
{ {
await this.InvokeAsync(() => ProjectStoppedRunning(projectModel)); await this.InvokeAsync(() => ProjectStoppedDebugging(projectModel));
}; };
} }
private void OnTabBarTabClicked(long idx) private void OnTabBarTabClicked(long idx)
{ {
var children = _tabsPanel.GetChildren().OfType<RunPanelTab>().ToList(); var children = _tabsPanel.GetChildren().OfType<DebugPanelTab>().ToList();
foreach (var child in children) foreach (var child in children)
{ {
child.Visible = false; child.Visible = false;
@@ -43,9 +44,9 @@ public partial class DebugPanel : Control
tab.Visible = true; tab.Visible = true;
} }
public void ProjectStartedRunning(SharpIdeProjectModel projectModel) public void ProjectStartedDebugging(SharpIdeProjectModel projectModel)
{ {
var existingRunPanelTab = _tabsPanel.GetChildren().OfType<RunPanelTab>().SingleOrDefault(s => s.Project == projectModel); var existingRunPanelTab = _tabsPanel.GetChildren().OfType<DebugPanelTab>().SingleOrDefault(s => s.Project == projectModel);
if (existingRunPanelTab != null) if (existingRunPanelTab != null)
{ {
_tabBar.SetTabIcon(existingRunPanelTab.TabBarTab, RunningIcon); _tabBar.SetTabIcon(existingRunPanelTab.TabBarTab, RunningIcon);
@@ -56,21 +57,21 @@ public partial class DebugPanel : Control
return; return;
} }
var runPanelTab = _runPanelTabScene.Instantiate<RunPanelTab>(); var debugPanelTab = _debugPanelTabScene.Instantiate<DebugPanelTab>();
runPanelTab.Project = projectModel; debugPanelTab.Project = projectModel;
_tabBar.AddTab(projectModel.Name); _tabBar.AddTab(projectModel.Name);
var tabIdx = _tabBar.GetTabCount() - 1; var tabIdx = _tabBar.GetTabCount() - 1;
runPanelTab.TabBarTab = tabIdx; debugPanelTab.TabBarTab = tabIdx;
_tabBar.SetTabIcon(runPanelTab.TabBarTab, RunningIcon); _tabBar.SetTabIcon(debugPanelTab.TabBarTab, RunningIcon);
_tabBar.CurrentTab = runPanelTab.TabBarTab; _tabBar.CurrentTab = debugPanelTab.TabBarTab;
_tabsPanel.AddChild(runPanelTab); _tabsPanel.AddChild(debugPanelTab);
OnTabBarTabClicked(runPanelTab.TabBarTab); OnTabBarTabClicked(debugPanelTab.TabBarTab);
runPanelTab.StartWritingFromProjectOutput(); debugPanelTab.StartWritingFromProjectOutput();
} }
public void ProjectStoppedRunning(SharpIdeProjectModel projectModel) public void ProjectStoppedDebugging(SharpIdeProjectModel projectModel)
{ {
var runPanelTab = _tabsPanel.GetChildren().OfType<RunPanelTab>().Single(s => s.Project == projectModel); var debugPanelTab = _tabsPanel.GetChildren().OfType<DebugPanelTab>().Single(s => s.Project == projectModel);
_tabBar.SetTabIcon(runPanelTab.TabBarTab, null); _tabBar.SetTabIcon(debugPanelTab.TabBarTab, null);
} }
} }

View File

@@ -1,6 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://dkjips8oudqou"] [gd_scene load_steps=3 format=3 uid="uid://dkjips8oudqou"]
[ext_resource type="Script" uid="uid://ddyadu54qitw4" path="res://Features/Debug_/DebugPanel.cs" id="1_h4rcc"] [ext_resource type="Script" uid="uid://ddyadu54qitw4" path="res://Features/Debug_/DebugPanel.cs" id="1_h4rcc"]
[ext_resource type="Texture2D" uid="uid://0digl54lqm6p" path="res://Features/Run/Resources/Running.svg" id="2_pub1e"]
[node name="DebugPanel" type="Control"] [node name="DebugPanel" type="Control"]
layout_mode = 3 layout_mode = 3
@@ -10,6 +11,7 @@ anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
script = ExtResource("1_h4rcc") script = ExtResource("1_h4rcc")
RunningIcon = ExtResource("2_pub1e")
[node name="Label" type="Label" parent="."] [node name="Label" type="Label" parent="."]
layout_mode = 1 layout_mode = 1

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" class="mud-icon-root mud-svg-icon mud-icon-size-medium" focusable="false" viewBox="0 0 24 24" aria-hidden="true" role="img" style="fill: rgb(11, 186, 131);">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/>
</svg>

After

Width:  |  Height:  |  Size: 672 B

View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c7cmou8hipsvc"
path="res://.godot/imported/Debug.svg-ae946e7dd0fbc448ad458ff70295702c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Features/Run/Resources/Debug.svg"
dest_files=["res://.godot/imported/Debug.svg-ae946e7dd0fbc448ad458ff70295702c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@@ -9,6 +9,7 @@ public partial class RunMenuItem : HBoxContainer
public SharpIdeProjectModel Project { get; set; } = null!; public SharpIdeProjectModel Project { get; set; } = null!;
private Label _label = null!; private Label _label = null!;
private Button _runButton = null!; private Button _runButton = null!;
private Button _debugButton = null!;
private Button _stopButton = null!; private Button _stopButton = null!;
public override void _Ready() public override void _Ready()
{ {
@@ -18,6 +19,8 @@ public partial class RunMenuItem : HBoxContainer
_runButton.Pressed += OnRunButtonPressed; _runButton.Pressed += OnRunButtonPressed;
_stopButton = GetNode<Button>("StopButton"); _stopButton = GetNode<Button>("StopButton");
_stopButton.Pressed += OnStopButtonPressed; _stopButton.Pressed += OnStopButtonPressed;
_debugButton = GetNode<Button>("DebugButton");
_debugButton.Pressed += OnDebugButtonPressed;
Project.ProjectStartedRunning += OnProjectStartedRunning; Project.ProjectStartedRunning += OnProjectStartedRunning;
Project.ProjectStoppedRunning += OnProjectStoppedRunning; Project.ProjectStoppedRunning += OnProjectStoppedRunning;
} }
@@ -27,6 +30,7 @@ public partial class RunMenuItem : HBoxContainer
await this.InvokeAsync(() => await this.InvokeAsync(() =>
{ {
_stopButton.Visible = false; _stopButton.Visible = false;
_debugButton.Visible = true;
_runButton.Visible = true; _runButton.Visible = true;
}); });
} }
@@ -36,6 +40,7 @@ public partial class RunMenuItem : HBoxContainer
await this.InvokeAsync(() => await this.InvokeAsync(() =>
{ {
_runButton.Visible = false; _runButton.Visible = false;
_debugButton.Visible = false;
_stopButton.Visible = true; _stopButton.Visible = true;
}); });
} }
@@ -50,4 +55,10 @@ public partial class RunMenuItem : HBoxContainer
GodotGlobalEvents.InvokeBottomPanelTabExternallySelected(BottomPanelType.Run); GodotGlobalEvents.InvokeBottomPanelTabExternallySelected(BottomPanelType.Run);
await Singletons.RunService.RunProject(Project).ConfigureAwait(false); await Singletons.RunService.RunProject(Project).ConfigureAwait(false);
} }
private async void OnDebugButtonPressed()
{
GodotGlobalEvents.InvokeBottomPanelTabExternallySelected(BottomPanelType.Debug);
await Singletons.RunService.RunProject(Project, true).ConfigureAwait(false);
}
} }

View File

@@ -1,7 +1,8 @@
[gd_scene load_steps=4 format=3 uid="uid://d2ewm2lajutpv"] [gd_scene load_steps=5 format=3 uid="uid://d2ewm2lajutpv"]
[ext_resource type="Script" uid="uid://btsnapfx0dlbb" path="res://Features/Run/RunMenuItem.cs" id="1_syj0f"] [ext_resource type="Script" uid="uid://btsnapfx0dlbb" path="res://Features/Run/RunMenuItem.cs" id="1_syj0f"]
[ext_resource type="Texture2D" uid="uid://bkty6563cthj8" path="res://Features/Run/Resources/Run.svg" id="2_hxkig"] [ext_resource type="Texture2D" uid="uid://bkty6563cthj8" path="res://Features/Run/Resources/Run.svg" id="2_hxkig"]
[ext_resource type="Texture2D" uid="uid://c7cmou8hipsvc" path="res://Features/Run/Resources/Debug.svg" id="3_cd138"]
[ext_resource type="Texture2D" uid="uid://debdmtqgw5dhf" path="res://Features/Run/Resources/Stop.svg" id="3_hxkig"] [ext_resource type="Texture2D" uid="uid://debdmtqgw5dhf" path="res://Features/Run/Resources/Stop.svg" id="3_hxkig"]
[node name="RunMenuItem" type="HBoxContainer"] [node name="RunMenuItem" type="HBoxContainer"]
@@ -22,6 +23,11 @@ layout_mode = 2
size_flags_vertical = 4 size_flags_vertical = 4
icon = ExtResource("2_hxkig") icon = ExtResource("2_hxkig")
[node name="DebugButton" type="Button" parent="."]
layout_mode = 2
size_flags_vertical = 4
icon = ExtResource("3_cd138")
[node name="StopButton" type="Button" parent="."] [node name="StopButton" type="Button" parent="."]
visible = false visible = false
layout_mode = 2 layout_mode = 2

View File

@@ -18,6 +18,7 @@ public partial class RunPanel : Control
private PackedScene _runPanelTabScene = GD.Load<PackedScene>("res://Features/Run/RunPanelTab.tscn"); private PackedScene _runPanelTabScene = GD.Load<PackedScene>("res://Features/Run/RunPanelTab.tscn");
public override void _Ready() public override void _Ready()
{ {
if (RunningIcon is null) throw new Exception("RunningIcon is null in RunPanel");
_tabBar = GetNode<TabBar>("%TabBar"); _tabBar = GetNode<TabBar>("%TabBar");
_tabBar.ClearTabs(); _tabBar.ClearTabs();
//_tabBar.TabClosePressed //_tabBar.TabClosePressed