From 01d5fcc72f6ea29d0f90b845b7565137e7daac14 Mon Sep 17 00:00:00 2001 From: pommicket Date: Sat, 7 Jan 2023 22:32:59 -0500 Subject: fix tags go-to-definition menu, silence errors for LSP not found --- build.c | 6 +++--- ide-definitions.c | 4 ++-- lsp.c | 26 +++++++++++++++++++++----- lsp.h | 5 ++++- main.c | 3 +++ os-posix.c | 24 +++++++++++++----------- os.h | 15 +++++++++++++-- ted.c | 15 +++++---------- 8 files changed, 64 insertions(+), 34 deletions(-) diff --git a/build.c b/build.c index 556cffb..93b6643 100644 --- a/build.c +++ b/build.c @@ -301,12 +301,12 @@ void build_frame(Ted *ted, float x1, float y1, float x2, float y2) { buffer_scroll_to_cursor(buffer); } - char message[64]; - int status = process_check_status(&ted->build_process, message, sizeof message); + ProcessExitInfo info = {0}; + int status = process_check_status(&ted->build_process, &info); if (status == 0) { // hasn't exited yet } else { - buffer_insert_utf8_at_cursor(buffer, message); + buffer_insert_utf8_at_cursor(buffer, info.message); buffer_insert_utf8_at_cursor(buffer, "\n"); if (!build_run_next_command_in_queue(ted)) { ted->building = false; diff --git a/ide-definitions.c b/ide-definitions.c index 673fe63..e956f5b 100644 --- a/ide-definitions.c +++ b/ide-definitions.c @@ -286,8 +286,7 @@ void definitions_selector_update(Ted *ted) { char *chosen = selector_update(ted, sel); if (chosen) { - free(chosen), chosen = NULL; - // we ignore `chosen` and use the cursor instead. + // for LSP go-to-definition, we ignore `chosen` and use the cursor instead. // this is because a single symbol can have multiple definitions, // e.g. with overloading. if (sel->cursor >= sel->n_entries) { @@ -311,6 +310,7 @@ void definitions_selector_update(Ted *ted) { menu_close(ted); tag_goto(ted, chosen); } + free(chosen); } } diff --git a/lsp.c b/lsp.c index e208617..12c5be1 100644 --- a/lsp.c +++ b/lsp.c @@ -294,12 +294,27 @@ static bool lsp_receive(LSP *lsp, size_t max_size) { { // check process status - char text[64] = {0}; - int status = process_check_status(&lsp->process, text, sizeof text); + ProcessExitInfo info = {0}; + int status = process_check_status(&lsp->process, &info); if (status != 0) { - lsp_set_error(lsp, "Can't access LSP server: %s\n" - "Run ted in a terminal or set lsp-log = on for more details." - , text); + bool not_found = + #if _WIN32 + #error "@TODO: what status does cmd return if the program is not found?" + #else + info.exit_code == 127; + #endif + + if (not_found) { + // don't give an error if the server is not found. + // still log it though. + if (lsp->log) + fprintf(lsp->log, "LSP server exited: %s. Probably the server is not installed.", + info.message); + } else { + lsp_set_error(lsp, "Can't access LSP server: %s\n" + "Run ted in a terminal or set lsp-log = on for more details." + , info.message); + } return false; } @@ -392,6 +407,7 @@ static bool lsp_send(LSP *lsp) { quit = true; } } + lsp->died = true; free(messages); return quit; diff --git a/lsp.h b/lsp.h index 61c5610..5d5fc1b 100644 --- a/lsp.h +++ b/lsp.h @@ -557,7 +557,10 @@ typedef struct LSP { // has the response to the initialize request been sent? // thread-safety: this starts out false, and only gets set to true once // (when the initialize response is received) - bool initialized; + _Atomic bool initialized; + // has the LSP server exited? + // thread-safety: only set to false once when the process dies + _Atomic bool died; // thread-safety: only set once in lsp_create. char *command; // this is set in lsp_create, then later set to NULL when we send over the configuration (after the initialized notification). diff --git a/main.c b/main.c index 8073262..71467ba 100644 --- a/main.c +++ b/main.c @@ -55,6 +55,9 @@ FUTURE FEATURES: #if __linux__ #include #endif +#if __unix__ +#include +#endif #if _WIN32 #include #pragma comment(lib, "dbghelp.lib") diff --git a/os-posix.c b/os-posix.c index 3e32c20..42c55bb 100644 --- a/os-posix.c +++ b/os-posix.c @@ -344,44 +344,46 @@ void process_kill(Process **pproc) { *pproc = NULL; } -int process_check_status(Process **pproc, char *message, size_t message_size) { +int process_check_status(Process **pproc, ProcessExitInfo *info) { Process *proc = *pproc; + memset(info, 0, sizeof *info); + if (!proc) { assert(0); - if (message) str_printf(message, message_size, "checked status twice"); + strbuf_printf(info->message, "checked status twice"); return -1; } - assert(!message || message_size > 0); int wait_status = 0; int ret = waitpid(proc->pid, &wait_status, WNOHANG); if (ret == 0) { // process still running - if (message) - *message = '\0'; return 0; } else if (ret > 0) { if (WIFEXITED(wait_status)) { process_kill(pproc); int code = WEXITSTATUS(wait_status); + info->exit_code = code; + info->exited = true; if (code == 0) { - if (message) str_printf(message, message_size, "exited successfully"); + strbuf_printf(info->message, "exited successfully"); return +1; } else { - if (message) str_printf(message, message_size, "exited with code %d", code); + strbuf_printf(info->message, "exited with code %d", code); return -1; } } else if (WIFSIGNALED(wait_status)) { + int signal = WTERMSIG(wait_status); + info->signal = signal; + info->signalled = true; process_close_pipes(proc); - if (message) - str_printf(message, message_size, "terminated by signal %d", WTERMSIG(wait_status)); + strbuf_printf(info->message, "terminated by signal %d", info->signal); return -1; } return 0; } else { // this process is gone or something? process_close_pipes(proc); - if (message) - str_printf(message, message_size, "process ended unexpectedly"); + strbuf_printf(info->message, "process ended unexpectedly"); return -1; } } diff --git a/os.h b/os.h index 20135ff..0af10cb 100644 --- a/os.h +++ b/os.h @@ -91,6 +91,17 @@ typedef struct { const char *working_directory; } ProcessSettings; +typedef struct { + // string like "exited with code 9" + char message[62]; + // it might be possible that both signalled and exited are false, + // if something weird happens. + bool signalled; + bool exited; + int exit_code; + int signal; +} ProcessExitInfo; + // get process ID of this process int process_get_id(void); // execute the given command (like if it was passed to system()), creating a new Process object. @@ -122,9 +133,9 @@ long long process_read_stderr(Process *process, char *data, size_t size); // -1 if the process returned a non-zero exit code, or got a signal. // 1 if the process exited successfully // 0 if the process hasn't exited. -// If message is not NULL, it will be set to a description of what happened (e.g. "exited successfully") +// If the process has exited, *info will be filled out with details. // if the process is no longer running, *process will be freed and set to NULL. -int process_check_status(Process **process, char *message, size_t message_size); +int process_check_status(Process **process, ProcessExitInfo *info); // kills process if still running // this also frees any resources used by `*process`. // *process will be set to NULL. diff --git a/ted.c b/ted.c index e7f3098..e3f5aeb 100644 --- a/ted.c +++ b/ted.c @@ -149,20 +149,13 @@ Settings *ted_get_settings(Ted *ted, const char *path, Language language) { LSP *ted_get_lsp_by_id(Ted *ted, LSPID id) { for (int i = 0; ted->lsps[i]; ++i) { - if (ted->lsps[i]->id == id) - return ted->lsps[i]; + LSP *lsp = ted->lsps[i]; + if (lsp->id == id) + return lsp->died ? NULL : lsp; } return NULL; } -// IMPORTANT NOTE ABOUT CACHING LSPs: -// - be careful if you want to cache LSPs, e.g. adding a LSP *lsp member to `buffer`. -// - right now we pretend that the server has workspace folder support until the initialize response is sent. -// - specifically, this means that: -// ted_get_lsp("/path1/a") => new LSP 0x12345 -// ted_get_lsp("/path2/b") => same LSP 0x12345 -// (receive initialize request, realize we don't have workspace folder support) -// ted_get_lsp("/path2/b") => new LSP 0x6789A LSP *ted_get_lsp(Ted *ted, const char *path, Language language) { Settings *settings = ted_get_settings(ted, path, language); if (!settings->lsp_enabled) @@ -180,6 +173,8 @@ LSP *ted_get_lsp(Ted *ted, const char *path, Language language) { // if the server supports workspaceFolders. return NULL; } + if (lsp->died) + return NULL; // check if root matches up or if we can add a workspace folder char *root = ted_get_root_dir_of(ted, path); -- cgit v1.2.3