From 93401ea027155fd72ec7850bd0ed74ab9e2b8b07 Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Fri, 19 Sep 2025 08:50:13 -0400 Subject: Improve hover information for constant proc lits --- src/server/documentation.odin | 70 +++++++++++++++++++++++++++++++++++-------- tests/completions_test.odin | 4 +-- tests/hover_test.odin | 44 ++++++++++++++++++++++++--- 3 files changed, 99 insertions(+), 19 deletions(-) diff --git a/src/server/documentation.odin b/src/server/documentation.odin index 53c9c36..fda1050 100644 --- a/src/server/documentation.odin +++ b/src/server/documentation.odin @@ -165,7 +165,7 @@ write_signature :: proc(sb: ^strings.Builder, ast_context: ^AstContext, symbol: } if len(v.names) == 0 { write_indent(sb, depth) - strings.write_string(sb, "enum {}") + strings.write_string(sb, "enum{}") if symbol.comment != "" { fmt.sbprintf(sb, " %s", symbol.comment) } @@ -220,7 +220,7 @@ write_signature :: proc(sb: ^strings.Builder, ast_context: ^AstContext, symbol: } write_where_clauses(sb, v.where_clauses) if len(v.types) == 0 { - strings.write_string(sb, " {}") + strings.write_string(sb, "{}") return } strings.write_string(sb, " {\n") @@ -332,7 +332,7 @@ write_short_signature :: proc(sb: ^strings.Builder, ast_context: ^AstContext, sy if len(v.names) > 0 { strings.write_string(sb, " {..}") } else { - strings.write_string(sb, " {}") + strings.write_string(sb, "{}") } return case SymbolMapValue: @@ -354,7 +354,7 @@ write_short_signature :: proc(sb: ^strings.Builder, ast_context: ^AstContext, sy if len(v.types) > 0 { strings.write_string(sb, " {..}") } else { - strings.write_string(sb, " {}") + strings.write_string(sb, "{}") } return case SymbolUnionValue: @@ -364,7 +364,7 @@ write_short_signature :: proc(sb: ^strings.Builder, ast_context: ^AstContext, sy if len(v.types) > 0 { strings.write_string(sb, " {..}") } else { - strings.write_string(sb, " {}") + strings.write_string(sb, "{}") } return case SymbolBitFieldValue: @@ -595,36 +595,49 @@ write_struct_hover :: proc(sb: ^strings.Builder, ast_context: ^AstContext, v: Sy strings.write_string(sb, "struct") write_poly_list(sb, v.poly, v.poly_names) + wrote_tag := false if v.max_field_align != nil { strings.write_string(sb, " #max_field_align") build_string_node(v.max_field_align, sb, false) + wrote_tag = true } if v.min_field_align != nil { strings.write_string(sb, " #min_field_align") build_string_node(v.min_field_align, sb, false) + wrote_tag = true } if v.align != nil { strings.write_string(sb, " #align") build_string_node(v.align, sb, false) + wrote_tag = true } for tag in v.tags { switch tag { case .Is_Raw_Union: + wrote_tag = true strings.write_string(sb, " #raw_union") case .Is_Packed: + wrote_tag = true strings.write_string(sb, " #packed") case .Is_No_Copy: + wrote_tag = true strings.write_string(sb, " #no_copy") } } - write_where_clauses(sb, v.where_clauses) + if len(v.where_clauses) > 0 { + write_where_clauses(sb, v.where_clauses) + wrote_tag = true + } if len(v.names) == 0 { - strings.write_string(sb, " {}") + if wrote_tag { + strings.write_string(sb, " ") + } + strings.write_string(sb, "{}") return } @@ -765,6 +778,31 @@ write_node :: proc( case ^ast.Proc_Type: symbol = make_symbol_procedure_from_ast(ast_context, nil, n^, name, {}, true, .None, nil) ok = true + case ^ast.Comp_Lit: + build_string(n.type, sb, false) + if len(n.elems) == 0 { + strings.write_string(sb, "{}") + return + } + if n.type != nil { + strings.write_string(sb, " {\n") + } else { + strings.write_string(sb, "{\n") + } + + for elem, i in n.elems { + write_indent(sb, depth) + if field, ok := elem.derived.(^ast.Field_Value); ok { + build_string(field.field, sb, false) + strings.write_string(sb, " = ") + build_string(field.value, sb, false) + } else { + build_string(elem, sb, false) + } + strings.write_string(sb, ",\n") + } + strings.write_string(sb, "}") + return } if ok { if short_signature { @@ -808,12 +846,18 @@ construct_symbol_information :: proc(ast_context: ^AstContext, symbol: Symbol) - } if symbol.type != .Field && .Mutable not_in symbol.flags { - if symbol.type_expr != nil && symbol.value_expr != nil { - strings.write_string(&sb, " : ") - build_string_node(symbol.type_expr, &sb, false) - strings.write_string(&sb, " : ") - build_string_node(symbol.value_expr, &sb, false) - return strings.to_string(sb) + if symbol.value_expr != nil { + if symbol.type_expr != nil { + strings.write_string(&sb, " : ") + build_string_node(symbol.type_expr, &sb, false) + strings.write_string(&sb, " : ") + write_node(&sb, ast_context, symbol.value_expr, "", 1, false) + return strings.to_string(sb) + } else if _, ok := symbol.value_expr.derived.(^ast.Comp_Lit); ok { + strings.write_string(&sb, " :: ") + write_node(&sb, ast_context, symbol.value_expr, "", 1, false) + return strings.to_string(sb) + } } strings.write_string(&sb, " :: ") } else { diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 13196a3..a97ff0f 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -4681,7 +4681,7 @@ ast_completion_struct_field_name :: proc(t: ^testing.T) { } `, } - test.expect_completion_docs(t, &source, "", {}, {"test.Foo :: struct {}"}) + test.expect_completion_docs(t, &source, "", {}, {"test.Foo :: struct{}"}) } @(test) @@ -4696,7 +4696,7 @@ ast_completion_struct_field_value :: proc(t: ^testing.T) { } `, } - test.expect_completion_docs(t, &source, "", {"test.Foo :: struct {}"}) + test.expect_completion_docs(t, &source, "", {"test.Foo :: struct{}"}) } @(test) diff --git a/tests/hover_test.odin b/tests/hover_test.odin index ee43c50..9f41c2c 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -237,7 +237,7 @@ ast_hover_on_array_infer_length_variable :: proc(t: ^testing.T) { `, } - test.expect_hover(t, &source, "test.vec :: [?]f32") + test.expect_hover(t, &source, "test.vec :: [?]f32 {\n\t1,\n\t2,\n\t3,\n}") } @(test) @@ -3192,7 +3192,7 @@ ast_hover_documentation_reexported :: proc(t: ^testing.T) { `, packages = packages[:], } - test.expect_hover(t, &source, "my_package.Foo :: struct {}\n Documentation for Foo") + test.expect_hover(t, &source, "my_package.Foo :: struct{}\n Documentation for Foo") } @(test) @@ -3218,7 +3218,7 @@ ast_hover_override_documentation_reexported :: proc(t: ^testing.T) { `, packages = packages[:], } - test.expect_hover(t, &source, "my_package.Foo :: struct {}\n New docs for Foo") + test.expect_hover(t, &source, "my_package.Foo :: struct{}\n New docs for Foo") } @(test) @@ -3913,7 +3913,7 @@ ast_hover_map_empty_struct_literal :: proc(t: ^testing.T) { m{*}: map[int]struct{} `, } - test.expect_hover(t, &source, "test.m: map[int]struct {}") + test.expect_hover(t, &source, "test.m: map[int]struct{}") } @(test) @@ -4878,6 +4878,42 @@ ast_hover_const_untyped_value :: proc(t: ^testing.T) { } test.expect_hover(t, &source, "test.FOO :: 123") } + +@(test) +ast_hover_const_comp_lit :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + a: int, + b: string, + } + + F{*}OO :: Foo { + a = 1, + b = "b", + } + `, + } + test.expect_hover(t, &source, "test.FOO :: Foo {\n\ta = 1,\n\tb = \"b\",\n}") +} + +@(test) +ast_hover_const_comp_lit_with_type :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + a: int, + b: string, + } + + F{*}OO : Foo : { + a = 1, + b = "b", + } + `, + } + test.expect_hover(t, &source, "test.FOO : Foo : {\n\ta = 1,\n\tb = \"b\",\n}") +} /* Waiting for odin fix -- cgit v1.2.3