From ea5bb6ac53b4712baf57ac2620cf0e7b986149a6 Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Fri, 8 Aug 2025 01:26:23 +1000 Subject: [PATCH] implement end running project --- .../Features/Run/RunService.cs | 23 +++++++++++++++++-- .../VsPersistence/SharpIdeModels.cs | 1 + .../SharpIDE.Application.csproj | 2 +- .../Components/RunPopover.razor | 2 +- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/SharpIDE.Application/Features/Run/RunService.cs b/src/SharpIDE.Application/Features/Run/RunService.cs index c7bec2c..bf30a47 100644 --- a/src/SharpIDE.Application/Features/Run/RunService.cs +++ b/src/SharpIDE.Application/Features/Run/RunService.cs @@ -20,6 +20,9 @@ public class RunService var semaphoreSlim = _projectLocks.GetOrAdd(project, new SemaphoreSlim(1, 1)); var waitResult = await semaphoreSlim.WaitAsync(0); if (waitResult is false) throw new InvalidOperationException($"Project {project.Name} is already running."); + if (project.RunningCancellationTokenSource is not null) throw new InvalidOperationException($"Project {project.Name} is already running with a cancellation token source."); + + project.RunningCancellationTokenSource = new CancellationTokenSource(); try { var processStartInfo = new ProcessStartInfo2 @@ -48,15 +51,31 @@ public class RunService project.Running = true; GlobalEvents.InvokeProjectsRunningChanged(); - await process.WaitForExitAsync(); + await process.WaitForExitAsync().WaitAsync(project.RunningCancellationTokenSource.Token).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing); + if (project.RunningCancellationTokenSource.IsCancellationRequested) + { + process.End(); + await process.WaitForExitAsync(); + } project.Running = false; GlobalEvents.InvokeProjectsRunningChanged(); - Console.WriteLine("Project ran successfully."); + Console.WriteLine("Project finished running"); } finally { semaphoreSlim.Release(); } } + + public async Task CancelRunningProject(SharpIdeProjectModel project) + { + Guard.Against.Null(project, nameof(project)); + if (project.Running is false) throw new InvalidOperationException($"Project {project.Name} is not running."); + if (project.RunningCancellationTokenSource is null) throw new InvalidOperationException($"Project {project.Name} does not have a running cancellation token source."); + + await project.RunningCancellationTokenSource.CancelAsync(); + project.RunningCancellationTokenSource.Dispose(); + project.RunningCancellationTokenSource = null; + } } diff --git a/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/SharpIdeModels.cs b/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/SharpIdeModels.cs index 609f3cd..8e8af4b 100644 --- a/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/SharpIdeModels.cs +++ b/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/SharpIdeModels.cs @@ -28,6 +28,7 @@ public class SharpIdeProjectModel : ISharpIdeNode public required List Files { get; set; } public bool Expanded { get; set; } public bool Running { get; set; } + public CancellationTokenSource? RunningCancellationTokenSource { get; set; } public required Task MsBuildEvaluationProjectTask { get; set; } public Project MsBuildEvaluationProject => MsBuildEvaluationProjectTask.IsCompletedSuccessfully diff --git a/src/SharpIDE.Application/SharpIDE.Application.csproj b/src/SharpIDE.Application/SharpIDE.Application.csproj index a360d28..bb9f708 100644 --- a/src/SharpIDE.Application/SharpIDE.Application.csproj +++ b/src/SharpIDE.Application/SharpIDE.Application.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/SharpIDE.Photino/Components/RunPopover.razor b/src/SharpIDE.Photino/Components/RunPopover.razor index b5ac7d5..5bd3ee9 100644 --- a/src/SharpIDE.Photino/Components/RunPopover.razor +++ b/src/SharpIDE.Photino/Components/RunPopover.razor @@ -23,7 +23,7 @@ @if (project.Running) { - + }