aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-06-25 22:43:37 -0400
committerBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-06-27 20:10:22 -0400
commit9bc4a0362e74c0d5f1ea10459fa9d7cb24d0ac9d (patch)
treecbe3f7deac4da806d1f191f88721896e1e788bae /src/server
parent747bd0539895fdf2ef9f47ba35238e86f3021fcc (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.odin234
-rw-r--r--src/server/completion.odin15
-rw-r--r--src/server/documentation.odin275
-rw-r--r--src/server/hover.odin5
-rw-r--r--src/server/signature.odin4
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,
}