using System.Globalization; using NubLang.Ast; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace NubLang.LSP; internal class HoverHandler(WorkspaceManager workspaceManager) : HoverHandlerBase { protected override HoverRegistrationOptions CreateRegistrationOptions(HoverCapability capability, ClientCapabilities clientCapabilities) { return new HoverRegistrationOptions { DocumentSelector = TextDocumentSelector.ForLanguage("nub") }; } public override Task Handle(HoverParams request, CancellationToken cancellationToken) { return Task.FromResult(HandleSync(request, cancellationToken)); } private Hover? HandleSync(HoverParams request, CancellationToken cancellationToken) { var compilationUnit = workspaceManager.GetCompilationUnit(request.TextDocument.Uri); if (compilationUnit == null) { return null; } var line = request.Position.Line; var character = request.Position.Character; var hoveredNode = compilationUnit.DeepestNodeAtPosition(line, character); if (hoveredNode == null) { return null; } // var message = CreateMessage(hoveredNode, compilationUnit); // if (message == null) // { // return null; // } // // return new Hover // { // Contents = new MarkedStringsOrMarkupContent(new MarkupContent // { // Value = message, // Kind = MarkupKind.Markdown, // }) // }; return null; } // private static string? CreateMessage(Node hoveredNode, CompilationUnit compilationUnit) // { // return hoveredNode switch // { // FuncNode funcNode => CreateFuncPrototypeMessage(funcNode.Prototype), // FuncPrototypeNode funcPrototypeNode => CreateFuncPrototypeMessage(funcPrototypeNode), // FuncIdentifierNode funcIdentifierNode => CreateFuncIdentifierMessage(funcIdentifierNode, compilationUnit), // FuncParameterNode funcParameterNode => CreateTypeNameMessage("Function parameter", funcParameterNode.NameToken.Value, funcParameterNode.Type), // VariableIdentifierNode variableIdentifierNode => CreateTypeNameMessage("Variable", variableIdentifierNode.NameToken.Value, variableIdentifierNode.Type), // VariableDeclarationNode variableDeclarationNode => CreateTypeNameMessage("Variable declaration", variableDeclarationNode.NameToken.Value, variableDeclarationNode.Type), // StructFieldAccessNode structFieldAccessNode => CreateTypeNameMessage("Struct field", $"{structFieldAccessNode.Target.Type}.{structFieldAccessNode.FieldToken.Value}", structFieldAccessNode.Type), // CStringLiteralNode cStringLiteralNode => CreateLiteralMessage(cStringLiteralNode.Type, '"' + cStringLiteralNode.Value + '"'), // StringLiteralNode stringLiteralNode => CreateLiteralMessage(stringLiteralNode.Type, '"' + stringLiteralNode.Value + '"'), // BoolLiteralNode boolLiteralNode => CreateLiteralMessage(boolLiteralNode.Type, boolLiteralNode.Value.ToString()), // Float32LiteralNode float32LiteralNode => CreateLiteralMessage(float32LiteralNode.Type, float32LiteralNode.Value.ToString(CultureInfo.InvariantCulture)), // Float64LiteralNode float64LiteralNode => CreateLiteralMessage(float64LiteralNode.Type, float64LiteralNode.Value.ToString(CultureInfo.InvariantCulture)), // I8LiteralNode i8LiteralNode => CreateLiteralMessage(i8LiteralNode.Type, i8LiteralNode.Value.ToString()), // I16LiteralNode i16LiteralNode => CreateLiteralMessage(i16LiteralNode.Type, i16LiteralNode.Value.ToString()), // I32LiteralNode i32LiteralNode => CreateLiteralMessage(i32LiteralNode.Type, i32LiteralNode.Value.ToString()), // I64LiteralNode i64LiteralNode => CreateLiteralMessage(i64LiteralNode.Type, i64LiteralNode.Value.ToString()), // U8LiteralNode u8LiteralNode => CreateLiteralMessage(u8LiteralNode.Type, u8LiteralNode.Value.ToString()), // U16LiteralNode u16LiteralNode => CreateLiteralMessage(u16LiteralNode.Type, u16LiteralNode.Value.ToString()), // U32LiteralNode u32LiteralNode => CreateLiteralMessage(u32LiteralNode.Type, u32LiteralNode.Value.ToString()), // U64LiteralNode u64LiteralNode => CreateLiteralMessage(u64LiteralNode.Type, u64LiteralNode.Value.ToString()), // // Expressions can have a generic fallback showing the resulting type // ExpressionNode expressionNode => $""" // **Expression** `{expressionNode.GetType().Name}` // ```nub // {expressionNode.Type} // ``` // """, // BlockNode => null, // _ => hoveredNode.GetType().Name // }; // } // // private static string CreateLiteralMessage(NubType type, string value) // { // return $""" // **Literal** `{type}` // ```nub // {value}: {type} // ``` // """; // } // // private static string CreateTypeNameMessage(string description, string name, NubType type) // { // return $""" // **{description}** `{name}` // ```nub // {name}: {type} // ``` // """; // } // // private static string CreateFuncIdentifierMessage(FuncIdentifierNode funcIdentifierNode, CompilationUnit compilationUnit) // { // var func = compilationUnit.ImportedFunctions // .Where(x => x.Key.Value == funcIdentifierNode.ModuleToken.Value) // .SelectMany(x => x.Value) // .FirstOrDefault(x => x.NameToken.Value == funcIdentifierNode.NameToken.Value); // // if (func == null) // { // return $""" // **Function** `{funcIdentifierNode.ModuleToken.Value}::{funcIdentifierNode.NameToken.Value}` // ```nub // // Declaration not found // ``` // """; // } // // return CreateFuncPrototypeMessage(func); // } // // private static string CreateFuncPrototypeMessage(FuncPrototypeNode funcPrototypeNode) // { // var parameterText = string.Join(", ", funcPrototypeNode.Parameters.Select(x => $"{x.NameToken.Value}: {x.Type}")); // var externText = funcPrototypeNode.ExternSymbolToken != null ? $"extern \"{funcPrototypeNode.ExternSymbolToken.Value}\" " : ""; // // return $""" // **Function** `{funcPrototypeNode.NameToken.Value}` // ```nub // {externText}func {funcPrototypeNode.NameToken.Value}({parameterText}): {funcPrototypeNode.ReturnType} // ``` // """; // } }