From 66da8ac5dcfe02d3aa79f72ba415235eb872ec1d Mon Sep 17 00:00:00 2001 From: pommicket Date: Sat, 7 Jan 2023 16:09:30 -0500 Subject: better request cancellation system --- ide-autocomplete.c | 16 +++++++--------- ide-definitions.c | 22 +++++++++------------- ide-highlights.c | 10 ++++------ ide-usages.c | 16 ++++++---------- lsp.c | 9 ++++++--- lsp.h | 10 ++++++++-- main.c | 3 +++ ted.c | 7 ++++--- ted.h | 22 +++++++--------------- 9 files changed, 54 insertions(+), 61 deletions(-) diff --git a/ide-autocomplete.c b/ide-autocomplete.c index 728a54b..f2382cb 100644 --- a/ide-autocomplete.c +++ b/ide-autocomplete.c @@ -106,8 +106,7 @@ void autocomplete_close(Ted *ted) { ac->open = false; autocomplete_clear_phantom(ac); autocomplete_clear_completions(ac); - ted_cancel_lsp_request(ted, ac->last_request_lsp, ac->last_request_id); - ac->last_request_id = 0; + ted_cancel_lsp_request(ted, &ac->last_request); } static void autocomplete_update_suggested(Ted *ted) { @@ -140,7 +139,7 @@ static void autocomplete_send_completion_request(Ted *ted, TextBuffer *buffer, B LSP *lsp = buffer_lsp(buffer); Autocomplete *ac = &ted->autocomplete; - ted_cancel_lsp_request(ted, ac->last_request_lsp, ac->last_request_id); + ted_cancel_lsp_request(ted, &ac->last_request); LSPRequest request = { .type = LSP_REQUEST_COMPLETION @@ -164,9 +163,8 @@ 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); - ac->last_request_id = lsp_send_request(lsp, &request); - if (ac->last_request_id) { - ac->last_request_lsp = lsp->id; + ac->last_request = lsp_send_request(lsp, &request); + if (ac->last_request.id) { ac->last_request_time = ted->frame_time; ac->last_request_phantom = phantom; // *technically sepaking* this can mess things up if a complete @@ -290,9 +288,9 @@ void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) { if (request->type != LSP_REQUEST_COMPLETION) return; Autocomplete *ac = &ted->autocomplete; - if (request->id != ac->last_request_id) + if (request->id != ac->last_request.id) return; // old request - ac->last_request_id = 0; + ac->last_request.id = 0; if (!ac->open && !ac->last_request_phantom) { // user hit escape or down or something before completions arrived. return; @@ -489,7 +487,7 @@ void autocomplete_frame(Ted *ted) { autocomplete_find_completions(ted, TRIGGER_INCOMPLETE, false); size_t ncompletions = arr_len(ac->suggested); - bool waiting_for_lsp = ac->last_request_id != 0; + bool waiting_for_lsp = ac->last_request.id != 0; if (waiting_for_lsp && ncompletions == 0) { double now = ted->frame_time; diff --git a/ide-definitions.c b/ide-definitions.c index a6809b6..673fe63 100644 --- a/ide-definitions.c +++ b/ide-definitions.c @@ -5,8 +5,7 @@ void definition_cancel_lookup(Ted *ted) { Definitions *defs = &ted->definitions; - ted_cancel_lsp_request(ted, defs->last_request_lsp, defs->last_request_id); - defs->last_request_id = 0; + ted_cancel_lsp_request(ted, &defs->last_request); } static SymbolKind symbol_kind_to_ted(LSPSymbolKind kind) { @@ -77,14 +76,13 @@ void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition p // send that request LSPRequest request = {.type = request_type}; request.data.definition.position = position; - LSPRequestID id = lsp_send_request(lsp, &request); - if (id == 0 && request.type == LSP_REQUEST_IMPLEMENTATION) { + LSPServerRequestID id = lsp_send_request(lsp, &request); + if (id.id == 0 && request.type == LSP_REQUEST_IMPLEMENTATION) { // if we can't go to the implementation, try going to the definition request.type = LSP_REQUEST_DEFINITION; id = lsp_send_request(lsp, &request); } - defs->last_request_id = id; - defs->last_request_lsp = lsp->id; + defs->last_request = id; defs->last_request_time = ted->frame_time; } else { // just go to the tag @@ -94,7 +92,7 @@ void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition p void definitions_frame(Ted *ted) { Definitions *defs = &ted->definitions; - if (defs->last_request_id && ted->frame_time - defs->last_request_time > 0.2) { + if (defs->last_request.id && ted->frame_time - defs->last_request_time > 0.2) { ted->cursor = ted->cursor_wait; } } @@ -162,12 +160,12 @@ static void definitions_selector_filter_entries(Ted *ted) { void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response) { Definitions *defs = &ted->definitions; - if (response->request.id != defs->last_request_id) { + if (response->request.id != defs->last_request.id) { // response to an old/irrelevant request return; } - defs->last_request_id = 0; + defs->last_request.id = 0; switch (response->request.type) { case LSP_REQUEST_DEFINITION: @@ -243,8 +241,7 @@ void definitions_send_request_if_needed(Ted *ted) { syms->query = str_dup(query); // cancel old request definition_cancel_lookup(ted); - defs->last_request_id = lsp_send_request(lsp, &request); - defs->last_request_lsp = lsp->id; + defs->last_request = lsp_send_request(lsp, &request); defs->last_request_time = ted->frame_time; free(defs->last_request_query); defs->last_request_query = query; @@ -271,8 +268,7 @@ void definitions_selector_open(Ted *ted) { void definitions_selector_close(Ted *ted) { Definitions *defs = &ted->definitions; definitions_clear_entries(defs); - ted_cancel_lsp_request(ted, defs->last_request_lsp, defs->last_request_id); - defs->last_request_id = 0; + ted_cancel_lsp_request(ted, &defs->last_request); free(defs->last_request_query); defs->last_request_query = NULL; } diff --git a/ide-highlights.c b/ide-highlights.c index 424d640..fee01d4 100644 --- a/ide-highlights.c +++ b/ide-highlights.c @@ -5,8 +5,7 @@ void highlights_close(Ted *ted) { Highlights *hls = &ted->highlights; arr_clear(hls->highlights); - ted_cancel_lsp_request(ted, hls->last_request_lsp, hls->last_request_id); - hls->last_request_id = 0; + ted_cancel_lsp_request(ted, &hls->last_request); hls->requested_position = (LSPDocumentPosition){0}; } @@ -26,9 +25,8 @@ static void highlights_send_request(Ted *ted) { LSPRequest request = {.type = LSP_REQUEST_HIGHLIGHT}; request.data.highlight.position = pos; - ted_cancel_lsp_request(ted, hls->last_request_lsp, hls->last_request_id); - hls->last_request_id = lsp_send_request(lsp, &request); - hls->last_request_lsp = lsp->id; + ted_cancel_lsp_request(ted, &hls->last_request); + hls->last_request = lsp_send_request(lsp, &request); hls->requested_position = pos; } @@ -37,7 +35,7 @@ void highlights_process_lsp_response(Ted *ted, LSPResponse *response) { Highlights *hls = &ted->highlights; if (response->request.type != LSP_REQUEST_HIGHLIGHT) return; // not a highlight request - if (response->request.id != hls->last_request_id) + if (response->request.id != hls->last_request.id) return; // old request const LSPResponseHighlight *hl_response = &response->data.highlight; arr_set_len(hls->highlights, arr_len(hl_response->highlights)); diff --git a/ide-usages.c b/ide-usages.c index 95324fd..a3b9194 100644 --- a/ide-usages.c +++ b/ide-usages.c @@ -4,10 +4,7 @@ void usages_cancel_lookup(Ted *ted) { Usages *usages = &ted->usages; - if (usages->last_request_id) { - ted_cancel_lsp_request(ted, usages->last_request_lsp, usages->last_request_id); - usages->last_request_id = 0; - } + ted_cancel_lsp_request(ted, &usages->last_request); } void usages_find(Ted *ted) { @@ -23,8 +20,7 @@ void usages_find(Ted *ted) { refs->include_declaration = true; refs->position = buffer_cursor_pos_as_lsp_document_position(buffer); usages_cancel_lookup(ted); - usages->last_request_lsp = lsp->id; - usages->last_request_id = lsp_send_request(lsp, &request); + usages->last_request= lsp_send_request(lsp, &request); usages->last_request_time = ted->frame_time; } @@ -33,9 +29,9 @@ void usages_process_lsp_response(Ted *ted, const LSPResponse *response) { Usages *usages = &ted->usages; if (response->request.type != LSP_REQUEST_REFERENCES) return; // not for us - if (response->request.id != usages->last_request_id) + if (response->request.id != usages->last_request.id) return; - LSP *lsp = ted_get_lsp_by_id(ted, usages->last_request_lsp); + LSP *lsp = ted_get_lsp_by_id(ted, usages->last_request.lsp); const LSPResponseReferences *refs = &response->data.references; if (lsp && arr_len(refs->locations)) { TextBuffer *buffer = &ted->build_buffer; @@ -126,11 +122,11 @@ void usages_process_lsp_response(Ted *ted, const LSPResponse *response) { } else { ted_flash_error_cursor(ted); } - usages->last_request_id = 0; + usages->last_request.id = 0; } void usages_frame(Ted *ted) { Usages *usages = &ted->usages; - if (usages->last_request_id && ted->frame_time - usages->last_request_time > 0.2) + if (usages->last_request.id && ted->frame_time - usages->last_request_time > 0.2) ted->cursor = ted->cursor_wait; // this request is takin a while } diff --git a/lsp.c b/lsp.c index 34f56ae..e208617 100644 --- a/lsp.c +++ b/lsp.c @@ -241,10 +241,10 @@ static bool request_type_is_notification(LSPRequestType type) { return false; } -LSPRequestID lsp_send_request(LSP *lsp, LSPRequest *request) { +LSPServerRequestID lsp_send_request(LSP *lsp, LSPRequest *request) { if (!lsp_supports_request(lsp, request)) { lsp_request_free(request); - return 0; + return (LSPServerRequestID){0}; } bool is_notification = request_type_is_notification(request->type); @@ -253,7 +253,10 @@ LSPRequestID lsp_send_request(LSP *lsp, LSPRequest *request) { LSPMessage message = {.type = LSP_REQUEST}; message.u.request = *request; lsp_send_message(lsp, &message); - return request->id; + return (LSPServerRequestID) { + .lsp = lsp->id, + .id = request->id + }; } void lsp_send_response(LSP *lsp, LSPResponse *response) { diff --git a/lsp.h b/lsp.h index b87f2a9..61c5610 100644 --- a/lsp.h +++ b/lsp.h @@ -18,6 +18,12 @@ typedef struct SDL_mutex *LSPMutex; typedef struct SDL_semaphore *LSPSemaphore; typedef struct SDL_Thread *LSPThread; +// a struct for keeping track of a LSP server ID and a request ID +typedef struct { + LSPID lsp; + LSPRequestID id; +} LSPServerRequestID; + // interface Position in the LSP spec typedef struct { u32 line; @@ -587,9 +593,9 @@ void lsp_message_free(LSPMessage *message); u32 lsp_document_id(LSP *lsp, const char *path); // returned pointer lives as long as lsp. const char *lsp_document_path(LSP *lsp, LSPDocumentID id); -// returns the ID of the sent request, or 0 if the request is not supported by the LSP +// returns the ID of the sent request, or (LSPServerRequestID){0} if the request is not supported by the LSP // don't free the contents of this request (even on failure)! let me handle it! -LSPRequestID lsp_send_request(LSP *lsp, LSPRequest *request); +LSPServerRequestID lsp_send_request(LSP *lsp, LSPRequest *request); // send a $/cancelRequest notification // if id = 0, nothing will happen. void lsp_cancel_request(LSP *lsp, LSPRequestID id); diff --git a/main.c b/main.c index d035efc..a1d3cab 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,8 @@ /* @TODO: +- cancel signature help requests +- cancel hover requests +- don't let 0 be a valid LSPDocumentID - TESTING: check all IDE features with different servers - run everything through valgrind ideally with leak checking - some way of opening + closing all C files in directory for clangd diff --git a/ted.c b/ted.c index ae1908b..e7f3098 100644 --- a/ted.c +++ b/ted.c @@ -637,11 +637,12 @@ void ted_go_to_lsp_document_position(Ted *ted, LSP *lsp, LSPDocumentPosition pos ted_go_to_position(ted, path, line, character, true); } -void ted_cancel_lsp_request(Ted *ted, LSPID lsp, LSPRequestID request) { +void ted_cancel_lsp_request(Ted *ted, LSPServerRequestID *request) { if (!request) return; - LSP *lsp_obj = ted_get_lsp_by_id(ted, lsp); + LSP *lsp_obj = ted_get_lsp_by_id(ted, request->lsp); if (!lsp_obj) return; - lsp_cancel_request(lsp_obj, request); + lsp_cancel_request(lsp_obj, request->id); + memset(request, 0, sizeof *request); } diff --git a/ted.h b/ted.h index a17fb23..500ba0d 100644 --- a/ted.h +++ b/ted.h @@ -376,8 +376,7 @@ typedef struct { // or one of the TRIGGER_* constants above uint32_t trigger; - LSPID last_request_lsp; - LSPRequestID last_request_id; + LSPServerRequestID last_request; // when we sent the request to the LSP for completions // (this is used to figure out when we should display "Loading...") double last_request_time; @@ -398,8 +397,7 @@ typedef struct { // data needed for finding usages typedef struct { - LSPID last_request_lsp; - LSPRequestID last_request_id; + LSPServerRequestID last_request; double last_request_time; } Usages; @@ -457,12 +455,8 @@ typedef enum { } GotoType; typedef struct { - LSPID last_request_lsp; // used for cancellation - // ID of the last request which was sent out. - // used to process responses in chronological order (= ID order). - // if we got a response for the last request, or no requests have been made, - // last_request_id is set to 0. - LSPRequestID last_request_id; + // information about last LSP request sent + LSPServerRequestID last_request; double last_request_time; char *last_request_query; // last query string which we sent a request for @@ -473,8 +467,7 @@ typedef struct { // "highlight" information from LSP server typedef struct { LSPHighlight *highlights; - LSPRequestID last_request_id; - LSPID last_request_lsp; + LSPServerRequestID last_request; LSPDocumentPosition requested_position; } Highlights; @@ -1373,9 +1366,8 @@ void ted_flash_error_cursor(Ted *ted); void ted_go_to_position(Ted *ted, const char *path, u32 line, u32 index, bool is_lsp); // go to this LSP document position, opening a new buffer containing the file if necessary. void ted_go_to_lsp_document_position(Ted *ted, LSP *lsp, LSPDocumentPosition position); -// cancel this LSP request. if `lsp` or `request` is 0, -// or if `lsp` is not a valid LSP ID, nothing happens. -void ted_cancel_lsp_request(Ted *ted, LSPID lsp, LSPRequestID request); +// cancel this LSP request. also zeroes *request +void ted_cancel_lsp_request(Ted *ted, LSPServerRequestID *request); // how tall is a line buffer? float ted_line_buffer_height(Ted *ted); // check for orphaned nodes and node cycles -- cgit v1.2.3