From 66367583a3b57e37e9198838222f45d99e77d8ae Mon Sep 17 00:00:00 2001 From: pommicket Date: Fri, 30 Dec 2022 12:42:32 -0500 Subject: definitions menu, but it's acting weird --- buffer.c | 2 + find.c | 2 +- ide-definitions.c | 128 +++++++++++++++++++++++++++++++++++++++++++++--------- lsp-parse.c | 2 +- lsp-write.c | 3 -- lsp.c | 2 +- main.c | 73 ++++++++++++++++--------------- menu.c | 8 ++-- tags.c | 66 +++++----------------------- ted.c | 2 +- ted.h | 21 ++++++--- 11 files changed, 180 insertions(+), 129 deletions(-) diff --git a/buffer.c b/buffer.c index 8079bf5..b4c85d5 100644 --- a/buffer.c +++ b/buffer.c @@ -312,6 +312,8 @@ static void buffer_send_lsp_did_open(TextBuffer *buffer, LSP *lsp, char *buffer_ } LSP *buffer_lsp(TextBuffer *buffer) { + if (!buffer) + return NULL; if (!buffer_is_named_file(buffer)) return NULL; if (buffer->view_only) diff --git a/find.c b/find.c index abdfc3e..13d1a24 100644 --- a/find.c +++ b/find.c @@ -10,7 +10,7 @@ static u32 find_replace_flags(Ted *ted) { } // which buffer will be searched? -static TextBuffer *find_search_buffer(Ted *ted) { +TextBuffer *find_search_buffer(Ted *ted) { if (ted->active_buffer && ted->active_buffer != &ted->find_buffer && ted->active_buffer != &ted->replace_buffer) { return ted->active_buffer; } diff --git a/ide-definitions.c b/ide-definitions.c index e63e977..a9ff945 100644 --- a/ide-definitions.c +++ b/ide-definitions.c @@ -51,6 +51,7 @@ void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition p LSPRequest request = {.type = LSP_REQUEST_DEFINITION}; request.data.definition.position = position; LSPRequestID id = lsp_send_request(lsp, &request); + // @TODO : cancel old request defs->last_request_id = id; defs->last_request_time = ted->frame_time; } else { @@ -64,38 +65,125 @@ void definition_cancel_lookup(Ted *ted) { defs->last_request_id = 0; } + +void definitions_frame(Ted *ted) { + Definitions *defs = &ted->definitions; + if (defs->last_request_id && timespec_sub(ted->frame_time, defs->last_request_time) > 0.2) { + ted->cursor = ted->cursor_wait; + } +} + +static void definitions_clear_entries(Definitions *defs) { + arr_foreach_ptr(defs->selector_all_entries, SelectorEntry, entry) { + free((char*)entry->name); + } + arr_clear(defs->selector_all_entries); + arr_clear(defs->selector.entries); + defs->selector.n_entries = 0; +} + + void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response) { - if (response->request.type != LSP_REQUEST_DEFINITION) - return; - - const LSPResponseDefinition *response_def = &response->data.definition; Definitions *defs = &ted->definitions; - if (response->request.id != defs->last_request_id) { - // response to an old request + // response to an old/irrelevant request return; } defs->last_request_id = 0; - if (!arr_len(response_def->locations)) { - // no definition. do the error cursor. - ted_flash_error_cursor(ted); - return; + switch (response->request.type) { + case LSP_REQUEST_DEFINITION: { + const LSPResponseDefinition *response_def = &response->data.definition; + + if (!arr_len(response_def->locations)) { + // no definition. do the error cursor. + ted_flash_error_cursor(ted); + return; + } + LSPLocation location = response_def->locations[0]; + const char *path = lsp_document_path(lsp, location.document); + if (!ted_open_file(ted, path)) { + ted_flash_error_cursor(ted); + return; + } + LSPDocumentPosition position = lsp_location_start_position(location); + ted_go_to_lsp_document_position(ted, lsp, position); + } break; + case LSP_REQUEST_WORKSPACE_SYMBOLS: { + const LSPResponseWorkspaceSymbols *response_syms = &response->data.workspace_symbols; + const LSPSymbolInformation *symbols = response_syms->symbols; + const Settings *settings = ted_active_settings(ted); + const u32 *colors = settings->colors; + + definitions_clear_entries(defs); + arr_set_len(defs->selector_all_entries, arr_len(symbols)); + for (size_t i = 0; i < arr_len(symbols); ++i) { + const LSPSymbolInformation *symbol = &symbols[i]; + SelectorEntry *entry = &defs->selector_all_entries[i]; + + entry->name = str_dup(lsp_response_string(response, symbol->name)); + SymbolKind kind = symbol_kind_to_ted(symbol->kind); + entry->color = colors[color_for_symbol_kind(kind)]; + } + + } break; + default: + debug_println("?? bad request type in %s", __func__); + break; } - LSPLocation location = response_def->locations[0]; - const char *path = lsp_document_path(lsp, location.document); - if (!ted_open_file(ted, path)) { - ted_flash_error_cursor(ted); - return; +} + +void definitions_selector_open(Ted *ted) { + Definitions *defs = &ted->definitions; + definitions_clear_entries(defs); + LSP *lsp = buffer_lsp(ted->prev_active_buffer); + if (lsp) { + LSPRequest request = {.type = LSP_REQUEST_WORKSPACE_SYMBOLS}; + LSPRequestWorkspaceSymbols *syms = &request.data.workspace_symbols; + syms->query = str_dup(""); + defs->last_request_id = lsp_send_request(lsp, &request); + defs->last_request_time = ted->frame_time; + } else { + defs->selector_all_entries = tags_get_entries(ted); } - LSPDocumentPosition position = lsp_location_start_position(location); - ted_go_to_lsp_document_position(ted, lsp, position); + ted_switch_to_buffer(ted, &ted->line_buffer); + buffer_select_all(ted->active_buffer); + defs->selector.cursor = 0; } -void definitions_frame(Ted *ted) { + +void definitions_selector_close(Ted *ted) { Definitions *defs = &ted->definitions; - if (defs->last_request_id && timespec_sub(ted->frame_time, defs->last_request_time) > 0.2) { - ted->cursor = ted->cursor_wait; + definitions_clear_entries(defs); + // @TODO : cancel + defs->last_request_id = 0; +} + +char *definitions_selector_update(Ted *ted) { + Definitions *defs = &ted->definitions; + Selector *sel = &defs->selector; + sel->enable_cursor = true; + + // create selector entries based on search term + char *search_term = str32_to_utf8_cstr(buffer_get_line(&ted->line_buffer, 0)); + + arr_clear(sel->entries); + + arr_foreach_ptr(defs->selector_all_entries, SelectorEntry, entry) { + if (!search_term || stristr(entry->name, search_term)) { + arr_add(sel->entries, *entry); + } } + + sel->n_entries = arr_len(sel->entries); + + return selector_update(ted, sel); +} + +void definitions_selector_render(Ted *ted, Rect bounds) { + Definitions *defs = &ted->definitions; + Selector *sel = &defs->selector; + sel->bounds = bounds; + selector_render(ted, sel); } diff --git a/lsp-parse.c b/lsp-parse.c index c98ae85..f720d12 100644 --- a/lsp-parse.c +++ b/lsp-parse.c @@ -569,7 +569,7 @@ static bool parse_symbol_information(LSP *lsp, const JSON *json, JSONValue value static bool parse_workspace_symbols(LSP *lsp, const JSON *json, LSPResponse *response) { LSPResponseWorkspaceSymbols *syms = &response->data.workspace_symbols; - JSONArray result = json_force_array(json_root(json)); + JSONArray result = json_force_array(json_get(json, "result")); arr_set_len(syms->symbols, result.len); for (size_t i = 0; i < result.len; ++i) { LSPSymbolInformation *info = &syms->symbols[i]; diff --git a/lsp-write.c b/lsp-write.c index 58c5a8f..b8167b4 100644 --- a/lsp-write.c +++ b/lsp-write.c @@ -622,9 +622,6 @@ static void write_message(LSP *lsp, LSPMessage *message) { write_response(lsp, &message->u.response); break; } - // it's okay to free the message here since the request/response part has been zeroed. - // (as i'm writing this, this won't do anything but it might in the future) - lsp_message_free(message); } #undef write_bool diff --git a/lsp.c b/lsp.c index c8de1a7..4b95179 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 diff --git a/main.c b/main.c index 61b319d..8048b3e 100644 --- a/main.c +++ b/main.c @@ -1,10 +1,12 @@ /* @TODO: - cancelling requests e.g. in ide-definitions.c +- sort symbols by score (clangd extension?) - more LSP stuff: - go to definition using LSP - find usages - refactoring? +- ted_active_lsp should return something even when buffer isn't open - test full unicode position handling - check if there are any other non-optional/nice-to-have-support-for server-to-client requests - better non-error window/showMessage(Request) @@ -14,6 +16,7 @@ - what to do if initialize request takes a long time? - delete old sent requests? but make sure requests that just take a long time are okay. (if the server never sends a response) +- make tags_dir the root folder - check that tags still works - TESTING: make rust-analyzer-slow (waits 10s before sending response) - run everything through valgrind ideally with leak checking @@ -868,45 +871,43 @@ int main(int argc, char **argv) { menu_update(ted); } - { - LSP *lsp = ted_get_active_lsp(ted); - if (lsp) { - LSPMessage message = {0}; - while (lsp_next_message(lsp, &message)) { - switch (message.type) { - case LSP_REQUEST: { - LSPRequest *r = &message.u.request; - switch (r->type) { - case LSP_REQUEST_SHOW_MESSAGE: { - LSPRequestMessage *m = &r->data.message; - // @TODO: multiple messages - ted_seterr(ted, "%s", m->message); - } break; - case LSP_REQUEST_LOG_MESSAGE: { - LSPRequestMessage *m = &r->data.message; - // @TODO: actual logging - printf("%s\n", m->message); - } break; - default: break; - } + for (int i = 0; ted->lsps[i]; ++i) { + LSP *lsp = ted->lsps[i]; + LSPMessage message = {0}; + while (lsp_next_message(lsp, &message)) { + switch (message.type) { + case LSP_REQUEST: { + LSPRequest *r = &message.u.request; + switch (r->type) { + case LSP_REQUEST_SHOW_MESSAGE: { + LSPRequestMessage *m = &r->data.message; + // @TODO: multiple messages + ted_seterr(ted, "%s", m->message); } break; - case LSP_RESPONSE: { - LSPResponse *r = &message.u.response; - if (r->error) { - // not displaying this right now - // idk it might be spammy - //ted_seterr(ted, "%s", r->error); - } - // it's important that we send error responses here too. - // we don't want to be waiting around for a response that's never coming. - autocomplete_process_lsp_response(ted, r); - signature_help_process_lsp_response(ted, r); - hover_process_lsp_response(ted, r); - definitions_process_lsp_response(ted, lsp, r); + case LSP_REQUEST_LOG_MESSAGE: { + LSPRequestMessage *m = &r->data.message; + // @TODO: actual logging + printf("%s\n", m->message); } break; + default: break; + } + } break; + case LSP_RESPONSE: { + LSPResponse *r = &message.u.response; + if (r->error) { + // not displaying this right now + // idk it might be spammy + //ted_seterr(ted, "%s", r->error); } - lsp_message_free(&message); + // it's important that we send error responses here too. + // we don't want to be waiting around for a response that's never coming. + autocomplete_process_lsp_response(ted, r); + signature_help_process_lsp_response(ted, r); + hover_process_lsp_response(ted, r); + definitions_process_lsp_response(ted, lsp, r); + } break; } + lsp_message_free(&message); } } @@ -1172,7 +1173,7 @@ int main(int argc, char **argv) { SDL_DestroyWindow(window); SDL_Quit(); if (log) fclose(log); - tag_selector_close(ted); + definitions_selector_close(ted); for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) if (ted->buffers_used[i]) buffer_free(&ted->buffers[i]); diff --git a/menu.c b/menu.c index 2e04d49..139ae07 100644 --- a/menu.c +++ b/menu.c @@ -23,7 +23,7 @@ static void menu_close_with_next(Ted *ted, Menu next) { *ted->ask_reload = 0; break; case MENU_GOTO_DEFINITION: - tag_selector_close(ted); + definitions_selector_close(ted); break; case MENU_GOTO_LINE: buffer_clear(&ted->line_buffer); @@ -77,7 +77,7 @@ void menu_open(Ted *ted, Menu menu) { assert(*ted->ask_reload); break; case MENU_GOTO_DEFINITION: - tag_selector_open(ted); + definitions_selector_open(ted); break; case MENU_GOTO_LINE: ted_switch_to_buffer(ted, &ted->line_buffer); @@ -238,7 +238,7 @@ static void menu_update(Ted *ted) { } break; case MENU_GOTO_DEFINITION: { - char *chosen_tag = tag_selector_update(ted); + char *chosen_tag = definitions_selector_update(ted); if (chosen_tag) { menu_close(ted); tag_goto(ted, chosen_tag); @@ -394,7 +394,7 @@ static void menu_render(Ted *ted) { file_selector_render(ted, fs); } break; case MENU_GOTO_DEFINITION: { - tag_selector_render(ted, rect4(x1, y1, x2, y2)); + definitions_selector_render(ted, rect4(x1, y1, x2, y2)); } break; case MENU_GOTO_LINE: { float menu_height = char_height + 2 * padding; diff --git a/tags.c b/tags.c index 66ed36e..ebd5497 100644 --- a/tags.c +++ b/tags.c @@ -1,6 +1,6 @@ -static char const *tags_filename(Ted *ted, bool error_if_does_not_exist) { +static const char *tags_filename(Ted *ted, bool error_if_does_not_exist) { change_directory(ted->cwd); - char const *filename = "tags"; + const char *filename = "tags"; ted_path_full(ted, ".", ted->tags_dir, sizeof ted->tags_dir); if (!fs_file_exists(filename)) { filename = "../tags"; @@ -347,70 +347,26 @@ top:; return success; } -static void tag_selector_open(Ted *ted) { +SelectorEntry *tags_get_entries(Ted *ted) { // read tags file and extract tag names char const *filename = tags_filename(ted, true); - if (!filename) return; + if (!filename) return NULL; FILE *file = fopen(filename, "rb"); - if (!file) return; + if (!file) return NULL; - arr_clear(ted->tag_selector_entries); + SelectorEntry *entries = NULL; + u32 color = ted_color(ted, COLOR_TEXT); if (file) { char line[1024]; while (fgets(line, sizeof line, file)) { if (line[0] != '!') { // tag metadata is formatted as tag names beginning with ! size_t len = strcspn(line, "\t"); - arr_add(ted->tag_selector_entries, strn_dup(line, len)); + SelectorEntry *entry = arr_addp(entries); + entry->name = strn_dup(line, len); + entry->color = color; } } - ted_switch_to_buffer(ted, &ted->line_buffer); - buffer_select_all(ted->active_buffer); - - ted->tag_selector.cursor = 0; - fclose(file); } -} - -static void tag_selector_close(Ted *ted) { - Selector *sel = &ted->tag_selector; - arr_clear(sel->entries); - sel->n_entries = 0; - arr_foreach_ptr(ted->tag_selector_entries, char *, entry) { - free(*entry); - } - arr_clear(ted->tag_selector_entries); -} - -// returns tag selected (should be free'd), or NULL if none was. -static char *tag_selector_update(Ted *ted) { - Selector *sel = &ted->tag_selector; - u32 color = ted_color(ted, COLOR_TEXT); - sel->enable_cursor = true; - - // create selector entries based on search term - char *search_term = str32_to_utf8_cstr(buffer_get_line(&ted->line_buffer, 0)); - - arr_clear(sel->entries); - - arr_foreach_ptr(ted->tag_selector_entries, char *, tagp) { - char const *tag = *tagp; - if (!search_term || stristr(tag, search_term)) { - SelectorEntry entry = { - .name = tag, - .color = color - }; - arr_add(sel->entries, entry); - } - } - - sel->n_entries = arr_len(sel->entries); - - return selector_update(ted, sel); -} - -static void tag_selector_render(Ted *ted, Rect bounds) { - Selector *sel = &ted->tag_selector; - sel->bounds = bounds; - selector_render(ted, sel); + return entries; } diff --git a/ted.c b/ted.c index 4a89e8f..0bf0668 100644 --- a/ted.c +++ b/ted.c @@ -143,7 +143,7 @@ LSP *ted_get_lsp(Ted *ted, const char *path, Language language) { return NULL; } -LSP *ted_get_active_lsp(Ted *ted) { +LSP *ted_active_lsp(Ted *ted) { if (!ted->active_buffer) return NULL; return buffer_lsp(ted->active_buffer); diff --git a/ted.h b/ted.h index 6f4174a..393aee6 100644 --- a/ted.h +++ b/ted.h @@ -420,11 +420,14 @@ typedef struct { // last_request_id is set to 0. LSPRequestID last_request_id; struct timespec last_request_time; + + Selector selector; // for "go to definition of..." menu + SelectorEntry *selector_all_entries; // an array of all definitions } Definitions; typedef struct Ted { - struct LSP *lsps[TED_LSP_MAX + 1]; + LSP *lsps[TED_LSP_MAX + 1]; // current time, as of the start of this frame struct timespec frame_time; @@ -453,7 +456,6 @@ typedef struct Ted { int scroll_total_x, scroll_total_y; // total amount scrolled in the x and y direction this frame Menu menu; FileSelector file_selector; - Selector tag_selector; // for "go to definition of..." menu Selector command_selector; TextBuffer line_buffer; // general-purpose line buffer for inputs -- used for menus TextBuffer find_buffer; // use for "find" term in find/find+replace @@ -502,7 +504,6 @@ typedef struct Ted { // if not NULL, points to the node whose split the user is currently resizing. Node *resizing_split; - char **tag_selector_entries; // an array of all tags (see tag_selector_open) char **shell_history; // dynamic array of history of commands run with :shell (UTF-8) u32 shell_history_pos; // for keeping track of where we are in the shell history. @@ -549,10 +550,10 @@ void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer); Settings *ted_active_settings(Ted *ted); Settings *ted_get_settings(Ted *ted, const char *path, Language lang); void ted_load_configs(Ted *ted, bool reloading); -struct LSP *ted_get_lsp(Ted *ted, const char *path, Language lang); -struct LSP *ted_active_lsp(Ted *ted); -struct LSP *ted_get_lsp_by_id(Ted *ted, u32 id); -static TextBuffer *find_search_buffer(Ted *ted); +LSP *ted_get_lsp(Ted *ted, const char *path, Language lang); +LSP *ted_active_lsp(Ted *ted); +LSP *ted_get_lsp_by_id(Ted *ted, u32 id); +TextBuffer *find_search_buffer(Ted *ted); // first, we read all config files, then we parse them. // this is because we want less specific settings (e.g. settings applied // to all languages instead of one particular language) to be applied first, @@ -581,3 +582,9 @@ void signature_help_retrigger(Ted *ted); // Note: the document position is required for LSP requests because of overloading (where the name // alone isn't sufficient) void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition pos); +void definitions_selector_open(Ted *ted); +// returns tag selected (should be free'd), or NULL if none was. +// if this is an LSP-based menu, this function will always return NULL. +char *definitions_selector_update(Ted *ted); +void definitions_selector_render(Ted *ted, Rect bounds); +void definitions_selector_close(Ted *ted); -- cgit v1.2.3