diff --git a/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs b/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs index b6fcab8..164302a 100644 --- a/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs +++ b/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs @@ -479,6 +479,35 @@ public static class RoslynAnalysis public static async Task LookupSymbol(SharpIdeFile fileModel, LinePosition linePosition) { await _solutionLoadedTcs.Task; + var symbol = fileModel.IsRazorFile ? await LookupSymbolInRazor(fileModel, linePosition) : await LookupSymbolInCs(fileModel, linePosition); + return symbol; + } + + private static async Task LookupSymbolInRazor(SharpIdeFile fileModel, LinePosition linePosition, CancellationToken cancellationToken = default) + { + var sharpIdeProjectModel = ((IChildSharpIdeNode) fileModel).GetNearestProjectNode()!; + var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == sharpIdeProjectModel!.FilePath); + + var additionalDocument = project.AdditionalDocuments.Single(s => s.FilePath == fileModel.Path); + + var razorProjectSnapshot = _snapshotManager!.GetSnapshot(project); + var documentSnapshot = razorProjectSnapshot.GetDocument(additionalDocument); + + var razorCodeDocument = await razorProjectSnapshot.GetRequiredCodeDocumentAsync(documentSnapshot, cancellationToken); + var razorCSharpDocument = razorCodeDocument.GetRequiredCSharpDocument(); + var generatedDocument = await razorProjectSnapshot.GetRequiredGeneratedDocumentAsync(documentSnapshot, cancellationToken); + var generatedDocSyntaxRoot = await generatedDocument.GetSyntaxRootAsync(cancellationToken); + + var razorText = await additionalDocument.GetTextAsync(cancellationToken); + + var mappedPosition = MapRazorLinePositionToGeneratedCSharpAbsolutePosition(razorCSharpDocument, razorText, linePosition); + var semanticModelAsync = await generatedDocument.GetSemanticModelAsync(cancellationToken); + var symbol = GetSymbolAtPosition(semanticModelAsync!, generatedDocSyntaxRoot!, mappedPosition!.Value); + return symbol; + } + + private static async Task LookupSymbolInCs(SharpIdeFile fileModel, LinePosition linePosition) + { var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == ((IChildSharpIdeNode)fileModel).GetNearestProjectNode()!.FilePath); var document = project.Documents.Single(s => s.FilePath == fileModel.Path); Guard.Against.Null(document, nameof(document)); @@ -487,9 +516,13 @@ public static class RoslynAnalysis var semanticModel = await document.GetSemanticModelAsync(); Guard.Against.Null(semanticModel, nameof(semanticModel)); var syntaxRoot = await document.GetSyntaxRootAsync(); - var node = syntaxRoot!.FindToken(position).Parent!; - var symbol = semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetDeclaredSymbol(node); + return GetSymbolAtPosition(semanticModel, syntaxRoot!, position); + } + private static ISymbol? GetSymbolAtPosition(SemanticModel semanticModel, SyntaxNode root, int position) + { + var node = root.FindToken(position).Parent!; + var symbol = semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetDeclaredSymbol(node); if (symbol is null) { Console.WriteLine("No symbol found at position"); @@ -500,6 +533,25 @@ public static class RoslynAnalysis return symbol; } + private static int? MapRazorLinePositionToGeneratedCSharpAbsolutePosition(RazorCSharpDocument razorCSharpDocument, SourceText razorText, LinePosition razorLinePosition) + { + var mappings = razorCSharpDocument.SourceMappings; + var razorOffset = razorText.Lines.GetPosition(razorLinePosition); + + foreach (var mapping in mappings) + { + var span = mapping.OriginalSpan; + if (razorOffset >= span.AbsoluteIndex && razorOffset < span.AbsoluteIndex + span.Length) + { + // Calculate offset within the mapping + var offsetInMapping = razorOffset - span.AbsoluteIndex; + // Map to generated C# position + return mapping.GeneratedSpan.AbsoluteIndex + offsetInMapping; + } + } + return null; + } + public static void UpdateDocument(SharpIdeFile fileModel, string newContent) { Guard.Against.Null(fileModel, nameof(fileModel)); diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs b/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs index 5c3b196..77495e8 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs @@ -23,7 +23,6 @@ public static class SymbolInfoComponents label.Pop(); label.AddText(" "); label.AddStaticModifier(methodSymbol); - label.AddText(" "); label.AddMethodReturnType(methodSymbol); label.AddText(" "); label.AddMethodName(methodSymbol); @@ -61,6 +60,7 @@ public static class SymbolInfoComponents label.PushColor(CachedColors.KeywordBlue); label.AddText("static"); label.Pop(); + label.AddText(" "); } }