From 6a95ea892c3ed680e02a2540ab25bc6c1a1e8819 Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:08:35 +1000 Subject: [PATCH] search modal v1 --- .../Features/Search/SearchService.cs | 29 ++++++++++++ .../Features/Search/SearchWindow.cs | 8 ++++ .../Features/Search/SearchWindow.cs.uid | 1 + .../Features/Search/SearchWindow.tscn | 45 +++++++++++++++++++ src/SharpIDE.Godot/IdeRoot.cs | 11 +++++ src/SharpIDE.Godot/IdeRoot.tscn | 7 ++- src/SharpIDE.Godot/InputStringNames.cs | 1 + 7 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/SharpIDE.Application/Features/Search/SearchService.cs create mode 100644 src/SharpIDE.Godot/Features/Search/SearchWindow.cs create mode 100644 src/SharpIDE.Godot/Features/Search/SearchWindow.cs.uid create mode 100644 src/SharpIDE.Godot/Features/Search/SearchWindow.tscn diff --git a/src/SharpIDE.Application/Features/Search/SearchService.cs b/src/SharpIDE.Application/Features/Search/SearchService.cs new file mode 100644 index 0000000..66f15df --- /dev/null +++ b/src/SharpIDE.Application/Features/Search/SearchService.cs @@ -0,0 +1,29 @@ +using System.Collections.Concurrent; +using System.IO.MemoryMappedFiles; +using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; + +namespace SharpIDE.Application.Features.Search; + +public static class SearchService +{ + public static async Task FindInFiles(SharpIdeSolutionModel solutionModel, string searchTerm) + { + if (searchTerm.Length < 4) + { + return; + } + var files = solutionModel.AllFiles; + ConcurrentBag 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()}"); + } + } + } + ); + } +} diff --git a/src/SharpIDE.Godot/Features/Search/SearchWindow.cs b/src/SharpIDE.Godot/Features/Search/SearchWindow.cs new file mode 100644 index 0000000..8d503de --- /dev/null +++ b/src/SharpIDE.Godot/Features/Search/SearchWindow.cs @@ -0,0 +1,8 @@ +using Godot; + +namespace SharpIDE.Godot.Features.Search; + +public partial class SearchWindow : PopupPanel +{ + +} \ No newline at end of file diff --git a/src/SharpIDE.Godot/Features/Search/SearchWindow.cs.uid b/src/SharpIDE.Godot/Features/Search/SearchWindow.cs.uid new file mode 100644 index 0000000..9a08470 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Search/SearchWindow.cs.uid @@ -0,0 +1 @@ +uid://bah6tmifl41ce diff --git a/src/SharpIDE.Godot/Features/Search/SearchWindow.tscn b/src/SharpIDE.Godot/Features/Search/SearchWindow.tscn new file mode 100644 index 0000000..b3033e0 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Search/SearchWindow.tscn @@ -0,0 +1,45 @@ +[gd_scene load_steps=2 format=3 uid="uid://8lk0qj233a7p"] + +[ext_resource type="Script" uid="uid://bah6tmifl41ce" path="res://Features/Search/SearchWindow.cs" id="1_ft33p"] + +[node name="SearchWindow" type="PopupPanel"] +oversampling_override = 1.0 +initial_position = 5 +size = Vector2i(1200, 800) +visible = true +script = ExtResource("1_ft33p") + +[node name="MarginContainer" type="MarginContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 4.0 +offset_right = -4.0 +offset_bottom = -4.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 5 +theme_override_constants/margin_top = 5 +theme_override_constants/margin_right = 5 +theme_override_constants/margin_bottom = 5 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 43.615) +layout_mode = 2 + +[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Find in Files" + +[node name="Label2" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +theme_override_font_sizes/font_size = 14 +text = " 30 matches in 5 files" + +[node name="LineEdit" type="LineEdit" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Test" diff --git a/src/SharpIDE.Godot/IdeRoot.cs b/src/SharpIDE.Godot/IdeRoot.cs index e4b3bd3..cb395bf 100644 --- a/src/SharpIDE.Godot/IdeRoot.cs +++ b/src/SharpIDE.Godot/IdeRoot.cs @@ -7,6 +7,7 @@ using SharpIDE.Godot.Features.BottomPanel; using SharpIDE.Godot.Features.CodeEditor; using SharpIDE.Godot.Features.CustomControls; using SharpIDE.Godot.Features.Run; +using SharpIDE.Godot.Features.Search; using SharpIDE.Godot.Features.SolutionExplorer; namespace SharpIDE.Godot; @@ -16,6 +17,7 @@ public partial class IdeRoot : Control private Button _openSlnButton = null!; private Button _buildSlnButton = null!; private FileDialog _fileDialog = null!; + private SearchWindow _searchWindow = null!; private CodeEditorPanel _codeEditorPanel = null!; private SolutionExplorerPanel _solutionExplorerPanel = null!; private InvertedVSplitContainer _invertedVSplitContainer = null!; @@ -35,6 +37,7 @@ public partial class IdeRoot : Control _runMenuButton = GetNode