cancel previous searches

This commit is contained in:
Matt Parker
2025-09-24 23:40:43 +10:00
parent 96dd10d296
commit 21dd4aa199
2 changed files with 19 additions and 12 deletions

View File

@@ -7,7 +7,7 @@ namespace SharpIDE.Application.Features.Search;
public static class SearchService public static class SearchService
{ {
public static async Task<List<SearchResult>> FindInFiles(SharpIdeSolutionModel solutionModel, string searchTerm) public static async Task<List<SearchResult>> FindInFiles(SharpIdeSolutionModel solutionModel, string searchTerm, CancellationToken cancellationToken)
{ {
if (searchTerm.Length < 4) if (searchTerm.Length < 4)
{ {
@@ -17,10 +17,12 @@ public static class SearchService
var timer = Stopwatch.StartNew(); var timer = Stopwatch.StartNew();
var files = solutionModel.AllFiles; var files = solutionModel.AllFiles;
ConcurrentBag<SearchResult> results = []; ConcurrentBag<SearchResult> results = [];
await Parallel.ForEachAsync(files, async (file, ct) => await Parallel.ForEachAsync(files, cancellationToken, async (file, ct) =>
{ {
if (cancellationToken.IsCancellationRequested) return;
await foreach (var (index, line) in File.ReadLinesAsync(file.Path, ct).Index().WithCancellation(ct)) await foreach (var (index, line) in File.ReadLinesAsync(file.Path, ct).Index().WithCancellation(ct))
{ {
if (cancellationToken.IsCancellationRequested) return;
if (line.Contains(searchTerm, StringComparison.OrdinalIgnoreCase)) if (line.Contains(searchTerm, StringComparison.OrdinalIgnoreCase))
{ {
results.Add(new SearchResult results.Add(new SearchResult
@@ -32,9 +34,9 @@ public static class SearchService
} }
} }
} }
); ).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
timer.Stop(); timer.Stop();
Console.WriteLine($"Search completed in {timer.ElapsedMilliseconds} ms. Found {results.Count} results."); Console.WriteLine($"Search completed in {timer.ElapsedMilliseconds} ms. Found {results.Count} results. {(cancellationToken.IsCancellationRequested ? "(Cancelled)" : "")}");
return results.ToList(); return results.ToList();
} }
} }

View File

@@ -10,6 +10,8 @@ public partial class SearchWindow : PopupPanel
private VBoxContainer _searchResultsContainer = null!; private VBoxContainer _searchResultsContainer = null!;
public SharpIdeSolutionModel Solution { get; set; } = null!; public SharpIdeSolutionModel Solution { get; set; } = null!;
private readonly PackedScene _searchResultEntryScene = ResourceLoader.Load<PackedScene>("res://Features/Search/SearchResultComponent.tscn"); private readonly PackedScene _searchResultEntryScene = ResourceLoader.Load<PackedScene>("res://Features/Search/SearchResultComponent.tscn");
private CancellationTokenSource _cancellationTokenSource = new();
public override void _Ready() public override void _Ready()
{ {
@@ -20,22 +22,25 @@ public partial class SearchWindow : PopupPanel
private async void OnTextChanged(string newText) private async void OnTextChanged(string newText)
{ {
GD.Print("Search text changed"); await _cancellationTokenSource.CancelAsync();
await Task.GodotRun(() => Search(newText)); // TODO: Investigate allocations
_cancellationTokenSource = new CancellationTokenSource();
var token = _cancellationTokenSource.Token;
await Task.GodotRun(() => Search(newText, token));
} }
private async Task Search(string text) private async Task Search(string text, CancellationToken cancellationToken)
{ {
var result = await SearchService.FindInFiles(Solution, text); var result = await SearchService.FindInFiles(Solution, text, cancellationToken);
await this.InvokeAsync(() => await this.InvokeAsync(() =>
{ {
_searchResultsContainer.GetChildren().ToList().ForEach(s => s.QueueFree()); _searchResultsContainer.GetChildren().ToList().ForEach(s => s.QueueFree());
foreach (var searchResult in result) foreach (var searchResult in result)
{ {
var result = _searchResultEntryScene.Instantiate<SearchResultComponent>(); var resultNode = _searchResultEntryScene.Instantiate<SearchResultComponent>();
result.Result = searchResult; resultNode.Result = searchResult;
_searchResultsContainer.AddChild(result); _searchResultsContainer.AddChild(resultNode);
} }
}); });
} }
} }