From 207b8fe3c85124854bee3899a636c3968563f802 Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Mon, 13 Oct 2025 19:41:56 +1000 Subject: [PATCH] Add search files popup --- .../Features/Search/FindFilesSearchResult.cs | 9 +++ ...chResult.cs => FindInFilesSearchResult.cs} | 2 +- .../Features/Search/SearchService.cs | 35 ++++++++-- .../SearchAllFilesResultComponent.cs | 43 ++++++++++++ .../SearchAllFilesResultComponent.cs.uid | 1 + .../SearchAllFilesResultComponent.tscn | 60 ++++++++++++++++ .../SearchAllFiles/SearchAllFilesWindow.cs | 56 +++++++++++++++ .../SearchAllFilesWindow.cs.uid | 1 + .../SearchAllFiles/SearchAllFilesWindow.tscn | 69 +++++++++++++++++++ .../SearchInFiles/SearchResultComponent.cs | 4 +- .../Search/SearchInFiles/SearchWindow.tscn | 2 +- src/SharpIDE.Godot/IdeRoot.cs | 8 +++ src/SharpIDE.Godot/IdeRoot.tscn | 7 +- src/SharpIDE.Godot/InputStringNames.cs | 1 + src/SharpIDE.Godot/project.godot | 5 ++ 15 files changed, 294 insertions(+), 9 deletions(-) create mode 100644 src/SharpIDE.Application/Features/Search/FindFilesSearchResult.cs rename src/SharpIDE.Application/Features/Search/{SearchResult.cs => FindInFilesSearchResult.cs} (88%) create mode 100644 src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesResultComponent.cs create mode 100644 src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesResultComponent.cs.uid create mode 100644 src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesResultComponent.tscn create mode 100644 src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesWindow.cs create mode 100644 src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesWindow.cs.uid create mode 100644 src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesWindow.tscn diff --git a/src/SharpIDE.Application/Features/Search/FindFilesSearchResult.cs b/src/SharpIDE.Application/Features/Search/FindFilesSearchResult.cs new file mode 100644 index 0000000..a8a696f --- /dev/null +++ b/src/SharpIDE.Application/Features/Search/FindFilesSearchResult.cs @@ -0,0 +1,9 @@ +using OneOf; +using SharpIDE.Application.Features.SolutionDiscovery; + +namespace SharpIDE.Application.Features.Search; + +public class FindFilesSearchResult +{ + public required SharpIdeFile File { get; set; } +} diff --git a/src/SharpIDE.Application/Features/Search/SearchResult.cs b/src/SharpIDE.Application/Features/Search/FindInFilesSearchResult.cs similarity index 88% rename from src/SharpIDE.Application/Features/Search/SearchResult.cs rename to src/SharpIDE.Application/Features/Search/FindInFilesSearchResult.cs index 9bd86cd..b0b9e3e 100644 --- a/src/SharpIDE.Application/Features/Search/SearchResult.cs +++ b/src/SharpIDE.Application/Features/Search/FindInFilesSearchResult.cs @@ -2,7 +2,7 @@ namespace SharpIDE.Application.Features.Search; -public class SearchResult +public class FindInFilesSearchResult { public required SharpIdeFile File { get; set; } public required int Line { get; set; } diff --git a/src/SharpIDE.Application/Features/Search/SearchService.cs b/src/SharpIDE.Application/Features/Search/SearchService.cs index aa546b4..6ab9391 100644 --- a/src/SharpIDE.Application/Features/Search/SearchService.cs +++ b/src/SharpIDE.Application/Features/Search/SearchService.cs @@ -7,16 +7,16 @@ namespace SharpIDE.Application.Features.Search; public static class SearchService { - public static async Task> FindInFiles(SharpIdeSolutionModel solutionModel, string searchTerm, CancellationToken cancellationToken) + public static async Task> FindInFiles(SharpIdeSolutionModel solutionModel, string searchTerm, CancellationToken cancellationToken) { - if (searchTerm.Length < 4) + if (searchTerm.Length < 4) // TODO: halt search once 100 results are found, and remove this restriction { return []; } var timer = Stopwatch.StartNew(); var files = solutionModel.AllFiles; - ConcurrentBag results = []; + ConcurrentBag results = []; await Parallel.ForEachAsync(files, cancellationToken, async (file, ct) => { if (cancellationToken.IsCancellationRequested) return; @@ -25,7 +25,7 @@ public static class SearchService if (cancellationToken.IsCancellationRequested) return; if (line.Contains(searchTerm, StringComparison.OrdinalIgnoreCase)) { - results.Add(new SearchResult + results.Add(new FindInFilesSearchResult { File = file, Line = index + 1, @@ -40,4 +40,31 @@ public static class SearchService Console.WriteLine($"Search completed in {timer.ElapsedMilliseconds} ms. Found {results.Count} results. {(cancellationToken.IsCancellationRequested ? "(Cancelled)" : "")}"); return results.ToList(); } + + public static async Task> FindFiles(SharpIdeSolutionModel solutionModel, string searchTerm, CancellationToken cancellationToken) + { + if (searchTerm.Length < 2) // TODO: halt search once 100 results are found, and remove this restriction + { + return []; + } + + var timer = Stopwatch.StartNew(); + var files = solutionModel.AllFiles; + ConcurrentBag results = []; + await Parallel.ForEachAsync(files, cancellationToken, async (file, ct) => + { + if (cancellationToken.IsCancellationRequested) return; + if (file.Name.Contains(searchTerm, StringComparison.OrdinalIgnoreCase)) + { + results.Add(new FindFilesSearchResult + { + File = file + }); + } + } + ).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing); + timer.Stop(); + Console.WriteLine($"File search completed in {timer.ElapsedMilliseconds} ms. Found {results.Count} results. {(cancellationToken.IsCancellationRequested ? "(Cancelled)" : "")}"); + return results.ToList(); + } } diff --git a/src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesResultComponent.cs b/src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesResultComponent.cs new file mode 100644 index 0000000..d7306f8 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Search/SearchAllFiles/SearchAllFilesResultComponent.cs @@ -0,0 +1,43 @@ +using Godot; +using SharpIDE.Application.Features.Analysis; +using SharpIDE.Application.Features.Search; + +namespace SharpIDE.Godot.Features.Search.SearchAllFiles; + +public partial class SearchAllFilesResultComponent : MarginContainer +{ + private TextureRect _textureRect = null!; + private Label _fileNameLabel = null!; + private Label _filePathLabel = null!; + private Button _button = null!; + + private Texture2D _csharpFileIcon = ResourceLoader.Load("uid://do0edciarrnp0"); + private Texture2D _folderIcon = ResourceLoader.Load("uid://xc8srvqwlwng"); + + public SearchAllFilesWindow ParentSearchAllFilesWindow { get; set; } = null!; + public FindFilesSearchResult Result { get; set; } = null!; + + public override void _Ready() + { + _button = GetNode