From a0f8332da674d452f7ae4f84f01d4682d464c9b2 Mon Sep 17 00:00:00 2001 From: pommicket Date: Thu, 29 Dec 2022 23:13:23 -0500 Subject: show the wait cursor when waiting for go to definition --- command.c | 1 + ide-definitions.c | 30 ++++++++++++++++++++++++------ lsp-write.c | 38 +++++--------------------------------- lsp.c | 40 +++++++++++++++++++++++++++++++++++++--- lsp.h | 9 +++++---- main.c | 4 +++- ted.h | 15 +++++++++------ 7 files changed, 84 insertions(+), 53 deletions(-) diff --git a/command.c b/command.c index 47dabef..4f2d643 100644 --- a/command.c +++ b/command.c @@ -394,6 +394,7 @@ void command_execute(Ted *ted, Command c, i64 argument) { break; case CMD_ESCAPE: + definition_cancel_lookup(ted); if (*ted->error_shown) { // dismiss error box *ted->error_shown = '\0'; diff --git a/ide-definitions.c b/ide-definitions.c index 3a36a96..8648325 100644 --- a/ide-definitions.c +++ b/ide-definitions.c @@ -1,15 +1,25 @@ void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition position) { + Definitions *defs = &ted->definitions; if (lsp) { // send that request LSPRequest request = {.type = LSP_REQUEST_DEFINITION}; request.data.definition.position = position; - lsp_send_request(lsp, &request); + LSPRequestID id = lsp_send_request(lsp, &request); + defs->last_request_lsp = lsp->id; + defs->last_request_id = id; + defs->last_request_time = ted->frame_time; } else { // just go to the tag tag_goto(ted, name); } } +void definition_cancel_lookup(Ted *ted) { + Definitions *defs = &ted->definitions; + defs->last_request_lsp = 0; + defs->last_request_id = 0; +} + void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response) { if (response->request.type != LSP_REQUEST_DEFINITION) return; @@ -17,13 +27,14 @@ void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *res const LSPResponseDefinition *response_def = &response->data.definition; Definitions *defs = &ted->definitions; - if (defs->last_response_lsp == lsp->id - && response->request.id < defs->last_response_id) { - // we just processed a later response, so let's ignore this + if (defs->last_request_lsp != lsp->id + || response->request.id != defs->last_request_id) { + // response to an old request return; } - defs->last_response_lsp = lsp->id; - defs->last_response_id = response->request.id; + + defs->last_request_lsp = 0; + defs->last_request_id = 0; if (!arr_len(response_def->locations)) { // no definition. do the error cursor. @@ -39,3 +50,10 @@ void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *res LSPDocumentPosition position = lsp_location_start_position(location); ted_go_to_lsp_document_position(ted, lsp, position); } + +void definitions_frame(Ted *ted) { + Definitions *defs = &ted->definitions; + if (defs->last_request_lsp && timespec_sub(ted->frame_time, defs->last_request_time) > 0.2) { + ted->cursor = ted->cursor_wait; + } +} diff --git a/lsp-write.c b/lsp-write.c index 9d7c2b1..82ba5b4 100644 --- a/lsp-write.c +++ b/lsp-write.c @@ -282,31 +282,6 @@ static const char *lsp_request_method(LSPRequest *request) { return "$/ignore"; } -static bool request_type_is_notification(LSPRequestType type) { - switch (type) { - case LSP_REQUEST_NONE: break; - case LSP_REQUEST_INITIALIZED: - case LSP_REQUEST_EXIT: - case LSP_REQUEST_DID_OPEN: - case LSP_REQUEST_DID_CLOSE: - case LSP_REQUEST_DID_CHANGE: - case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: - case LSP_REQUEST_JDTLS_CONFIGURATION: - return true; - case LSP_REQUEST_INITIALIZE: - case LSP_REQUEST_SHUTDOWN: - case LSP_REQUEST_SHOW_MESSAGE: - case LSP_REQUEST_LOG_MESSAGE: - case LSP_REQUEST_COMPLETION: - case LSP_REQUEST_SIGNATURE_HELP: - case LSP_REQUEST_HOVER: - case LSP_REQUEST_DEFINITION: - case LSP_REQUEST_WORKSPACE_FOLDERS: - return false; - } - assert(0); - return false; -} static const size_t max_header_size = 64; @@ -352,11 +327,8 @@ static void write_request(LSP *lsp, LSPRequest *request) { write_obj_start(o); write_key_string(o, "jsonrpc", "2.0"); - bool is_notification = request_type_is_notification(request->type); - if (!is_notification) { - u32 id = lsp->request_id++; - request->id = id; - write_key_number(o, "id", id); + if (request->id) { // i.e. if this is a request as opposed to a notification + write_key_number(o, "id", request->id); } write_key_string(o, "method", lsp_request_method(request)); @@ -564,12 +536,12 @@ static void write_request(LSP *lsp, LSPRequest *request) { message_writer_write_and_free(lsp, o); - if (is_notification) { - lsp_request_free(request); - } else { + if (request->id) { SDL_LockMutex(lsp->messages_mutex); arr_add(lsp->requests_sent, *request); SDL_UnlockMutex(lsp->messages_mutex); + } else { + lsp_request_free(request); } } diff --git a/lsp.c b/lsp.c index e1fdd16..8b147b2 100644 --- a/lsp.c +++ b/lsp.c @@ -162,15 +162,48 @@ void lsp_send_message(LSP *lsp, LSPMessage *message) { SDL_UnlockMutex(lsp->messages_mutex); } -bool lsp_send_request(LSP *lsp, LSPRequest *request) { +static bool request_type_is_notification(LSPRequestType type) { + switch (type) { + case LSP_REQUEST_NONE: break; + case LSP_REQUEST_INITIALIZED: + case LSP_REQUEST_EXIT: + case LSP_REQUEST_DID_OPEN: + case LSP_REQUEST_DID_CLOSE: + case LSP_REQUEST_DID_CHANGE: + case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: + case LSP_REQUEST_JDTLS_CONFIGURATION: + return true; + case LSP_REQUEST_INITIALIZE: + case LSP_REQUEST_SHUTDOWN: + case LSP_REQUEST_SHOW_MESSAGE: + case LSP_REQUEST_LOG_MESSAGE: + case LSP_REQUEST_COMPLETION: + case LSP_REQUEST_SIGNATURE_HELP: + case LSP_REQUEST_HOVER: + case LSP_REQUEST_DEFINITION: + case LSP_REQUEST_WORKSPACE_FOLDERS: + return false; + } + assert(0); + return false; +} + +LSPRequestID lsp_send_request(LSP *lsp, LSPRequest *request) { if (!lsp_supports_request(lsp, request)) { lsp_request_free(request); - return false; + return 0; + } + + bool is_notification = request_type_is_notification(request->type); + LSPRequestID id = 0; + if (!is_notification) { + id = ++lsp->request_id; + request->id = id; } LSPMessage message = {.type = LSP_REQUEST}; message.u.request = *request; lsp_send_message(lsp, &message); - return true; + return id; } void lsp_send_response(LSP *lsp, LSPResponse *response) { @@ -395,6 +428,7 @@ LSP *lsp_create(const char *root_dir, Language language, const char *analyzer_co LSPRequest initialize = { .type = LSP_REQUEST_INITIALIZE }; + initialize.id = ++lsp->request_id; // immediately send the request rather than queueing it. // this is a small request, so it shouldn't be a problem. write_request(lsp, &initialize); diff --git a/lsp.h b/lsp.h index 7d45f5b..a5120cd 100644 --- a/lsp.h +++ b/lsp.h @@ -1,5 +1,6 @@ typedef u32 LSPDocumentID; typedef u32 LSPID; +typedef u32 LSPRequestID; typedef struct { u32 line; @@ -350,8 +351,8 @@ typedef struct LSP { Process process; // Which ID number the next request will get - // thread-safety: only accessed in communication thread - u32 request_id; + // thread-safety: atomic, all that matters is `LSPRequestID id = ++lsp->request_id;` works + _Atomic LSPRequestID request_id; SDL_mutex *document_mutex; // for our purposes, folders are "documents" @@ -402,9 +403,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); -// returns false if the request is not supported by the LSP +// returns the ID of the sent request, or 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! -bool lsp_send_request(LSP *lsp, LSPRequest *request); +LSPRequestID 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); diff --git a/main.c b/main.c index 2162577..172a415 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,5 @@ /* @TODO: -- some way of showing that we're currently loading the definition location (different cursor color?) - more LSP stuff: - go to definition using LSP - find usages @@ -587,6 +586,7 @@ int main(int argc, char **argv) { ted->cursor_ibeam = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); + ted->cursor_wait = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); ted->cursor_arrow = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); ted->cursor_resize_h = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); ted->cursor_resize_v = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); @@ -1009,6 +1009,7 @@ int main(int argc, char **argv) { autocomplete_frame(ted); signature_help_frame(ted); hover_frame(ted, frame_dt); + definitions_frame(ted); } else { autocomplete_close(ted); text_utf8_anchored(font, "Press Ctrl+O to open a file or Ctrl+N to create a new one.", @@ -1161,6 +1162,7 @@ int main(int argc, char **argv) { SDL_FreeCursor(ted->cursor_arrow); SDL_FreeCursor(ted->cursor_ibeam); + SDL_FreeCursor(ted->cursor_wait); SDL_FreeCursor(ted->cursor_resize_h); SDL_FreeCursor(ted->cursor_resize_v); SDL_FreeCursor(ted->cursor_hand); diff --git a/ted.h b/ted.h index be8fcb0..fd2cf9f 100644 --- a/ted.h +++ b/ted.h @@ -414,11 +414,13 @@ typedef struct { } Hover; typedef struct { - - // LSPID and ID of the last response which was processed. - // used to process responses in chronological order (= ID order) - LSPID last_response_lsp; - u32 last_response_id; + // LSPID and 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_lsp is set to 0. + LSPID last_request_lsp; + u32 last_request_id; + struct timespec last_request_time; } Definitions; @@ -488,7 +490,8 @@ typedef struct Ted { // used by menus to keep track of the scroll position so we can return to it. v2d prev_active_buffer_scroll; - SDL_Cursor *cursor_arrow, *cursor_ibeam, *cursor_resize_h, *cursor_resize_v, *cursor_hand, *cursor_move; + SDL_Cursor *cursor_arrow, *cursor_ibeam, *cursor_wait, + *cursor_resize_h, *cursor_resize_v, *cursor_hand, *cursor_move; SDL_Cursor *cursor; // which cursor to use this frame (NULL for no cursor) // node containing tab user is dragging around, NULL if user is not dragging a tab -- cgit v1.2.3