diff options
| author | Brad Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-06-25 22:43:37 -0400 |
|---|---|---|
| committer | Brad Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-06-27 20:10:22 -0400 |
| commit | 9bc4a0362e74c0d5f1ea10459fa9d7cb24d0ac9d (patch) | |
| tree | cbe3f7deac4da806d1f191f88721896e1e788bae /src/server | |
| parent | 747bd0539895fdf2ef9f47ba35238e86f3021fcc (diff) | |
Correct tests after the refactor and add comment docs to struct field completions
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/ast.odin | 234 | ||||
| -rw-r--r-- | src/server/completion.odin | 15 | ||||
| -rw-r--r-- | src/server/documentation.odin | 275 | ||||
| -rw-r--r-- | src/server/hover.odin | 5 | ||||
| -rw-r--r-- | src/server/signature.odin | 4 |
5 files changed, 294 insertions, 239 deletions
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, } |