aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2025-07-30 13:35:28 +0200
committerGitHub <noreply@github.com>2025-07-30 13:35:28 +0200
commitbe3caa6defc11668c384e49c0e0acfb73ef83042 (patch)
tree9c42b35c7f6c8bd9787d860e115abeac10695900 /src/server
parent6c769f52ffd2cd40def26f758498ca4a8b2bce2b (diff)
parentac4eba2c94fdc2d0ad12409eddd00b58b2f282bd (diff)
Merge pull request #792 from BradLewis/feat/rework-documentation
Improve completion processing
Diffstat (limited to 'src/server')
-rw-r--r--src/server/analysis.odin22
-rw-r--r--src/server/completion.odin716
-rw-r--r--src/server/documentation.odin136
-rw-r--r--src/server/hover.odin71
-rw-r--r--src/server/methods.odin5
-rw-r--r--src/server/signature.odin23
-rw-r--r--src/server/snippets.odin6
-rw-r--r--src/server/symbol.odin31
8 files changed, 469 insertions, 541 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index 48d2452..9c2315e 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -891,7 +891,7 @@ resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) ->
out commented because of an infinite loop in parse_f64
else if v, ok := strconv.parse_f64(basic_lit.tok.text); ok {
value.type = .Float
- }
+ }
*/
symbol.pkg = ast_context.current_package
@@ -922,7 +922,10 @@ resolve_basic_directive :: proc(
// Gets the return type of the proc.
// Requires the underlying call expression to handle some builtin procs
get_proc_return_types :: proc(
- ast_context: ^AstContext, symbol: Symbol, call: ^ast.Call_Expr, is_mutable: bool,
+ ast_context: ^AstContext,
+ symbol: Symbol,
+ call: ^ast.Call_Expr,
+ is_mutable: bool,
) -> []^ast.Expr {
return_types := make([dynamic]^ast.Expr, context.temp_allocator)
if ret, ok := check_builtin_proc_return_type(symbol, call, is_mutable); ok {
@@ -1028,7 +1031,7 @@ check_builtin_proc_return_type :: proc(symbol: Symbol, call: ^ast.Call_Expr, is_
}
if curr_candidate != nil {
return convert_candidate(curr_candidate, is_mutable), true
- }
+ }
case "abs":
for arg in call.args {
if lit, _, ok := get_basic_lit_value(arg); ok {
@@ -1757,12 +1760,9 @@ internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ide
}
if return_symbol, ok = internal_resolve_type_expression(ast_context, v.expr); ok {
- return_types := get_proc_return_types(ast_context, return_symbol, v, global.mutable);
+ return_types := get_proc_return_types(ast_context, return_symbol, v, global.mutable)
if len(return_types) > 0 {
- return_symbol, ok = internal_resolve_type_expression(
- ast_context,
- return_types[0],
- )
+ return_symbol, ok = internal_resolve_type_expression(ast_context, return_types[0])
}
// Otherwise should be a parapoly style
}
@@ -3601,11 +3601,11 @@ get_locals_block_stmt :: proc(
ast_context: ^AstContext,
document_position: ^DocumentPositionContext,
) {
- /*
+ /*
We need to handle blocks for non mutable and mutable: non mutable has no order for their value declarations, except for nested blocks where they are hidden by scope
- For non_mutable_only we set the document_position.position to be the end of the function to get all the non-mutable locals, but that shouldn't apply to the nested block itself,
+ For non_mutable_only we set the document_position.position to be the end of the function to get all the non-mutable locals, but that shouldn't apply to the nested block itself,
but will for it's content.
-
+
Therefore we use nested_position that is the exact token we are interested in.
Example:
diff --git a/src/server/completion.odin b/src/server/completion.odin
index 8e62e15..5bf2e88 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -23,6 +23,15 @@ import "src:common"
*/
+
+CompletionResult :: struct {
+ symbol: Symbol,
+ snippet: Snippet_Info,
+ completion_item: Maybe(CompletionItem), // if we provide the completion item it will just use that
+ detail: string,
+ score: f32,
+}
+
Completion_Type :: enum {
Implicit,
Selector,
@@ -140,31 +149,177 @@ get_completion_list :: proc(
}
}
+ results := make([dynamic]CompletionResult, 0, allocator = context.temp_allocator)
+ is_incomplete := false
+
+ // TODO: as these are mutally exclusive, should probably just make them return a slice?
switch completion_type {
case .Comp_Lit:
- get_comp_lit_completion(&ast_context, &position_context, &list)
+ is_incomplete = get_comp_lit_completion(&ast_context, &position_context, &results)
case .Identifier:
- get_identifier_completion(&ast_context, &position_context, &list)
+ is_incomplete = get_identifier_completion(&ast_context, &position_context, &results)
case .Implicit:
- get_implicit_completion(&ast_context, &position_context, &list)
+ is_incomplete = get_implicit_completion(&ast_context, &position_context, &results)
case .Selector:
- get_selector_completion(&ast_context, &position_context, &list)
+ is_incomplete = get_selector_completion(&ast_context, &position_context, &results)
case .Switch_Type:
- get_type_switch_completion(&ast_context, &position_context, &list)
+ is_incomplete = get_type_switch_completion(&ast_context, &position_context, &results)
case .Directive:
- get_directive_completion(&ast_context, &position_context, &list)
+ is_incomplete = get_directive_completion(&ast_context, &position_context, &results)
case .Package:
- get_package_completion(&ast_context, &position_context, &list)
+ is_incomplete = get_package_completion(&ast_context, &position_context, &results)
+ }
+
+ items := convert_completion_results(&ast_context, &position_context, results[:], completion_type)
+ list.items = items
+ list.isIncomplete = is_incomplete
+ return list, true
+}
+
+convert_completion_results :: proc(
+ ast_context: ^AstContext,
+ position_context: ^DocumentPositionContext,
+ results: []CompletionResult,
+ completion_type: Completion_Type,
+) -> []CompletionItem {
+
+ slice.sort_by(results[:], proc(i, j: CompletionResult) -> bool {
+ return j.score < i.score
+ })
+
+ //hard code for now
+ top_results := results[0:(min(100, len(results)))]
+
+ items := make([dynamic]CompletionItem, 0, len(top_results), allocator = context.temp_allocator)
+
+ // TODO: add scores to items
+
+ for result in top_results {
+ result := result
+ if item, ok := result.completion_item.?; ok {
+ if common.config.enable_label_details {
+ item.labelDetails = CompletionItemLabelDetails {
+ description = item.detail,
+ }
+ }
+ // temporary as we move things to use the symbols directly
+ if item.documentation == nil {
+ item.documentation = MarkupContent {
+ kind = "markdown",
+ value = fmt.tprintf("```odin\n%v\n```", item.detail)
+ }
+ item.detail = ""
+ } else if s, ok := item.documentation.(string); ok && s == "" {
+ item.documentation = MarkupContent {
+ kind = "markdown",
+ value = fmt.tprintf("```odin\n%v\n```", item.detail)
+ }
+ item.detail = ""
+ }
+ append(&items, item)
+ continue
+ }
+
+ //Skip procedures when the position is in proc decl
+ if position_in_proc_decl(position_context) &&
+ result.symbol.type == .Function &&
+ common.config.enable_procedure_context {
+ continue
+ }
+
+ if result.snippet.insert != "" {
+ item := CompletionItem {
+ label = result.symbol.name,
+ insertText = result.snippet.insert,
+ kind = .Snippet,
+ detail = result.snippet.detail,
+ documentation = result.symbol.doc,
+ insertTextFormat = .Snippet,
+ }
+
+ edits := make([dynamic]TextEdit, context.temp_allocator)
+
+ for pkg in result.snippet.packages {
+ edit, ok := get_core_insert_package_if_non_existent(ast_context, pkg)
+ if ok {
+ append(&edits, edit)
+ }
+ }
+
+ item.additionalTextEdits = edits[:]
+
+ append(&items, item)
+ continue
+ }
+
+ build_documentation(ast_context, &result.symbol, true)
+ item := CompletionItem {
+ label = result.symbol.name,
+ documentation = write_hover_content(ast_context, result.symbol),
+ }
+ if common.config.enable_label_details {
+ // detail = left
+ // description = right
+ details := CompletionItemLabelDetails{}
+ if result.detail != "" {
+ details.description = result.detail
+ } else {
+ details.detail = get_completion_details(ast_context, result.symbol)
+ details.description = get_completion_description(ast_context, result.symbol)
+ }
+ // hack for sublime text's issue
+ // remove when this issue is fixed: https://github.com/sublimehq/sublime_text/issues/6033
+ // or if this PR gets merged: https://github.com/sublimelsp/LSP/pull/2293
+ if common.config.client_name == "Sublime Text LSP" {
+ if strings.contains(details.detail, "..") && strings.contains(details.detail, "#") {
+ s, _ := strings.replace_all(details.detail, "..", "ꓸꓸ", allocator = context.temp_allocator)
+ details.detail = s
+ }
+ }
+ item.labelDetails = details
+ }
+
+ item.kind = symbol_type_to_completion_kind(result.symbol.type)
+
+ if result.symbol.type == .Function && common.config.enable_snippets && common.config.enable_procedure_snippet {
+ item.insertText = fmt.tprintf("%v($0)", item.label)
+ item.insertTextFormat = .Snippet
+ item.deprecated = .Deprecated in result.symbol.flags
+ item.command = Command {
+ command = "editor.action.triggerParameterHints",
+ }
+ }
+
+ append(&items, item)
}
- // For now we simply convert all the docs to markdown here.
- convert_docs_to_markdown(&list)
+ if completion_type == .Identifier {
+ append_non_imported_packages(ast_context, position_context, &items)
+ }
+
+ return items[:]
+}
- if common.config.enable_label_details {
- format_to_label_details(&list)
+get_completion_details :: proc(ast_context: ^AstContext, symbol: Symbol) -> string {
+ #partial switch v in symbol.value {
+ case SymbolProcedureValue:
+ sb := strings.builder_make(ast_context.allocator)
+ write_proc_param_list_and_return(&sb, v)
+ return strings.to_string(sb)
+ case SymbolAggregateValue:
+ return "(..)"
}
+ return ""
+}
- return list, true
+get_completion_description :: proc(ast_context: ^AstContext, symbol: Symbol) -> string {
+ #partial switch v in symbol.value {
+ case SymbolProcedureValue:
+ return ""
+ case SymbolAggregateValue:
+ return ""
+ }
+ return get_short_signature(ast_context, symbol)
}
get_attribute_completion :: proc(
@@ -235,37 +390,36 @@ DIRECTIVE_NAME_LIST :: []string {
"optional_allocator_error",
}
-completion_items_directives: []CompletionItem
+completion_items_directives: []CompletionResult
@(init)
_init_completion_items_directives :: proc() {
- completion_items_directives = slice.mapper(DIRECTIVE_NAME_LIST, proc(name: string) -> CompletionItem {
- return {detail = strings.concatenate({"#", name}) or_else name, label = name, kind = .Constant}
+ completion_items_directives = slice.mapper(DIRECTIVE_NAME_LIST, proc(name: string) -> CompletionResult {
+ return CompletionResult{
+ completion_item = CompletionItem{
+ detail = strings.concatenate({"#", name}) or_else name, label = name, kind = .Constant,
+ }
+ }
})
}
get_directive_completion :: proc(
ast_context: ^AstContext,
position_context: ^DocumentPositionContext,
- list: ^CompletionList,
-) {
-
- list.isIncomplete = false
+ results: ^[dynamic]CompletionResult,
+) -> bool {
+ is_incomplete := false
- /*
- Right now just return all the possible completions, but later on I should give the context specific ones
- */
-
- list.items = completion_items_directives[:]
+ // Right now just return all the possible completions, but later on I should give the context specific ones
+ append(results, ..completion_items_directives[:])
+ return is_incomplete
}
get_comp_lit_completion :: proc(
ast_context: ^AstContext,
position_context: ^DocumentPositionContext,
- list: ^CompletionList,
-) {
- items := make([dynamic]CompletionItem, context.temp_allocator)
-
+ results: ^[dynamic]CompletionResult,
+) -> bool {
if symbol, ok := resolve_comp_literal(ast_context, position_context); ok {
#partial switch v in symbol.value {
case SymbolStructValue:
@@ -281,14 +435,8 @@ get_comp_lit_completion :: proc(
continue
}
- item := CompletionItem {
- label = name,
- kind = .Field,
- detail = fmt.tprintf("%v.%v: %v", symbol.name, name, node_to_string(v.types[i])),
- documentation = resolved.doc,
- }
-
- append(&items, item)
+ construct_struct_field_symbol(&resolved, symbol.name, v, i)
+ append(results, CompletionResult{symbol = resolved})
}
}
case SymbolBitFieldValue:
@@ -304,14 +452,8 @@ get_comp_lit_completion :: proc(
continue
}
- item := CompletionItem {
- label = name,
- kind = .Field,
- detail = fmt.tprintf("%v.%v: %v", symbol.name, name, node_to_string(v.types[i])),
- documentation = resolved.doc,
- }
-
- append(&items, item)
+ construct_bit_field_field_symbol(&resolved, symbol.name, v, i)
+ append(results, CompletionResult{symbol = resolved})
}
}
case SymbolFixedArrayValue:
@@ -322,47 +464,41 @@ get_comp_lit_completion :: proc(
continue
}
- item := CompletionItem {
- label = name,
- detail = fmt.tprintf(".%s", name),
- documentation = symbol.doc,
- }
-
- append(&items, item)
+ construct_enum_field_symbol(&symbol, v, i)
+ append(results, CompletionResult{symbol = symbol})
}
}
}
}
}
- list.items = items[:]
+ return false
}
get_selector_completion :: proc(
ast_context: ^AstContext,
position_context: ^DocumentPositionContext,
- list: ^CompletionList,
-) {
- items := make([dynamic]CompletionItem, context.temp_allocator)
-
+ results: ^[dynamic]CompletionResult,
+) -> bool {
ast_context.current_package = ast_context.document_package
selector: Symbol
ok: bool
+ is_incomplete := false
reset_ast_context(ast_context)
selector, ok = resolve_type_expression(ast_context, position_context.selector)
if !ok {
- return
+ return is_incomplete
}
if selector.type != .Variable &&
selector.type != .Package &&
selector.type != .Enum &&
selector.type != .Function {
- return
+ return is_incomplete
}
set_ast_package_from_symbol_scoped(ast_context, selector)
@@ -383,19 +519,19 @@ get_selector_completion :: proc(
if s, ok := selector.value.(SymbolProcedureValue); ok {
if len(s.return_types) == 1 {
if selector, ok = resolve_type_expression(ast_context, s.return_types[0].type); !ok {
- return
+ return false
}
}
}
if common.config.enable_fake_method {
- append_method_completion(ast_context, selector, position_context, &items, receiver)
+ append_method_completion(ast_context, selector, position_context, results, receiver)
}
#partial switch v in selector.value {
case SymbolFixedArrayValue:
- list.isIncomplete = true
- append_magic_array_like_completion(position_context, selector, &items)
+ is_incomplete = true
+ append_magic_array_like_completion(position_context, selector, results)
containsColor := 1
containsCoord := 1
@@ -418,7 +554,7 @@ get_selector_completion :: proc(
} else if _, ok := swizzle_coord_map[c]; ok {
containsCoord += 1
} else {
- return
+ return is_incomplete
}
}
}
@@ -437,7 +573,7 @@ get_selector_completion :: proc(
kind = .Property,
detail = fmt.tprintf("%v%v: %v", field, k, node_to_string(v.expr)),
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
expr_len = save
@@ -454,7 +590,7 @@ get_selector_completion :: proc(
kind = .Property,
detail = fmt.tprintf("%v%v: %v", field, k, node_to_string(v.expr)),
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
@@ -471,7 +607,7 @@ get_selector_completion :: proc(
kind = .Property,
detail = fmt.tprintf("%v%v: [%v]%v", field, k, containsColor, node_to_string(v.expr)),
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
} else if containsCoord > 1 {
for k in swizzle_coord_components {
@@ -486,13 +622,13 @@ get_selector_completion :: proc(
kind = .Property,
detail = fmt.tprintf("%v%v: [%v]%v", field, k, containsCoord, node_to_string(v.expr)),
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
case SymbolUnionValue:
- list.isIncomplete = false
+ is_incomplete = false
- append_magic_union_completion(position_context, selector, &items)
+ append_magic_union_completion(position_context, selector, results)
for type in v.types {
if symbol, ok := resolve_type_expression(ast_context, type); ok {
@@ -524,13 +660,12 @@ get_selector_completion :: proc(
node_to_string(type, true),
)
}
-
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
case SymbolEnumValue:
- list.isIncomplete = false
+ is_incomplete = false
for name in v.names {
item := CompletionItem {
@@ -538,11 +673,11 @@ get_selector_completion :: proc(
kind = .EnumMember,
detail = fmt.tprintf("%v.%v", selector.name, name),
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
case SymbolBitSetValue:
- list.isIncomplete = false
+ is_incomplete = false
enumv, ok := unwrap_bitset(ast_context, selector)
if !ok {break}
@@ -565,18 +700,20 @@ get_selector_completion :: proc(
for name in enumv.names {
append(
- &items,
- CompletionItem {
- label = fmt.tprintf(".%s", name),
- kind = .EnumMember,
- detail = fmt.tprintf("%s.%s", selector.name, name),
- additionalTextEdits = additionalTextEdits,
- },
+ results,
+ CompletionResult{
+ completion_item = CompletionItem{
+ label = fmt.tprintf(".%s", name),
+ kind = .EnumMember,
+ detail = fmt.tprintf("%s.%s", selector.name, name),
+ additionalTextEdits = additionalTextEdits,
+ },
+ }
)
}
case SymbolStructValue:
- list.isIncomplete = false
+ is_incomplete = false
for name, i in v.names {
if name == "_" {
@@ -603,23 +740,8 @@ get_selector_completion :: proc(
continue
}
- symbol.type_pkg = symbol.pkg
- symbol.type_name = symbol.name
- symbol.name = name
- symbol.pkg = selector.name
- symbol.type = .Field
- symbol.doc = get_doc(v.docs[i], context.temp_allocator)
- symbol.comment = get_comment(v.comments[i])
- build_documentation(ast_context, &symbol)
-
- item := CompletionItem {
- label = name,
- kind = .Field,
- detail = concatenate_symbol_information(ast_context, symbol),
- documentation = symbol.doc,
- }
-
- append(&items, item)
+ construct_struct_field_symbol(&symbol, selector.name, v, i)
+ append(results, CompletionResult{symbol = symbol})
} else {
//just give some generic symbol with name.
item := CompletionItem {
@@ -629,12 +751,12 @@ get_selector_completion :: proc(
documentation = symbol.doc,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
case SymbolBitFieldValue:
- list.isIncomplete = false
+ is_incomplete = false
for name, i in v.names {
if name == "_" {
@@ -656,7 +778,7 @@ get_selector_completion :: proc(
documentation = symbol.doc,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
} else {
//just give some generic symbol with name.
item := CompletionItem {
@@ -665,13 +787,12 @@ get_selector_completion :: proc(
detail = fmt.tprintf("%v: %v", name, node_to_string(v.types[i])),
documentation = symbol.doc,
}
-
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
case SymbolPackageValue:
- list.isIncomplete = true
+ is_incomplete = true
pkg := selector.pkg
@@ -684,60 +805,38 @@ get_selector_completion :: proc(
}
resolve_unresolved_symbol(ast_context, &symbol)
- build_documentation(ast_context, &symbol)
-
- item := CompletionItem {
- label = symbol.name,
- kind = symbol_type_to_completion_kind(symbol.type),
- detail = concatenate_symbol_information(ast_context, symbol),
- documentation = symbol.doc,
- }
-
- if symbol.type == .Function &&
- common.config.enable_snippets &&
- common.config.enable_procedure_snippet {
- item.insertText = fmt.tprintf("%v($0)", item.label)
- item.insertTextFormat = .Snippet
- item.command = Command {
- command = "editor.action.triggerParameterHints",
- }
- item.deprecated = .Deprecated in symbol.flags
- }
-
- append(&items, item)
+ append(results, CompletionResult{symbol = symbol})
}
} else {
log.errorf("Failed to fuzzy search, field: %v, package: %v", field, selector.pkg)
- return
+ return is_incomplete
}
case SymbolDynamicArrayValue:
- list.isIncomplete = false
- append_magic_array_like_completion(position_context, selector, &items)
+ is_incomplete = false
+ append_magic_array_like_completion(position_context, selector, results)
case SymbolSliceValue:
- list.isIncomplete = false
- append_magic_array_like_completion(position_context, selector, &items)
+ is_incomplete = false
+ append_magic_array_like_completion(position_context, selector, results)
case SymbolMapValue:
- list.isIncomplete = false
- append_magic_map_completion(position_context, selector, &items)
+ is_incomplete = false
+ append_magic_map_completion(position_context, selector, results)
case SymbolBasicValue:
if selector.signature == "string" {
- append_magic_array_like_completion(position_context, selector, &items)
+ append_magic_array_like_completion(position_context, selector, results)
}
}
- list.items = items[:]
+ return is_incomplete
}
get_implicit_completion :: proc(
ast_context: ^AstContext,
position_context: ^DocumentPositionContext,
- list: ^CompletionList,
-) {
- items := make([dynamic]CompletionItem, context.temp_allocator)
-
- list.isIncomplete = false
+ results: ^[dynamic]CompletionResult,
+) -> bool{
+ is_incomplete := false
selector: Symbol
@@ -757,11 +856,10 @@ get_implicit_completion :: proc(
kind = .EnumMember,
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
if position_context.comp_lit != nil {
@@ -780,10 +878,9 @@ get_implicit_completion :: proc(
documentation = symbol.doc,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
} else if v, ok := symbol.value.(SymbolStructValue); ok {
@@ -800,11 +897,10 @@ get_implicit_completion :: proc(
kind = .EnumMember,
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
}
@@ -844,11 +940,10 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
@@ -871,11 +966,10 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
@@ -896,11 +990,10 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
@@ -926,11 +1019,9 @@ get_implicit_completion :: proc(
detail = enum_name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
-
- list.items = items[:]
- return
+ return is_incomplete
}
}
}
@@ -945,7 +1036,7 @@ get_implicit_completion :: proc(
if field, ok := position_context.field_value.field.derived.(^ast.Ident); ok {
field_name = field.name
} else {
- return
+ return is_incomplete
}
}
@@ -991,11 +1082,10 @@ get_implicit_completion :: proc(
detail = enum_name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
} else if bitset_symbol, ok := resolve_type_expression(ast_context, type); ok {
set_ast_package_set_scoped(ast_context, bitset_symbol.pkg)
@@ -1008,10 +1098,9 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
} else {
@@ -1024,11 +1113,10 @@ get_implicit_completion :: proc(
detail = enum_name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
}
@@ -1061,11 +1149,10 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
@@ -1084,7 +1171,7 @@ get_implicit_completion :: proc(
if symbol, ok := resolve_type_expression(ast_context, elem); ok {
if procedure, ok := symbol.value.(SymbolProcedureValue); ok {
if procedure.return_types == nil {
- return
+ return is_incomplete
}
rhs_index += len(procedure.return_types)
@@ -1104,11 +1191,10 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
@@ -1119,7 +1205,7 @@ get_implicit_completion :: proc(
return_index: int
if position_context.returns.results == nil {
- return
+ return is_incomplete
}
for result, i in position_context.returns.results {
@@ -1130,11 +1216,11 @@ get_implicit_completion :: proc(
}
if position_context.function.type == nil {
- return
+ return is_incomplete
}
if position_context.function.type.results == nil {
- return
+ return is_incomplete
}
if len(position_context.function.type.results.list) > return_index {
@@ -1149,11 +1235,10 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
@@ -1178,7 +1263,7 @@ get_implicit_completion :: proc(
if proc_value, ok := symbol.value.(SymbolProcedureValue); ok {
arg_type, arg_type_ok := get_proc_arg_type_from_index(proc_value, parameter_index)
if !arg_type_ok {
- return
+ return is_incomplete
}
if position_context.field_value != nil {
// we are using a named param so we want to ensure we use that type and not the
@@ -1201,10 +1286,9 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
} else if enum_value, ok := symbol.value.(SymbolEnumValue); ok {
for name in enum_value.names {
@@ -1214,11 +1298,10 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
}
@@ -1232,7 +1315,7 @@ get_implicit_completion :: proc(
if position_context.previous_index != nil {
symbol, ok = resolve_type_expression(ast_context, position_context.previous_index)
if !ok {
- return
+ return is_incomplete
}
} else {
symbol, ok = resolve_type_expression(ast_context, position_context.index.expr)
@@ -1248,11 +1331,10 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
case SymbolMapValue:
if enum_value, ok := unwrap_enum(ast_context, v.key); ok {
@@ -1263,34 +1345,23 @@ get_implicit_completion :: proc(
detail = name,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
- return
+ return is_incomplete
}
}
}
+ return is_incomplete
}
get_identifier_completion :: proc(
ast_context: ^AstContext,
position_context: ^DocumentPositionContext,
- list: ^CompletionList,
-) {
- CombinedResult :: struct {
- score: f32,
- snippet: Snippet_Info,
- symbol: Symbol,
- }
-
- items := make([dynamic]CompletionItem, context.temp_allocator)
-
- list.isIncomplete = true
-
- combined := make([dynamic]CombinedResult, context.temp_allocator)
-
+ results: ^[dynamic]CompletionResult,
+) -> bool {
lookup_name := ""
+ is_incomplete := true
if position_context.identifier != nil {
if ident, ok := position_context.identifier.derived.(^ast.Ident); ok {
@@ -1309,16 +1380,13 @@ get_identifier_completion :: proc(
append(&pkgs, ast_context.document_package)
append(&pkgs, "$builtin")
- if results, ok := fuzzy_search(lookup_name, pkgs[:]); ok {
- for r in results {
+ if fuzzy_results, ok := fuzzy_search(lookup_name, pkgs[:]); ok {
+ for r in fuzzy_results {
r := r
resolve_unresolved_symbol(ast_context, &r.symbol)
-
- build_documentation(ast_context, &r.symbol)
-
uri, _ := common.parse_uri(r.symbol.uri, context.temp_allocator)
if uri.path != ast_context.fullpath {
- append(&combined, CombinedResult{score = r.score, symbol = r.symbol})
+ append(results, CompletionResult{score = r.score, symbol = r.symbol})
}
}
}
@@ -1331,7 +1399,7 @@ get_identifier_completion :: proc(
}
//combined is sorted and should do binary search instead.
- for result in combined {
+ for result in results {
if result.symbol.name == k {
continue global
}
@@ -1345,11 +1413,11 @@ get_identifier_completion :: proc(
ident.name = k
if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
- symbol.name = k
- build_documentation(ast_context, &symbol)
-
if score, ok := common.fuzzy_match(matcher, ident.name); ok == 1 {
- append(&combined, CombinedResult{score = score * 1.1, symbol = symbol})
+ symbol.type_name = symbol.name
+ symbol.type_pkg = symbol.pkg
+ symbol.name = clean_ident(ident.name)
+ append(results, CompletionResult{score = score * 1.1, symbol = symbol})
}
}
}
@@ -1374,11 +1442,11 @@ get_identifier_completion :: proc(
ident.name = k
if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
- build_documentation(ast_context, &symbol)
-
if score, ok := common.fuzzy_match(matcher, ident.name); ok == 1 {
+ symbol.type_name = symbol.name
+ symbol.type_pkg = symbol.pkg
symbol.name = clean_ident(ident.name)
- append(&combined, CombinedResult{score = score * 1.7, symbol = symbol})
+ append(results, CompletionResult{score = score * 1.7, symbol = symbol})
}
}
}
@@ -1395,7 +1463,7 @@ get_identifier_completion :: proc(
}
if score, ok := common.fuzzy_match(matcher, symbol.name); ok == 1 {
- append(&combined, CombinedResult{score = score * 1.1, symbol = symbol})
+ append(results, CompletionResult{score = score * 1.1, symbol = symbol})
}
}
@@ -1406,7 +1474,7 @@ get_identifier_completion :: proc(
}
if score, ok := common.fuzzy_match(matcher, keyword); ok == 1 {
- append(&combined, CombinedResult{score = score, symbol = symbol})
+ append(results, CompletionResult{score = score, symbol = symbol})
}
}
@@ -1417,7 +1485,7 @@ get_identifier_completion :: proc(
}
if score, ok := common.fuzzy_match(matcher, keyword); ok == 1 {
- append(&combined, CombinedResult{score = score * 1.1, symbol = symbol})
+ append(results, CompletionResult{score = score * 1.1, symbol = symbol})
}
}
@@ -1427,85 +1495,20 @@ get_identifier_completion :: proc(
symbol := Symbol {
name = k,
}
- append(&combined, CombinedResult{score = score * 1.1, snippet = v, symbol = symbol})
- }
- }
- }
-
- slice.sort_by(combined[:], proc(i, j: CombinedResult) -> bool {
- return j.score < i.score
- })
-
- //hard code for now
- top_results := combined[0:(min(100, len(combined)))]
-
- for result in top_results {
- result := result
-
- //Skip procedures when the position is in proc decl
- if position_in_proc_decl(position_context) &&
- result.symbol.type == .Function &&
- common.config.enable_procedure_context {
- continue
- }
-
- if result.snippet.insert != "" {
- item := CompletionItem {
- label = result.symbol.name,
- insertText = result.snippet.insert,
- kind = .Snippet,
- detail = result.snippet.detail,
- documentation = result.symbol.doc,
- insertTextFormat = .Snippet,
- }
-
- edits := make([dynamic]TextEdit, context.temp_allocator)
-
- for pkg in result.snippet.packages {
- edit, ok := get_core_insert_package_if_non_existent(ast_context, pkg)
- if ok {
- append(&edits, edit)
- }
+ append(results, CompletionResult{score = score * 1.1, snippet = v, symbol = symbol})
}
-
- item.additionalTextEdits = edits[:]
-
- append(&items, item)
- } else {
- item := CompletionItem {
- label = result.symbol.name,
- documentation = result.symbol.doc,
- }
-
- item.kind = symbol_type_to_completion_kind(result.symbol.type)
-
- if result.symbol.type == .Function && common.config.enable_snippets && common.config.enable_procedure_snippet {
- item.insertText = fmt.tprintf("%v($0)", item.label)
- item.insertTextFormat = .Snippet
- item.deprecated = .Deprecated in result.symbol.flags
- item.command = Command {
- command = "editor.action.triggerParameterHints",
- }
- }
-
- item.detail = concatenate_symbol_information(ast_context, result.symbol)
- append(&items, item)
}
}
- append_non_imported_packages(ast_context, position_context, &items)
-
- list.items = items[:]
+ return is_incomplete
}
get_package_completion :: proc(
ast_context: ^AstContext,
position_context: ^DocumentPositionContext,
- list: ^CompletionList,
-) {
- items := make([dynamic]CompletionItem, context.temp_allocator)
-
- list.isIncomplete = false
+ results: ^[dynamic]CompletionResult,
+) -> bool {
+ is_incomplete := false
without_quotes := position_context.import_stmt.fullpath
@@ -1551,7 +1554,7 @@ get_package_completion :: proc(
kind = .Module,
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
@@ -1566,10 +1569,10 @@ get_package_completion :: proc(
continue
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
- list.items = items[:]
+ return is_incomplete
}
clean_ident :: proc(ident: string) -> string {
@@ -1614,10 +1617,9 @@ get_used_switch_name :: proc(node: ^ast.Expr) -> (string, bool) {
get_type_switch_completion :: proc(
ast_context: ^AstContext,
position_context: ^DocumentPositionContext,
- list: ^CompletionList,
-) {
- items := make([dynamic]CompletionItem, context.temp_allocator)
- list.isIncomplete = false
+ results: ^[dynamic]CompletionResult,
+) -> bool {
+ is_incomplete := false
used_unions := make(map[string]bool, 5, context.temp_allocator)
@@ -1663,13 +1665,13 @@ get_type_switch_completion :: proc(
item.detail = item.label
}
- append(&items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
}
}
- list.items = items[:]
+ return is_incomplete
}
get_core_insert_package_if_non_existent :: proc(ast_context: ^AstContext, pkg: string) -> (TextEdit, bool) {
@@ -1708,6 +1710,7 @@ append_non_imported_packages :: proc(
position_context: ^DocumentPositionContext,
items: ^[dynamic]CompletionItem,
) {
+ // Keep these as is for now with the completion items as they are a special case
if !common.config.enable_auto_import {
return
}
@@ -1760,7 +1763,7 @@ append_non_imported_packages :: proc(
append_magic_map_completion :: proc(
position_context: ^DocumentPositionContext,
symbol: Symbol,
- items: ^[dynamic]CompletionItem,
+ results: ^[dynamic]CompletionResult,
) {
range, ok := get_range_from_selection_start_to_dot(position_context)
@@ -1775,7 +1778,7 @@ append_magic_map_completion :: proc(
kind = .Field,
detail = fmt.tprintf("%v.%v: %v", "Raw_Map", "allocator", "runtime.Allocator"),
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
remove_range := common.Range {
@@ -1813,7 +1816,7 @@ append_magic_map_completion :: proc(
InsertTextMode = .adjustIndentation,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
//len
@@ -1828,7 +1831,7 @@ append_magic_map_completion :: proc(
additionalTextEdits = additionalTextEdits,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
//cap
@@ -1843,7 +1846,7 @@ append_magic_map_completion :: proc(
additionalTextEdits = additionalTextEdits,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
prefix := "&"
@@ -1868,7 +1871,7 @@ append_magic_map_completion :: proc(
additionalTextEdits = additionalTextEdits,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
map_builtins_with_args := []string{"delete_key", "reserve", "map_insert", "map_upsert", "map_entry"}
@@ -1887,9 +1890,10 @@ append_magic_map_completion :: proc(
InsertTextMode = .adjustIndentation,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
+
get_expression_string_from_position_context :: proc(position_context: ^DocumentPositionContext) -> string {
src := position_context.file.src
if position_context.call != nil {
@@ -1915,7 +1919,7 @@ get_expression_string_from_position_context :: proc(position_context: ^DocumentP
append_magic_array_like_completion :: proc(
position_context: ^DocumentPositionContext,
symbol: Symbol,
- items: ^[dynamic]CompletionItem,
+ results: ^[dynamic]CompletionResult,
) {
range, ok := get_range_from_selection_start_to_dot(position_context)
@@ -1955,7 +1959,7 @@ append_magic_array_like_completion :: proc(
additionalTextEdits = additionalTextEdits,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
//for
@@ -1973,7 +1977,7 @@ append_magic_array_like_completion :: proc(
InsertTextMode = .adjustIndentation,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
// This proc is shared between slices and dynamic arrays.
@@ -1993,7 +1997,7 @@ append_magic_array_like_completion :: proc(
additionalTextEdits = additionalTextEdits,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
// allocator
@@ -2003,7 +2007,7 @@ append_magic_array_like_completion :: proc(
kind = .Field,
detail = fmt.tprintf("%v.%v: %v", "Raw_Dynamic_Array", "allocator", "runtime.Allocator"),
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
prefix := "&"
@@ -2028,7 +2032,7 @@ append_magic_array_like_completion :: proc(
additionalTextEdits = additionalTextEdits,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
dynamic_array_builtins := []string {
@@ -2060,14 +2064,14 @@ append_magic_array_like_completion :: proc(
InsertTextMode = .adjustIndentation,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
append_magic_union_completion :: proc(
position_context: ^DocumentPositionContext,
symbol: Symbol,
- items: ^[dynamic]CompletionItem,
+ items: ^[dynamic]CompletionResult,
) {
range, ok := get_range_from_selection_start_to_dot(position_context)
@@ -2103,71 +2107,9 @@ append_magic_union_completion :: proc(
InsertTextMode = .adjustIndentation,
}
- append(items, item)
- }
-
-}
-
-//Temporary hack to support labeldetails
-format_to_label_details :: proc(list: ^CompletionList) {
- // detail = left
- // description = right
-
- for &item in list.items {
- // log.errorf("item:%v: %v:%v", item.kind, item.label, item.detail)
- #partial switch item.kind {
- case .Function:
- proc_info := ""
- // Split the leading name of the proc
- proc_info_split := strings.split_n(item.detail, " proc", 2)
- if len(proc_info_split) == 1 {
- // No proc declaration (eg for a proc group)
- proc_info = "(..)"
- } else if len(proc_info_split) == 2 {
- proc_info = proc_info_split[1]
- }
-
- item.labelDetails = CompletionItemLabelDetails {
- detail = proc_info,
- description = "",
- }
- case .Variable, .Constant, .Field:
- type_index := strings.index(item.detail, ":")
- item.labelDetails = CompletionItemLabelDetails {
- detail = "",
- description = item.detail[type_index + 1:],
- }
- case .Struct, .Enum, .Class:
- type_index := strings.index(item.detail, ":")
- item.labelDetails = CompletionItemLabelDetails {
- detail = "",
- description = item.detail[type_index + 1:],
- }
- }
-
- // hack for sublime text's issue
- // remove when this issue is fixed: https://github.com/sublimehq/sublime_text/issues/6033
- // or if this PR gets merged: https://github.com/sublimelsp/LSP/pull/2293
- if common.config.client_name == "Sublime Text LSP" {
- dt := &item.labelDetails.? or_else nil
- if dt == nil do continue
- if strings.contains(dt.detail, "..") && strings.contains(dt.detail, "#") {
- s, _ := strings.replace_all(dt.detail, "..", "ꓸꓸ", allocator = context.temp_allocator)
- dt.detail = s
- }
- }
+ append(items, CompletionResult{completion_item = item})
}
-}
-convert_docs_to_markdown :: proc(list: ^CompletionList) {
- for &item in list.items {
- if s, ok := item.documentation.(string); ok {
- item.documentation = MarkupContent {
- kind = "markdown",
- value = s,
- }
- }
- }
}
bitset_operators: map[string]bool = {
diff --git a/src/server/documentation.odin b/src/server/documentation.odin
index c57e078..9d72043 100644
--- a/src/server/documentation.odin
+++ b/src/server/documentation.odin
@@ -107,9 +107,9 @@ keywords_docs: map[string]bool = {
// Adds signature and docs information to the provided symbol
build_documentation :: proc(ast_context: ^AstContext, symbol: ^Symbol, short_signature := true) {
if short_signature {
- symbol.signature = get_short_signature(ast_context, symbol)
+ symbol.signature = get_short_signature(ast_context, symbol^)
} else {
- symbol.signature = get_signature(ast_context, symbol)
+ symbol.signature = get_signature(ast_context, symbol^)
}
if symbol.doc == "" && symbol.comment == "" {
@@ -121,7 +121,7 @@ build_documentation :: proc(ast_context: ^AstContext, symbol: ^Symbol, short_sig
// Adds signature and docs information for a bit field field
build_bit_field_field_documentation :: proc(
- ast_context: ^AstContext, symbol: ^Symbol, value: SymbolBitFieldValue, index: int, allocator := context.temp_allocator
+ symbol: ^Symbol, value: SymbolBitFieldValue, index: int, allocator := context.temp_allocator
) {
symbol.signature = get_bit_field_field_signature(value, index, allocator)
symbol.doc = construct_symbol_docs(symbol.doc, symbol.comment)
@@ -144,16 +144,16 @@ construct_symbol_docs :: proc(docs, comment: string, allocator := context.temp_a
}
// Returns the fully detailed signature for the symbol, including things like attributes and fields
-get_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string {
- is_variable := symbol.type == .Variable
+get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string {
+ show_type_info := symbol.type == .Variable || symbol.type == .Field
pointer_prefix := repeat("^", symbol.pointers, ast_context.allocator)
#partial switch v in symbol.value {
case SymbolEnumValue:
sb := strings.builder_make(ast_context.allocator)
- if is_variable {
- append_variable_full_name(&sb, ast_context, symbol, pointer_prefix)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
strings.write_string(&sb, " :: ")
}
if len(v.names) == 0 {
@@ -189,15 +189,8 @@ get_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string {
return strings.to_string(sb)
case SymbolStructValue:
sb := strings.builder_make(ast_context.allocator)
- if symbol.type_name != "" {
- if symbol.type_pkg == "" {
- fmt.sbprintf(&sb, "%s%s :: ", pointer_prefix, symbol.type_name)
- } else {
- pkg_name := get_pkg_name(ast_context, symbol.type_pkg)
- fmt.sbprintf(&sb, "%s%s.%s :: ", pointer_prefix, pkg_name, symbol.type_name)
- }
- } else if is_variable {
- append_variable_full_name(&sb, ast_context, symbol, pointer_prefix)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
strings.write_string(&sb, " :: ")
}
if len(v.names) == 0 {
@@ -211,8 +204,8 @@ get_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string {
return strings.to_string(sb)
case SymbolUnionValue:
sb := strings.builder_make(ast_context.allocator)
- if is_variable {
- append_variable_full_name(&sb, ast_context, symbol, pointer_prefix)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
strings.write_string(&sb, " :: ")
}
if len(v.types) == 0 {
@@ -241,24 +234,17 @@ get_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string {
return strings.to_string(sb)
case SymbolProcedureValue:
sb := strings.builder_make(ast_context.allocator)
- if symbol.type_pkg != "" && symbol.type_name != "" {
- pkg_name := get_pkg_name(ast_context, symbol.type_pkg)
- fmt.sbprintf(&sb, "%s%s.%s :: ", pointer_prefix, pkg_name, symbol.type_name)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
+ strings.write_string(&sb, " :: ")
}
write_procedure_symbol_signature(&sb, v, detailed_signature=true)
return strings.to_string(sb)
case SymbolBitFieldValue:
sb := strings.builder_make(ast_context.allocator)
- if is_variable {
- append_variable_full_name(&sb, ast_context, symbol, pointer_prefix)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
strings.write_string(&sb, " :: ")
- } else if symbol.type_name != "" {
- if symbol.type_pkg == "" {
- fmt.sbprintf(&sb, "%s%s :: ", pointer_prefix, symbol.type_name)
- } else {
- pkg_name := get_pkg_name(ast_context, symbol.type_pkg)
- fmt.sbprintf(&sb, "%s%s.%s :: ", pointer_prefix, pkg_name, symbol.type_name)
- }
}
strings.write_string(&sb, "bit_field ")
build_string_node(v.backing_type, &sb, false)
@@ -299,14 +285,15 @@ get_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string {
return get_short_signature(ast_context, symbol)
}
-get_short_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string {
- is_variable := symbol.type == .Variable
+get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string {
+ // TODO: this is also a bit much, might need to clean it up into a function
+ show_type_info := (symbol.type == .Variable || symbol.type == .Field) && !(.Anonymous in symbol.flags) && symbol.type_name != ""
pointer_prefix := repeat("^", symbol.pointers, ast_context.allocator)
#partial switch v in symbol.value {
case SymbolBasicValue:
sb := strings.builder_make(ast_context.allocator)
- if symbol.type_name != "" {
+ if show_type_info {
write_symbol_type_information(ast_context, &sb, symbol, pointer_prefix)
} else if .Distinct in symbol.flags {
if symbol.type == .Keyword {
@@ -327,11 +314,13 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string
strings.write_string(&sb, "]")
return strings.to_string(sb)
case SymbolEnumValue:
+ // TODO: we need a better way to do this for enum fields
+ if symbol.type == .Field && symbol.type_name == "" {
+ return symbol.signature
+ }
sb := strings.builder_make(ast_context.allocator)
- if is_variable {
- append_variable_full_name(&sb, ast_context, symbol, pointer_prefix)
- } else if symbol.type_name != "" {
- write_symbol_type_information(ast_context, &sb, symbol, pointer_prefix)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
} else {
strings.write_string(&sb, pointer_prefix)
strings.write_string(&sb, "enum {..}")
@@ -346,20 +335,18 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string
return strings.to_string(sb)
case SymbolProcedureValue:
sb := strings.builder_make(ast_context.allocator)
- if symbol.type_pkg != "" && symbol.type_name != "" {
- pkg_name := get_pkg_name(ast_context, symbol.type_pkg)
- fmt.sbprintf(&sb, "%s%s.%s :: ", pointer_prefix, pkg_name, symbol.type_name)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
+ strings.write_string(&sb, " :: ")
}
- write_procedure_symbol_signature(&sb, v, detailed_signature=false)
+ write_procedure_symbol_signature(&sb, v, detailed_signature=true)
return strings.to_string(sb)
case SymbolAggregateValue:
- return "proc"
+ return "proc (..)"
case SymbolStructValue:
sb := strings.builder_make(ast_context.allocator)
- if is_variable {
- append_variable_full_name(&sb, ast_context, symbol, pointer_prefix)
- } else if symbol.type_name != "" {
- write_symbol_type_information(ast_context, &sb, symbol, pointer_prefix)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
} else {
strings.write_string(&sb, pointer_prefix)
strings.write_string(&sb, "struct {..}")
@@ -367,10 +354,8 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string
return strings.to_string(sb)
case SymbolUnionValue:
sb := strings.builder_make(ast_context.allocator)
- if is_variable {
- append_variable_full_name(&sb, ast_context, symbol, pointer_prefix)
- } else if symbol.type_name != "" {
- write_symbol_type_information(ast_context, &sb, symbol, pointer_prefix)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
} else {
strings.write_string(&sb, pointer_prefix)
strings.write_string(&sb, "union {..}")
@@ -378,10 +363,8 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> string
return strings.to_string(sb)
case SymbolBitFieldValue:
sb := strings.builder_make(ast_context.allocator)
- if is_variable {
- append_variable_full_name(&sb, ast_context, symbol, pointer_prefix)
- } else if symbol.type_name != "" {
- write_symbol_type_information(ast_context, &sb, symbol, pointer_prefix)
+ if show_type_info {
+ append_type_information(&sb, ast_context, symbol, pointer_prefix)
} else {
fmt.sbprintf(&sb, "%sbit_field ", pointer_prefix)
build_string_node(v.backing_type, &sb, false)
@@ -456,10 +439,10 @@ get_bit_field_field_signature :: proc(value: SymbolBitFieldValue, index: int, al
return strings.to_string(sb)
}
-write_symbol_type_information :: proc(ast_context: ^AstContext, sb: ^strings.Builder, symbol: ^Symbol, pointer_prefix: string) {
+write_symbol_type_information :: proc(ast_context: ^AstContext, sb: ^strings.Builder, symbol: Symbol, pointer_prefix: string) {
append_type_pkg := false
pkg_name := get_pkg_name(ast_context, symbol.type_pkg)
- if pkg_name != "" {
+ if pkg_name != "" && pkg_name != "$builtin" {
if _, ok := keywords_docs[symbol.type_name]; !ok {
append_type_pkg = true
}
@@ -471,18 +454,7 @@ write_symbol_type_information :: proc(ast_context: ^AstContext, sb: ^strings.Bui
}
}
-write_procedure_symbol_signature :: proc(sb: ^strings.Builder, value: SymbolProcedureValue, detailed_signature: bool) {
- if detailed_signature {
- if value.inlining == .Inline {
- strings.write_string(sb, "#force_inline ")
- } else if value.inlining == .No_Inline {
- strings.write_string(sb, "#force_no_inline ")
- }
- }
- strings.write_string(sb, "proc")
- if s, ok := value.calling_convention.(string); ok && detailed_signature {
- fmt.sbprintf(sb, " %s ", s)
- }
+write_proc_param_list_and_return :: proc(sb: ^strings.Builder, value: SymbolProcedureValue) {
strings.write_string(sb, "(")
for arg, i in value.orig_arg_types {
build_string_node(arg, sb, false)
@@ -512,6 +484,22 @@ write_procedure_symbol_signature :: proc(sb: ^strings.Builder, value: SymbolProc
} else if value.diverging {
strings.write_string(sb, " -> !")
}
+
+}
+
+write_procedure_symbol_signature :: proc(sb: ^strings.Builder, value: SymbolProcedureValue, detailed_signature: bool) {
+ if detailed_signature {
+ if value.inlining == .Inline {
+ strings.write_string(sb, "#force_inline ")
+ } else if value.inlining == .No_Inline {
+ strings.write_string(sb, "#force_no_inline ")
+ }
+ }
+ strings.write_string(sb, "proc")
+ if s, ok := value.calling_convention.(string); ok && detailed_signature {
+ fmt.sbprintf(sb, " %s ", s)
+ }
+ write_proc_param_list_and_return(sb, value)
if detailed_signature {
for tag in value.tags {
s := ""
@@ -623,18 +611,18 @@ write_struct_hover :: proc(ast_context: ^AstContext, sb: ^strings.Builder, v: Sy
strings.write_string(sb, "}")
}
-append_variable_full_name :: proc(
+append_type_information :: proc(
sb: ^strings.Builder,
ast_context: ^AstContext,
- symbol: ^Symbol,
+ symbol: Symbol,
pointer_prefix: string,
) {
- pkg_name := get_symbol_pkg_name(ast_context, symbol)
+ pkg_name := get_pkg_name(ast_context, symbol.type_pkg)
if pkg_name == "" {
- fmt.sbprintf(sb, "%s%s", pointer_prefix, symbol.name)
+ fmt.sbprintf(sb, "%s%s", pointer_prefix, symbol.type_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.type_name)
return
}
@@ -698,7 +686,6 @@ concatenate_raw_symbol_information :: proc(ast_context: ^AstContext, symbol: Sym
symbol.name,
symbol.signature,
symbol.type,
- symbol.comment,
)
}
@@ -708,7 +695,6 @@ concatenate_raw_string_information :: proc(
name: string,
signature: string,
type: SymbolType,
- comment: string,
) -> string {
pkg := path.base(pkg, false, context.temp_allocator)
diff --git a/src/server/hover.odin b/src/server/hover.odin
index 919a041..0a82406 100644
--- a/src/server/hover.odin
+++ b/src/server/hover.odin
@@ -121,13 +121,8 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
if position_in_node(ident, position_context.position) {
for name, i in v.names {
if name == ident.name {
- symbol := Symbol {
- pkg = ast_context.current_package,
- name = enum_symbol.name,
- range = common.get_token_range(ident, ast_context.file.src),
- signature = get_enum_field_signature(v, i),
- }
- hover.contents = write_hover_content(&ast_context, symbol)
+ construct_enum_field_symbol(&enum_symbol, v, i)
+ hover.contents = write_hover_content(&ast_context, enum_symbol)
return hover, true, true
}
}
@@ -137,13 +132,8 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
if ident, ok := value.field.derived.(^ast.Ident); ok {
for name, i in v.names {
if name == ident.name {
- symbol := Symbol {
- pkg = ast_context.current_package,
- range = common.get_token_range(value.field, ast_context.file.src),
- name = enum_symbol.name,
- signature = get_enum_field_signature(v, i),
- }
- hover.contents = write_hover_content(&ast_context, symbol)
+ construct_enum_field_symbol(&enum_symbol, v, i)
+ hover.contents = write_hover_content(&ast_context, enum_symbol)
}
}
}
@@ -166,14 +156,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
position_context.value_decl.names[0],
); ok {
if value, ok := struct_symbol.value.(SymbolStructValue); ok {
- symbol.range = common.get_token_range(field.node, ast_context.file.src)
- symbol.type_name = symbol.name
- symbol.type_pkg = symbol.pkg
- symbol.pkg = struct_symbol.name
- symbol.name = identifier.name
- symbol.comment = get_comment(value.comments[field_index + name_index])
- symbol.doc = get_doc(value.docs[field_index + name_index], context.temp_allocator)
-
+ construct_struct_field_symbol(&symbol, struct_symbol.name, value, field_index+name_index)
build_documentation(&ast_context, &symbol, true)
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
@@ -196,15 +179,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
position_context.value_decl.names[0],
); ok {
if value, ok := bit_field_symbol.value.(SymbolBitFieldValue); ok {
- symbol.range = common.get_token_range(field.node, ast_context.file.src)
- symbol.type_name = symbol.name
- symbol.type_pkg = symbol.pkg
- symbol.pkg = bit_field_symbol.name
- symbol.name = identifier.name
- symbol.comment = get_comment(value.comments[i])
- symbol.doc = get_doc(value.docs[i], context.temp_allocator)
-
- build_bit_field_field_documentation(&ast_context, &symbol, value, i)
+ construct_bit_field_field_symbol(&symbol, bit_field_symbol.name, value, i)
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
}
@@ -225,9 +200,8 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
for name, i in v.names {
if name == field.name {
if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok {
- symbol.name = name
- symbol.pkg = comp_symbol.name
- symbol.signature = node_to_string(v.types[i])
+ construct_struct_field_symbol(&symbol, comp_symbol.name, v, i)
+ build_documentation(&ast_context, &symbol, true)
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
}
@@ -238,9 +212,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
for name, i in v.names {
if name == field.name {
if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok {
- symbol.name = name
- symbol.pkg = comp_symbol.name
- symbol.signature = node_to_string(v.types[i])
+ construct_bit_field_field_symbol(&symbol, comp_symbol.name, v, i)
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
}
@@ -324,12 +296,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
for name, i in v.names {
if name == field {
if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok {
- symbol.type_name = symbol.name
- symbol.type_pkg = symbol.pkg
- symbol.name = name
- symbol.pkg = selector.name
- symbol.comment = get_comment(v.comments[i])
- symbol.doc = get_doc(v.docs[i], context.temp_allocator)
+ construct_struct_field_symbol(&symbol, selector.name, v, i)
build_documentation(&ast_context, &symbol, true)
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
@@ -340,12 +307,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
for name, i in v.names {
if name == field {
if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok {
- symbol.name = name
- symbol.pkg = selector.name
- symbol.doc = get_doc(v.docs[i], ast_context.allocator)
- symbol.comment = get_comment(v.comments[i])
-
- build_bit_field_field_documentation(&ast_context, &symbol, v, i)
+ construct_bit_field_field_symbol(&symbol, selector.name, v, i)
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
}
@@ -396,7 +358,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
case SymbolEnumValue:
for name, i in v.names {
if strings.compare(name, implicit_selector.field.name) == 0 {
- symbol.signature = get_enum_field_signature(v, i)
+ construct_enum_field_symbol(&symbol, v, i)
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
}
@@ -407,7 +369,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
v := enum_symbol.value.(SymbolEnumValue) or_continue
for name, i in v.names {
if strings.compare(name, implicit_selector.field.name) == 0 {
- enum_symbol.signature = get_enum_field_signature(v, i)
+ construct_enum_field_symbol(&enum_symbol, v, i)
hover.contents = write_hover_content(&ast_context, enum_symbol)
return hover, true, true
}
@@ -418,7 +380,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
if v, ok := enum_symbol.value.(SymbolEnumValue); ok {
for name, i in v.names {
if strings.compare(name, implicit_selector.field.name) == 0 {
- enum_symbol.signature = get_enum_field_signature(v, i)
+ construct_enum_field_symbol(&enum_symbol, v, i)
hover.contents = write_hover_content(&ast_context, enum_symbol)
return hover, true, true
}
@@ -451,13 +413,14 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
}
if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
- build_documentation(&ast_context, &resolved, false)
+ resolved.type_name = resolved.name
+ resolved.type_pkg = resolved.pkg
resolved.name = ident.name
-
if resolved.type == .Variable {
resolved.pkg = ast_context.document_package
}
+ build_documentation(&ast_context, &resolved, false)
hover.contents = write_hover_content(&ast_context, resolved)
return hover, true, true
}
diff --git a/src/server/methods.odin b/src/server/methods.odin
index 4b8e74e..bcd96c0 100644
--- a/src/server/methods.odin
+++ b/src/server/methods.odin
@@ -46,7 +46,7 @@ append_method_completion :: proc(
ast_context: ^AstContext,
selector_symbol: Symbol,
position_context: ^DocumentPositionContext,
- items: ^[dynamic]CompletionItem,
+ results: ^[dynamic]CompletionResult,
receiver: string,
) {
if selector_symbol.type != .Variable && selector_symbol.type != .Struct {
@@ -125,7 +125,6 @@ append_method_completion :: proc(
} else {
new_text = fmt.tprintf("%v(%v%v%v)$0", new_text, references, receiver, dereferences)
}
- build_documentation(ast_context, &symbol)
item := CompletionItem {
label = symbol.name,
@@ -138,7 +137,7 @@ append_method_completion :: proc(
documentation = symbol.doc,
}
- append(items, item)
+ append(results, CompletionResult{completion_item = item})
}
}
}
diff --git a/src/server/signature.odin b/src/server/signature.odin
index 03634d5..f333b61 100644
--- a/src/server/signature.odin
+++ b/src/server/signature.odin
@@ -134,11 +134,14 @@ get_signature_information :: proc(document: ^Document, position: common.Position
parameters[i].label = node_to_string(arg)
}
- build_documentation(&ast_context, &call)
-
+ call.doc = construct_symbol_docs(call.doc, call.comment)
+ sb := strings.builder_make(context.temp_allocator)
+ write_procedure_symbol_signature(&sb, value, detailed_signature = false)
+ call.signature = strings.to_string(sb)
+
info := SignatureInformation {
- label = concatenate_symbol_information(&ast_context, call),
- documentation = call.doc,
+ label = concatenate_raw_string_information(&ast_context, call.pkg, call.name, call.signature, call.type),
+ documentation = construct_symbol_docs(call.doc, call.comment),
parameters = parameters,
}
append(&signature_information, info)
@@ -160,11 +163,15 @@ get_signature_information :: proc(document: ^Document, position: common.Position
parameters[i].label = node_to_string(arg)
}
- build_documentation(&ast_context, &symbol)
-
+ symbol.doc = construct_symbol_docs(symbol.doc, symbol.comment)
+ sb := strings.builder_make(context.temp_allocator)
+ write_procedure_symbol_signature(&sb, value, detailed_signature = false)
+ symbol.signature = strings.to_string(sb)
+
info := SignatureInformation {
- label = concatenate_symbol_information(&ast_context, symbol),
- documentation = symbol.doc,
+ label = concatenate_raw_string_information(&ast_context, symbol.pkg, symbol.name, symbol.signature, symbol.type),
+ documentation = construct_symbol_docs(symbol.doc, symbol.comment),
+ parameters = parameters,
}
append(&signature_information, info)
diff --git a/src/server/snippets.odin b/src/server/snippets.odin
index 3dbbc29..8a68818 100644
--- a/src/server/snippets.odin
+++ b/src/server/snippets.odin
@@ -2,9 +2,9 @@
package server
Snippet_Info :: struct {
- insert: string,
- detail: string,
- packages: []string,
+ insert: string,
+ detail: string,
+ packages: []string,
}
snippets: map[string]Snippet_Info = {
diff --git a/src/server/symbol.odin b/src/server/symbol.odin
index fa6fbbf..0ead07f 100644
--- a/src/server/symbol.odin
+++ b/src/server/symbol.odin
@@ -767,3 +767,34 @@ symbol_to_expr :: proc(symbol: Symbol, file: string, allocator := context.temp_a
return nil
}
+
+// TODO: these will need ranges of the fields as well
+construct_struct_field_symbol :: proc(symbol: ^Symbol, parent_name: string, value: SymbolStructValue, index: int) {
+ symbol.type_pkg = symbol.pkg
+ symbol.type_name = symbol.name
+ symbol.name = value.names[index]
+ symbol.pkg = parent_name
+ symbol.type = .Field
+ symbol.doc = get_doc(value.docs[index], context.temp_allocator)
+ symbol.comment = get_comment(value.comments[index])
+}
+
+construct_bit_field_field_symbol :: proc(symbol: ^Symbol, parent_name: string, value: SymbolBitFieldValue, index: int) {
+ symbol.type_pkg = symbol.pkg
+ symbol.type_name = symbol.name
+ symbol.name = value.names[index]
+ symbol.pkg = parent_name
+ symbol.type = .Field
+ symbol.doc = get_doc(value.docs[index], context.temp_allocator)
+ symbol.comment = get_comment(value.comments[index])
+ symbol.doc = construct_symbol_docs(symbol.doc, symbol.comment)
+ symbol.signature = get_bit_field_field_signature(value, index)
+ //build_bit_field_field_documentation(symbol, value, index)
+}
+
+construct_enum_field_symbol :: proc(symbol: ^Symbol, value: SymbolEnumValue, index: int) {
+ symbol.type = .Field
+ //symbol.doc = get_doc(value.docs[index], context.temp_allocator)
+ //symbol.comment = get_comment(value.comments[index])
+ symbol.signature = get_enum_field_signature(value, index)
+}