Add IdeFileChangeHandler

This commit is contained in:
Matt Parker
2025-10-17 20:05:04 +10:00
parent 4652c66269
commit e3b18c56f2
6 changed files with 47 additions and 15 deletions

View File

@@ -1,4 +1,5 @@
using SharpIDE.Application.Features.Debugging;
using SharpIDE.Application.Features.SolutionDiscovery;
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
namespace SharpIDE.Application.Features.Events;
@@ -13,6 +14,8 @@ public class GlobalEvents
public EventWrapper<SharpIdeProjectModel, Task> ProjectStartedRunning { get; } = new(_ => Task.CompletedTask);
public EventWrapper<SharpIdeProjectModel, Task> ProjectStoppedRunning { get; } = new(_ => Task.CompletedTask);
public EventWrapper<ExecutionStopInfo, Task> DebuggerExecutionStopped { get; } = new(_ => Task.CompletedTask);
/// Meaning saved/persisted to disk
public EventWrapper<SharpIdeFile, Task> IdeFileChanged { get; } = new(_ => Task.CompletedTask);
public FileSystemWatcherInternal FileSystemWatcherInternal { get; } = new();
}

View File

@@ -0,0 +1,35 @@
using SharpIDE.Application.Features.Analysis;
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.FileWatching;
public class IdeFileChangeHandler
{
public SharpIdeSolutionModel SolutionModel { get; set; } = null!;
public IdeFileChangeHandler()
{
GlobalEvents.Instance.IdeFileChanged.Subscribe(HandleIdeFileChanged);
}
private async Task HandleIdeFileChanged(SharpIdeFile file)
{
await file.FileContentsChangedExternallyFromDisk.InvokeParallelAsync();
if (file.IsCsprojFile)
{
await HandleCsprojChanged(file);
}
}
private async Task HandleCsprojChanged(SharpIdeFile file)
{
var project = SolutionModel.AllProjects.SingleOrDefault(p => p.FilePath == file.Path);
if (project is null) return;
await ProjectEvaluation.ReloadProject(file.Path);
await RoslynAnalysis.ReloadProject(project);
await RoslynAnalysis.UpdateSolutionDiagnostics();
}
}

View File

@@ -23,24 +23,15 @@ public class IdeFileExternalChangeHandler
var now = DateTimeOffset.Now;
if (now - sharpIdeFile.LastIdeWriteTime.Value < TimeSpan.FromMilliseconds(300))
{
Console.WriteLine($"IdeFileChangeHandler: Ignored - {filePath}");
Console.WriteLine($"IdeFileExternalChangeHandler: Ignored - {filePath}");
return;
}
}
Console.WriteLine($"IdeFileChangeHandler: Changed - {filePath}");
await sharpIdeFile.FileContentsChangedExternallyFromDisk.InvokeParallelAsync();
if (sharpIdeFile.IsCsprojFile)
Console.WriteLine($"IdeFileExternalChangeHandler: Changed - {filePath}");
var file = SolutionModel.AllFiles.SingleOrDefault(f => f.Path == filePath);
if (file is not null)
{
await HandleCsprojChanged(filePath);
await GlobalEvents.Instance.IdeFileChanged.InvokeParallelAsync(file);
}
}
private async Task HandleCsprojChanged(string filePath)
{
var project = SolutionModel.AllProjects.SingleOrDefault(p => p.FilePath == filePath);
if (project is null) return;
await ProjectEvaluation.ReloadProject(filePath);
await RoslynAnalysis.ReloadProject(project);
await RoslynAnalysis.UpdateSolutionDiagnostics();
}
}

View File

@@ -12,13 +12,14 @@ public class SharpIdeFile : ISharpIdeNode, IChildSharpIdeNode
public required string Path { get; set; }
public required string Name { get; set; }
public bool IsRazorFile => Path.EndsWith(".razor", StringComparison.OrdinalIgnoreCase);
public bool IsCsprojFile => Path.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase);
public bool IsCshtmlFile => Path.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase);
public bool IsCsharpFile => Path.EndsWith(".cs", StringComparison.OrdinalIgnoreCase);
public bool IsRoslynWorkspaceFile => IsCsharpFile || IsRazorFile || IsCshtmlFile;
public required ReactiveProperty<bool> IsDirty { get; init; }
public required bool SuppressDiskChangeEvents { get; set; } // probably has concurrency issues
public required DateTimeOffset? LastIdeWriteTime { get; set; }
public EventWrapper<Task> FileContentsChangedExternallyFromDisk { get; } = new(() => Task.CompletedTask);
public EventWrapper<Task> FileContentsChangedExternallyFromDisk { get; } = new(() => Task.CompletedTask); // Refactor to global event - this currently doesn't handle updating un-opened files
public EventWrapper<Task> FileContentsChangedExternally { get; } = new(() => Task.CompletedTask);
[SetsRequiredMembers]