summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autocomplete.c66
-rw-r--r--lsp-parse.c6
-rw-r--r--lsp-write.c9
-rw-r--r--lsp.c10
-rw-r--r--lsp.h12
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
@@ -112,6 +113,10 @@ typedef struct {
} LSPRequestSignatureHelp;
typedef struct {
+ LSPDocumentPosition position;
+} LSPRequestHover;
+
+typedef struct {
LSPDocumentID *removed; // dynamic array
LSPDocumentID *added; // dynamic array
} LSPRequestDidChangeWorkspaceFolders;
@@ -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);