From ea8a4e667b453aa8132a76e41d5b487f4f4d39c3 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Mon, 8 Sep 2025 14:59:22 -0400 Subject: [PATCH] feat(lsp): Add submodule information to module hover --- compiler/src/diagnostics/modules.re | 20 +++++++++++----- compiler/src/language_server/hover.re | 1 + compiler/test/suites/grainlsp.re | 34 +++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/compiler/src/diagnostics/modules.re b/compiler/src/diagnostics/modules.re index 052f8a25e5..f6a7c4541a 100644 --- a/compiler/src/diagnostics/modules.re +++ b/compiler/src/diagnostics/modules.re @@ -6,7 +6,8 @@ type export_kind = | Record | Enum | Abstract - | Exception; + | Exception + | Module; type export = { name: string, @@ -33,31 +34,38 @@ let rec get_provides = (md: Types.module_declaration) => kind: Value, signature: Printtyp.string_of_value_description(~ident, vd), }) - | TSigType(ident, {type_kind: TDataRecord(_), _} as td, recstatus) => + | TSigType(ident, {type_kind: TDataRecord(_), _} as td, _) => Some({ name: ident.name, kind: Record, signature: Printtyp.string_of_type_declaration(~ident, td), }) - | TSigType(ident, {type_kind: TDataVariant(_), _} as td, recstatus) => + | TSigType(ident, {type_kind: TDataVariant(_), _} as td, _) => Some({ name: ident.name, kind: Enum, signature: Printtyp.string_of_type_declaration(~ident, td), }) - | TSigType(ident, {type_kind: TDataAbstract, _} as td, recstatus) => + | TSigType(ident, {type_kind: TDataAbstract, _} as td, _) => Some({ name: ident.name, kind: Abstract, signature: Printtyp.string_of_type_declaration(~ident, td), }) - | TSigType(ident, {type_kind: TDataOpen, _} as td, recstatus) => + | TSigType(ident, {type_kind: TDataOpen, _} as td, _) => Some({ name: ident.name, kind: Exception, // Currently we only use TDataOpen for exceptions signature: Printtyp.string_of_type_declaration(~ident, td), }) - | _ => None + | TSigModule(ident, {md_type}, _) => + Some({ + name: ident.name, + kind: Module, + signature: ident.name, + }) + | TSigModType(_, _) + | TSigTypeExt(_, _, _) => None } }, sigs, diff --git a/compiler/src/language_server/hover.re b/compiler/src/language_server/hover.re index a3009e6ac8..2ea5cc5363 100644 --- a/compiler/src/language_server/hover.re +++ b/compiler/src/language_server/hover.re @@ -99,6 +99,7 @@ let module_lens = (decl: Types.module_declaration) => { | Enum | Abstract | Exception => v.signature + | Module => Format.sprintf("module %s", v.signature) }, vals, ); diff --git a/compiler/test/suites/grainlsp.re b/compiler/test/suites/grainlsp.re index 09cbbc652a..0e9e387f40 100644 --- a/compiler/test/suites/grainlsp.re +++ b/compiler/test/suites/grainlsp.re @@ -631,6 +631,40 @@ module B { ]), ); + assertLspOutput( + "hover_submodule", + "file:///a.gr", + {|module A +module B { + provide let a = 1 + provide let b = 2 + let c = 3 + provide module C { + provide let d = 4 + } +} +|}, + lsp_input( + "textDocument/hover", + lsp_text_document_position("file:///a.gr", 1, 0), + ), + `Assoc([ + ( + "contents", + `Assoc([ + ("kind", `String("markdown")), + ( + "value", + `String( + "```grain\nlet a: Number\nlet b: Number\nmodule C\n```\n\n", + ), + ), + ]), + ), + ("range", lsp_range((1, 0), (8, 1))), + ]), + ); + assertLspOutput( "hover_include", make_test_utils_uri("a.gr"),