diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2020-12-07 00:52:15 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2020-12-07 00:52:15 +0100 |
| commit | 4abc7efc0d8089db35120a16b6fd8ae079db1104 (patch) | |
| tree | 0e7773d9f91d5894a5e685a97c25f44a8beca114 /src | |
| parent | a564f967118551f339cf00d107b45953e8c10505 (diff) | |
better detail on completion and signatures with documentation
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/config.odin | 1 | ||||
| -rw-r--r-- | src/index/collector.odin | 76 | ||||
| -rw-r--r-- | src/index/indexer.odin | 10 | ||||
| -rw-r--r-- | src/index/memory_index.odin | 10 | ||||
| -rw-r--r-- | src/index/symbol.odin | 10 | ||||
| -rw-r--r-- | src/server/analysis.odin | 442 | ||||
| -rw-r--r-- | src/server/requests.odin | 35 | ||||
| -rw-r--r-- | src/server/semantic_tokens.odin | 4 | ||||
| -rw-r--r-- | src/server/types.odin | 12 |
9 files changed, 459 insertions, 141 deletions
diff --git a/src/common/config.odin b/src/common/config.odin index d9131d6..f2a733f 100644 --- a/src/common/config.odin +++ b/src/common/config.odin @@ -7,5 +7,6 @@ Config :: struct { signature_offset_support: bool, collections: map [string] string, running: bool, + debug_single_thread: bool, }; diff --git a/src/index/collector.odin b/src/index/collector.odin index f8dfb63..dc2c050 100644 --- a/src/index/collector.odin +++ b/src/index/collector.odin @@ -88,16 +88,16 @@ collect_procedure_fields :: proc(collection: ^SymbolCollection, proc_type: ^ast. return value; } -collect_struct_fields :: proc(collection: ^SymbolCollection, fields: ^ast.Field_List, package_map: map [string] string) -> SymbolStructValue { +collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.Struct_Type, package_map: map [string] string) -> SymbolStructValue { names := make([dynamic] string, 0, collection.allocator); types := make([dynamic] ^ast.Expr, 0, collection.allocator); - for field in fields.list { + for field in struct_type.fields.list { for n in field.names { - identifier := n.derived.(ast.Ident); - append(&names, get_index_unique_string(collection, identifier.name)); + ident := n.derived.(ast.Ident); + append(&names, get_index_unique_string(collection, ident.name)); cloned := clone_type(field.type, collection.allocator, &collection.unique_strings); replace_package_alias(cloned, package_map, collection); @@ -115,7 +115,45 @@ collect_struct_fields :: proc(collection: ^SymbolCollection, fields: ^ast.Field_ return value; } +collect_enum_fields :: proc(collection: ^SymbolCollection, fields: [] ^ast.Expr, package_map: map [string] string) -> SymbolEnumValue { + names := make([dynamic] string, 0, collection.allocator); + + for n in fields { + + if ident, ok := n.derived.(ast.Ident); ok { + append(&names, get_index_unique_string(collection, ident.name)); + } + + } + + value := SymbolEnumValue { + names = names[:], + }; + + + return value; +} + +collect_union_fields :: proc(collection: ^SymbolCollection, union_type: ast.Union_Type, package_map: map [string] string) -> SymbolUnionValue { + + names := make([dynamic] string, 0, collection.allocator); + + + for variant in union_type.variants { + + if ident, ok := variant.derived.(ast.Ident); ok { + append(&names, get_index_unique_string(collection, ident.name)); + } + + } + + value := SymbolUnionValue { + names = names[:], + }; + + return value; +} collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: string) -> common.Error { @@ -158,18 +196,42 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri case ast.Struct_Type: token = v; token_type = .Struct; - symbol.value = collect_struct_fields(collection, v.fields, package_map); + symbol.value = collect_struct_fields(collection, v, package_map); + case ast.Enum_Type: + token = v; + token_type = .Enum; + symbol.value = collect_enum_fields(collection, v.fields, package_map); + case ast.Union_Type: + token = v; + token_type = .Enum; + symbol.value = collect_union_fields(collection, v, package_map); case: // default break; } symbol.range = common.get_token_range(token, file.src); symbol.name = get_index_unique_string(collection, name); - symbol.scope = get_index_unique_string(collection, directory); + symbol.pkg = get_index_unique_string(collection, directory); symbol.type = token_type; symbol.uri = get_index_unique_string(collection, uri); - cat := strings.concatenate({symbol.scope, name}, context.temp_allocator); + + if value_decl.docs != nil { + + tmp: string; + + for doc in value_decl.docs.list { + tmp = strings.concatenate({tmp, "\n", doc.text}, context.temp_allocator); + } + + if tmp != "" { + replaced, allocated := strings.replace_all(tmp, "//", "", context.temp_allocator); + symbol.doc = strings.clone(replaced, collection.allocator); + } + + } + + cat := strings.concatenate({symbol.pkg, name}, context.temp_allocator); id := get_symbol_id(cat); diff --git a/src/index/indexer.odin b/src/index/indexer.odin index e7d23e3..0cd25fe 100644 --- a/src/index/indexer.odin +++ b/src/index/indexer.odin @@ -44,14 +44,14 @@ Indexer :: struct { indexer: Indexer; -lookup :: proc(name: string, scope: string, loc := #caller_location) -> (Symbol, bool) { - symbol, ok := memory_index_lookup(&indexer.static_index, name, scope); - log.infof("lookup name: %v scope: %v, symbol %v location %v", name, scope, symbol, loc); +lookup :: proc(name: string, pkg: string, loc := #caller_location) -> (Symbol, bool) { + symbol, ok := memory_index_lookup(&indexer.static_index, name, pkg); + log.infof("lookup name: %v pkg: %v, symbol %v location %v", name, pkg, symbol, loc); return symbol, ok; } -fuzzy_search :: proc(name: string, scope: [] string) -> ([] Symbol, bool) { - return memory_index_fuzzy_search(&indexer.static_index, name, scope); +fuzzy_search :: proc(name: string, pkgs: [] string) -> ([] Symbol, bool) { + return memory_index_fuzzy_search(&indexer.static_index, name, pkgs); } diff --git a/src/index/memory_index.odin b/src/index/memory_index.odin index 05de53b..c7ab26e 100644 --- a/src/index/memory_index.odin +++ b/src/index/memory_index.odin @@ -26,14 +26,12 @@ make_memory_index :: proc(collection: SymbolCollection) -> MemoryIndex { } -memory_index_lookup :: proc(index: ^MemoryIndex, name: string, scope: string) -> (Symbol, bool) { - //hashed := hash.murmur64(transmute([]u8)strings.concatenate({scope, name}, context.temp_allocator)); - - id := get_symbol_id(strings.concatenate({scope, name}, context.temp_allocator)); +memory_index_lookup :: proc(index: ^MemoryIndex, name: string, pkg: string) -> (Symbol, bool) { + id := get_symbol_id(strings.concatenate({pkg, name}, context.temp_allocator)); return index.collection.symbols[id]; } -memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, scope: [] string) -> ([] Symbol, bool) { +memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, pkgs: [] string) -> ([] Symbol, bool) { symbols := make([dynamic] Symbol, 0, context.temp_allocator); @@ -48,7 +46,7 @@ memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, scope: [] s break; } - if !exists_in_scope(symbol.scope, scope) { + if !exists_in_scope(symbol.pkg, pkgs) { continue; } diff --git a/src/index/symbol.odin b/src/index/symbol.odin index 6630015..ab8f0da 100644 --- a/src/index/symbol.odin +++ b/src/index/symbol.odin @@ -17,12 +17,6 @@ import "shared:common" */ - -SymbolFile :: struct { - imports: [] string, -}; - - SymbolStructValue :: struct { names: [] string, types: [] ^ast.Expr, @@ -71,12 +65,12 @@ SymbolValue :: union { Symbol :: struct { range: common.Range, uri: string, - scope: string, + pkg: string, name: string, + doc: string, signature: string, type: SymbolType, value: SymbolValue, - file: ^SymbolFile, }; SymbolType :: enum { diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 82f415b..d91e4fa 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -27,6 +27,7 @@ DocumentPositionContextHint :: enum { DocumentPositionContext :: struct { file: ast.File, position: common.AbsolutePosition, + line: int, function: ^ast.Node, //used to help with type resolving in function scope selector: ^ast.Expr, //used for completion identifier: ^ast.Node, @@ -502,8 +503,6 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i using ast; - v2, ok := node.derived.(ast.Pointer_Type); - switch v in node.derived { case Ident: return resolve_type_identifier(ast_context, v); @@ -548,6 +547,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i if ident, ok := v.expr.derived.(Ident); ok { if !resolve_ident_is_variable(ast_context, ident) && !resolve_ident_is_package(ast_context, ident) { + log.debugf("not a variable or package %v", ident.name); return {}, false; } @@ -559,9 +559,8 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i #partial switch s in selector.value { case index.SymbolStructValue: - if selector.uri != "" { - ast_context.current_package = selector.scope; + ast_context.current_package = selector.pkg; } else { @@ -575,10 +574,10 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i } case index.SymbolPackageValue: - ast_context.current_package = selector.scope; + ast_context.current_package = selector.pkg; if v.field != nil { - return resolve_symbol_return(ast_context, index.lookup(v.field.name, selector.scope)); + return resolve_symbol_return(ast_context, index.lookup(v.field.name, selector.pkg)); } else { @@ -594,7 +593,14 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i if ptr, ok := s.expr.derived.(Pointer_Type); ok { - log.info(ptr); + if ident, ok := v.expr.derived.(Ident); ok { + + if !resolve_ident_is_variable(ast_context, ident) && !resolve_ident_is_package(ast_context, ident) { + log.debugf("not a variable or package %v", ident.name); + return {}, false; + } + + } if symbol, ok := resolve_type_expression(ast_context, ptr.elem); ok { @@ -602,7 +608,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i case index.SymbolStructValue: if selector.uri != "" { - ast_context.current_package = symbol.scope; + ast_context.current_package = symbol.pkg; } else { @@ -628,7 +634,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i return index.Symbol {}, false; } case: - log.debugf("default node kind, resolve_type_expression: %T", v); + //log.debugf("default node kind, resolve_type_expression: %T", v); return make_symbol_generic_from_ast(ast_context, node), true; } @@ -652,7 +658,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i symbol := index.Symbol { type = .Package, - scope = imp.name, + pkg = imp.name, value = index.SymbolPackageValue { } }; @@ -750,15 +756,16 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i //keywords else if v, ok := common.keyword_map[node.name]; ok { - symbol := index.Symbol { - type = .Keyword, - }; - ident := index.new_type(Ident, node.pos, node.end, context.temp_allocator); ident.name = node.name; - symbol.value = index.SymbolGenericValue { - expr = ident, + symbol := index.Symbol { + type = .Keyword, + signature = node.name, + pkg = ast_context.current_package, + value = index.SymbolGenericValue { + expr = ident, + }, }; return symbol, true; @@ -771,7 +778,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i symbol := index.Symbol { type = .Package, - scope = node.name, + pkg = node.name, value = index.SymbolPackageValue { } }; @@ -789,7 +796,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i symbol := index.Symbol { type = .Package, - scope = imp.name, + pkg = imp.name, value = index.SymbolPackageValue { } }; @@ -926,6 +933,7 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, v: ast.Proc_Lit symbol := index.Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Function, + pkg = ast_context.current_package, }; symbol.name = name; @@ -963,6 +971,8 @@ make_symbol_generic_from_ast :: proc(ast_context: ^AstContext, expr: ^ast.Expr) symbol := index.Symbol { range = common.get_token_range(expr, ast_context.file.src), type = .Variable, + pkg = ast_context.current_package, + signature = common.get_ast_node_string(expr, ast_context.file.src), }; symbol.value = index.SymbolGenericValue { @@ -977,6 +987,7 @@ make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type) symbol := index.Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Enum, + pkg = ast_context.current_package, }; names := make([dynamic] string, context.temp_allocator); @@ -1001,6 +1012,7 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type) -> symbol := index.Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Enum, + pkg = ast_context.current_package, }; names := make([dynamic] string, context.temp_allocator); @@ -1025,6 +1037,7 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type symbol := index.Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Struct, + pkg = ast_context.current_package, }; names := make([dynamic] string, context.temp_allocator); @@ -1127,7 +1140,7 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A append(results, make_bool_ast()); } case: - log.debugf("default node get_generic_assignment %v", v); + //log.debugf("default node get_generic_assignment %v", v); append(results, value); } @@ -1205,7 +1218,7 @@ get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContex case Using_Stmt: get_locals_using_stmt(file, v, ast_context); case: - log.debugf("default node local stmt %v", v); + //log.debugf("default node local stmt %v", v); } @@ -1292,31 +1305,76 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont results := make([dynamic]^Expr, context.temp_allocator); - get_generic_assignment(file, stmt.expr, ast_context, &results); - if len(results) > 0 && stmt.val0 != nil { + if stmt.expr == nil { + return; + } + + if symbol, ok := resolve_type_expression(ast_context, stmt.expr); ok { - //treating the for range as indexed, there by returning the indexed type - indexed := index.new_type(ast.Index_Expr, results[0].pos, results[0].end, context.temp_allocator); + if generic, ok := symbol.value.(index.SymbolGenericValue); ok { - if ident, ok := stmt.val0.derived.(Ident); ok { - indexed.expr = results[0]; - ast_context.locals[ident.name] = indexed; - ast_context.variables[ident.name] = true; - } + switch v in generic.expr.derived { + case Map_Type: + if stmt.val0 != nil { - } + if ident, ok := stmt.val0.derived.(Ident); ok { + ast_context.locals[ident.name] = v.key; + ast_context.variables[ident.name] = true; + } - else if len(results) > 1 && stmt.val0 != nil && stmt.val1 != nil { + } + + if stmt.val1 != nil { + + if ident, ok := stmt.val1.derived.(Ident); ok { + ast_context.locals[ident.name] = v.value; + ast_context.variables[ident.name] = true; + } + + } + case Dynamic_Array_Type: + if stmt.val0 != nil { + + if ident, ok := stmt.val0.derived.(Ident); ok { + ast_context.locals[ident.name] = v.elem; + ast_context.variables[ident.name] = true; + } + + } + + if stmt.val1 != nil { + + if ident, ok := stmt.val1.derived.(Ident); ok { + ast_context.locals[ident.name] = make_int_ast(); + ast_context.variables[ident.name] = true; + } + + } + case Array_Type: + if stmt.val0 != nil { + + if ident, ok := stmt.val0.derived.(Ident); ok { + ast_context.locals[ident.name] = v.elem; + ast_context.variables[ident.name] = true; + } + + } + + if stmt.val1 != nil { + + if ident, ok := stmt.val1.derived.(Ident); ok { + ast_context.locals[ident.name] = make_int_ast(); + ast_context.variables[ident.name] = true; + } + + } + } - if ident, ok := stmt.val1.derived.(Ident); ok { - ast_context.locals[ident.name] = make_int_ast(); - ast_context.variables[ident.name] = true; } } - get_locals_stmt(file, stmt.body, ast_context, document_position); } @@ -1423,18 +1481,57 @@ clear_locals :: proc(ast_context: ^AstContext) { clear(&ast_context.usings); } +concatenate_symbols_information :: proc(ast_context: ^AstContext, symbol: index.Symbol) -> string { + + pkg := path.base(symbol.pkg, false, context.temp_allocator); + + if symbol.type == .Function { + + if value, ok := symbol.value.(index.SymbolProcedureValue); ok { + + if len(value.return_types) > 0 { + + tmp: string; + + for ret in value.return_types { + if ret.type != nil { + tmp = strings.concatenate({tmp, common.get_ast_node_string(ret.type, ast_context.file.src)}, context.temp_allocator); + } + } + + return strings.concatenate({pkg, "::", symbol.name, "::", symbol.signature, " -> ", "(", tmp, ")"}, context.temp_allocator); + } + + else { + return strings.concatenate({pkg, "::", symbol.name, "::", symbol.signature}, context.temp_allocator); + } + + } + + } + + else { + if symbol.signature != "" { + return strings.concatenate({pkg, "::", symbol.name, ": ", symbol.signature}, context.temp_allocator); + } + else { + return strings.concatenate({pkg, "::", symbol.name}, context.temp_allocator); + } + } + + return ""; //weird bug requires this +} + get_definition_location :: proc(document: ^Document, position: common.Position) -> (common.Location, bool) { location: common.Location; - ast_context := make_ast_context(document.ast, document.imports, document.package_name); uri: string; position_context, ok := get_document_position_context(document, position, .Definition); - if !ok { log.error("Failed to get position context"); return location, false; @@ -1446,25 +1543,13 @@ get_definition_location :: proc(document: ^Document, position: common.Position) get_locals(document.ast, position_context.function, &ast_context, &position_context); } - if position_context.identifier != nil { - - if resolved, ok := resolve_location_identifier(&ast_context, position_context.identifier.derived.(ast.Ident)); ok { - location.range = resolved.range; - uri = resolved.uri; - } - - else { - return location, false; - } - - } - - else if position_context.selector != nil { + if position_context.selector != nil { selector: index.Symbol; ast_context.use_locals = true; ast_context.use_globals = true; + ast_context.current_package = ast_context.document_package; selector, ok = resolve_type_expression(&ast_context, position_context.selector); @@ -1495,7 +1580,7 @@ get_definition_location :: proc(document: ^Document, position: common.Position) } } case index.SymbolPackageValue: - if symbol, ok := index.lookup(field, selector.scope); ok { + if symbol, ok := index.lookup(field, selector.pkg); ok { location.range = symbol.range; uri = symbol.uri; } @@ -1510,6 +1595,19 @@ get_definition_location :: proc(document: ^Document, position: common.Position) } + else if position_context.identifier != nil { + + if resolved, ok := resolve_location_identifier(&ast_context, position_context.identifier.derived.(ast.Ident)); ok { + location.range = resolved.range; + uri = resolved.uri; + } + + else { + return location, false; + } + + } + else { return location, false; } @@ -1526,6 +1624,7 @@ get_definition_location :: proc(document: ^Document, position: common.Position) return location, true; } +//ERROR can't got to common.Position get_completion_list :: proc(document: ^Document, position: common.Position) -> (CompletionList, bool) { list: CompletionList; @@ -1542,6 +1641,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( items := make([dynamic] CompletionItem, context.temp_allocator); + //log.infof("ident %v", position_context.identifier); if position_context.selector != nil { symbols := make([dynamic] index.Symbol, context.temp_allocator); @@ -1550,6 +1650,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( ast_context.use_locals = true; ast_context.use_globals = true; + ast_context.current_package = ast_context.document_package; selector, ok = resolve_type_expression(&ast_context, position_context.selector); @@ -1559,9 +1660,8 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( return list, true; } - if selector.uri != "" { - ast_context.current_package = selector.scope; + ast_context.current_package = selector.pkg; } else { @@ -1583,8 +1683,6 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( case index.SymbolEnumValue: list.isIncomplete = false; - log.info("enum value"); - for name in v.names { symbol: index.Symbol; symbol.name = name; @@ -1598,7 +1696,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( for name, i in v.names { if selector.uri != "" { - ast_context.current_package = selector.scope; + ast_context.current_package = selector.pkg; } else { @@ -1608,6 +1706,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok { symbol.name = name; symbol.type = .Field; + symbol.signature = common.get_ast_node_string(v.types[i], ast_context.file.src); append(&symbols, symbol); } @@ -1623,9 +1722,9 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( list.isIncomplete = true; - log.infof("search field %v, scope %v", field, selector.scope); + log.infof("search field %v, pkg %v", field, selector.pkg); - if searched, ok := index.fuzzy_search(field, {selector.scope}); ok { + if searched, ok := index.fuzzy_search(field, {selector.pkg}); ok { for search in searched { append(&symbols, search); @@ -1634,7 +1733,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( } else { - log.errorf("Failed to fuzzy search, field: %v, package: %v", field, selector.scope); + log.errorf("Failed to fuzzy search, field: %v, package: %v", field, selector.pkg); return list, true; } @@ -1652,7 +1751,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( for name, i in s.names { if selector.uri != "" { - ast_context.current_package = selector.scope; + ast_context.current_package = selector.pkg; } else { @@ -1662,6 +1761,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( if symbol, ok := resolve_type_expression(&ast_context, s.types[i]); ok { symbol.name = name; symbol.type = .Field; + symbol.signature = common.get_ast_node_string(s.types[i], ast_context.file.src); append(&symbols, symbol); } @@ -1678,9 +1778,12 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( } for symbol, i in symbols { + item := CompletionItem { label = symbol.name, kind = cast(CompletionItemKind) symbol.type, + detail = concatenate_symbols_information(&ast_context, symbol), + documentation = symbol.doc, }; append(&items, item); @@ -1705,7 +1808,6 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( label = k, }; - append(&items, item); } @@ -1725,21 +1827,26 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( ident.name = item.label; if symbol, ok := resolve_type_identifier(&ast_context, ident^); ok { - items[i].kind = .Variable; - } - else if symbol, ok := resolve_type_identifier(&ast_context, ident^); ok { - items[i].kind = cast(CompletionItemKind)symbol.type; - } + symbol.name = ident.name; + if ok := resolve_ident_is_variable(&ast_context, ident^); ok { + items[i].kind = .Variable; + } + else { + items[i].kind = cast(CompletionItemKind)symbol.type; + } + + items[i].detail = concatenate_symbols_information(&ast_context, symbol); + } + + //ERROR items[i]. } list.items = items[:]; } - - return list, true; } @@ -1770,7 +1877,8 @@ get_signature_information :: proc(document: ^Document, position: common.Position signature_information := make([] SignatureInformation, 1, context.temp_allocator); - signature_information[0].label = strings.concatenate({call.name, call.signature}, context.temp_allocator); + signature_information[0].label = concatenate_symbols_information(&ast_context, call); + signature_information[0].documentation = call.doc; signature_help.signatures = signature_information; @@ -1843,6 +1951,7 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi position_context.hint = hint; position_context.file = document.ast; + position_context.line = position.line; absolute_position, ok := common.get_absolute_position(position, document.text); @@ -1857,9 +1966,162 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi get_document_position(decl, &position_context); } + if hint == .Completion && position_context.selector == nil && position_context.field == nil { + fallback_position_context_completion(document, position, &position_context); + } + + else if hint == .SignatureHelp && position_context.call == nil { + fallback_position_context_signature(document, position, &position_context); + } + return position_context, true; } + +fallback_position_context_completion :: proc(document: ^Document, position: common.Position, position_context: ^DocumentPositionContext) { + + //log.info("FALLBACK TIME"); + + //log.infof("position character %c", position_context.file.src[position_context.position]); + + paren_count: int; + end: int; + start: int; + empty_dot: bool; + i := position_context.position; + + if position_context.file.src[max(0, position_context.position-1)] == '.' { + i -= 1; + empty_dot = true; + } + + + end = i; + + for i >= 0 { + + c := position_context.file.src[i]; + + if c == '(' && (paren_count == 0 || paren_count == -1) { + start = i+1; + break; + } + + else if c == ')' { + paren_count -= 1; + } + + else if c == '(' { + paren_count += 1; + } + + if c == ' ' || c == '[' || c == '{' || c == ',' || c == '}' { + start = i+1; + break; + } + + i -= 1; + } + + str := position_context.file.src[max(0, start):max(start, end)]; + + log.infof("parser string %v", string(str)); + + p := parser.Parser { + err = parser_warning_handler, //empty + warn = parser_warning_handler, //empty + file = &position_context.file, + }; + + tokenizer.init(&p.tok, str, position_context.file.fullpath); + + p.tok.line_count = position.line; + + parser.advance_token(&p); + + context.allocator = context.temp_allocator; + + e := parser.parse_expr(&p, true); + + if empty_dot { + position_context.selector = e; + } + + else if s, ok := e.derived.(ast.Selector_Expr); ok { + position_context.selector = s.expr; + position_context.field = s.field; + } + + else { + position_context.identifier = e; + } + +} + +fallback_position_context_signature :: proc(document: ^Document, position: common.Position, position_context: ^DocumentPositionContext) { + + paren_count: int; + end: int; + start: int; + first_paren: bool; + i := position_context.position; + + for i >= 0 { + + c := position_context.file.src[i]; + + if c == '(' && (paren_count == 0 || paren_count == -1) { + end = i; + first_paren = true; + } + + else if c == ')' { + paren_count -= 1; + } + + else if c == '(' { + paren_count += 1; + } + + else if c == ' ' && end != 0 { + start = i+1; + break; + } + //not good enough if you want multi function signature help + else if c == '\n' || c == '\r' { + start = i+1; + break; + } + + i -= 1; + } + + if !first_paren { + return; + } + + str := position_context.file.src[max(0, start):max(start, end)]; + + p := parser.Parser { + err = parser_warning_handler, //empty + warn = parser_warning_handler, //empty + file = &position_context.file, + }; + + tokenizer.init(&p.tok, str, position_context.file.fullpath); + + p.tok.line_count = position.line; + + parser.advance_token(&p); + + context.allocator = context.temp_allocator; + + e := parser.parse_expr(&p, true); + + position_context.call = e; +} + + get_document_position :: proc{ get_document_position_array, get_document_position_dynamic_array, @@ -1900,38 +2162,6 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP switch n in node.derived { case Bad_Expr: - - if position_context.hint == .Completion && position_context.file.src[max(0, node.end.offset-1)] == '.' { - - - str := position_context.file.src[node.pos.offset:max(0, node.end.offset-1)]; - - p := parser.Parser { - err = parser_warning_handler, //empty - warn = parser_warning_handler, //empty - file = &position_context.file, - }; - - tokenizer.init(&p.tok, str, position_context.file.fullpath); - - parser.advance_token(&p); - - context.allocator = context.temp_allocator; - - //do we still have recursive dots? - if strings.contains(string(str), ".") { - e := parser.parse_expr(&p, true); - position_context.selector = e; - } - - else { - e := parser.parse_ident(&p); - position_context.selector = e; - } - - - } - case Ident: position_context.identifier = node; return; @@ -1966,9 +2196,11 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP get_document_position(n.expr, position_context); get_document_position(n.args, position_context); case Selector_Expr: - if position_context.hint == .Completion || position_context.hint == .Definition { - position_context.selector = n.expr; - position_context.field = n.field; + if position_context.hint == .Completion || position_context.hint == .Definition { + if n.field != nil && n.field.pos.line == position_context.line { + position_context.selector = n.expr; + position_context.field = n.field; + } } else { get_document_position(n.expr, position_context); diff --git a/src/server/requests.odin b/src/server/requests.odin index 0a05bfc..ff540c7 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -229,7 +229,6 @@ handle_request :: proc(request: json.Value, config: ^common.Config, writer: ^Wri request_type: RequestType; request_type, ok = request_map[method]; - if !ok { response := make_response_message_error( id = id, @@ -338,9 +337,22 @@ handle_request :: proc(request: json.Value, config: ^common.Config, writer: ^Wri info.document = document; - common.pool_add_task(&pool, task_proc, info); + if !config.debug_single_thread { + common.pool_add_task(&pool, task_proc, info); + } + + else{ + task_proc(&task); + } case: - common.pool_add_task(&pool, task_proc, info); + + if !config.debug_single_thread { + common.pool_add_task(&pool, task_proc, info); + } + + else { + task_proc(&task); + } } } @@ -409,12 +421,21 @@ request_initialize :: proc(task: ^common.Task) { common.pool_init(&pool, thread_count); common.pool_start(&pool); + //ERROR can't go to defintion for format in initialize_params.capabilities.textDocument.hover.contentFormat { if format == .Markdown { config.hover_support_md = true; } } + + for format in initialize_params.capabilities.textDocument.completion.documentationFormat { + if format == .Markdown { + config.completion_support_md = true; + } + } + + config.signature_offset_support = initialize_params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport; completionTriggerCharacters := [] string { "." }; @@ -749,8 +770,8 @@ request_semantic_token_full :: proc(task: ^common.Task) { } }; - //symbols: SemanticTokens; - symbols := get_semantic_tokens(document, range); + symbols: SemanticTokens; + //symbols := get_semantic_tokens(document, range); response := make_response_message( params = symbols, @@ -784,8 +805,8 @@ request_semantic_token_range :: proc(task: ^common.Task) { return; } - //symbols: SemanticTokens; - symbols := get_semantic_tokens(document, semantic_params.range); + symbols: SemanticTokens; + //symbols := get_semantic_tokens(document, semantic_params.range); response := make_response_message( params = symbols, diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index 3e25209..229ae7e 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -364,6 +364,10 @@ write_semantic_tokens_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuild case Using_Stmt: write_semantic_token_pos(builder, n.pos, "using", ast_context.file.src, .Keyword, .None); write_semantic_tokens(n.list, builder, ast_context); + case Map_Type: + write_semantic_tokens(n.key, builder, ast_context); + //write_semantic_token_pos(builder, n.tok_pos, "map", ast_context.file.src, .Keyword, .None); + write_semantic_tokens(n.value, builder, ast_context); case: log.infof("unhandled write node %v", n); } diff --git a/src/server/types.odin b/src/server/types.odin index fbd0341..820ae3a 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -73,12 +73,16 @@ RequestInitializeParams :: struct { capabilities: ClientCapabilities, }; -//Can't really follow the uppercase style for enums when i need to represent it as text as well MarkupKind :: enum { Plaintext, Markdown, }; +MarkupContent :: struct { + kind: MarkupKind, + value: string, +}; + ServerCapabilities :: struct { textDocumentSync: TextDocumentSyncOptions, definitionProvider: bool, @@ -115,7 +119,7 @@ TextDocumentClientCapabilities :: struct { }; CompletionClientCapabilities :: struct { - + documentationFormat: [dynamic] MarkupKind, }; ParameterInformationCapabilities :: struct { @@ -245,6 +249,8 @@ CompletionItemKind :: enum { CompletionItem :: struct { label: string, kind: CompletionItemKind, + detail: string, + documentation: string, }; CompletionList :: struct { @@ -265,6 +271,7 @@ SignatureHelp :: struct { SignatureInformation :: struct { label: string, + documentation: string, parameters: [] ParameterInformation, }; @@ -313,7 +320,6 @@ SymbolKind :: enum { DocumentSymbol :: struct { name: string, - //detail?: string, kind: SymbolKind, range: common.Range, selectionRange: common.Range, |