From 4d67503e1377a72e078dc6794b1e2547cda4237f Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:47:00 +1000 Subject: [PATCH] better file syncing (poorly) --- .../FilePersistence/IdeOpenTabsFileManager.cs | 18 ++++++++++++------ .../FileWatching/IdeFileSavedToDiskHandler.cs | 11 +++++++++++ .../Features/CodeEditor/SharpIdeCodeEdit.cs | 4 ++-- src/SharpIDE.Godot/IdeRoot.cs | 3 ++- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/SharpIDE.Application/Features/FilePersistence/IdeOpenTabsFileManager.cs b/src/SharpIDE.Application/Features/FilePersistence/IdeOpenTabsFileManager.cs index db9a507..3e926a3 100644 --- a/src/SharpIDE.Application/Features/FilePersistence/IdeOpenTabsFileManager.cs +++ b/src/SharpIDE.Application/Features/FilePersistence/IdeOpenTabsFileManager.cs @@ -9,6 +9,7 @@ namespace SharpIDE.Application.Features.FilePersistence; /// Holds the in memory copies of files, and manages saving/loading them to/from disk. public class IdeOpenTabsFileManager { + public static IdeOpenTabsFileManager Instance { get; set; } = null!; private ConcurrentDictionary>> _openFiles = new(); /// Implicitly 'opens' a file if not already open, and returns the text. @@ -46,12 +47,17 @@ public class IdeOpenTabsFileManager var newTextTaskLazy = new Lazy>(() => File.ReadAllTextAsync(file.Path)); _openFiles[file] = newTextTaskLazy; var textTask = newTextTaskLazy.Value; - if (file.IsRoslynWorkspaceFile) - { - var text = await textTask; - await RoslynAnalysis.UpdateDocument(file, text); - GlobalEvents.Instance.SolutionAltered.InvokeParallelFireAndForget(); - } + + } + + public async Task ReloadFileFromDiskIfOpenInEditor(SharpIdeFile file) + { + if (!_openFiles.ContainsKey(file)) return false; + + var newTextTaskLazy = new Lazy>(() => File.ReadAllTextAsync(file.Path)); + _openFiles[file] = newTextTaskLazy; + //var textTask = newTextTaskLazy.Value; + return true; } public async Task SaveFileAsync(SharpIdeFile file) diff --git a/src/SharpIDE.Application/Features/FileWatching/IdeFileSavedToDiskHandler.cs b/src/SharpIDE.Application/Features/FileWatching/IdeFileSavedToDiskHandler.cs index 7ed3472..8d8dfbc 100644 --- a/src/SharpIDE.Application/Features/FileWatching/IdeFileSavedToDiskHandler.cs +++ b/src/SharpIDE.Application/Features/FileWatching/IdeFileSavedToDiskHandler.cs @@ -1,6 +1,7 @@ using SharpIDE.Application.Features.Analysis; using SharpIDE.Application.Features.Evaluation; using SharpIDE.Application.Features.Events; +using SharpIDE.Application.Features.FilePersistence; using SharpIDE.Application.Features.SolutionDiscovery; using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; @@ -38,6 +39,16 @@ public class IdeFileSavedToDiskHandler private async Task HandleWorkspaceFileChanged(SharpIdeFile file) { + // TODO: Don't reload from disk if we raised the change event ourselves (e.g. save from IDE). Cleanup this whole disaster + var wasOpenAndUpdated = await IdeOpenTabsFileManager.Instance.ReloadFileFromDiskIfOpenInEditor(file); + if (file.IsRoslynWorkspaceFile) + { + var fileText = wasOpenAndUpdated ? + await IdeOpenTabsFileManager.Instance.GetFileTextAsync(file) : + await File.ReadAllTextAsync(file.Path); + await RoslynAnalysis.UpdateDocument(file, fileText); + GlobalEvents.Instance.SolutionAltered.InvokeParallelFireAndForget(); + } await RoslynAnalysis.UpdateSolutionDiagnostics(); } } diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs index 670158e..734a50f 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs @@ -60,6 +60,8 @@ public partial class SharpIdeCodeEdit : CodeEdit { if (_currentFile is null) return; GD.Print("Solution altered, updating project diagnostics for current file"); + var documentDiagnostics = await RoslynAnalysis.GetDocumentDiagnostics(_currentFile); + await this.InvokeAsync(() => SetDiagnostics(documentDiagnostics)); var projectDiagnostics = await RoslynAnalysis.GetProjectDiagnosticsForFile(_currentFile); await this.InvokeAsync(() => SetProjectDiagnostics(projectDiagnostics)); } @@ -308,7 +310,6 @@ public partial class SharpIdeCodeEdit : CodeEdit var syntaxHighlighting = RoslynAnalysis.GetDocumentSyntaxHighlighting(_currentFile); var razorSyntaxHighlighting = RoslynAnalysis.GetRazorDocumentSyntaxHighlighting(_currentFile); var diagnostics = RoslynAnalysis.GetDocumentDiagnostics(_currentFile); - var slnDiagnostics = RoslynAnalysis.UpdateSolutionDiagnostics(); await Task.WhenAll(syntaxHighlighting, razorSyntaxHighlighting, diagnostics); Callable.From(() => { @@ -323,7 +324,6 @@ public partial class SharpIdeCodeEdit : CodeEdit SetVScroll(vScroll); EndComplexOperation(); }).CallDeferred(); - await slnDiagnostics; } public void SetFileLinePosition(SharpIdeFileLinePosition fileLinePosition) diff --git a/src/SharpIDE.Godot/IdeRoot.cs b/src/SharpIDE.Godot/IdeRoot.cs index 6becd22..6646339 100644 --- a/src/SharpIDE.Godot/IdeRoot.cs +++ b/src/SharpIDE.Godot/IdeRoot.cs @@ -45,11 +45,12 @@ public partial class IdeRoot : Control GodotGlobalEvents.Instance = new GodotGlobalEvents(); GlobalEvents.Instance = new GlobalEvents(); BuildService.Instance = new BuildService(); // TODO: Sort out this mess with singletons, especially access across Application services + IdeOpenTabsFileManager.Instance = new IdeOpenTabsFileManager(); Singletons.RunService = new RunService(); Singletons.BuildService = BuildService.Instance; Singletons.FileWatcher?.Dispose(); Singletons.FileWatcher = new IdeFileWatcher(); - Singletons.OpenTabsFileManager = new IdeOpenTabsFileManager(); + Singletons.OpenTabsFileManager = IdeOpenTabsFileManager.Instance; Singletons.FileExternalChangeHandler = new IdeFileExternalChangeHandler(); Singletons.FileSavedToDiskHandler = new IdeFileSavedToDiskHandler(); }