diff options
| author | Daniel Gavin <danielgavin5@hotmail.com> | 2022-01-19 23:44:50 +0100 |
|---|---|---|
| committer | Daniel Gavin <danielgavin5@hotmail.com> | 2022-01-19 23:44:50 +0100 |
| commit | 989345d0438429ae719287f9c7343f87b558f7e3 (patch) | |
| tree | fa789c8e61dcc53d7cffc7f2485770a5026abdc8 /src/server | |
| parent | 329180066047e6dd802872104af5be2955f092cf (diff) | |
Remove the failed idea of making request tasks
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/caches.odin | 19 | ||||
| -rw-r--r-- | src/server/completion.odin | 2 | ||||
| -rw-r--r-- | src/server/definition.odin | 2 | ||||
| -rw-r--r-- | src/server/document_symbols.odin | 2 | ||||
| -rw-r--r-- | src/server/documents.odin | 12 | ||||
| -rw-r--r-- | src/server/hover.odin | 2 | ||||
| -rw-r--r-- | src/server/inlay_hints.odin | 20 | ||||
| -rw-r--r-- | src/server/lens.odin | 2 | ||||
| -rw-r--r-- | src/server/requests.odin | 635 | ||||
| -rw-r--r-- | src/server/semantic_tokens.odin | 98 | ||||
| -rw-r--r-- | src/server/signature.odin | 2 | ||||
| -rw-r--r-- | src/server/types.odin | 6 |
12 files changed, 311 insertions, 491 deletions
diff --git a/src/server/caches.odin b/src/server/caches.odin new file mode 100644 index 0000000..640677f --- /dev/null +++ b/src/server/caches.odin @@ -0,0 +1,19 @@ +package server + +import "shared:index" +import "shared:analysis" +import "shared:common" + +//Used in semantic tokens and inlay hints to handle the entire file being resolved. +FileResolveCache :: struct { + files: map[string]map[uintptr]index.Symbol, +} + +file_resolve_cache: FileResolveCache + +resolve_entire_file :: proc(document: ^common.Document) { + file_resolve_cache.files[document.uri.uri] = analysis.resolve_entire_file( + document, + common.scratch_allocator(document.allocator), + ) +} diff --git a/src/server/completion.odin b/src/server/completion.odin index e869006..6b24d9d 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -49,7 +49,7 @@ get_completion_list :: proc(document: ^common.Document, position: common.Positio return list, true; } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); get_globals(document.ast, &ast_context); diff --git a/src/server/definition.odin b/src/server/definition.odin index 52e09dd..116fbd9 100644 --- a/src/server/definition.odin +++ b/src/server/definition.odin @@ -26,7 +26,7 @@ get_definition_location :: proc(document: ^common.Document, position: common.Pos location: common.Location; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); uri: string; diff --git a/src/server/document_symbols.odin b/src/server/document_symbols.odin index 3d3a296..7105465 100644 --- a/src/server/document_symbols.odin +++ b/src/server/document_symbols.odin @@ -23,7 +23,7 @@ import "shared:analysis" get_document_symbols :: proc(document: ^common.Document) -> []DocumentSymbol { using analysis; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); get_globals(document.ast, &ast_context); diff --git a/src/server/documents.odin b/src/server/documents.odin index 94c0cd6..4f5610a 100644 --- a/src/server/documents.odin +++ b/src/server/documents.odin @@ -23,7 +23,7 @@ ParserError :: struct { } DocumentStorage :: struct { - documents: map[string] common.Document, + documents: map[string]common.Document, free_allocators: [dynamic]^common.Scratch_Allocator, } @@ -224,8 +224,8 @@ document_close :: proc(uri_string: string) -> common.Error { free_all(common.scratch_allocator(document.allocator)); document_free_allocator(document.allocator); - document.allocator = nil; + document.allocator = nil; document.client_owned = false; common.delete_uri(document.uri); @@ -298,6 +298,12 @@ document_refresh :: proc(document: ^common.Document, config: ^common.Config, wri } } + //We only resolve the entire file, if we are dealing with the heavy features that require the entire file resolved. + //This gives the user a choice to use "fast mode" with only completion and gotos. + if config.enable_semantic_tokens || config.enable_inlay_hints { + resolve_entire_file(document); + } + return .None; } @@ -324,8 +330,6 @@ parse_document :: proc(document: ^common.Document, config: ^common.Config) -> ([ context.allocator = common.scratch_allocator(document.allocator); - document.symbol_cache = make(map[int]rawptr, 10, common.scratch_allocator(document.allocator)); - //have to cheat the parser since it really wants to parse an entire package with the new changes... pkg := new(ast.Package); pkg.kind = .Normal; diff --git a/src/server/hover.odin b/src/server/hover.odin index 1a45b8c..e7c5dba 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -57,7 +57,7 @@ get_hover_information :: proc(document: ^common.Document, position: common.Posit }, }; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); position_context, ok := get_document_position_context(document, position, .Hover); diff --git a/src/server/inlay_hints.odin b/src/server/inlay_hints.odin index e67aac9..1e7d2c3 100644 --- a/src/server/inlay_hints.odin +++ b/src/server/inlay_hints.odin @@ -8,20 +8,19 @@ import "shared:analysis" import "shared:index" //document -get_inlay_hints :: proc(document: ^common.Document) -> ([]InlayHint, bool) { - +get_inlay_hints :: proc(document: ^common.Document, symbols: map[uintptr]index.Symbol) -> ([]InlayHint, bool) { using analysis; hints := make([dynamic]InlayHint, context.temp_allocator); - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); Visit_Data :: struct { - calls: [dynamic]ast.Call_Expr, + calls: [dynamic]^ast.Node, } data := Visit_Data { - calls = make([dynamic]ast.Call_Expr, context.temp_allocator), + calls = make([dynamic]^ast.Node, context.temp_allocator), }; visit :: proc(visitor: ^ast.Visitor, node: ^ast.Node) -> ^ast.Visitor { @@ -32,7 +31,7 @@ get_inlay_hints :: proc(document: ^common.Document) -> ([]InlayHint, bool) { data := cast(^Visit_Data)visitor.data; if call, ok := node.derived.(ast.Call_Expr); ok { - append(&data.calls, call); + append(&data.calls, node); } return visitor; @@ -47,15 +46,18 @@ get_inlay_hints :: proc(document: ^common.Document) -> ([]InlayHint, bool) { ast.walk(&visitor, decl); } - loop: for call in &data.calls { + loop: for node_call in &data.calls { symbol_arg_count := 0 + + call := node_call.derived.(ast.Call_Expr); + for arg in call.args { if _, ok := arg.derived.(ast.Field); ok { continue loop; } } - if symbol, ok := resolve_type_expression(&ast_context, &call); ok { + if symbol, ok := symbols[cast(uintptr)node_call]; ok { if symbol_call, ok := symbol.value.(index.SymbolProcedureValue); ok { for arg in symbol_call.arg_types { for name in arg.names { @@ -66,7 +68,7 @@ get_inlay_hints :: proc(document: ^common.Document) -> ([]InlayHint, bool) { if ident, ok := name.derived.(ast.Ident); ok { hint := InlayHint { kind = "parameter", - label = fmt.tprintf("%v:", ident.name), + label = fmt.tprintf("%v = ", ident.name), range = common.get_token_range(call.args[symbol_arg_count], string(document.text)), } append(&hints, hint); diff --git a/src/server/lens.odin b/src/server/lens.odin index 822a115..9d80d0c 100644 --- a/src/server/lens.odin +++ b/src/server/lens.odin @@ -24,7 +24,7 @@ get_code_lenses :: proc(document: ^common.Document, position: common.Position) - using analysis; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); get_globals(document.ast, &ast_context); diff --git a/src/server/requests.odin b/src/server/requests.odin index 4fc4b48..5ab8dde 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -56,11 +56,6 @@ RequestInfo :: struct { result: common.Error, } -pool: common.Pool; - -get_request_info :: proc (task: ^common.Task) -> ^RequestInfo { - return cast(^RequestInfo)task.data; -} make_response_message :: proc (id: RequestId, params: ResponseParams) -> ResponseMessage { @@ -159,7 +154,7 @@ read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bo err: json.Error; - value, err = json.parse(data = data, allocator = context.allocator, parse_integers = true); + value, err = json.parse(data = data, allocator = context.temp_allocator, parse_integers = true); if (err != json.Error.None) { log.error("Failed to parse body"); @@ -169,41 +164,27 @@ read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bo return value, true; } -request_map: map[string]RequestType = { - "initialize" = .Initialize, - "initialized" = .Initialized, - "shutdown" = .Shutdown, - "exit" = .Exit, - "textDocument/didOpen" = .DidOpen, - "textDocument/didChange" = .DidChange, - "textDocument/didClose" = .DidClose, - "textDocument/didSave" = .DidSave, - "textDocument/definition" = .Definition, - "textDocument/completion" = .Completion, - "textDocument/signatureHelp" = .SignatureHelp, - "textDocument/documentSymbol" = .DocumentSymbol, - "textDocument/semanticTokens/full" = .SemanticTokensFull, - "textDocument/semanticTokens/range" = .SemanticTokensRange, - "textDocument/hover" = .Hover, - "$/cancelRequest" = .CancelRequest, - "textDocument/formatting" = .FormatDocument, - "odin/inlayHints" = .InlayHint, +call_map : map [string] proc(json.Value, RequestId, ^common.Config, ^Writer) -> common.Error = +{ + "initialize" = request_initialize, + "initialized" = request_initialized, + "shutdown" = request_shutdown, + "exit" = notification_exit, + "textDocument/didOpen" = notification_did_open, + "textDocument/didChange" = notification_did_change, + "textDocument/didClose" = notification_did_close, + "textDocument/didSave" = notification_did_save, + "textDocument/definition" = request_definition, + "textDocument/completion" = request_completion, + "textDocument/signatureHelp" = request_signature_help, + "textDocument/documentSymbol" = request_document_symbols, + "textDocument/semanticTokens/full" = request_semantic_token_full, + "textDocument/semanticTokens/range" = request_semantic_token_range, + "textDocument/hover" = request_hover, + "textDocument/formatting" = request_format_document, }; -handle_error :: proc (err: common.Error, id: RequestId, writer: ^Writer) { - - if err != .None { - - response := make_response_message_error( - id = id, - error = ResponseError {code = err, message = ""}); - - send_error(response, writer); - } -} - handle_request :: proc (request: json.Value, config: ^common.Config, writer: ^Writer) -> bool { - root, ok := request.(json.Object); if !ok { @@ -229,8 +210,8 @@ handle_request :: proc (request: json.Value, config: ^common.Config, writer: ^Wr method := root["method"].(json.String); - request_type: RequestType; - request_type, ok = request_map[method]; + fn: proc(json.Value, RequestId, ^common.Config, ^Writer) -> common.Error; + fn, ok = call_map[method]; if !ok { response := make_response_message_error( @@ -239,157 +220,31 @@ handle_request :: proc (request: json.Value, config: ^common.Config, writer: ^Wr send_error(response, writer); } else { - - info := new(RequestInfo); - - info.root = request; - info.params = root["params"]; - info.id = id; - info.config = config; - info.writer = writer; - - task_proc: common.Task_Proc; - - switch request_type { - case .Initialize: - task_proc = request_initialize; - case .Initialized: - task_proc = request_initialized; - case .Shutdown: - task_proc = request_shutdown; - case .Exit: - task_proc = notification_exit; - case .DidOpen: - task_proc = notification_did_open; - case .DidChange: - task_proc = notification_did_change; - case .DidClose: - task_proc = notification_did_close; - case .DidSave: - task_proc = notification_did_save; - case .Definition: - task_proc = request_definition; - case .Completion: - task_proc = request_completion; - case .SignatureHelp: - task_proc = request_signature_help; - case .DocumentSymbol: - task_proc = request_document_symbols; - case .SemanticTokensFull: - task_proc = request_semantic_token_full; - case .SemanticTokensRange: - task_proc = request_semantic_token_range; - case .Hover: - task_proc = request_hover; - case .CancelRequest: - case .FormatDocument: - task_proc = request_format_document; - case .InlayHint: - task_proc = request_inlay_hint; - } - - task := common.Task { - data = info, - procedure = task_proc, - }; - - #partial switch request_type { - case .CancelRequest: - for { - if task, ok := common.pool_try_and_pop_task(&pool); ok { - common.pool_do_work(&pool, &task); - } else { - break; - } - } - case .Initialize, .Initialized: - task_proc(&task); - case .Completion, .Definition, .Hover, .FormatDocument: - - uri := root["params"].(json.Object)["textDocument"].(json.Object)["uri"].(json.String); - - document := document_get(uri); - - if document == nil { - handle_error(.InternalError, id, writer); - return false; - } - - info.document = document; - - task_proc(&task); - - case .DidClose, .DidChange, .DidOpen, .DidSave: - - uri := root["params"].(json.Object)["textDocument"].(json.Object)["uri"].(json.String); - - document := document_get(uri); - - if document != nil { - - for intrinsics.atomic_load(&document.operating_on) > 1 { - if task, ok := common.pool_try_and_pop_task(&pool); ok { - common.pool_do_work(&pool, &task); - } - } - } - - task_proc(&task); - - document_release(document); - case .Shutdown,.Exit: - task_proc(&task); - case .SignatureHelp, .SemanticTokensFull, .SemanticTokensRange, .DocumentSymbol, .InlayHint: - - uri := root["params"].(json.Object)["textDocument"].(json.Object)["uri"].(json.String); - - document := document_get(uri); - - if document == nil { - handle_error(.InternalError, id, writer); - return false; - } - - info.document = document; - - if !config.debug_single_thread { - common.pool_add_task(&pool, task_proc, info); - } else { - task_proc(&task); - } - case: - - if !config.debug_single_thread { - common.pool_add_task(&pool, task_proc, info); - } else { - task_proc(&task); - } - } + err := fn(root["params"], id, config, writer); + if err != .None { + response := make_response_message_error( + id = id, + error = ResponseError {code = err, message = ""}, + ); + send_error(response, writer); + } } return true; } -request_initialize :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; +request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { - defer free(info); - defer json.destroy_value(info.root); - params_object, ok := params.(json.Object); - - if !ok { - handle_error(.ParseError, id, writer); - return; - } + + if !ok { + return .ParseError; + } initialize_params: RequestInitializeParams; if unmarshal(params, initialize_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } config.workspace_folders = make([dynamic]common.WorkspaceFolder); @@ -424,6 +279,7 @@ request_initialize :: proc (task: ^common.Task) { config.formatter = ols_config.formatter; config.odin_command = strings.clone(ols_config.odin_command, context.allocator); config.checker_args = ols_config.checker_args; + config.enable_inlay_hints = ols_config.enable_inlay_hints; for p in ols_config.collections { @@ -479,8 +335,6 @@ request_initialize :: proc (task: ^common.Task) { config.collections["vendor"] = path.join(elems = {forward_path, "vendor"}, allocator = context.allocator); } - common.pool_init(&pool, config.thread_count); - common.pool_start(&pool); for format in initialize_params.capabilities.textDocument.hover.contentFormat { if format == "markdown" { @@ -578,58 +432,40 @@ request_initialize :: proc (task: ^common.Task) { } log.info("Finished indexing"); -} - -request_initialized :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; - json.destroy_value(root); - free(info); + return .None; } -request_shutdown :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; - - defer { - json.destroy_value(root); - free(info); - } - - response := make_response_message( - params = nil, - id = id); - - send_response(response, writer); +request_initialized :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { + return .None; } -request_definition :: proc (task: ^common.Task) { - info := get_request_info(task); +request_shutdown :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { + response := make_response_message(params = nil, id = id); - using info; + send_response(response, writer); - defer { - document_release(document); - json.destroy_value(root); - free(info); - } + return .None; +} +request_definition :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } definition_params: TextDocumentPositionParams; if unmarshal(params, definition_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } + + document := document_get(definition_params.textDocument.uri); + + if document == nil { + return .InternalError; + } locations, ok2 := get_definition_location(document, definition_params.position); @@ -644,260 +480,192 @@ request_definition :: proc (task: ^common.Task) { response := make_response_message(params = locations, id = id); send_response(response, writer); } -} - -request_completion :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; - defer { - document_release(document); - json.destroy_value(root); - free(info); - } + return .None; +} +request_completion :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } completition_params: CompletionParams; if unmarshal(params, completition_params, context.temp_allocator) != .None { log.error("Failed to unmarshal completion request"); - handle_error(.ParseError, id, writer); - return; + return .ParseError; } - //context.allocator = common.scratch_allocator(document.allocator); + document := document_get(completition_params.textDocument.uri); + + if document == nil { + return .InternalError; + } list: CompletionList; list, ok = get_completion_list(document, completition_params.position, completition_params.context_); if !ok { - handle_error(.InternalError, id, writer); - return; + return .InternalError; } - response := make_response_message( - params = list, - id = id); + response := make_response_message(params = list, id = id); send_response(response, writer); -} - -request_signature_help :: proc (task: ^common.Task) { - info := get_request_info(task); - using info; - - defer { - document_release(document); - json.destroy_value(root); - free(info); - } + return .None; +} +request_signature_help :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } signature_params: SignatureHelpParams; if unmarshal(params, signature_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } + document := document_get(signature_params.textDocument.uri); + + if document == nil { + return .InternalError; + } + help: SignatureHelp; help, ok = get_signature_information(document, signature_params.position); if !ok { - handle_error(.InternalError, id, writer); - return; + return .InternalError; } - response := make_response_message( - params = help, - id = id); + response := make_response_message(params = help, id = id); send_response(response, writer); -} -request_format_document :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; - - defer { - document_release(document); - json.destroy_value(root); - free(info); - } + return .None; +} +request_format_document :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } format_params: DocumentFormattingParams; if unmarshal(params, format_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } + document := document_get(format_params.textDocument.uri); + + if document == nil { + return .InternalError; + } + edit: []TextEdit; edit, ok = get_complete_format(document, config); if !ok { - handle_error(.InternalError, id, writer); - return; + return .InternalError; } - response := make_response_message( - params = edit, - id = id); + response := make_response_message(params = edit, id = id); send_response(response, writer); -} - -notification_exit :: proc (task: ^common.Task) { - info := get_request_info(task); - using info; - defer { - json.destroy_value(root); - free(info); - } + return .None; +} +notification_exit :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { config.running = false; + return .None; } -notification_did_open :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; - - defer { - json.destroy_value(root); - free(info); - } - +notification_did_open :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { log.error("Failed to parse open document notification"); - handle_error(.ParseError, id, writer); - return; + return .ParseError; } open_params: DidOpenTextDocumentParams; if unmarshal(params, open_params, context.allocator) != .None { log.error("Failed to parse open document notification"); - handle_error(.ParseError, id, writer); - return; + return .ParseError; } if n := document_open(open_params.textDocument.uri, open_params.textDocument.text, config, writer); n != .None { - handle_error(n, id, writer); + return .InternalError; } -} - -notification_did_change :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; - defer { - json.destroy_value(root); - free(info); - } + return .None; +} +notification_did_change :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } change_params: DidChangeTextDocumentParams; if unmarshal(params, change_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, config, writer); -} -notification_did_close :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; - - defer { - json.destroy_value(root); - free(info); - } + return .None; +} +notification_did_close :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } close_params: DidCloseTextDocumentParams; if unmarshal(params, close_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } if n := document_close(close_params.textDocument.uri); n != .None { - handle_error(n, id, writer); - return; + return .InternalError; } -} - -notification_did_save :: proc (task: ^common.Task) { - info := get_request_info(task); - using info; - - defer { - json.destroy_value(root); - free(info); - } + return .None; +} +notification_did_save :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } save_params: DidSaveTextDocumentParams; if unmarshal(params, save_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } uri: common.Uri; if uri, ok = common.parse_uri(save_params.textDocument.uri, context.temp_allocator); !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } fullpath := uri.path; @@ -942,34 +710,29 @@ notification_did_save :: proc (task: ^common.Task) { } check(uri, writer, config); -} - -request_semantic_token_full :: proc (task: ^common.Task) { - info := get_request_info(task); - using info; - - defer { - document_release(document); - json.destroy_value(root); - free(info); - - } + return .None; +} +request_semantic_token_full :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } semantic_params: SemanticTokensParams; if unmarshal(params, semantic_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } + document := document_get(semantic_params.textDocument.uri); + + if document == nil { + return .InternalError; + } + range := common.Range { start = common.Position { line = 0, @@ -982,155 +745,145 @@ request_semantic_token_full :: proc (task: ^common.Task) { symbols: SemanticTokens; if config.enable_semantic_tokens { - symbols = get_semantic_tokens(document, range); + if cache_symbols, ok := file_resolve_cache.files[document.uri.uri]; ok { + symbols = get_semantic_tokens(document, range, cache_symbols); + } } - response := make_response_message( - params = symbols, - id = id); + response := make_response_message(params = symbols, id = id); send_response(response, writer); -} - -request_semantic_token_range :: proc (task: ^common.Task) { - info := get_request_info(task); - using info; + return .None; +} +request_semantic_token_range :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); - defer { - document_release(document); - json.destroy_value(root); - free(info); - } - if !ok { - handle_error(.ParseError, id, writer); - return; + return .None; } semantic_params: SemanticTokensRangeParams; if unmarshal(params, semantic_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .None; } + document := document_get(semantic_params.textDocument.uri); + + if document == nil { + return .InternalError; + } + symbols: SemanticTokens; if config.enable_semantic_tokens { - symbols = get_semantic_tokens(document, semantic_params.range); + if cache_symbols, ok := file_resolve_cache.files[document.uri.uri]; ok { + symbols = get_semantic_tokens(document, semantic_params.range, cache_symbols); + } } - response := make_response_message( - params = symbols, - id = id); + response := make_response_message(params = symbols, id = id); send_response(response, writer); -} - -request_document_symbols :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; - defer { - document_release(document); - json.destroy_value(root); - free(info); - } + return .None; +} +request_document_symbols :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } symbol_params: DocumentSymbolParams; if unmarshal(params, symbol_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } + document := document_get(symbol_params.textDocument.uri); + + if document == nil { + return .InternalError; + } + symbols := get_document_symbols(document); - response := make_response_message( - params = symbols, - id = id); + response := make_response_message(params = symbols, id = id); send_response(response, writer); -} -request_hover :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; + return .None; +} - defer { - document_release(document); - json.destroy_value(root); - free(info); - } - +request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } hover_params: HoverParams; if unmarshal(params, hover_params, context.temp_allocator) != .None { - handle_error(.ParseError, id, writer); - return; + return .ParseError; } + document := document_get(hover_params.textDocument.uri); + + if document == nil { + return .InternalError; + } + hover: Hover; hover, ok = get_hover_information(document, hover_params.position); if !ok { - handle_error(.InternalError, id, writer); - return; + return .InternalError; } - response := make_response_message( - params = hover, - id = id); + response := make_response_message(params = hover, id = id); send_response(response, writer); -} -request_inlay_hint :: proc (task: ^common.Task) { - info := get_request_info(task); - - using info; + return .None; +} - defer { - document_release(document); - json.destroy_value(root); - free(info); - } - +request_inlay_hint :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { params_object, ok := params.(json.Object); if !ok { - handle_error(.ParseError, id, writer); - return; + return .ParseError; + } + + inlay_params: InlayParams; + + if unmarshal(params, inlay_params, context.temp_allocator) != .None { + return .ParseError; } + document := document_get(inlay_params.textDocument.uri); + + if document == nil { + return .InternalError; + } + hints: []InlayHint; - hints, ok = get_inlay_hints(document); + + if cache_symbols, ok := file_resolve_cache.files[document.uri.uri]; ok && config.enable_inlay_hints { + hints, ok = get_inlay_hints(document, cache_symbols); + } if !ok { - handle_error(.InternalError, id, writer); - return; + return .InternalError; } response := make_response_message(params = hints, id = id); send_response(response, writer); + + return .None; }
\ No newline at end of file diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index 095bb91..2977ddc 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -3,6 +3,7 @@ package server import "core:odin/tokenizer" import "core:odin/ast" import "core:log" +import "core:fmt" import "shared:common" import "shared:index" @@ -32,11 +33,11 @@ SemanticTokenTypes :: enum { Method, } -SemanticTokenModifiers :: enum { - None, - Declaration, - Definition, - Deprecated, +SemanticTokenModifiers :: enum(u32) { + None = 0, + Declaration = 2, + Definition = 4, + Deprecated = 8, } SemanticTokensClientCapabilities :: struct { @@ -77,6 +78,8 @@ SemanticTokens :: struct { SemanticTokenBuilder :: struct { current_start: int, tokens: [dynamic]u32, + symbols: map[uintptr]index.Symbol, + selector: bool, } make_token_builder :: proc(allocator := context.temp_allocator) -> SemanticTokenBuilder { @@ -91,7 +94,7 @@ get_tokens :: proc(builder: SemanticTokenBuilder) -> SemanticTokens { }; } -get_semantic_tokens :: proc(document: ^common.Document, range: common.Range) -> SemanticTokens { +get_semantic_tokens :: proc(document: ^common.Document, range: common.Range, symbols: map[uintptr]index.Symbol) -> SemanticTokens { using analysis; builder := make_token_builder(); @@ -100,9 +103,9 @@ get_semantic_tokens :: proc(document: ^common.Document, range: common.Range) -> write_semantic_token(&builder, document.ast.pkg_token, document.ast.src, .Keyword, .None); } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); - //resolve_entire_file(document, &ast_context, context.temp_allocator); + builder.symbols = symbols; ast_context.current_package = ast_context.document_package; @@ -118,19 +121,19 @@ get_semantic_tokens :: proc(document: ^common.Document, range: common.Range) -> write_semantic_node :: proc(builder: ^SemanticTokenBuilder, node: ^ast.Node, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { position := common.get_relative_token_position(node.pos.offset, transmute([]u8)src, builder.current_start); name := common.get_ast_node_string(node, src); - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, 0); + append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, cast(u32)modifier); builder.current_start = node.pos.offset; } write_semantic_token :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { position := common.get_relative_token_position(token.pos.offset, transmute([]u8)src, builder.current_start); - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(token.text), cast(u32)type, 0); + append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(token.text), cast(u32)type, cast(u32)modifier); builder.current_start = token.pos.offset; } write_semantic_string :: proc(builder: ^SemanticTokenBuilder, pos: tokenizer.Pos, name: string, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { position := common.get_relative_token_position(pos.offset, transmute([]u8)src, builder.current_start); - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, 0); + append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, cast(u32)modifier); builder.current_start = pos.offset; } @@ -169,11 +172,7 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: write_semantic_string(builder, node.pos, "..", ast_context.file.src, .Operator, .None); visit(n.expr, builder, ast_context); case Ident: - if true { - write_semantic_node(builder, node, ast_context.file.src, .Variable, .None); - return; - } - if symbol, ok := analysis.lookup_symbol_cache(ast_context, n); ok { + if symbol, ok := builder.symbols[cast(uintptr)node]; ok { if symbol.type == .Variable { write_semantic_node(builder, node, ast_context.file.src, .Variable, .None); } @@ -195,6 +194,12 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: } case Selector_Expr: visit_selector(cast(^Selector_Expr)node, builder, ast_context); + builder.selector = false; + case When_Stmt: + write_semantic_string(builder, n.when_pos, "when", ast_context.file.src, .Keyword, .None); + visit(n.cond, builder, ast_context); + visit(n.body, builder, ast_context); + visit(n.else_stmt, builder, ast_context); case Pointer_Type: write_semantic_string(builder, node.pos, "^", ast_context.file.src, .Operator, .None); visit(n.elem, builder, ast_context); @@ -204,6 +209,12 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: visit(n.stmts, builder, ast_context); case Expr_Stmt: visit(n.expr, builder, ast_context); + case Branch_Stmt: + write_semantic_token(builder, n.tok, ast_context.file.src, .Type, .None); + case Poly_Type: + write_semantic_string(builder, n.dollar, "$", ast_context.file.src, .Operator, .None); + visit(n.type, builder, ast_context); + visit(n.specialization, builder, ast_context); case Range_Stmt: write_semantic_string(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None); @@ -329,7 +340,8 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: write_semantic_token(builder, n.relpath, ast_context.file.src, .String, .None); case: - log.warnf("unhandled write node %v", n); + log.errorf("unhandled semantic token node %v", n); + //panic(fmt.tprintf("Missed semantic token handling %v", n)); } } @@ -337,16 +349,14 @@ visit_basic_lit :: proc(basic_lit: ast.Basic_Lit, builder: ^SemanticTokenBuilder using analysis; if symbol, ok := resolve_basic_lit(ast_context, basic_lit); ok { - - if generic, ok := symbol.value.(index.SymbolGenericValue); ok { - - ident := generic.expr.derived.(ast.Ident); - - if ident.name == "string" { - write_semantic_node(builder, generic.expr, ast_context.file.src, .String, .None); - } else if ident.name == "int" { - write_semantic_node(builder, generic.expr, ast_context.file.src, .Number, .None); - } else { + if untyped, ok := symbol.value.(index.SymbolUntypedValue); ok { + switch untyped.type { + case .Bool: + write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .Keyword, .None); + case .Float, .Integer: + write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .Number, .None); + case .String: + write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .String, .None); } } } @@ -455,7 +465,6 @@ visit_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder, a } for field in node.fields { - if ident, ok := field.derived.(Ident); ok { write_semantic_node(builder, field, ast_context.file.src, .EnumMember, .None); } @@ -476,7 +485,6 @@ visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilde } for field in node.fields.list { - for name in field.names { if ident, ok := name.derived.(Ident); ok { write_semantic_node(builder, name, ast_context.file.src, .Property, .None); @@ -488,6 +496,34 @@ visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilde } visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - using analysis; - using ast; + + if _, ok := selector.expr.derived.(ast.Selector_Expr); ok { + visit_selector(cast(^ast.Selector_Expr)selector.expr, builder, ast_context); + } else { + visit(selector.expr, builder, ast_context); + builder.selector = true; + } + + if symbol, ok := builder.symbols[cast(uintptr)selector]; ok { + if symbol.type == .Variable { + write_semantic_node(builder, selector.field, ast_context.file.src, .Method, .None); + } + #partial switch v in symbol.value { + case index.SymbolPackageValue: + write_semantic_node(builder, selector.field, ast_context.file.src, .Namespace, .None); + case index.SymbolStructValue: + write_semantic_node(builder, selector.field, ast_context.file.src, .Struct, .None); + case index.SymbolEnumValue: + write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None); + case index.SymbolUnionValue: + write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None); + case index.SymbolProcedureValue: + write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None); + case index.SymbolProcedureGroupValue: + write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None); + } + } + + + //((a.d).b).c }
\ No newline at end of file diff --git a/src/server/signature.odin b/src/server/signature.odin index 03d9ce7..d187336 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -118,7 +118,7 @@ get_signature_information :: proc(document: ^common.Document, position: common.P signature_help: SignatureHelp; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); position_context, ok := get_document_position_context(document, position, .SignatureHelp); diff --git a/src/server/types.odin b/src/server/types.odin index 1dbcbe1..bf0cff4 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -298,6 +298,7 @@ OlsConfig :: struct { enable_format: bool, enable_procedure_context: bool, enable_snippets: bool, + enable_inlay_hints: bool, verbose: bool, file_log: bool, formatter: common.Format_Config, @@ -352,6 +353,11 @@ HoverParams :: struct { position: common.Position, } + +InlayParams :: struct { + textDocument: TextDocumentIdentifier, +} + Hover :: struct { contents: MarkupContent, range: common.Range, |