From 747bd0539895fdf2ef9f47ba35238e86f3021fcc Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:23:29 -0400 Subject: Consolidate documentation writing code into new file and base it around symbols --- src/server/hover.odin | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/server/hover.odin') diff --git a/src/server/hover.odin b/src/server/hover.odin index e69249b..79c97c1 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -34,13 +34,10 @@ write_hover_content :: proc(ast_context: ^AstContext, symbol: Symbol) -> MarkupC } } - build_procedure_symbol_signature(&symbol, false) - cat := concatenate_symbol_information(ast_context, symbol, false) - - if cat != "" { + if symbol.signature != "" { content.kind = "markdown" - content.value = fmt.tprintf("```odin\n%v\n```%v", cat, symbol.doc) + content.value = fmt.tprintf("```odin\n%v\n```%v", symbol.signature, symbol.doc) } else { content.kind = "plaintext" } -- cgit v1.2.3 From 9bc4a0362e74c0d5f1ea10459fa9d7cb24d0ac9d Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Wed, 25 Jun 2025 22:43:37 -0400 Subject: Correct tests after the refactor and add comment docs to struct field completions --- src/server/ast.odin | 234 +++++++++++++++++++++++++++++++++++ src/server/completion.odin | 15 ++- src/server/documentation.odin | 275 +++++++----------------------------------- src/server/hover.odin | 5 +- src/server/signature.odin | 4 +- tests/completions_test.odin | 2 +- tests/objc_test.odin | 6 +- 7 files changed, 298 insertions(+), 243 deletions(-) (limited to 'src/server/hover.odin') diff --git a/src/server/ast.odin b/src/server/ast.odin index 629a04a..9abc1e5 100644 --- a/src/server/ast.odin +++ b/src/server/ast.odin @@ -961,6 +961,240 @@ node_equal_node :: proc(a, b: ^ast.Node) -> bool { return false } +/* + Returns the string representation of a type. This allows us to print the signature without storing it in the indexer as a string(saving memory). +*/ + +node_to_string :: proc(node: ^ast.Node, remove_pointers := false) -> string { + builder := strings.builder_make(context.temp_allocator) + + build_string(node, &builder, remove_pointers) + + return strings.to_string(builder) +} + +build_string :: proc { + build_string_ast_array, + build_string_dynamic_array, + build_string_node, +} + +build_string_dynamic_array :: proc(array: $A/[]^$T, builder: ^strings.Builder, remove_pointers: bool) { + for elem, i in array { + build_string(elem, builder, remove_pointers) + } +} + +build_string_ast_array :: proc(array: $A/[dynamic]^$T, builder: ^strings.Builder, remove_pointers: bool) { + for elem, i in array { + build_string(elem, builder, remove_pointers) + } +} + +build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder, remove_pointers: bool) { + using ast + + if node == nil { + return + } + + #partial switch n in node.derived { + case ^Bad_Expr: + case ^Ident: + if strings.contains(n.name, "/") { + strings.write_string(builder, path.base(n.name, false, context.temp_allocator)) + } else { + strings.write_string(builder, n.name) + } + case ^Implicit: + strings.write_string(builder, n.tok.text) + case ^Undef: + case ^Basic_Lit: + strings.write_string(builder, n.tok.text) + case ^Basic_Directive: + strings.write_string(builder, "#") + strings.write_string(builder, n.name) + case ^Implicit_Selector_Expr: + strings.write_string(builder, ".") + build_string(n.field, builder, remove_pointers) + case ^Ellipsis: + strings.write_string(builder, "..") + build_string(n.expr, builder, remove_pointers) + case ^Proc_Lit: + build_string(n.type, builder, remove_pointers) + build_string(n.body, builder, remove_pointers) + case ^Comp_Lit: + build_string(n.type, builder, remove_pointers) + strings.write_string(builder, "{") + for elem, i in n.elems { + build_string(elem, builder, remove_pointers) + if len(n.elems) - 1 != i { + strings.write_string(builder, ", ") + } + } + strings.write_string(builder, "}") + case ^Tag_Expr: + build_string(n.expr, builder, remove_pointers) + case ^Unary_Expr: + strings.write_string(builder, n.op.text) + build_string(n.expr, builder, remove_pointers) + case ^Binary_Expr: + build_string(n.left, builder, remove_pointers) + strings.write_string(builder, " ") + strings.write_string(builder, n.op.text) + strings.write_string(builder, " ") + build_string(n.right, builder, remove_pointers) + case ^Paren_Expr: + strings.write_string(builder, "(") + build_string(n.expr, builder, remove_pointers) + strings.write_string(builder, ")") + case ^Call_Expr: + build_string(n.expr, builder, remove_pointers) + strings.write_string(builder, "(") + for arg, i in n.args { + build_string(arg, builder, remove_pointers) + if len(n.args) - 1 != i { + strings.write_string(builder, ", ") + } + } + strings.write_string(builder, ")") + case ^Selector_Expr: + build_string(n.expr, builder, remove_pointers) + strings.write_string(builder, ".") + build_string(n.field, builder, remove_pointers) + case ^Index_Expr: + build_string(n.expr, builder, remove_pointers) + strings.write_string(builder, "[") + build_string(n.index, builder, remove_pointers) + strings.write_string(builder, "]") + case ^Deref_Expr: + build_string(n.expr, builder, remove_pointers) + case ^Slice_Expr: + build_string(n.expr, builder, remove_pointers) + build_string(n.low, builder, remove_pointers) + build_string(n.high, builder, remove_pointers) + case ^Field_Value: + build_string(n.field, builder, remove_pointers) + strings.write_string(builder, ": ") + build_string(n.value, builder, remove_pointers) + case ^Type_Cast: + build_string(n.type, builder, remove_pointers) + build_string(n.expr, builder, remove_pointers) + case ^Bad_Stmt: + case ^Bad_Decl: + case ^Attribute: + build_string(n.elems, builder, remove_pointers) + case ^Field: + for name, i in n.names { + build_string(name, builder, remove_pointers) + if len(n.names) - 1 != i { + strings.write_string(builder, ", ") + } + } + + if len(n.names) > 0 && n.type != nil { + strings.write_string(builder, ": ") + build_string(n.type, builder, remove_pointers) + + if n.default_value != nil && n.type != nil { + strings.write_string(builder, " = ") + } + + } else if len(n.names) > 0 && n.default_value != nil { + strings.write_string(builder, " := ") + } else { + build_string(n.type, builder, remove_pointers) + } + + build_string(n.default_value, builder, remove_pointers) + case ^Field_List: + for field, i in n.list { + build_string(field, builder, remove_pointers) + if len(n.list) - 1 != i { + strings.write_string(builder, ",") + } + } + case ^Typeid_Type: + strings.write_string(builder, "typeid") + build_string(n.specialization, builder, remove_pointers) + case ^Helper_Type: + build_string(n.type, builder, remove_pointers) + case ^Distinct_Type: + build_string(n.type, builder, remove_pointers) + case ^Poly_Type: + strings.write_string(builder, "$") + + build_string(n.type, builder, remove_pointers) + + if n.specialization != nil { + strings.write_string(builder, "/") + build_string(n.specialization, builder, remove_pointers) + } + case ^Proc_Type: + strings.write_string(builder, "proc(") + build_string(n.params, builder, remove_pointers) + strings.write_string(builder, ")") + if n.results != nil { + strings.write_string(builder, " -> ") + build_string(n.results, builder, remove_pointers) + } + case ^Pointer_Type: + if !remove_pointers { + strings.write_string(builder, "^") + } + build_string(n.elem, builder, remove_pointers) + case ^Array_Type: + strings.write_string(builder, "[") + build_string(n.len, builder, remove_pointers) + strings.write_string(builder, "]") + build_string(n.elem, builder, remove_pointers) + case ^Dynamic_Array_Type: + strings.write_string(builder, "[dynamic]") + build_string(n.elem, builder, remove_pointers) + case ^Struct_Type: + build_string(n.poly_params, builder, remove_pointers) + build_string(n.align, builder, remove_pointers) + build_string(n.fields, builder, remove_pointers) + case ^Union_Type: + build_string(n.poly_params, builder, remove_pointers) + build_string(n.align, builder, remove_pointers) + build_string(n.variants, builder, remove_pointers) + case ^Enum_Type: + build_string(n.base_type, builder, remove_pointers) + build_string(n.fields, builder, remove_pointers) + case ^Bit_Set_Type: + strings.write_string(builder, "bit_set") + strings.write_string(builder, "[") + build_string(n.elem, builder, remove_pointers) + strings.write_string(builder, "]") + build_string(n.underlying, builder, remove_pointers) + case ^Map_Type: + strings.write_string(builder, "map") + strings.write_string(builder, "[") + build_string(n.key, builder, remove_pointers) + strings.write_string(builder, "]") + build_string(n.value, builder, remove_pointers) + case ^ast.Multi_Pointer_Type: + strings.write_string(builder, "[^]") + build_string(n.elem, builder, remove_pointers) + case ^ast.Bit_Field_Type: + strings.write_string(builder, "bit_field") + build_string(n.backing_type, builder, remove_pointers) + for field, i in n.fields { + build_string(field, builder, remove_pointers) + if len(n.fields) - 1 != i { + strings.write_string(builder, ",") + } + } + case ^ast.Bit_Field_Field: + build_string(n.name, builder, remove_pointers) + strings.write_string(builder, ": ") + build_string(n.type, builder, remove_pointers) + strings.write_string(builder, " | ") + build_string(n.bit_size, builder, remove_pointers) + } +} + repeat :: proc(value: string, count: int, allocator := context.allocator) -> string { if count <= 0 { return "" diff --git a/src/server/completion.odin b/src/server/completion.odin index 7d76fa9..4b8fd35 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -140,7 +140,6 @@ get_completion_list :: proc( } } - switch completion_type { case .Comp_Lit: get_comp_lit_completion(&ast_context, &position_context, &list) @@ -584,16 +583,20 @@ get_selector_completion :: proc( if !position_context.arrow && .ObjC in selector.flags { continue } + + symbol.type_pkg = symbol.pkg + symbol.type_name = symbol.name symbol.name = name - symbol.pkg = selector.pkg + symbol.pkg = selector.name symbol.type = .Field symbol.doc = get_doc(v.docs[i], context.temp_allocator) symbol.comment = get_comment(v.comments[i]) + symbol.signature = get_short_signature(ast_context, symbol) item := CompletionItem { label = name, kind = .Field, - detail = get_short_signature(ast_context, symbol), + detail = concatenate_symbol_information(ast_context, symbol), documentation = symbol.doc, } @@ -667,7 +670,7 @@ get_selector_completion :: proc( item := CompletionItem { label = symbol.name, kind = symbol_type_to_completion_kind(symbol.type), - detail = get_short_signature(ast_context, symbol), + detail = concatenate_symbol_information(ast_context, symbol), documentation = symbol.doc, } @@ -1275,6 +1278,7 @@ get_identifier_completion :: proc( ident.name = k if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { + symbol.name = k symbol.signature = get_short_signature(ast_context, symbol) if score, ok := common.fuzzy_match(matcher, ident.name); ok == 1 { @@ -1417,8 +1421,7 @@ get_identifier_completion :: proc( } } - item.detail = get_short_signature(ast_context, result.symbol) - + item.detail = concatenate_symbol_information(ast_context, result.symbol) append(&items, item) } } diff --git a/src/server/documentation.odin b/src/server/documentation.odin index 57122d9..265c9d9 100644 --- a/src/server/documentation.odin +++ b/src/server/documentation.odin @@ -1,7 +1,6 @@ package server import "core:fmt" -import "core:odin/ast" import path "core:path/slashpath" import "core:strings" @@ -103,7 +102,12 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string #partial switch v in symbol.value { case SymbolBasicValue: - return strings.concatenate({pointer_prefix, node_to_string(v.ident)}, ast_context.allocator) + builder := strings.builder_make(ast_context.allocator) + fmt.sbprintf(&builder, "%s%s", pointer_prefix, node_to_string(v.ident)) + if symbol.type == .Field && symbol.comment != "" { + fmt.sbprintf(&builder, " %s", symbol.comment) + } + return strings.to_string(builder) case SymbolBitSetValue: return strings.concatenate( a = {pointer_prefix, "bit_set[", node_to_string(v.expr), "]"}, @@ -123,6 +127,10 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string ) case SymbolProcedureValue: builder := strings.builder_make(context.temp_allocator) + if symbol.type_pkg != "" { + pkg_name := get_pkg_name(ast_context, symbol.type_pkg) + fmt.sbprintf(&builder, "%s%s.%s :: ", pointer_prefix, pkg_name, symbol.type_name) + } write_procedure_symbol_signature(&builder, v) return strings.to_string(builder) case SymbolAggregateValue: @@ -301,236 +309,45 @@ append_variable_full_name :: proc( return } -/* - Returns the string representation of a type. This allows us to print the signature without storing it in the indexer as a string(saving memory). -*/ - -node_to_string :: proc(node: ^ast.Node, remove_pointers := false) -> string { - builder := strings.builder_make(context.temp_allocator) - - build_string(node, &builder, remove_pointers) - - return strings.to_string(builder) -} - -build_string :: proc { - build_string_ast_array, - build_string_dynamic_array, - build_string_node, -} - -build_string_dynamic_array :: proc(array: $A/[]^$T, builder: ^strings.Builder, remove_pointers: bool) { - for elem, i in array { - build_string(elem, builder, remove_pointers) - } +concatenate_symbol_information :: proc { + concatenate_raw_symbol_information, + concatenate_raw_string_information, } -build_string_ast_array :: proc(array: $A/[dynamic]^$T, builder: ^strings.Builder, remove_pointers: bool) { - for elem, i in array { - build_string(elem, builder, remove_pointers) - } +concatenate_raw_symbol_information :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { + return concatenate_raw_string_information( + ast_context, + symbol.pkg, + symbol.name, + symbol.signature, + symbol.type, + symbol.comment, + ) } -build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder, remove_pointers: bool) { - using ast - - if node == nil { - return - } - - #partial switch n in node.derived { - case ^Bad_Expr: - case ^Ident: - if strings.contains(n.name, "/") { - strings.write_string(builder, path.base(n.name, false, context.temp_allocator)) - } else { - strings.write_string(builder, n.name) - } - case ^Implicit: - strings.write_string(builder, n.tok.text) - case ^Undef: - case ^Basic_Lit: - strings.write_string(builder, n.tok.text) - case ^Basic_Directive: - strings.write_string(builder, "#") - strings.write_string(builder, n.name) - case ^Implicit_Selector_Expr: - strings.write_string(builder, ".") - build_string(n.field, builder, remove_pointers) - case ^Ellipsis: - strings.write_string(builder, "..") - build_string(n.expr, builder, remove_pointers) - case ^Proc_Lit: - build_string(n.type, builder, remove_pointers) - build_string(n.body, builder, remove_pointers) - case ^Comp_Lit: - build_string(n.type, builder, remove_pointers) - strings.write_string(builder, "{") - for elem, i in n.elems { - build_string(elem, builder, remove_pointers) - if len(n.elems) - 1 != i { - strings.write_string(builder, ", ") - } - } - strings.write_string(builder, "}") - case ^Tag_Expr: - build_string(n.expr, builder, remove_pointers) - case ^Unary_Expr: - strings.write_string(builder, n.op.text) - build_string(n.expr, builder, remove_pointers) - case ^Binary_Expr: - build_string(n.left, builder, remove_pointers) - strings.write_string(builder, " ") - strings.write_string(builder, n.op.text) - strings.write_string(builder, " ") - build_string(n.right, builder, remove_pointers) - case ^Paren_Expr: - strings.write_string(builder, "(") - build_string(n.expr, builder, remove_pointers) - strings.write_string(builder, ")") - case ^Call_Expr: - build_string(n.expr, builder, remove_pointers) - strings.write_string(builder, "(") - for arg, i in n.args { - build_string(arg, builder, remove_pointers) - if len(n.args) - 1 != i { - strings.write_string(builder, ", ") - } - } - strings.write_string(builder, ")") - case ^Selector_Expr: - build_string(n.expr, builder, remove_pointers) - strings.write_string(builder, ".") - build_string(n.field, builder, remove_pointers) - case ^Index_Expr: - build_string(n.expr, builder, remove_pointers) - strings.write_string(builder, "[") - build_string(n.index, builder, remove_pointers) - strings.write_string(builder, "]") - case ^Deref_Expr: - build_string(n.expr, builder, remove_pointers) - case ^Slice_Expr: - build_string(n.expr, builder, remove_pointers) - build_string(n.low, builder, remove_pointers) - build_string(n.high, builder, remove_pointers) - case ^Field_Value: - build_string(n.field, builder, remove_pointers) - strings.write_string(builder, ": ") - build_string(n.value, builder, remove_pointers) - case ^Type_Cast: - build_string(n.type, builder, remove_pointers) - build_string(n.expr, builder, remove_pointers) - case ^Bad_Stmt: - case ^Bad_Decl: - case ^Attribute: - build_string(n.elems, builder, remove_pointers) - case ^Field: - for name, i in n.names { - build_string(name, builder, remove_pointers) - if len(n.names) - 1 != i { - strings.write_string(builder, ", ") - } - } - - if len(n.names) > 0 && n.type != nil { - strings.write_string(builder, ": ") - build_string(n.type, builder, remove_pointers) - - if n.default_value != nil && n.type != nil { - strings.write_string(builder, " = ") - } - - } else if len(n.names) > 0 && n.default_value != nil { - strings.write_string(builder, " := ") - } else { - build_string(n.type, builder, remove_pointers) - } - - build_string(n.default_value, builder, remove_pointers) - case ^Field_List: - for field, i in n.list { - build_string(field, builder, remove_pointers) - if len(n.list) - 1 != i { - strings.write_string(builder, ",") - } - } - case ^Typeid_Type: - strings.write_string(builder, "typeid") - build_string(n.specialization, builder, remove_pointers) - case ^Helper_Type: - build_string(n.type, builder, remove_pointers) - case ^Distinct_Type: - build_string(n.type, builder, remove_pointers) - case ^Poly_Type: - strings.write_string(builder, "$") - - build_string(n.type, builder, remove_pointers) - - if n.specialization != nil { - strings.write_string(builder, "/") - build_string(n.specialization, builder, remove_pointers) - } - case ^Proc_Type: - strings.write_string(builder, "proc(") - build_string(n.params, builder, remove_pointers) - strings.write_string(builder, ")") - if n.results != nil { - strings.write_string(builder, " -> ") - build_string(n.results, builder, remove_pointers) - } - case ^Pointer_Type: - if !remove_pointers { - strings.write_string(builder, "^") - } - build_string(n.elem, builder, remove_pointers) - case ^Array_Type: - strings.write_string(builder, "[") - build_string(n.len, builder, remove_pointers) - strings.write_string(builder, "]") - build_string(n.elem, builder, remove_pointers) - case ^Dynamic_Array_Type: - strings.write_string(builder, "[dynamic]") - build_string(n.elem, builder, remove_pointers) - case ^Struct_Type: - build_string(n.poly_params, builder, remove_pointers) - build_string(n.align, builder, remove_pointers) - build_string(n.fields, builder, remove_pointers) - case ^Union_Type: - build_string(n.poly_params, builder, remove_pointers) - build_string(n.align, builder, remove_pointers) - build_string(n.variants, builder, remove_pointers) - case ^Enum_Type: - build_string(n.base_type, builder, remove_pointers) - build_string(n.fields, builder, remove_pointers) - case ^Bit_Set_Type: - strings.write_string(builder, "bit_set") - strings.write_string(builder, "[") - build_string(n.elem, builder, remove_pointers) - strings.write_string(builder, "]") - build_string(n.underlying, builder, remove_pointers) - case ^Map_Type: - strings.write_string(builder, "map") - strings.write_string(builder, "[") - build_string(n.key, builder, remove_pointers) - strings.write_string(builder, "]") - build_string(n.value, builder, remove_pointers) - case ^ast.Multi_Pointer_Type: - strings.write_string(builder, "[^]") - build_string(n.elem, builder, remove_pointers) - case ^ast.Bit_Field_Type: - strings.write_string(builder, "bit_field") - build_string(n.backing_type, builder, remove_pointers) - for field, i in n.fields { - build_string(field, builder, remove_pointers) - if len(n.fields) - 1 != i { - strings.write_string(builder, ",") - } - } - case ^ast.Bit_Field_Field: - build_string(n.name, builder, remove_pointers) - strings.write_string(builder, ": ") - build_string(n.type, builder, remove_pointers) - strings.write_string(builder, " | ") - build_string(n.bit_size, builder, remove_pointers) +concatenate_raw_string_information :: proc( + ast_context: ^AstContext, + pkg: string, + name: string, + signature: string, + type: SymbolType, + comment: string, +) -> string { + pkg := path.base(pkg, false, context.temp_allocator) + + if type == .Package { + return fmt.tprintf("%v: package", name) + //} else if type == .Keyword { + // return name + } else { + sb := strings.builder_make() + if type == .Function && comment != "" { + fmt.sbprintf(&sb, "%s\n", comment) + } + fmt.sbprintf(&sb, "%v.%v", pkg, name) + if signature != "" { + fmt.sbprintf(&sb, ": %v", signature) + } + return strings.to_string(sb) } } diff --git a/src/server/hover.odin b/src/server/hover.odin index 79c97c1..f8b73e9 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -34,10 +34,11 @@ write_hover_content :: proc(ast_context: ^AstContext, symbol: Symbol) -> MarkupC } } + cat := concatenate_symbol_information(ast_context, symbol) - if symbol.signature != "" { + if cat != "" { content.kind = "markdown" - content.value = fmt.tprintf("```odin\n%v\n```%v", symbol.signature, symbol.doc) + content.value = fmt.tprintf("```odin\n%v\n```%v", cat, symbol.doc) } else { content.kind = "plaintext" } diff --git a/src/server/signature.odin b/src/server/signature.odin index e076f0b..00e6fb9 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -137,7 +137,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position call.signature = get_short_signature(&ast_context, call) info := SignatureInformation { - label = get_short_signature(&ast_context, call), + label = concatenate_symbol_information(&ast_context, call), documentation = call.doc, parameters = parameters, } @@ -163,7 +163,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position symbol.signature = get_short_signature(&ast_context, symbol) info := SignatureInformation { - label = get_short_signature(&ast_context, symbol), + label = concatenate_symbol_information(&ast_context, symbol), documentation = symbol.doc, } diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 8817a2f..14bbe8b 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -2048,7 +2048,7 @@ ast_procedure_in_procedure_non_mutable_completion :: proc(t: ^testing.T) { packages = {}, } - test.expect_completion_details(t, &source, "", {"Int"}) + test.expect_completion_details(t, &source, "", {"test.Int: int"}) } @(test) diff --git a/tests/objc_test.odin b/tests/objc_test.odin index 915a3b1..9d41377 100644 --- a/tests/objc_test.odin +++ b/tests/objc_test.odin @@ -43,7 +43,7 @@ objc_return_type_with_selector_expression :: proc(t: ^testing.T) { t, &source, "->", - {"Window.initWithContentRect: my_package.Window_initWithContentRect"}, + {"Window.initWithContentRect: my_package.Window_initWithContentRect :: proc(self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: BOOL) -> ^Window"}, ) } @@ -91,7 +91,7 @@ objc_return_type_with_selector_expression_2 :: proc(t: ^testing.T) { t, &source, "->", - {"Window.initWithContentRect: my_package.Window_initWithContentRect"}, + {"Window.initWithContentRect: my_package.Window_initWithContentRect :: proc(self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: BOOL) -> ^Window"}, ) } @@ -141,7 +141,7 @@ objc_hover_chained_selector :: proc(t: ^testing.T) { test.expect_hover( t, &source, - "Window.initWithContentRect: proc(self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: BOOL) -> ^Window", + "Window.initWithContentRect: my_package.Window_initWithContentRect :: proc(self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: BOOL) -> ^Window", ) } -- cgit v1.2.3 From c8630395d0c3314c356db0cc40b4b79904909c6d Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Fri, 27 Jun 2025 21:19:02 -0400 Subject: Improve completion struct information --- src/server/analysis.odin | 2 -- src/server/documentation.odin | 43 +++++++++++++++++++++++----------------- src/server/hover.odin | 2 +- tests/completions_test.odin | 46 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 66 insertions(+), 27 deletions(-) (limited to 'src/server/hover.odin') diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 3798adc..9703ece 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -226,10 +226,8 @@ resolve_type_comp_literal :: proc( return {}, nil, false } - set_ast_package_set_scoped(ast_context, current_symbol.pkg) - for elem, element_index in current_comp_lit.elems { if !position_in_node(elem, position_context.position) { continue diff --git a/src/server/documentation.odin b/src/server/documentation.odin index 265c9d9..663d32a 100644 --- a/src/server/documentation.odin +++ b/src/server/documentation.odin @@ -1,6 +1,7 @@ package server import "core:fmt" +import "core:log" import path "core:path/slashpath" import "core:strings" @@ -11,7 +12,6 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { } is_variable := symbol.type == .Variable - is_field := symbol.type == .Field pointer_prefix := repeat("^", symbol.pointers, context.temp_allocator) @@ -21,6 +21,7 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { builder := strings.builder_make(ast_context.allocator) if is_variable { append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) + strings.write_string(&builder, " :: ") } strings.write_string(&builder, "enum {\n") for i in 0 ..< len(v.names) { @@ -34,17 +35,7 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { builder := strings.builder_make(ast_context.allocator) if is_variable { append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) - } else if is_field { - pkg_name := get_pkg_name(ast_context, symbol.type_pkg) - if pkg_name == "" { - fmt.sbprintf(&builder, "%s%s", pointer_prefix, symbol.type_name) - } else { - fmt.sbprintf(&builder, "%s%s.%s", pointer_prefix, pkg_name, symbol.type_name) - } - if symbol.comment != "" { - fmt.sbprintf(&builder, " %s", symbol.comment) - } - return strings.to_string(builder) + strings.write_string(&builder, " :: ") } else if symbol.type_name != "" { if symbol.type_pkg == "" { fmt.sbprintf(&builder, "%s%s :: ", pointer_prefix, symbol.type_name) @@ -55,6 +46,9 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { } if len(v.names) == 0 { strings.write_string(&builder, "struct {}") + if symbol.comment != "" { + fmt.sbprintf(&builder, " %s", symbol.comment) + } return strings.to_string(builder) } write_struct_hover(ast_context, &builder, v) @@ -63,6 +57,7 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { builder := strings.builder_make(ast_context.allocator) if is_variable { append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) + strings.write_string(&builder, " :: ") } strings.write_string(&builder, "union {\n") for i in 0 ..< len(v.types) { @@ -95,7 +90,6 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string } is_variable := symbol.type == .Variable - is_field := symbol.type == .Field pointer_prefix := repeat("^", symbol.pointers, context.temp_allocator) @@ -117,8 +111,9 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string builder := strings.builder_make(ast_context.allocator) if is_variable { append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) + } else { + strings.write_string(&builder, "enum") } - strings.write_string(&builder, "enum") return strings.to_string(builder) case SymbolMapValue: return strings.concatenate( @@ -139,15 +134,27 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string builder := strings.builder_make(ast_context.allocator) if is_variable { append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) + } else if symbol.type_name != "" { + pkg_name := get_pkg_name(ast_context, symbol.type_pkg) + if pkg_name == "" { + fmt.sbprintf(&builder, "%s%s", pointer_prefix, symbol.type_name) + } else { + fmt.sbprintf(&builder, "%s%s.%s", pointer_prefix, pkg_name, symbol.type_name) + } + } else { + strings.write_string(&builder, "struct") + } + if symbol.comment != "" { + fmt.sbprintf(&builder, " %s", symbol.comment) } - strings.write_string(&builder, "struct") return strings.to_string(builder) case SymbolUnionValue: builder := strings.builder_make(ast_context.allocator) if is_variable { append_variable_full_name(&builder, ast_context, symbol, pointer_prefix) + } else { + strings.write_string(&builder, "union") } - strings.write_string(&builder, "union") return strings.to_string(builder) case SymbolBitFieldValue: if is_variable { @@ -302,10 +309,10 @@ append_variable_full_name :: proc( ) { pkg_name := get_symbol_pkg_name(ast_context, symbol) if pkg_name == "" { - fmt.sbprintf(sb, "%s%s :: ", pointer_prefix, symbol.name) + fmt.sbprintf(sb, "%s%s", pointer_prefix, symbol.name) return } - fmt.sbprintf(sb, "%s%s.%s :: ", pointer_prefix, pkg_name, symbol.name) + fmt.sbprintf(sb, "%s%s.%s", pointer_prefix, pkg_name, symbol.name) return } diff --git a/src/server/hover.odin b/src/server/hover.odin index f8b73e9..52663a8 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -144,7 +144,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> } } - symbol.signature = get_signature(&ast_context, symbol) + symbol.signature = get_short_signature(&ast_context, symbol) hover.contents = write_hover_content(&ast_context, symbol) return hover, true, true } diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 14bbe8b..2e078e8 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -651,7 +651,7 @@ ast_for_in_identifier_completion :: proc(t: ^testing.T) { } - test.expect_completion_details(t, &source, "", {"test.my_element: test.My_Struct :: struct"}) + test.expect_completion_details(t, &source, "", {"test.my_element: test.My_Struct"}) } @(test) @@ -675,7 +675,7 @@ ast_for_in_call_expr_completion :: proc(t: ^testing.T) { } - test.expect_completion_details(t, &source, ".", {"test.zstep: test.Step :: struct"}) + test.expect_completion_details(t, &source, ".", {"test.zstep: test.Step"}) } @@ -1661,7 +1661,7 @@ ast_new_clone_completion :: proc(t: ^testing.T) { `, } - test.expect_completion_details(t, &source, "", {"test.adzz: ^test.Foo :: struct"}) + test.expect_completion_details(t, &source, "", {"test.adzz: ^test.Foo"}) } @(test) @@ -1735,7 +1735,7 @@ ast_index_proc_parameter_completion :: proc(t: ^testing.T) { packages = packages[:], } - test.expect_completion_details(t, &source, ".", {"my_package.param: my_package.My_Struct :: struct"}) + test.expect_completion_details(t, &source, ".", {"my_package.param: my_package.My_Struct"}) } @(test) @@ -2534,7 +2534,7 @@ ast_poly_struct_with_poly :: proc(t: ^testing.T) { `, } - test.expect_completion_details(t, &source, "", {"test.first: ^test.Animal :: struct"}) + test.expect_completion_details(t, &source, "", {"test.first: ^test.Animal"}) } @(test) @@ -3013,7 +3013,7 @@ ast_enumerated_array_range_completion :: proc(t: ^testing.T) { `, } - test.expect_completion_details(t, &source, "", {"test.indezx: test.Enum :: enum"}) + test.expect_completion_details(t, &source, "", {"test.indezx: test.Enum"}) } @(test) @@ -3306,3 +3306,37 @@ ast_completion_multi_pointer_nested :: proc(t: ^testing.T) { test.expect_completion_details(t, &source, "", {"S3.s3: int"}) } + +@(test) +ast_completion_struct_documentation :: 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 { + } + `, + }, + ) + source := test.Source { + main = `package main + + import "my_package" + + Foo :: struct { + bazz: my_package.My_Struct // bazz + } + + main :: proc() { + p := Foo{} + p.b{*} + } + `, + packages = packages[:], + } + + test.expect_completion_details(t, &source, "", {"Foo.bazz: my_package.My_Struct // bazz"}) +} -- cgit v1.2.3