search v2
This commit is contained in:
10
src/SharpIDE.Application/Features/Search/SearchResult.cs
Normal file
10
src/SharpIDE.Application/Features/Search/SearchResult.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||
|
||||
namespace SharpIDE.Application.Features.Search;
|
||||
|
||||
public class SearchResult
|
||||
{
|
||||
public required SharpIdeFile File { get; set; }
|
||||
public required int LineNumber { get; set; }
|
||||
public required string LineText { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||
|
||||
@@ -6,24 +7,34 @@ namespace SharpIDE.Application.Features.Search;
|
||||
|
||||
public static class SearchService
|
||||
{
|
||||
public static async Task FindInFiles(SharpIdeSolutionModel solutionModel, string searchTerm)
|
||||
public static async Task<List<SearchResult>> FindInFiles(SharpIdeSolutionModel solutionModel, string searchTerm)
|
||||
{
|
||||
if (searchTerm.Length < 4)
|
||||
{
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
var timer = Stopwatch.StartNew();
|
||||
var files = solutionModel.AllFiles;
|
||||
ConcurrentBag<string> results = [];
|
||||
ConcurrentBag<SearchResult> results = [];
|
||||
await Parallel.ForEachAsync(files, async (file, ct) =>
|
||||
{
|
||||
await foreach (var (index, line) in File.ReadLinesAsync(file.Path, ct).Index().WithCancellation(ct))
|
||||
{
|
||||
if (line.Contains(searchTerm, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
results.Add($"{file.Path} (Line {index + 1}): {line.Trim()}");
|
||||
results.Add(new SearchResult
|
||||
{
|
||||
File = file,
|
||||
LineNumber = index + 1,
|
||||
LineText = line.Trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
timer.Stop();
|
||||
Console.WriteLine($"Search completed in {timer.ElapsedMilliseconds} ms. Found {results.Count} results.");
|
||||
return results.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
29
src/SharpIDE.Godot/Features/Search/SearchResultComponent.cs
Normal file
29
src/SharpIDE.Godot/Features/Search/SearchResultComponent.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Godot;
|
||||
using SharpIDE.Application.Features.Search;
|
||||
|
||||
namespace SharpIDE.Godot.Features.Search;
|
||||
|
||||
public partial class SearchResultComponent : MarginContainer
|
||||
{
|
||||
private Label _matchingLineLabel = null!;
|
||||
private Label _fileNameLabel = null!;
|
||||
private Label _lineNumberLabel = null!;
|
||||
|
||||
public SearchResult Result { get; set; } = null!;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_matchingLineLabel = GetNode<Label>("%MatchingLineLabel");
|
||||
_fileNameLabel = GetNode<Label>("%FileNameLabel");
|
||||
_lineNumberLabel = GetNode<Label>("%LineNumberLabel");
|
||||
SetValue(Result);
|
||||
}
|
||||
|
||||
private void SetValue(SearchResult result)
|
||||
{
|
||||
if (result is null) return;
|
||||
_matchingLineLabel.Text = result.LineText;
|
||||
_fileNameLabel.Text = result.File.Name;
|
||||
_lineNumberLabel.Text = result.LineNumber.ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://6sdu34jtdrux
|
||||
@@ -0,0 +1,30 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://d358tex0duum8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://6sdu34jtdrux" path="res://Features/Search/SearchResultComponent.cs" id="1_6ov2c"]
|
||||
|
||||
[node name="SearchResultComponent" type="MarginContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_bottom = 23.0
|
||||
grow_horizontal = 2
|
||||
script = ExtResource("1_6ov2c")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MatchingLineLabel" type="Label" parent="HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Line matching search result"
|
||||
text_overrun_behavior = 3
|
||||
|
||||
[node name="FileNameLabel" type="Label" parent="HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "FileName.cs"
|
||||
|
||||
[node name="LineNumberLabel" type="Label" parent="HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "24"
|
||||
@@ -1,8 +1,41 @@
|
||||
using Godot;
|
||||
using SharpIDE.Application.Features.Search;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||
|
||||
namespace SharpIDE.Godot.Features.Search;
|
||||
|
||||
public partial class SearchWindow : PopupPanel
|
||||
{
|
||||
private LineEdit _lineEdit = null!;
|
||||
private VBoxContainer _searchResultsContainer = null!;
|
||||
public SharpIdeSolutionModel Solution { get; set; } = null!;
|
||||
private readonly PackedScene _searchResultEntryScene = ResourceLoader.Load<PackedScene>("res://Features/Search/SearchResultComponent.tscn");
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_lineEdit = GetNode<LineEdit>("%SearchLineEdit");
|
||||
_searchResultsContainer = GetNode<VBoxContainer>("%SearchResultsVBoxContainer");
|
||||
_lineEdit.TextChanged += OnTextChanged;
|
||||
}
|
||||
|
||||
private async void OnTextChanged(string newText)
|
||||
{
|
||||
GD.Print("Search text changed");
|
||||
await Task.GodotRun(() => Search(newText));
|
||||
}
|
||||
|
||||
private async Task Search(string text)
|
||||
{
|
||||
var result = await SearchService.FindInFiles(Solution, text);
|
||||
await this.InvokeAsync(() =>
|
||||
{
|
||||
_searchResultsContainer.GetChildren().ToList().ForEach(s => s.QueueFree());
|
||||
foreach (var searchResult in result)
|
||||
{
|
||||
var result = _searchResultEntryScene.Instantiate<SearchResultComponent>();
|
||||
result.Result = searchResult;
|
||||
_searchResultsContainer.AddChild(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://8lk0qj233a7p"]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://8lk0qj233a7p"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bah6tmifl41ce" path="res://Features/Search/SearchWindow.cs" id="1_ft33p"]
|
||||
[ext_resource type="PackedScene" uid="uid://d358tex0duum8" path="res://Features/Search/SearchResultComponent.tscn" id="2_cuaw5"]
|
||||
|
||||
[node name="SearchWindow" type="PopupPanel"]
|
||||
oversampling_override = 1.0
|
||||
@@ -40,6 +41,19 @@ layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = " 30 matches in 5 files"
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="MarginContainer/VBoxContainer"]
|
||||
[node name="SearchLineEdit" type="LineEdit" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Test"
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="SearchResultsVBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="SearchResultComponent" parent="MarginContainer/VBoxContainer/ScrollContainer/SearchResultsVBoxContainer" instance=ExtResource("2_cuaw5")]
|
||||
layout_mode = 2
|
||||
|
||||
@@ -80,6 +80,7 @@ public partial class IdeRoot : Control
|
||||
_solutionExplorerPanel.SolutionModel = solutionModel;
|
||||
_codeEditorPanel.Solution = solutionModel;
|
||||
_bottomPanelManager.Solution = solutionModel;
|
||||
_searchWindow.Solution = solutionModel;
|
||||
Callable.From(_solutionExplorerPanel.RepopulateTree).CallDeferred();
|
||||
RoslynAnalysis.StartSolutionAnalysis(solutionModel);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user