summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.c6
-rw-r--r--ide-definitions.c4
-rw-r--r--lsp.c26
-rw-r--r--lsp.h5
-rw-r--r--main.c3
-rw-r--r--os-posix.c24
-rw-r--r--os.h15
-rw-r--r--ted.c15
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 <execinfo.h>
#endif
+#if __unix__
+#include <unistd.h>
+#endif
#if _WIN32
#include <shellapi.h>
#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);