diff --git a/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs b/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs index 5bf4a49..779f806 100644 --- a/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs +++ b/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs @@ -667,12 +667,30 @@ public class RoslynAnalysis(ILogger logger, BuildService buildSe return changedFilesWithText; } - public async Task GetEnclosingSymbolForReferenceLocation(ReferenceLocation referenceLocation) + public record IdeReferenceLocationResult(ReferenceLocation ReferenceLocation, SharpIdeFile? File, ISymbol? EnclosingSymbol); + public async Task GetIdeReferenceLocationResult(ReferenceLocation referenceLocation) { var semanticModel = await referenceLocation.Document.GetSemanticModelAsync(); if (semanticModel is null) return null; var enclosingSymbol = ReferenceLocationExtensions.GetEnclosingMethodOrPropertyOrField(semanticModel, referenceLocation); - return enclosingSymbol; + var lineSpan = referenceLocation.Location.GetMappedLineSpan(); + var file = _sharpIdeSolutionModel!.AllFiles.SingleOrDefault(f => f.Path == lineSpan.Path); + var result = new IdeReferenceLocationResult(referenceLocation, file!, enclosingSymbol); + return result; + } + + public async Task> GetIdeReferenceLocationResults(ImmutableArray referenceLocations) + { + var results = new List(); + foreach (var referenceLocation in referenceLocations) + { + var result = await GetIdeReferenceLocationResult(referenceLocation); + if (result is not null) + { + results.Add(result); + } + } + return results.ToImmutableArray(); } public async Task> FindAllSymbolReferences(ISymbol symbol, CancellationToken cancellationToken = default) @@ -682,7 +700,7 @@ public class RoslynAnalysis(ILogger logger, BuildService buildSe var solution = _workspace!.CurrentSolution; var references = await SymbolFinder.FindReferencesAsync(symbol, solution, cancellationToken); - return references.AsImmutable(); + return references.ToImmutableArray(); } public async Task<(ISymbol?, LinePositionSpan?, TokenSemanticInfo?)> LookupSymbolSemanticInfo(SharpIdeFile fileModel, LinePosition linePosition) diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit_SymbolLookup.cs b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit_SymbolLookup.cs index 044b7f6..e69237e 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit_SymbolLookup.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit_SymbolLookup.cs @@ -48,20 +48,15 @@ public partial class SharpIdeCodeEdit else { // Show popup to select which reference to go to - var scene = _symbolUsagePopupScene.Instantiate(); - var locationsAndFiles = locations.Select(s => - { - var lineSpan = s.Location.GetMappedLineSpan(); - var file = Solution!.AllFiles.SingleOrDefault(f => f.Path == lineSpan.Path); - return (s, file); - }).Where(t => t.file is not null).ToImmutableArray(); - scene.Locations = locations; - scene.LocationsAndFiles = locationsAndFiles!; - scene.Symbol = semanticInfo.Value.DeclaredSymbol; + var symbolLookupPopup = _symbolUsagePopupScene.Instantiate(); + var ideReferenceLocationResults = await _roslynAnalysis.GetIdeReferenceLocationResults(locations); + symbolLookupPopup.IdeReferenceLocationResults = ideReferenceLocationResults; + symbolLookupPopup.Symbol = semanticInfo.Value.DeclaredSymbol; + symbolLookupPopup.Size = new Vector2I(1, 1); // Set tiny size so it autosizes up based on child content await this.InvokeAsync(() => { - AddChild(scene); - scene.PopupCenteredClamped(); + AddChild(symbolLookupPopup); + symbolLookupPopup.PopupCentered(); }); } } diff --git a/src/SharpIDE.Godot/Features/SymbolLookup/SymbolLookupPopup.cs b/src/SharpIDE.Godot/Features/SymbolLookup/SymbolLookupPopup.cs index a88e2c7..92367f4 100644 --- a/src/SharpIDE.Godot/Features/SymbolLookup/SymbolLookupPopup.cs +++ b/src/SharpIDE.Godot/Features/SymbolLookup/SymbolLookupPopup.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using Godot; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.FindSymbols; +using SharpIDE.Application.Features.Analysis; using SharpIDE.Application.Features.SolutionDiscovery; namespace SharpIDE.Godot.Features.SymbolLookup; @@ -10,8 +11,8 @@ public partial class SymbolLookupPopup : PopupPanel { private Label _symbolNameLabel = null!; private VBoxContainer _usagesContainer = null!; - public ImmutableArray Locations { get; set; } - public ImmutableArray<(ReferenceLocation location, SharpIdeFile file)> LocationsAndFiles { get; set; } + + public ImmutableArray IdeReferenceLocationResults { get; set; } public ISymbol Symbol { get; set; } = null!; private readonly PackedScene _symbolUsageScene = ResourceLoader.Load("uid://dokm0dyac2enh"); @@ -24,11 +25,12 @@ public partial class SymbolLookupPopup : PopupPanel AboutToPopup += OnAboutToPopup; _usagesContainer.GetChildren().ToList().ForEach(s => s.QueueFree()); - foreach (var (location, file) in LocationsAndFiles) + foreach (var result in IdeReferenceLocationResults) { var resultNode = _symbolUsageScene.Instantiate(); - resultNode.Location = location; - resultNode.File = file; + resultNode.Location = result.ReferenceLocation; + resultNode.File = result.File; + resultNode.EnclosingSymbol = result.EnclosingSymbol; resultNode.ParentSearchWindow = this; _usagesContainer.AddChild(resultNode); } diff --git a/src/SharpIDE.Godot/Features/SymbolLookup/SymbolLookupPopup.tscn b/src/SharpIDE.Godot/Features/SymbolLookup/SymbolLookupPopup.tscn index 18390c1..882eca2 100644 --- a/src/SharpIDE.Godot/Features/SymbolLookup/SymbolLookupPopup.tscn +++ b/src/SharpIDE.Godot/Features/SymbolLookup/SymbolLookupPopup.tscn @@ -14,7 +14,7 @@ shadow_size = 4 [node name="SymbolLookupPopup" type="PopupPanel"] oversampling_override = 1.0 -size = Vector2i(505, 340) +size = Vector2i(564, 340) visible = true theme_override_styles/panel = SubResource("StyleBoxFlat_cuaw5") script = ExtResource("1_f5udm") @@ -50,15 +50,10 @@ unique_name_in_owner = true layout_mode = 2 text = "'UseWebApi()'" -[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 -follow_focus = true - -[node name="UsagesVBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"] +[node name="UsagesVBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer"] unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 3 -[node name="SymbolUsageComponent" parent="MarginContainer/VBoxContainer/ScrollContainer/UsagesVBoxContainer" instance=ExtResource("1_k5g0h")] +[node name="SymbolUsageComponent" parent="MarginContainer/VBoxContainer/UsagesVBoxContainer" instance=ExtResource("1_k5g0h")] layout_mode = 2 diff --git a/src/SharpIDE.Godot/Features/SymbolLookup/SymbolUsageComponent.cs b/src/SharpIDE.Godot/Features/SymbolLookup/SymbolUsageComponent.cs index f1d4f2c..c5e1e82 100644 --- a/src/SharpIDE.Godot/Features/SymbolLookup/SymbolUsageComponent.cs +++ b/src/SharpIDE.Godot/Features/SymbolLookup/SymbolUsageComponent.cs @@ -1,4 +1,5 @@ using Godot; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.FindSymbols; using SharpIDE.Application.Features.Analysis; using SharpIDE.Application.Features.SolutionDiscovery; @@ -14,9 +15,8 @@ public partial class SymbolUsageComponent : MarginContainer public SymbolLookupPopup ParentSearchWindow { get; set; } = null!; public ReferenceLocation? Location { get; set; } - public SharpIdeFile File { get; set; } = null!; - - [Inject] private readonly RoslynAnalysis _roslynAnalysis = null!; + public ISymbol? EnclosingSymbol { get; set; } = null!; + public SharpIdeFile? File { get; set; } = null!; public override void _Ready() { @@ -32,7 +32,10 @@ public partial class SymbolUsageComponent : MarginContainer { var mappedLineSpan = Location!.Value.Location.GetMappedLineSpan(); var fileLinePosition = new SharpIdeFileLinePosition { Line = mappedLineSpan.StartLinePosition.Line, Column = mappedLineSpan.StartLinePosition.Character }; - GodotGlobalEvents.Instance.FileExternallySelected.InvokeParallelFireAndForget(File, fileLinePosition); + if (File is not null) + { + GodotGlobalEvents.Instance.FileExternallySelected.InvokeParallelFireAndForget(File, fileLinePosition); + } ParentSearchWindow.Hide(); } @@ -41,13 +44,8 @@ public partial class SymbolUsageComponent : MarginContainer if (result is null) return; var mappedLineSpan = result.Value.Location.GetMappedLineSpan(); - _fileNameLabel.Text = File.Name; + _fileNameLabel.Text = File?.Name ?? Path.GetFileName(mappedLineSpan.Path); _lineNumberLabel.Text = (mappedLineSpan.StartLinePosition.Line + 1).ToString(); - - _ = Task.GodotRun(async () => - { - var enclosingSymbol = await _roslynAnalysis.GetEnclosingSymbolForReferenceLocation(result.Value); - await this.InvokeAsync(() => _enclosingSymbolLabel.Text = enclosingSymbol?.Name); - }); + _enclosingSymbolLabel.Text = EnclosingSymbol?.Name; } } \ No newline at end of file diff --git a/src/SharpIDE.Godot/Features/SymbolLookup/SymbolUsageComponent.tscn b/src/SharpIDE.Godot/Features/SymbolLookup/SymbolUsageComponent.tscn index 42b1e36..a60dc0a 100644 --- a/src/SharpIDE.Godot/Features/SymbolLookup/SymbolUsageComponent.tscn +++ b/src/SharpIDE.Godot/Features/SymbolLookup/SymbolUsageComponent.tscn @@ -29,33 +29,32 @@ layout_mode = 2 theme_override_styles/normal = SubResource("StyleBoxFlat_6ov2c") theme_override_styles/focus = SubResource("StyleBoxFlat_dtmd4") -[node name="MarginContainer" type="MarginContainer" parent="Button"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_behavior_recursive = 1 theme_override_constants/margin_left = 5 theme_override_constants/margin_right = 5 -[node name="HBoxContainer" type="HBoxContainer" parent="Button/MarginContainer"] +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] layout_mode = 2 -[node name="EnclosingSymbolLabel" type="Label" parent="Button/MarginContainer/HBoxContainer"] +[node name="EnclosingSymbolLabel" type="Label" parent="MarginContainer/HBoxContainer"] unique_name_in_owner = true layout_mode = 2 -size_flags_horizontal = 3 text = "Containing Symbol Name" -text_overrun_behavior = 3 -[node name="FileNameLabel" type="Label" parent="Button/MarginContainer/HBoxContainer"] +[node name="Spacer" type="Control" parent="MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="FileNameLabel" type="Label" parent="MarginContainer/HBoxContainer"] unique_name_in_owner = true layout_mode = 2 theme_override_colors/font_color = Color(1, 1, 1, 0.7411765) text = "FileName.cs" -[node name="LineNumberLabel" type="Label" parent="Button/MarginContainer/HBoxContainer"] +[node name="LineNumberLabel" type="Label" parent="MarginContainer/HBoxContainer"] unique_name_in_owner = true layout_mode = 2 theme_override_colors/font_color = Color(1, 1, 1, 0.7411765)