summaryrefslogtreecommitdiff
path: root/src/dged/lsp.c
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2024-05-22 00:00:29 +0200
committerAlbert Cervin <albert@acervin.com>2024-09-12 20:17:56 +0200
commit405da5f84b072ea97b69359454899f45d92d24b6 (patch)
tree20525b4bc44a5d8cbab4d62abe8413e174731db6 /src/dged/lsp.c
parent4ab7e453e26afc6e9f4938c65f89463fbba9e267 (diff)
downloaddged-405da5f84b072ea97b69359454899f45d92d24b6.tar.gz
dged-405da5f84b072ea97b69359454899f45d92d24b6.tar.xz
dged-405da5f84b072ea97b69359454899f45d92d24b6.zip
WIP LSP client
This contains the start of an LSP client. Nothing (except starting the LSP server) works at the moment and the feature is disabled by default.
Diffstat (limited to 'src/dged/lsp.c')
-rw-r--r--src/dged/lsp.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/dged/lsp.c b/src/dged/lsp.c
new file mode 100644
index 0000000..3c699f4
--- /dev/null
+++ b/src/dged/lsp.c
@@ -0,0 +1,163 @@
+#include "lsp.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "buffer.h"
+#include "process.h"
+#include "reactor.h"
+
+struct lsp {
+ const char *name;
+ char *const *command;
+ struct process *process;
+ struct reactor *reactor;
+ struct buffer *stderr_buffer;
+ struct lsp_client client_impl;
+ uint32_t stdin_event;
+ uint32_t stdout_event;
+ uint32_t stderr_event;
+};
+
+struct lsp *lsp_create(char *const command[], struct reactor *reactor,
+ struct buffer *stderr_buffer,
+ struct lsp_client client_impl, const char *name) {
+ // check length of command
+ if (command == NULL) {
+ return NULL;
+ }
+
+ uint32_t command_len = 0;
+ while (command[command_len] != NULL) {
+ ++command_len;
+ }
+
+ if (command_len == 0) {
+ return NULL;
+ }
+
+ struct lsp *lsp = calloc(1, sizeof(struct lsp));
+
+ char **cmd = calloc(command_len + 1, sizeof(const char *));
+ memcpy(cmd, command, sizeof(const char *) * command_len);
+ cmd[command_len] = NULL;
+ lsp->command = cmd;
+
+ if (name != NULL) {
+ lsp->name = strdup(name);
+ } else {
+#ifdef __unix__
+ const char *lslash = strrchr(lsp->command[0], '/');
+#elif defined(_WIN32) || defined(WIN32)
+ const char *lslash = strrchr(lsp->command[0], '\\');
+#endif
+ if (lslash == NULL) {
+ lsp->name = strdup(lsp->command[0]);
+ } else {
+ lsp->name = strdup(lslash + 1);
+ }
+ }
+ lsp->stderr_buffer = stderr_buffer;
+ lsp->client_impl = client_impl;
+ lsp->reactor = reactor;
+ lsp->stdin_event = -1;
+ lsp->stdout_event = -1;
+ lsp->stderr_event = -1;
+
+ return lsp;
+}
+
+void lsp_destroy(struct lsp *lsp) {
+ free((void *)lsp->name);
+ if (lsp->process != NULL) {
+ free(lsp->process);
+ }
+ if (lsp->command != NULL) {
+ char *command = lsp->command[0];
+ while (command != NULL) {
+ free(command);
+ ++command;
+ }
+
+ free((void *)lsp->command);
+ }
+ free(lsp);
+}
+
+uint32_t lsp_update(struct lsp *lsp, struct lsp_response **responses,
+ uint32_t responses_capacity) {
+
+ (void)responses;
+ (void)responses_capacity;
+
+ if (!lsp_server_running(lsp)) {
+ return -1;
+ }
+
+ // read stderr
+ if (lsp->stderr_event != (uint32_t)-1) {
+ uint8_t buf[1024];
+ if (reactor_poll_event(lsp->reactor, lsp->stderr_event)) {
+ ssize_t nb = 0;
+ while ((nb = read(lsp->process->stderr, buf, 1024)) > 0) {
+ buffer_set_readonly(lsp->stderr_buffer, false);
+ buffer_add(lsp->stderr_buffer, buffer_end(lsp->stderr_buffer), buf, nb);
+ buffer_set_readonly(lsp->stderr_buffer, true);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int lsp_start_server(struct lsp *lsp) {
+ struct process p;
+ struct process_create_result res = process_create(lsp->command, &p);
+
+ if (!res.ok) {
+ // TODO: losing error message here
+ return -1;
+ }
+
+ lsp->process = calloc(1, sizeof(struct process));
+ memcpy(lsp->process, &p, sizeof(struct process));
+ lsp->stderr_event = reactor_register_interest(
+ lsp->reactor, lsp->process->stderr, ReadInterest);
+
+ return 0;
+}
+
+int lsp_restart_server(struct lsp *lsp) {
+ if (lsp_server_running(lsp)) {
+ lsp_stop_server(lsp);
+ }
+
+ return lsp_start_server(lsp);
+}
+
+void lsp_stop_server(struct lsp *lsp) {
+ process_kill(lsp->process);
+ process_destroy(lsp->process);
+ free(lsp->process);
+ lsp->process = NULL;
+}
+
+bool lsp_server_running(const struct lsp *lsp) {
+ if (lsp->process == NULL) {
+ return false;
+ }
+
+ return process_running(lsp->process);
+}
+
+uint64_t lsp_server_pid(const struct lsp *lsp) {
+ if (!lsp_server_running(lsp)) {
+ return -1;
+ }
+
+ return lsp->process->id;
+}
+
+const char *lsp_server_name(const struct lsp *lsp) { return lsp->name; }