diff options
Diffstat (limited to 'src/main/lsp.c')
| -rw-r--r-- | src/main/lsp.c | 108 |
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); + } +} |
