From 00374034c0d01815d89d80d84c0936684cc8ed2e Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Sun, 12 Oct 2025 12:24:09 +1000 Subject: [PATCH] refactor --- .../Features/CodeEditor/SharpIdeCodeEdit.cs | 2 +- .../CodeEditor/SymbolInfoComponents.cs.uid | 1 - .../Common.cs} | 214 +---------------- .../SymbolTooltips/MethodTooltip.cs | 221 ++++++++++++++++++ 4 files changed, 234 insertions(+), 204 deletions(-) delete mode 100644 src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs.uid rename src/SharpIDE.Godot/Features/CodeEditor/{SymbolInfoComponents.cs => SymbolTooltips/Common.cs} (63%) create mode 100644 src/SharpIDE.Godot/Features/CodeEditor/SymbolTooltips/MethodTooltip.cs diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs index 4c97b8a..1075811 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs @@ -132,7 +132,7 @@ public partial class SharpIdeCodeEdit : CodeEdit IFieldSymbol fieldSymbol => SymbolInfoComponents.GetFieldSymbolInfo(fieldSymbol), IParameterSymbol parameterSymbol => SymbolInfoComponents.GetParameterSymbolInfo(parameterSymbol), ILocalSymbol localSymbol => SymbolInfoComponents.GetLocalVariableSymbolInfo(localSymbol), - _ => new Control() + _ => SymbolInfoComponents.GetUnknownTooltip(roslynSymbol) }; popupPanel.AddChild(symbolInfoNode); AddChild(popupPanel); diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs.uid b/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs.uid deleted file mode 100644 index 9487be6..0000000 --- a/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c48r2nff1ckv diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs b/src/SharpIDE.Godot/Features/CodeEditor/SymbolTooltips/Common.cs similarity index 63% rename from src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs rename to src/SharpIDE.Godot/Features/CodeEditor/SymbolTooltips/Common.cs index c339402..4e9e473 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/SymbolInfoComponents.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/SymbolTooltips/Common.cs @@ -9,7 +9,8 @@ namespace SharpIDE.Godot.Features.CodeEditor; public static partial class SymbolInfoComponents { private static readonly FontVariation MonospaceFont = ResourceLoader.Load("uid://cctwlwcoycek7"); - public static RichTextLabel GetMethodSymbolInfo(IMethodSymbol methodSymbol) + + public static Control GetUnknownTooltip(ISymbol symbol) { var label = new RichTextLabel(); label.FitContent = true; @@ -17,25 +18,18 @@ public static partial class SymbolInfoComponents label.SetAnchorsPreset(Control.LayoutPreset.FullRect); label.PushColor(CachedColors.White); label.PushFont(MonospaceFont); - label.AddAttributes(methodSymbol); - label.AddAccessibilityModifier(methodSymbol); - label.AddMethodStaticModifier(methodSymbol); - label.AddVirtualModifier(methodSymbol); - label.AddAbstractModifier(methodSymbol); - label.AddOverrideModifier(methodSymbol); - label.AddMethodReturnType(methodSymbol); - label.AddText(" "); - label.AddMethodName(methodSymbol); - label.AddTypeParameters(methodSymbol); - label.AddText("("); - label.AddParameters(methodSymbol); - label.AddText(")"); - label.AddContainingNamespaceAndClass(methodSymbol); + label.AddText($"UNHANDLED SYMBOL TYPE: {symbol.GetType().Name} - please create an issue!"); + label.Newline(); + label.AddText(symbol.Kind.ToString()); + label.AddText(" "); + label.AddText(symbol.Name); + label.Newline(); + label.AddContainingNamespaceAndClass(symbol); label.Newline(); - label.AddTypeParameterArguments(methodSymbol); label.Pop(); // font - label.AddDocs(methodSymbol); - label.Pop(); // default white + label.AddDocs(symbol); + + label.Pop(); return label; } @@ -58,17 +52,6 @@ public static partial class SymbolInfoComponents label.Pop(); } - private static void AddMethodStaticModifier(this RichTextLabel label, IMethodSymbol methodSymbol) - { - if (methodSymbol.IsStatic || methodSymbol.ReducedFrom?.IsStatic is true) - { - label.PushColor(CachedColors.KeywordBlue); - label.AddText("static"); - label.Pop(); - label.AddText(" "); - } - } - private static void AddOverrideModifier(this RichTextLabel label, ISymbol methodSymbol) { if (methodSymbol.IsOverride) @@ -112,156 +95,6 @@ public static partial class SymbolInfoComponents } } - private static void AddMethodReturnType(this RichTextLabel label, IMethodSymbol methodSymbol) - { - if (methodSymbol.ReturnsVoid) - { - label.PushColor(CachedColors.KeywordBlue); - label.AddText("void"); - label.Pop(); - return; - } - - label.PushColor(CachedColors.ClassGreen); - label.AddText(methodSymbol.ReturnType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); - label.Pop(); - } - - private static void AddMethodName(this RichTextLabel label, IMethodSymbol methodSymbol) - { - label.PushColor(CachedColors.Yellow); - label.AddText(methodSymbol.Name); - label.Pop(); - } - - private static void AddTypeParameters(this RichTextLabel label, IMethodSymbol methodSymbol) - { - if (methodSymbol.TypeParameters.Length == 0) return; - label.PushColor(CachedColors.White); - label.AddText("<"); - label.Pop(); - foreach (var (index, typeParameter) in methodSymbol.TypeParameters.Index()) - { - label.PushColor(CachedColors.ClassGreen); - label.AddText(typeParameter.Name); - label.Pop(); - if (index < methodSymbol.TypeParameters.Length - 1) - { - label.AddText(", "); - } - } - label.PushColor(CachedColors.White); - label.AddText(">"); - label.Pop(); - } - - private static void AddParameters(this RichTextLabel label, IMethodSymbol methodSymbol) - { - if (methodSymbol.IsExtensionMethod) - { - label.PushColor(CachedColors.KeywordBlue); - label.AddText("this"); - label.Pop(); - label.AddText(" "); - } - - var parameters = methodSymbol.ReducedFrom?.Parameters ?? methodSymbol.Parameters; - foreach (var (index, parameterSymbol) in parameters.Index()) - { - var attributes = parameterSymbol.GetAttributes(); - if (attributes.Length is not 0) - { - foreach (var (attrIndex, attribute) in attributes.Index()) - { - label.AddAttribute(attribute, false); - } - } - if (parameterSymbol.RefKind != RefKind.None) // ref, in, out - { - label.PushColor(CachedColors.KeywordBlue); - label.AddText(parameterSymbol.RefKind.ToString().ToLower()); - label.Pop(); - label.AddText(" "); - } - else if (parameterSymbol.IsParams) - { - label.PushColor(CachedColors.KeywordBlue); - label.AddText("params"); - label.Pop(); - label.AddText(" "); - } - label.PushColor(parameterSymbol.Type.GetSymbolColourByType()); - label.AddText(parameterSymbol.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); - label.Pop(); - label.AddText(" "); - label.PushColor(CachedColors.VariableBlue); - label.AddText(parameterSymbol.Name); - label.Pop(); - // default value - if (parameterSymbol.HasExplicitDefaultValue) - { - label.AddText(" = "); - if (parameterSymbol.ExplicitDefaultValue is null) - { - label.PushColor(CachedColors.KeywordBlue); - label.AddText("null"); - label.Pop(); - } - else if (parameterSymbol.Type.TypeKind == TypeKind.Enum) - { - var explicitDefaultValue = parameterSymbol.ExplicitDefaultValue; - // Find the enum field with the same constant value - var enumMember = parameterSymbol.Type.GetMembers() - .OfType() - .FirstOrDefault(f => f.HasConstantValue && Equals(f.ConstantValue, explicitDefaultValue)); - - if (enumMember != null) - { - label.PushColor(CachedColors.InterfaceGreen); - label.AddText(parameterSymbol.Type.Name); - label.Pop(); - label.PushColor(CachedColors.White); - label.AddText("."); - label.Pop(); - label.PushColor(CachedColors.White); - label.AddText(enumMember.Name); - label.Pop(); - } - else - { - label.PushColor(CachedColors.InterfaceGreen); - label.AddText(parameterSymbol.Type.Name); - label.Pop(); - label.AddText($"({explicitDefaultValue})"); - } - } - else if (parameterSymbol.ExplicitDefaultValue is string str) - { - label.PushColor(CachedColors.LightOrangeBrown); - label.AddText($""" - "{str}" - """); - label.Pop(); - } - else if (parameterSymbol.ExplicitDefaultValue is bool b) - { - label.PushColor(CachedColors.KeywordBlue); - label.AddText(b ? "true" : "false"); - label.Pop(); - } - else - { - label.AddText(parameterSymbol.ExplicitDefaultValue.ToString() ?? "unknown"); - } - } - - if (index < parameters.Length - 1) - { - label.AddText(", "); - } - } - } - private static void AddContainingNamespaceAndClass(this RichTextLabel label, ISymbol symbol) { if (symbol.ContainingNamespace is null || symbol.ContainingNamespace.IsGlobalNamespace) return; // might be wrong @@ -293,29 +126,6 @@ public static partial class SymbolInfoComponents label.Pop(); // meta } - private static void AddTypeParameterArguments(this RichTextLabel label, IMethodSymbol methodSymbol) - { - if (methodSymbol.TypeArguments.Length == 0) return; - label.Newline(); // TODO: Make this only 0.5 lines high - var typeParameters = methodSymbol.TypeParameters; - var typeArguments = methodSymbol.TypeArguments; - if (typeParameters.Length != typeArguments.Length) throw new Exception("Type parameters and type arguments length mismatch."); - foreach (var (index, (typeArgument, typeParameter)) in methodSymbol.TypeArguments.Zip(typeParameters).Index()) - { - label.PushColor(CachedColors.ClassGreen); - label.AddText(typeParameter.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); - label.Pop(); - label.AddText(" is "); - label.PushColor(typeArgument.GetSymbolColourByType()); - label.AddText(typeArgument.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); - label.Pop(); - if (index < methodSymbol.TypeArguments.Length - 1) - { - label.Newline(); - } - } - } - private static void AddAttribute(this RichTextLabel label, AttributeData attribute, bool newLines) { label.AddText("["); diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SymbolTooltips/MethodTooltip.cs b/src/SharpIDE.Godot/Features/CodeEditor/SymbolTooltips/MethodTooltip.cs new file mode 100644 index 0000000..b9512cf --- /dev/null +++ b/src/SharpIDE.Godot/Features/CodeEditor/SymbolTooltips/MethodTooltip.cs @@ -0,0 +1,221 @@ +using Godot; +using Microsoft.CodeAnalysis; + +namespace SharpIDE.Godot.Features.CodeEditor; + +public static partial class SymbolInfoComponents +{ + public static RichTextLabel GetMethodSymbolInfo(IMethodSymbol methodSymbol) + { + var label = new RichTextLabel(); + label.FitContent = true; + label.AutowrapMode = TextServer.AutowrapMode.Off; + label.SetAnchorsPreset(Control.LayoutPreset.FullRect); + label.PushColor(CachedColors.White); + label.PushFont(MonospaceFont); + label.AddAttributes(methodSymbol); + label.AddAccessibilityModifier(methodSymbol); + label.AddMethodStaticModifier(methodSymbol); + label.AddVirtualModifier(methodSymbol); + label.AddAbstractModifier(methodSymbol); + label.AddOverrideModifier(methodSymbol); + label.AddMethodReturnType(methodSymbol); + label.AddText(" "); + label.AddMethodName(methodSymbol); + label.AddTypeParameters(methodSymbol); + label.AddText("("); + label.AddParameters(methodSymbol); + label.AddText(")"); + label.AddContainingNamespaceAndClass(methodSymbol); + label.Newline(); + label.AddTypeParameterArguments(methodSymbol); + label.Pop(); // font + label.AddDocs(methodSymbol); + label.Pop(); // default white + return label; + } + + private static void AddMethodStaticModifier(this RichTextLabel label, IMethodSymbol methodSymbol) + { + if (methodSymbol.IsStatic || methodSymbol.ReducedFrom?.IsStatic is true) + { + label.PushColor(CachedColors.KeywordBlue); + label.AddText("static"); + label.Pop(); + label.AddText(" "); + } + } + + private static void AddMethodReturnType(this RichTextLabel label, IMethodSymbol methodSymbol) + { + if (methodSymbol.ReturnsVoid) + { + label.PushColor(CachedColors.KeywordBlue); + label.AddText("void"); + label.Pop(); + return; + } + + label.PushColor(CachedColors.ClassGreen); + label.AddText(methodSymbol.ReturnType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); + label.Pop(); + } + + private static void AddMethodName(this RichTextLabel label, IMethodSymbol methodSymbol) + { + label.PushColor(CachedColors.Yellow); + label.AddText(methodSymbol.Name); + label.Pop(); + } + + private static void AddTypeParameters(this RichTextLabel label, IMethodSymbol methodSymbol) + { + if (methodSymbol.TypeParameters.Length == 0) return; + label.PushColor(CachedColors.White); + label.AddText("<"); + label.Pop(); + foreach (var (index, typeParameter) in methodSymbol.TypeParameters.Index()) + { + label.PushColor(CachedColors.ClassGreen); + label.AddText(typeParameter.Name); + label.Pop(); + if (index < methodSymbol.TypeParameters.Length - 1) + { + label.AddText(", "); + } + } + label.PushColor(CachedColors.White); + label.AddText(">"); + label.Pop(); + } + + private static void AddParameters(this RichTextLabel label, IMethodSymbol methodSymbol) + { + if (methodSymbol.IsExtensionMethod) + { + label.PushColor(CachedColors.KeywordBlue); + label.AddText("this"); + label.Pop(); + label.AddText(" "); + } + + var parameters = methodSymbol.ReducedFrom?.Parameters ?? methodSymbol.Parameters; + foreach (var (index, parameterSymbol) in parameters.Index()) + { + var attributes = parameterSymbol.GetAttributes(); + if (attributes.Length is not 0) + { + foreach (var (attrIndex, attribute) in attributes.Index()) + { + label.AddAttribute(attribute, false); + } + } + if (parameterSymbol.RefKind != RefKind.None) // ref, in, out + { + label.PushColor(CachedColors.KeywordBlue); + label.AddText(parameterSymbol.RefKind.ToString().ToLower()); + label.Pop(); + label.AddText(" "); + } + else if (parameterSymbol.IsParams) + { + label.PushColor(CachedColors.KeywordBlue); + label.AddText("params"); + label.Pop(); + label.AddText(" "); + } + label.PushColor(parameterSymbol.Type.GetSymbolColourByType()); + label.AddText(parameterSymbol.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); + label.Pop(); + label.AddText(" "); + label.PushColor(CachedColors.VariableBlue); + label.AddText(parameterSymbol.Name); + label.Pop(); + // default value + if (parameterSymbol.HasExplicitDefaultValue) + { + label.AddText(" = "); + if (parameterSymbol.ExplicitDefaultValue is null) + { + label.PushColor(CachedColors.KeywordBlue); + label.AddText("null"); + label.Pop(); + } + else if (parameterSymbol.Type.TypeKind == TypeKind.Enum) + { + var explicitDefaultValue = parameterSymbol.ExplicitDefaultValue; + // Find the enum field with the same constant value + var enumMember = parameterSymbol.Type.GetMembers() + .OfType() + .FirstOrDefault(f => f.HasConstantValue && Equals(f.ConstantValue, explicitDefaultValue)); + + if (enumMember != null) + { + label.PushColor(CachedColors.InterfaceGreen); + label.AddText(parameterSymbol.Type.Name); + label.Pop(); + label.PushColor(CachedColors.White); + label.AddText("."); + label.Pop(); + label.PushColor(CachedColors.White); + label.AddText(enumMember.Name); + label.Pop(); + } + else + { + label.PushColor(CachedColors.InterfaceGreen); + label.AddText(parameterSymbol.Type.Name); + label.Pop(); + label.AddText($"({explicitDefaultValue})"); + } + } + else if (parameterSymbol.ExplicitDefaultValue is string str) + { + label.PushColor(CachedColors.LightOrangeBrown); + label.AddText($""" + "{str}" + """); + label.Pop(); + } + else if (parameterSymbol.ExplicitDefaultValue is bool b) + { + label.PushColor(CachedColors.KeywordBlue); + label.AddText(b ? "true" : "false"); + label.Pop(); + } + else + { + label.AddText(parameterSymbol.ExplicitDefaultValue.ToString() ?? "unknown"); + } + } + + if (index < parameters.Length - 1) + { + label.AddText(", "); + } + } + } + + private static void AddTypeParameterArguments(this RichTextLabel label, IMethodSymbol methodSymbol) + { + if (methodSymbol.TypeArguments.Length == 0) return; + label.Newline(); // TODO: Make this only 0.5 lines high + var typeParameters = methodSymbol.TypeParameters; + var typeArguments = methodSymbol.TypeArguments; + if (typeParameters.Length != typeArguments.Length) throw new Exception("Type parameters and type arguments length mismatch."); + foreach (var (index, (typeArgument, typeParameter)) in methodSymbol.TypeArguments.Zip(typeParameters).Index()) + { + label.PushColor(CachedColors.ClassGreen); + label.AddText(typeParameter.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); + label.Pop(); + label.AddText(" is "); + label.PushColor(typeArgument.GetSymbolColourByType()); + label.AddText(typeArgument.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); + label.Pop(); + if (index < methodSymbol.TypeArguments.Length - 1) + { + label.Newline(); + } + } + } +} \ No newline at end of file