summaryrefslogtreecommitdiff
path: root/src/main/lsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/lsp.c')
-rw-r--r--src/main/lsp.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/main/lsp.c b/src/main/lsp.c
new file mode 100644
index 0000000..d56ca07
--- /dev/null
+++ b/src/main/lsp.c
@@ -0,0 +1,108 @@
+#include "lsp.h"
+
+#include "dged/buffer.h"
+#include "dged/buffers.h"
+#include "dged/hash.h"
+#include "dged/hashmap.h"
+#include "dged/lsp.h"
+#include "dged/minibuffer.h"
+#include "dged/reactor.h"
+#include "dged/settings.h"
+
+HASHMAP_ENTRY_TYPE(lsp_entry, struct lsp *);
+
+HASHMAP(struct lsp_entry) g_lsp_clients;
+
+static struct create_data {
+ struct reactor *reactor;
+ struct buffers *buffers;
+} g_create_data;
+
+static void log_message(int type, struct s8 msg) {
+ (void)type;
+ message("%s", msg);
+}
+
+static void create_lsp_client(struct buffer *buffer, void *userdata) {
+ (void)userdata;
+
+ struct create_data *data = &g_create_data;
+ const char *id = buffer->lang.id;
+ HASHMAP_GET(&g_lsp_clients, struct lsp_entry, id, struct lsp * *lsp);
+ if (lsp == NULL) {
+ // we need to start a new server
+ struct setting *s = lang_setting(&buffer->lang, "language-server");
+ if (!s) { // no language server set
+ return;
+ }
+
+ char *const command[] = {s->value.data.string_value, NULL};
+
+ char bufname[1024] = {0};
+ snprintf(bufname, 1024, "*%s-lsp-stderr*", command[0]);
+ struct buffer *stderr_buf = buffers_find(data->buffers, bufname);
+ if (stderr_buf == NULL) {
+ struct buffer buf = buffer_create(bufname);
+ buf.lazy_row_add = false;
+ stderr_buf = buffers_add(data->buffers, buf);
+ buffer_set_readonly(stderr_buf, true);
+ }
+
+ struct lsp_client client_impl = {
+ .log_message = log_message,
+ };
+ struct lsp *new_lsp =
+ lsp_create(command, data->reactor, stderr_buf, client_impl, NULL);
+
+ if (new_lsp == NULL) {
+ minibuffer_echo("failed to create language server %s", command[0]);
+ buffers_remove(data->buffers, bufname);
+ return;
+ }
+
+ HASHMAP_APPEND(&g_lsp_clients, struct lsp_entry, id,
+ struct lsp_entry * new);
+ new->value = new_lsp;
+
+ if (lsp_start_server(new_lsp) < 0) {
+ minibuffer_echo("failed to start language server %s process.",
+ lsp_server_name(new_lsp));
+ return;
+ }
+ }
+}
+
+static void set_default_lsp(const char *lang_id, const char *server) {
+ struct language l = lang_from_id(lang_id);
+ if (!lang_is_fundamental(&l)) {
+ lang_setting_set_default(
+ &l, "language-server",
+ (struct setting_value){.type = Setting_String,
+ .data.string_value = (char *)server});
+ lang_destroy(&l);
+ }
+}
+
+void lang_servers_init(struct reactor *reactor, struct buffers *buffers) {
+ HASHMAP_INIT(&g_lsp_clients, 32, hash_name);
+
+ set_default_lsp("c", "clangd");
+ set_default_lsp("rs", "rust-analyzer");
+ set_default_lsp("python", "pylsp");
+
+ g_create_data.reactor = reactor;
+ g_create_data.buffers = buffers;
+ buffer_add_create_hook(create_lsp_client, NULL);
+}
+
+void lang_servers_update(void) {
+ HASHMAP_FOR_EACH(&g_lsp_clients, struct lsp_entry * e) {
+ lsp_update(e->value, NULL, 0);
+ }
+}
+
+void lang_servers_teardown(void) {
+ HASHMAP_FOR_EACH(&g_lsp_clients, struct lsp_entry * e) {
+ lsp_stop_server(e->value);
+ }
+}