From 35cf5697e1420456d17e67749e96e7f82c164a3b Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sat, 7 Jun 2025 09:39:35 -0400 Subject: Add full struct definition on hover --- src/server/analysis.odin | 12 +++++++++++- tests/hover_test.odin | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 668260b..d1ce01e 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3805,7 +3805,17 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol if is_variable { return strings.concatenate({pointer_prefix, symbol.name}, ast_context.allocator) } else { - return "struct" + builder := strings.builder_make(ast_context.allocator) + strings.write_string(&builder, "struct {\n") + for i in 0.. int, + } + + foo := F{*}oo{} + ` + } + + test.expect_hover(t, &source, "test.Foo: struct {\n\tbar: int,\n\tf: proc(a: int) -> int,\n}") +} + /* Waiting for odin fix -- cgit v1.2.3 From d150a6be3806f5d21fbfaa4ebf3c889cbc974574 Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sat, 7 Jun 2025 12:32:01 -0400 Subject: Align types in the hover text --- src/server/analysis.odin | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index d1ce01e..0ef14e7 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3805,12 +3805,18 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol if is_variable { return strings.concatenate({pointer_prefix, symbol.name}, ast_context.allocator) } else { + longestNameLen := 0 + for name in v.names { + if len(name) > longestNameLen { + longestNameLen = len(name) + } + } builder := strings.builder_make(ast_context.allocator) strings.write_string(&builder, "struct {\n") for i in 0.. Date: Sat, 7 Jun 2025 12:38:55 -0400 Subject: Add full definition for enums and unions on hover --- src/server/analysis.odin | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 0ef14e7..52ed4e0 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3792,7 +3792,15 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol if is_variable { return symbol.name } else { - return "enum" + builder := strings.builder_make(ast_context.allocator) + strings.write_string(&builder, "enum {\n") + for i in 0.. Date: Sat, 7 Jun 2025 14:07:23 -0400 Subject: Include encriched struct information on variable hover --- src/server/analysis.odin | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 52ed4e0..f7c956d 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3810,27 +3810,26 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol case SymbolProcedureValue: return "proc" case SymbolStructValue: + builder := strings.builder_make(ast_context.allocator) if is_variable { - return strings.concatenate({pointer_prefix, symbol.name}, ast_context.allocator) - } else { - longestNameLen := 0 - for name in v.names { - if len(name) > longestNameLen { - longestNameLen = len(name) - } - } - builder := strings.builder_make(ast_context.allocator) - strings.write_string(&builder, "struct {\n") - for i in 0.. longestNameLen { + longestNameLen = len(name) } - strings.write_string(&builder, "}") - return strings.to_string(builder) } + strings.write_string(&builder, "struct {\n") + for i in 0.. Date: Sat, 7 Jun 2025 14:10:38 -0400 Subject: Enrich enum and union information on variable hover --- src/server/analysis.odin | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index f7c956d..8a21c7d 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3789,19 +3789,18 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol allocator = ast_context.allocator, ) case SymbolEnumValue: + builder := strings.builder_make(ast_context.allocator) if is_variable { - return symbol.name - } else { - builder := strings.builder_make(ast_context.allocator) - strings.write_string(&builder, "enum {\n") - for i in 0.. Date: Sat, 7 Jun 2025 14:20:19 -0400 Subject: Update tests for the enriched over information --- tests/hover_test.odin | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/tests/hover_test.odin b/tests/hover_test.odin index 7d1f231..abf3143 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -425,9 +425,88 @@ ast_hover_struct :: proc(t: ^testing.T) { ` } - test.expect_hover(t, &source, "test.Foo: struct {\n\tbar: int,\n\tf: proc(a: int) -> int,\n}") + test.expect_hover(t, &source, "test.Foo: struct {\n\tbar: int,\n\tf: proc(a: int) -> int,\n}") } +@(test) +ast_hover_struct_variable :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + bar: int, + f: proc(a: int) -> int, + } + + fo{*}o := Foo{} + ` + } + + test.expect_hover(t, &source, "test.foo: test.Foo :: struct {\n\tbar: int,\n\tf: proc(a: int) -> int,\n}") +} + +@(test) +ast_hover_enum :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: enum { + Foo1, + Foo2, + } + + foo: F{*}oo + ` + } + + test.expect_hover(t, &source, "test.Foo: enum {\n\tFoo1,\n\tFoo2,\n}") +} + +@(test) +ast_hover_enum_variable :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: enum { + Foo1, + Foo2, + } + + f{*}oo: Foo + ` + } + + test.expect_hover(t, &source, "test.foo: test.Foo :: enum {\n\tFoo1,\n\tFoo2,\n}") +} + +@(test) +ast_hover_union :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: union { + string, + int, + } + + foo: F{*}oo + ` + } + + test.expect_hover(t, &source, "test.Foo: union {\n\tstring,\n\tint,\n}") +} + +@(test) +ast_hover_union_variable :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: union { + string, + int, + } + + f{*}oo: Foo + ` + } + + test.expect_hover(t, &source, "test.foo: test.Foo :: union {\n\tstring,\n\tint,\n}") +} /* Waiting for odin fix -- cgit v1.2.3 From 41c5c76526aad8ca69525abfed045d501171fe24 Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sat, 7 Jun 2025 19:31:20 -0400 Subject: Add hover for struct fields within definition --- src/server/analysis.odin | 2 +- src/server/completion.odin | 4 ++-- src/server/hover.odin | 26 ++++++++++++++++++++++++-- tests/hover_test.odin | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 8a21c7d..d04ef9d 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3765,7 +3765,7 @@ unwrap_bitset :: proc(ast_context: ^AstContext, bitset_symbol: Symbol) -> (Symbo return {}, false } -get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol, was_variable := false) -> string { +get_signature :: proc(ast_context: ^AstContext, ident: ast.Any_Node, symbol: Symbol, was_variable := false) -> string { if symbol.type == .Function { return symbol.signature } diff --git a/src/server/completion.odin b/src/server/completion.odin index 8d61e3e..54bff1f 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -1289,7 +1289,7 @@ get_identifier_completion :: proc( ident.name = k if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { - symbol.signature = get_signature(ast_context, ident^, symbol) + symbol.signature = get_signature(ast_context, ident, symbol) build_procedure_symbol_signature(&symbol) @@ -1330,7 +1330,7 @@ get_identifier_completion :: proc( ident.name = k if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { - symbol.signature = get_signature(ast_context, ident^, symbol) + symbol.signature = get_signature(ast_context, ident, symbol) build_procedure_symbol_signature(&symbol) diff --git a/src/server/hover.odin b/src/server/hover.odin index cc3c5b2..9dbfc2d 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -108,6 +108,28 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> } } + if position_context.struct_type != nil { + for field in position_context.struct_type.fields.list { + for name in field.names { + if position_in_node(name, position_context.position) { + if identifier, ok := name.derived.(^ast.Ident); ok && field.type != nil { + if position_context.value_decl != nil && len(position_context.value_decl.names) != 0 { + if symbol, ok := resolve_type_expression(&ast_context, field.type); ok { + if struct_symbol, ok := resolve_type_expression(&ast_context, position_context.value_decl.names[0]); ok { + symbol.pkg = struct_symbol.name + symbol.name = identifier.name + symbol.signature = get_signature(&ast_context, field.type.derived, symbol) + hover.contents = write_hover_content(&ast_context, symbol) + return hover, true, true + } + } + } + } + } + } + } + } + if position_context.field_value != nil && position_context.comp_lit != nil { if comp_symbol, ok := resolve_comp_literal(&ast_context, &position_context); ok { if field, ok := position_context.field_value.field.derived.(^ast.Ident); ok { @@ -155,7 +177,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> if position_in_node(base, position_context.position) { if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { - resolved.signature = get_signature(&ast_context, ident, resolved) + resolved.signature = get_signature(&ast_context, &ident, resolved) resolved.name = ident.name if resolved.type == .Variable { @@ -282,7 +304,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> } if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { - resolved.signature = get_signature(&ast_context, ident, resolved) + resolved.signature = get_signature(&ast_context, &ident, resolved) resolved.name = ident.name if resolved.type == .Variable { diff --git a/tests/hover_test.odin b/tests/hover_test.odin index abf3143..840538f 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -507,6 +507,24 @@ ast_hover_union_variable :: proc(t: ^testing.T) { test.expect_hover(t, &source, "test.foo: test.Foo :: union {\n\tstring,\n\tint,\n}") } + +@(test) +ast_hover_struct_field_definition :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + b{*}ar: int, + f: proc(a: int) -> int, + } + + foo := Foo{ + bar = 1 + } + ` + } + + test.expect_hover(t, &source, "Foo.bar: int") +} /* Waiting for odin fix -- cgit v1.2.3 From 8ec7acff2b5a4a628d09ad3fe4f4b8f74fb8d856 Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sat, 7 Jun 2025 20:29:30 -0400 Subject: Fix hover on external package structs returned from procedures --- src/server/analysis.odin | 16 ++++++++++--- src/server/hover.odin | 3 ++- tests/hover_test.odin | 62 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index d04ef9d..dc3a380 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3765,6 +3765,16 @@ unwrap_bitset :: proc(ast_context: ^AstContext, bitset_symbol: Symbol) -> (Symbo return {}, false } +append_variable_full_name :: proc(sb: ^strings.Builder,ast_context: ^AstContext, symbol: Symbol, pointer_prefix: string) { + pkg_name := get_symbol_pkg_name(ast_context, symbol) + if pkg_name == "" { + fmt.sbprintf(sb, "%s%s :: ", pointer_prefix, symbol.name) + return + } + fmt.sbprintf(sb, "%s%s.%s :: ", pointer_prefix, pkg_name, symbol.name) + return +} + get_signature :: proc(ast_context: ^AstContext, ident: ast.Any_Node, symbol: Symbol, was_variable := false) -> string { if symbol.type == .Function { return symbol.signature @@ -3791,7 +3801,7 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Any_Node, symbol: Sym case SymbolEnumValue: builder := strings.builder_make(ast_context.allocator) if is_variable { - fmt.sbprintf(&builder, "%s%s.%s :: ", get_symbol_pkg_name(ast_context, symbol), pointer_prefix, symbol.name) + append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) } strings.write_string(&builder, "enum {\n") for i in 0.. if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok { symbol.name = name symbol.pkg = selector.name - symbol.signature = common.node_to_string(v.types[i]) + symbol.signature = get_signature(&ast_context, v.types[i].derived, symbol) hover.contents = write_hover_content(&ast_context, symbol) return hover, true, true } @@ -250,6 +250,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> if position_context.field != nil { if ident, ok := position_context.field.derived.(^ast.Ident); ok { if symbol, ok := resolve_type_identifier(&ast_context, ident^); ok { + symbol.signature = get_signature(&ast_context, ident, symbol) hover.contents = write_hover_content(&ast_context, symbol) return hover, true, true } diff --git a/tests/hover_test.odin b/tests/hover_test.odin index 840538f..3f941b1 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -83,7 +83,37 @@ ast_hover_external_package_parameter :: proc(t: ^testing.T) { packages = packages[:], } - test.expect_hover(t, &source, "test.cool: My_Struct") + test.expect_hover(t, &source, "test.cool: my_package.My_Struct :: struct {\n\tone: int,\n\ttwo: int,\n\tthree: int,\n}") +} + +@(test) +ast_hover_external_package_parameter_pointer :: proc(t: ^testing.T) { + packages := make([dynamic]test.Package, context.temp_allocator) + + append( + &packages, + test.Package { + pkg = "my_package", + source = `package my_package + My_Struct :: struct { + one: int, + two: int, + three: int, + } + `, + }, + ) + source := test.Source { + main = `package test + import "my_package" + main :: proc(cool: ^my_package.My_Struct) { + cool{*} + } + `, + packages = packages[:], + } + + test.expect_hover(t, &source, "test.cool: ^my_package.My_Struct :: struct {\n\tone: int,\n\ttwo: int,\n\tthree: int,\n}") } @(test) @@ -428,6 +458,36 @@ ast_hover_struct :: proc(t: ^testing.T) { test.expect_hover(t, &source, "test.Foo: struct {\n\tbar: int,\n\tf: proc(a: int) -> int,\n}") } +@(test) +ast_hover_proc_param_with_struct_from_another_package :: proc(t: ^testing.T) { + packages := make([dynamic]test.Package, context.temp_allocator) + + append( + &packages, + test.Package { + pkg = "my_package", + source = `package my_package + My_Struct :: struct { + one: int, + two: int, + three: int, + } + `, + }, + ) + source := test.Source { + main = `package test + import "my_package" + main :: proc(cool: my_package.My{*}_Struct) { + cool + } + `, + packages = packages[:], + } + + test.expect_hover(t, &source, "test.cool: My_Struct :: struct {\n\tone: int,\n\ttwo: int,\n\tthree: int\n}") +} + @(test) ast_hover_struct_variable :: proc(t: ^testing.T) { source := test.Source { -- cgit v1.2.3 From cea7502466e9a413d1b8980b6447c9316f03a93a Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sat, 7 Jun 2025 20:52:55 -0400 Subject: Add short signature parameter and update completion tests --- src/server/analysis.odin | 45 ++++++++++++++++++++++++++++++++++++++++----- src/server/completion.odin | 4 ++-- tests/completions_test.odin | 12 ++++++------ tests/hover_test.odin | 4 ++-- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index dc3a380..e67b31e 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3765,7 +3765,12 @@ unwrap_bitset :: proc(ast_context: ^AstContext, bitset_symbol: Symbol) -> (Symbo return {}, false } -append_variable_full_name :: proc(sb: ^strings.Builder,ast_context: ^AstContext, symbol: Symbol, pointer_prefix: string) { +append_variable_full_name :: proc( + sb: ^strings.Builder, + ast_context: ^AstContext, + symbol: Symbol, + pointer_prefix: string, +) { pkg_name := get_symbol_pkg_name(ast_context, symbol) if pkg_name == "" { fmt.sbprintf(sb, "%s%s :: ", pointer_prefix, symbol.name) @@ -3775,7 +3780,13 @@ append_variable_full_name :: proc(sb: ^strings.Builder,ast_context: ^AstContext, return } -get_signature :: proc(ast_context: ^AstContext, ident: ast.Any_Node, symbol: Symbol, was_variable := false) -> string { +get_signature :: proc( + ast_context: ^AstContext, + ident: ast.Any_Node, + symbol: Symbol, + was_variable := false, + short_signature := false, +) -> string { if symbol.type == .Function { return symbol.signature } @@ -3799,12 +3810,20 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Any_Node, symbol: Sym allocator = ast_context.allocator, ) case SymbolEnumValue: + if short_signature { + builder := strings.builder_make(ast_context.allocator) + if is_variable { + append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) + } + strings.write_string(&builder, "enum") + return strings.to_string(builder) + } builder := strings.builder_make(ast_context.allocator) if is_variable { append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) } strings.write_string(&builder, "enum {\n") - for i in 0..