diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2020-12-12 00:08:13 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2020-12-12 00:08:13 +0100 |
| commit | eb1bf335ada34c25410fecd5dc8885e2572fb212 (patch) | |
| tree | c00572c1a84666bb0c81e22c7a401f711bf7f147 /src | |
| parent | 2400136b4e8627733980cb9baf692cfa119a4d0f (diff) | |
started work on hover(disabled currently through json config, unstable)
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/config.odin | 1 | ||||
| -rw-r--r-- | src/common/position.odin | 4 | ||||
| -rw-r--r-- | src/server/analysis.odin | 149 | ||||
| -rw-r--r-- | src/server/requests.odin | 75 | ||||
| -rw-r--r-- | src/server/types.odin | 28 |
5 files changed, 234 insertions, 23 deletions
diff --git a/src/common/config.odin b/src/common/config.odin index f2a733f..c55efd6 100644 --- a/src/common/config.odin +++ b/src/common/config.odin @@ -8,5 +8,6 @@ Config :: struct { collections: map [string] string, running: bool, debug_single_thread: bool, + enable_semantic_tokens: bool, //This will be removed when vscode client stops sending me semantic tokens after disabling it in requests initialize. }; diff --git a/src/common/position.odin b/src/common/position.odin index 220f347..21c4f1d 100644 --- a/src/common/position.odin +++ b/src/common/position.odin @@ -102,7 +102,7 @@ get_token_range :: proc(node: ast.Node, document_text: [] u8) -> Range { index := offset; - for index > 0 && (document_text[index] != '\n' || document_text[index] != '\r') { + for index > 0 && document_text[index] != '\n' && document_text[index] != '\r' { index -= 1; } @@ -243,7 +243,7 @@ get_character_offset_u8_to_u16 :: proc(character_offset: int, document_text: [] utf8_idx := 0; utf16_idx := 0; - for utf16_idx < character_offset { + for utf8_idx < character_offset { r, w := utf8.decode_rune(document_text[utf8_idx:]); diff --git a/src/server/analysis.odin b/src/server/analysis.odin index e348781..f588bfd 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -29,6 +29,7 @@ DocumentPositionContextHint :: enum { Completion, SignatureHelp, Definition, + Hover, }; DocumentPositionContext :: struct { @@ -1568,11 +1569,11 @@ concatenate_symbols_information :: proc(ast_context: ^AstContext, symbol: index. if symbol.type == .Function { if symbol.returns != "" { - return strings.concatenate({pkg, "::", symbol.name, "::", symbol.signature, " -> ", symbol.returns}, context.temp_allocator); + return strings.concatenate({pkg, ".", symbol.name, ": proc", symbol.signature, " -> ", symbol.returns}, context.temp_allocator); } else { - return strings.concatenate({pkg, "::", symbol.name, "::", symbol.signature}, context.temp_allocator); + return strings.concatenate({pkg, ".", symbol.name, ": proc", symbol.signature}, context.temp_allocator); } } @@ -1616,6 +1617,37 @@ get_definition_location :: proc(document: ^Document, position: common.Position) if position_context.selector != nil { + //if the base selector is the client wants to go to. + if base, ok := position_context.selector.derived.(ast.Ident); ok && position_context.identifier != nil { + + ident := position_context.identifier.derived.(ast.Ident); + + if ident.name == base.name { + + if resolved, ok := resolve_location_identifier(&ast_context, ident); ok { + location.range = resolved.range; + + if resolved.uri == "" { + location.uri = document.uri.uri; + } + + else { + location.uri = resolved.uri; + } + + return location, true; + } + + else { + return location, false; + } + + } + + } + + //otherwise it's the field the client wants to go to. + selector: index.Symbol; ast_context.use_locals = true; @@ -1695,6 +1727,117 @@ get_definition_location :: proc(document: ^Document, position: common.Position) return location, true; } +write_hover_content :: proc(ast_context: ^AstContext, symbol: index.Symbol) -> MarkupContent { + content: MarkupContent; + + cat := concatenate_symbols_information(ast_context, symbol); + + if cat != "" { + content.kind = "markdown"; + content.value = fmt.tprintf("```odin\n %v\n```\n%v", cat, symbol.doc); + } + + else { + content.kind = "plaintext"; + } + + return content; +} + +get_hover_information :: proc(document: ^Document, position: common.Position) -> (Hover, bool) { + + hover: Hover; + + ast_context := make_ast_context(document.ast, document.imports, document.package_name); + + position_context, ok := get_document_position_context(document, position, .Hover); + + get_globals(document.ast, &ast_context); + + if position_context.function != nil { + get_locals(document.ast, position_context.function, &ast_context, &position_context); + } + + if position_context.selector != nil && position_context.identifier != nil { + + //if the base selector is the client wants to go to. + if base, ok := position_context.selector.derived.(ast.Ident); ok && position_context.identifier != nil { + + ident := position_context.identifier.derived.(ast.Ident); + + if ident.name == base.name { + + if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { + hover.range = common.get_token_range(position_context.identifier^, document.ast.src); + hover.contents = write_hover_content(&ast_context, resolved); + return hover, true; + } + + } + + } + + + ast_context.use_locals = true; + ast_context.use_globals = true; + ast_context.current_package = ast_context.document_package; + + selector: index.Symbol; + selector, ok = resolve_type_expression(&ast_context, position_context.selector); + + if !ok { + return {}, true; + } + + field: string; + + if position_context.field != nil { + + switch v in position_context.field.derived { + case ast.Ident: + field = v.name; + } + + } + + hover.range = common.get_token_range(position_context.identifier^, document.ast.src); + + log.info(hover); + + #partial switch v in selector.value { + case index.SymbolStructValue: + for name, i in v.names { + if strings.compare(name, field) == 0 { + if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok { + hover.contents = write_hover_content(&ast_context, symbol); + return hover, true; + } + } + } + case index.SymbolPackageValue: + if symbol, ok := index.lookup(field, selector.pkg); ok { + hover.contents = write_hover_content(&ast_context, symbol); + return hover, true; + } + } + + } + + else if position_context.identifier != nil { + + if resolved, ok := resolve_type_identifier(&ast_context, position_context.identifier.derived.(ast.Ident)); ok { + log.info(position_context.identifier^); + hover.range = common.get_token_range(position_context.identifier^, document.ast.src); + log.info(hover.range); + hover.contents = write_hover_content(&ast_context, resolved); + return hover, true; + } + + } + + return {}, true; +} + //ERROR can't got to common.Position get_completion_list :: proc(document: ^Document, position: common.Position) -> (CompletionList, bool) { @@ -2433,7 +2576,7 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP } } - else if position_context.hint == .Definition && n.field != nil { + else if (position_context.hint == .Definition || position_context.hint == .Hover) && n.field != nil { position_context.selector = n.expr; position_context.field = n.field; get_document_position(n.expr, position_context); diff --git a/src/server/requests.odin b/src/server/requests.odin index fdda2e8..7c0b2c1 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -37,6 +37,7 @@ RequestType :: enum { DocumentSymbol, SemanticTokensFull, SemanticTokensRange, + Hover, }; RequestInfo :: struct { @@ -184,7 +185,8 @@ request_map : map [string] RequestType = "textDocument/signatureHelp" = .SignatureHelp, "textDocument/documentSymbol" = .DocumentSymbol, "textDocument/semanticTokens/full" = .SemanticTokensFull, - "textDocument/semanticTokens/range" = .SemanticTokensRange}; + "textDocument/semanticTokens/range" = .SemanticTokensRange, + "textDocument/hover" = .Hover}; handle_error :: proc(err: common.Error, id: RequestId, writer: ^Writer) { @@ -280,6 +282,8 @@ handle_request :: proc(request: json.Value, config: ^common.Config, writer: ^Wri task_proc = request_semantic_token_full; case .SemanticTokensRange: task_proc = request_semantic_token_range; + case .Hover: + task_proc = request_hover; } task := common.Task { @@ -290,7 +294,7 @@ handle_request :: proc(request: json.Value, config: ^common.Config, writer: ^Wri #partial switch request_type { case .Initialize, .Initialized: task_proc(&task); - case .Completion, .Definition: + case .Completion, .Definition, .Hover: uri := root["params"].value.(json.Object)["textDocument"].value.(json.Object)["uri"].value.(json.String); @@ -393,6 +397,9 @@ request_initialize :: proc(task: ^common.Task) { thread_count := 2; + enable_document_symbols: bool; + enable_hover: bool; + if len(config.workspace_folders) > 0 { //right now just look at the first workspace - TODO(daniel, add multiple workspace support) @@ -409,6 +416,9 @@ request_initialize :: proc(task: ^common.Task) { if unmarshal(value, ols_config, context.temp_allocator) == .None { thread_count = ols_config.thread_pool_count; + enable_document_symbols = ols_config.enable_document_symbols; + enable_hover = ols_config.enable_hover; + //config.enable_semantic_tokens = ols_config.enable_semantic_tokens; for p in ols_config.collections { config.collections[strings.clone(p.name)] = strings.clone(strings.to_lower(p.path, context.temp_allocator)); @@ -429,14 +439,14 @@ request_initialize :: proc(task: ^common.Task) { //ERROR can't go to defintion for format in initialize_params.capabilities.textDocument.hover.contentFormat { - if format == .Markdown { + if format == "markdown" { config.hover_support_md = true; } } for format in initialize_params.capabilities.textDocument.completion.documentationFormat { - if format == .Markdown { + if format == "markdown" { config.completion_support_md = true; } } @@ -477,14 +487,15 @@ request_initialize :: proc(task: ^common.Task) { triggerCharacters = signatureTriggerCharacters, }, semanticTokensProvider = SemanticTokensOptions { - range = true, - full = true, + range = config.enable_semantic_tokens, + full = config.enable_semantic_tokens, legend = SemanticTokensLegend { tokenTypes = token_types, tokenModifiers = token_modifiers, }, }, - documentSymbolProvider = true, + documentSymbolProvider = enable_document_symbols, + hoverProvider = enable_hover, }, }, id = id, @@ -794,7 +805,10 @@ request_semantic_token_full :: proc(task: ^common.Task) { }; symbols: SemanticTokens; - //symbols := get_semantic_tokens(document, range); + + if config.enable_semantic_tokens { + symbols = get_semantic_tokens(document, range); + } response := make_response_message( params = symbols, @@ -829,7 +843,10 @@ request_semantic_token_range :: proc(task: ^common.Task) { } symbols: SemanticTokens; - //symbols := get_semantic_tokens(document, semantic_params.range); + + if config.enable_semantic_tokens { + symbols = get_semantic_tokens(document, semantic_params.range); + } response := make_response_message( params = symbols, @@ -871,4 +888,44 @@ request_document_symbols :: proc(task: ^common.Task) { ); send_response(response, writer); +} + +request_hover :: proc(task: ^common.Task) { + + info := get_request_info(task); + + using info; + + defer document_release(document); + defer json.destroy_value(root); + defer free(info); + + params_object, ok := params.value.(json.Object); + + if !ok { + handle_error(.ParseError, id, writer); + return; + } + + hover_params: HoverParams; + + if unmarshal(params, hover_params, context.temp_allocator) != .None { + handle_error(.ParseError, id, writer); + return; + } + + hover: Hover; + hover, ok = get_hover_information(document, hover_params.position); + + if !ok { + handle_error(.InternalError, id, writer); + return; + } + + response := make_response_message( + params = hover, + id = id, + ); + + send_response(response, writer); }
\ No newline at end of file diff --git a/src/server/types.odin b/src/server/types.odin index 820ae3a..87d1370 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -23,6 +23,7 @@ ResponseParams :: union { SignatureHelp, [] DocumentSymbol, SemanticTokens, + Hover, }; ResponseMessage :: struct { @@ -38,7 +39,7 @@ ResponseMessageError :: struct { }; ResponseError :: struct { - code: common.Error, + code: common.Error, message: string, }; @@ -73,13 +74,8 @@ RequestInitializeParams :: struct { capabilities: ClientCapabilities, }; -MarkupKind :: enum { - Plaintext, - Markdown, -}; - MarkupContent :: struct { - kind: MarkupKind, + kind: string, value: string, }; @@ -90,6 +86,7 @@ ServerCapabilities :: struct { signatureHelpProvider: SignatureHelpOptions, semanticTokensProvider: SemanticTokensOptions, documentSymbolProvider: bool, + hoverProvider: bool, }; CompletionOptions :: struct { @@ -99,7 +96,7 @@ CompletionOptions :: struct { HoverClientCapabilities :: struct { dynamicRegistration: bool, - contentFormat: [dynamic] MarkupKind, + contentFormat: [dynamic] string, }; DocumentSymbolClientCapabilities :: struct { @@ -119,7 +116,7 @@ TextDocumentClientCapabilities :: struct { }; CompletionClientCapabilities :: struct { - documentationFormat: [dynamic] MarkupKind, + documentationFormat: [dynamic] string, }; ParameterInformationCapabilities :: struct { @@ -282,6 +279,9 @@ ParameterInformation :: struct { OlsConfig :: struct { collections: [dynamic] OlsConfigCollection, thread_pool_count: int, + enable_semantic_tokens: bool, + enable_document_symbols: bool, + enable_hover: bool, }; OlsConfigCollection :: struct { @@ -325,3 +325,13 @@ DocumentSymbol :: struct { selectionRange: common.Range, children: [] DocumentSymbol, }; + +HoverParams :: struct { + textDocument: TextDocumentIdentifier, + position: common.Position, +}; + +Hover :: struct { + contents: MarkupContent, + range: common.Range, +};
\ No newline at end of file |