From 1f2d770c5a8adff1a01c48ec9b5b91248d160903 Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Fri, 24 Oct 2025 18:55:36 +1000 Subject: [PATCH] code editor tab on file delete --- .../Features/FileWatching/FileChangedService.cs | 1 + .../Features/SolutionDiscovery/SharpIdeFile.cs | 1 + .../Features/CodeEditor/SharpIdeCodeEdit.cs | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/src/SharpIDE.Application/Features/FileWatching/FileChangedService.cs b/src/SharpIDE.Application/Features/FileWatching/FileChangedService.cs index 8388b1f..c8e18f1 100644 --- a/src/SharpIDE.Application/Features/FileWatching/FileChangedService.cs +++ b/src/SharpIDE.Application/Features/FileWatching/FileChangedService.cs @@ -53,6 +53,7 @@ public class FileChangedService(RoslynAnalysis roslynAnalysis, IdeOpenTabsFileMa public async Task SharpIdeFileRemoved(SharpIdeFile file) { + await file.FileDeleted.InvokeParallelAsync(); if (file.IsRoslynWorkspaceFile) { await HandleWorkspaceFileRemoved(file); diff --git a/src/SharpIDE.Application/Features/SolutionDiscovery/SharpIdeFile.cs b/src/SharpIDE.Application/Features/SolutionDiscovery/SharpIdeFile.cs index 1b32d4a..d152985 100644 --- a/src/SharpIDE.Application/Features/SolutionDiscovery/SharpIdeFile.cs +++ b/src/SharpIDE.Application/Features/SolutionDiscovery/SharpIdeFile.cs @@ -21,6 +21,7 @@ public class SharpIdeFile : ISharpIdeNode, IChildSharpIdeNode, IFileOrFolder public required bool SuppressDiskChangeEvents { get; set; } // probably has concurrency issues public required DateTimeOffset? LastIdeWriteTime { get; set; } public EventWrapper FileContentsChangedExternally { get; } = new((_) => Task.CompletedTask); + public EventWrapper FileDeleted { get; } = new(() => Task.CompletedTask); [SetsRequiredMembers] internal SharpIdeFile(string fullPath, string name, IExpandableSharpIdeNode parent, ConcurrentBag allFiles) diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs index 7c721e9..58be543 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs @@ -43,6 +43,7 @@ public partial class SharpIdeCodeEdit : CodeEdit private ImmutableArray _currentCodeActionsInPopup = []; private bool _fileChangingSuppressBreakpointToggleEvent; private bool _settingWholeDocumentTextSuppressLineEditsEvent; // A dodgy workaround - setting the whole document doesn't guarantee that the line count stayed the same etc. We are still going to have broken highlighting. TODO: Investigate getting minimal text change ranges, and change those ranges only + private bool _fileDeleted; [Inject] private readonly IdeOpenTabsFileManager _openTabsFileManager = null!; [Inject] private readonly RunService _runService = null!; @@ -73,6 +74,7 @@ public partial class SharpIdeCodeEdit : CodeEdit private async Task OnSolutionAltered() { if (_currentFile is null) return; + if (_fileDeleted) return; GD.Print($"[{_currentFile.Name}] Solution altered, updating project diagnostics for file"); await _solutionAlteredCts.CancelAsync(); _solutionAlteredCts = new CancellationTokenSource(); @@ -125,6 +127,7 @@ public partial class SharpIdeCodeEdit : CodeEdit public override void _ExitTree() { _currentFile?.FileContentsChangedExternally.Unsubscribe(OnFileChangedExternally); + _currentFile?.FileDeleted.Unsubscribe(OnFileDeleted); GlobalEvents.Instance.SolutionAltered.Unsubscribe(OnSolutionAltered); if (_currentFile is not null) _openTabsFileManager.CloseFile(_currentFile); } @@ -307,6 +310,7 @@ public partial class SharpIdeCodeEdit : CodeEdit private async Task OnFileChangedExternally(SharpIdeFileLinePosition? linePosition) { + if (_fileDeleted) return; // We have QueueFree'd this node, however it may not have been freed yet. var fileContents = await _openTabsFileManager.GetFileTextAsync(_currentFile); await this.InvokeAsync(() => { @@ -340,6 +344,7 @@ public partial class SharpIdeCodeEdit : CodeEdit _currentFile = file; var readFileTask = _openTabsFileManager.GetFileTextAsync(file); _currentFile.FileContentsChangedExternally.Subscribe(OnFileChangedExternally); + _currentFile.FileDeleted.Subscribe(OnFileDeleted); var syntaxHighlighting = _roslynAnalysis.GetDocumentSyntaxHighlighting(_currentFile); var razorSyntaxHighlighting = _roslynAnalysis.GetRazorDocumentSyntaxHighlighting(_currentFile); @@ -364,6 +369,12 @@ public partial class SharpIdeCodeEdit : CodeEdit }); } + private async Task OnFileDeleted() + { + _fileDeleted = true; + QueueFree(); + } + public void UnderlineRange(int line, int caretStartCol, int caretEndCol, Color color, float thickness = 1.5f) { if (line < 0 || line >= GetLineCount())