From 1f9cd2a40d72d7982e8a9ff93e5ad432e14accc3 Mon Sep 17 00:00:00 2001 From: pommicket Date: Thu, 29 Dec 2022 10:52:41 -0500 Subject: fix autocomplete, start hover --- autocomplete.c | 66 +++++++++++++++++++++++++++++++--------------------------- lsp-parse.c | 6 ++++++ lsp-write.c | 9 ++++++++ lsp.c | 10 ++++++--- lsp.h | 12 +++++++++-- 5 files changed, 67 insertions(+), 36 deletions(-) diff --git a/autocomplete.c b/autocomplete.c index 5045a3d..9166ea1 100644 --- a/autocomplete.c +++ b/autocomplete.c @@ -130,14 +130,15 @@ static void autocomplete_send_completion_request(Ted *ted, TextBuffer *buffer, B }; if (trigger < UNICODE_CODE_POINTS) unicode_utf32_to_utf8(request.data.completion.context.trigger_character, trigger); - lsp_send_request(lsp, &request); - ac->waiting_for_lsp = true; - ac->lsp_request_time = ted->frame_time; - // *technically sepaking* this can mess things up if a complete - // list arrives only after the user has typed some stuff - // (in that case we'll send a TriggerKind = incomplete request even though it makes no sense). - // but i don't think any servers will have a problem with that. - ac->is_list_complete = false; + if (lsp_send_request(lsp, &request)) { + ac->waiting_for_lsp = true; + ac->lsp_request_time = ted->frame_time; + // *technically sepaking* this can mess things up if a complete + // list arrives only after the user has typed some stuff + // (in that case we'll send a TriggerKind = incomplete request even though it makes no sense). + // but i don't think any servers will have a problem with that. + ac->is_list_complete = false; + } } static void autocomplete_find_completions(Ted *ted, uint32_t trigger) { @@ -186,6 +187,10 @@ static void autocomplete_find_completions(Ted *ted, uint32_t trigger) { } static void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) { + const LSPRequest *request = &response->request; + if (request->type != LSP_REQUEST_COMPLETION) + return; + Autocomplete *ac = &ted->autocomplete; ac->waiting_for_lsp = false; if (!ac->open) { @@ -193,30 +198,29 @@ static void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *respo return; } - const LSPRequest *request = &response->request; - if (request->type == LSP_REQUEST_COMPLETION) { - const LSPResponseCompletion *completion = &response->data.completion; - size_t ncompletions = arr_len(completion->items); - arr_set_len(ac->completions, ncompletions); - for (size_t i = 0; i < ncompletions; ++i) { - const LSPCompletionItem *lsp_completion = &completion->items[i]; - Autocompletion *ted_completion = &ac->completions[i]; - ted_completion->label = str_dup(lsp_response_string(response, lsp_completion->label)); - ted_completion->filter = str_dup(lsp_response_string(response, lsp_completion->filter_text)); - // NOTE: here we don't deal with snippets. - // right now we are sending "snippetSupport: false" in the capabilities, - // so this should be okay. - ted_completion->text = str_dup(lsp_response_string(response, lsp_completion->text_edit.new_text)); - const char *detail = lsp_response_string(response, lsp_completion->detail); - ted_completion->detail = *detail ? str_dup(detail) : NULL; - ted_completion->kind = lsp_completion_kind_to_ted(lsp_completion->kind); - ted_completion->deprecated = lsp_completion->deprecated; - const char *documentation = lsp_response_string(response, lsp_completion->documentation); - ted_completion->documentation = *documentation ? str_dup(documentation) : NULL; - - } - ac->is_list_complete = completion->is_complete; + + const LSPResponseCompletion *completion = &response->data.completion; + size_t ncompletions = arr_len(completion->items); + arr_set_len(ac->completions, ncompletions); + for (size_t i = 0; i < ncompletions; ++i) { + const LSPCompletionItem *lsp_completion = &completion->items[i]; + Autocompletion *ted_completion = &ac->completions[i]; + ted_completion->label = str_dup(lsp_response_string(response, lsp_completion->label)); + ted_completion->filter = str_dup(lsp_response_string(response, lsp_completion->filter_text)); + // NOTE: here we don't deal with snippets. + // right now we are sending "snippetSupport: false" in the capabilities, + // so this should be okay. + ted_completion->text = str_dup(lsp_response_string(response, lsp_completion->text_edit.new_text)); + const char *detail = lsp_response_string(response, lsp_completion->detail); + ted_completion->detail = *detail ? str_dup(detail) : NULL; + ted_completion->kind = lsp_completion_kind_to_ted(lsp_completion->kind); + ted_completion->deprecated = lsp_completion->deprecated; + const char *documentation = lsp_response_string(response, lsp_completion->documentation); + ted_completion->documentation = *documentation ? str_dup(documentation) : NULL; + } + ac->is_list_complete = completion->is_complete; + autocomplete_update_suggested(ted); switch (arr_len(ac->suggested)) { case 0: diff --git a/lsp-parse.c b/lsp-parse.c index b5f687f..555a62a 100644 --- a/lsp-parse.c +++ b/lsp-parse.c @@ -127,6 +127,12 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti arr_add(lsp->signature_help_retrigger_chars, '>'); } + // check for hover support + JSONValue hover_value = json_object_get(json, capabilities, "hoverProvider"); + if (hover_value.type != JSON_UNDEFINED) { + cap->hover_support = true; + } + JSONObject workspace = json_object_get_object(json, capabilities, "workspace"); // check WorkspaceFoldersServerCapabilities JSONObject workspace_folders = json_object_get_object(json, workspace, "workspaceFolders"); diff --git a/lsp-write.c b/lsp-write.c index 4c9bce3..dce4c22 100644 --- a/lsp-write.c +++ b/lsp-write.c @@ -265,6 +265,8 @@ static const char *lsp_request_method(LSPRequest *request) { return "textDocument/completion"; case LSP_REQUEST_SIGNATURE_HELP: return "textDocument/signatureHelp"; + case LSP_REQUEST_HOVER: + return "textDocument/hover"; case LSP_REQUEST_WORKSPACE_FOLDERS: return "workspace/workspaceFolders"; case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: @@ -293,6 +295,7 @@ static bool request_type_is_notification(LSPRequestType type) { case LSP_REQUEST_LOG_MESSAGE: case LSP_REQUEST_COMPLETION: case LSP_REQUEST_SIGNATURE_HELP: + case LSP_REQUEST_HOVER: case LSP_REQUEST_WORKSPACE_FOLDERS: return false; } @@ -494,6 +497,12 @@ static void write_request(LSP *lsp, LSPRequest *request) { write_document_position(o, help->position); write_obj_end(o); } break; + case LSP_REQUEST_HOVER: { + const LSPRequestHover *hover = &request->data.hover; + write_key_obj_start(o, "params"); + write_document_position(o, hover->position); + write_obj_end(o); + } break; case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: { const LSPRequestDidChangeWorkspaceFolders *w = &request->data.change_workspace_folders; write_key_obj_start(o, "params"); diff --git a/lsp.c b/lsp.c index 47b2b72..73a7045 100644 --- a/lsp.c +++ b/lsp.c @@ -1,5 +1,5 @@ // print server-to-client communication -#define LSP_SHOW_S2C 0 +#define LSP_SHOW_S2C 1 // print client-to-server communication #define LSP_SHOW_C2S 0 @@ -43,6 +43,7 @@ static void lsp_request_free(LSPRequest *r) { case LSP_REQUEST_EXIT: case LSP_REQUEST_COMPLETION: case LSP_REQUEST_SIGNATURE_HELP: + case LSP_REQUEST_HOVER: case LSP_REQUEST_DID_CLOSE: case LSP_REQUEST_WORKSPACE_FOLDERS: case LSP_REQUEST_JDTLS_CONFIGURATION: @@ -142,6 +143,8 @@ static bool lsp_supports_request(LSP *lsp, const LSPRequest *request) { return cap->signature_help_support; case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: return cap->workspace_folders_support; + case LSP_REQUEST_HOVER: + return cap->hover_support; } assert(0); return false; @@ -153,14 +156,15 @@ void lsp_send_message(LSP *lsp, LSPMessage *message) { SDL_UnlockMutex(lsp->messages_mutex); } -void lsp_send_request(LSP *lsp, LSPRequest *request) { +bool lsp_send_request(LSP *lsp, LSPRequest *request) { if (!lsp_supports_request(lsp, request)) { lsp_request_free(request); - return; + return false; } LSPMessage message = {.type = LSP_REQUEST}; message.u.request = *request; lsp_send_message(lsp, &message); + return true; } void lsp_send_response(LSP *lsp, LSPResponse *response) { diff --git a/lsp.h b/lsp.h index 02cbbc7..9bbdd77 100644 --- a/lsp.h +++ b/lsp.h @@ -38,6 +38,7 @@ typedef enum { LSP_REQUEST_DID_CHANGE, // textDocument/didChange LSP_REQUEST_COMPLETION, // textDocument/completion LSP_REQUEST_SIGNATURE_HELP, // textDocument/signatureHelp + LSP_REQUEST_HOVER, // textDocument/hover LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS, // workspace/didChangeWorkspaceFolders // server-to-client @@ -111,6 +112,10 @@ typedef struct { LSPDocumentPosition position; } LSPRequestSignatureHelp; +typedef struct { + LSPDocumentPosition position; +} LSPRequestHover; + typedef struct { LSPDocumentID *removed; // dynamic array LSPDocumentID *added; // dynamic array @@ -128,6 +133,7 @@ typedef struct { LSPRequestDidChange change; LSPRequestCompletion completion; LSPRequestSignatureHelp signature_help; + LSPRequestHover hover; // LSP_REQUEST_SHOW_MESSAGE or LSP_REQUEST_LOG_MESSAGE LSPRequestMessage message; LSPRequestDidChangeWorkspaceFolders change_workspace_folders; @@ -297,6 +303,7 @@ typedef struct { typedef struct { bool signature_help_support; bool completion_support; + bool hover_support; // support for multiple root folders // sadly, as of me writing this, clangd and rust-analyzer don't support this // (but jdtls and gopls do) @@ -371,8 +378,9 @@ void lsp_message_free(LSPMessage *message); u32 lsp_document_id(LSP *lsp, const char *path); // returned pointer lives exactly as long as lsp. const char *lsp_document_path(LSP *lsp, LSPDocumentID id); -// don't free the contents of this request! let me handle it! -void lsp_send_request(LSP *lsp, LSPRequest *request); +// returns false if the request is not supported by the LSP +// don't free the contents of this request (even on failure)! let me handle it! +bool lsp_send_request(LSP *lsp, LSPRequest *request); // don't free the contents of this response! let me handle it! void lsp_send_response(LSP *lsp, LSPResponse *response); const char *lsp_response_string(const LSPResponse *response, LSPString string); -- cgit v1.2.3