summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-12-23 21:43:07 -0500
committerpommicket <pommicket@gmail.com>2022-12-23 21:43:07 -0500
commit8d96a4b0f0ebb059a63cc4c3193e0169ccf4f5b5 (patch)
tree7155b5d90b9eb8836fa637ed1db44f4e3304fdba
parentaabe543ee93796330158fa7fd247fb1ebeb8e3bb (diff)
framework for having multiple/configurable LSPs
-rw-r--r--buffer.c2
-rw-r--r--lsp.c12
-rw-r--r--lsp.h9
-rw-r--r--main.c80
-rw-r--r--process-posix.c1
-rw-r--r--process-win.c2
-rw-r--r--process.h1
-rw-r--r--ted.c12
-rw-r--r--ted.cfg4
-rw-r--r--ted.h7
10 files changed, 44 insertions, 86 deletions
diff --git a/buffer.c b/buffer.c
index 6df6c9c..d904c38 100644
--- a/buffer.c
+++ b/buffer.c
@@ -289,7 +289,7 @@ Language buffer_language(TextBuffer *buffer) {
LSP *buffer_lsp(TextBuffer *buffer) {
if (!buffer_is_named_file(buffer))
return NULL;
- return ted_get_lsp(buffer->ted, buffer_language(buffer));
+ return ted_get_lsp(buffer->ted, buffer->filename, buffer_language(buffer));
}
diff --git a/lsp.c b/lsp.c
index 01a2bf6..a8a2445 100644
--- a/lsp.c
+++ b/lsp.c
@@ -291,12 +291,16 @@ u32 lsp_document_id(LSP *lsp, const char *path) {
return *value;
}
-bool lsp_create(LSP *lsp, const char *analyzer_command) {
+LSP *lsp_create(const char *root_dir, Language language, const char *analyzer_command) {
+ LSP *lsp = calloc(1, sizeof *lsp);
+ if (!lsp) return NULL;
+
ProcessSettings settings = {
.stdin_blocking = true,
.stdout_blocking = false,
.stderr_blocking = false,
.separate_stderr = true,
+ .working_directory = root_dir,
};
process_run_ex(&lsp->process, analyzer_command, &settings);
LSPRequest initialize = {
@@ -307,11 +311,13 @@ bool lsp_create(LSP *lsp, const char *analyzer_command) {
write_request(lsp, &initialize);
str_hash_table_create(&lsp->document_ids, sizeof(u32));
+ strbuf_cpy(lsp->root_dir, root_dir);
+ lsp->language = language;
lsp->quit_sem = SDL_CreateSemaphore(0);
lsp->messages_mutex = SDL_CreateMutex();
lsp->requests_mutex = SDL_CreateMutex();
lsp->communication_thread = SDL_CreateThread(lsp_communication_thread, "LSP communicate", lsp);
- return true;
+ return lsp;
}
bool lsp_next_message(LSP *lsp, LSPMessage *message) {
@@ -343,6 +349,8 @@ void lsp_free(LSP *lsp) {
}
arr_free(lsp->messages);
arr_free(lsp->trigger_chars);
+ memset(lsp, 0, sizeof *lsp);
+ free(lsp);
}
void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent change) {
diff --git a/lsp.h b/lsp.h
index 16a6491..8383191 100644
--- a/lsp.h
+++ b/lsp.h
@@ -271,10 +271,7 @@ typedef struct LSP {
LSPRequest *requests_server2client;
// we keep track of client-to-server requests
// so that we can process responses.
- // also fucking rust-analyzer gives "waiting for cargo metadata or cargo check"
- // WHY NOT JUST WAIT UNTIL YOUVE DONE THAT BEFORE SENDING THE INITIALIZE RESPONSE. YOU HAVE NOT FINISHED INITIALIZATION. YOU ARE LYING.
- // YOU GIVE A -32801 ERROR CODE WHICH IS "ContentModified" -- WHAT THE FUCK? THATS JUST COMPLETLY WRONG
- // so we need to re-send requests in that case.
+ // this also lets us re-send requests if that's ever necessary.
LSPRequest *requests_sent;
SDL_mutex *requests_mutex;
bool initialized; // has the response to the initialize request been sent?
@@ -284,6 +281,8 @@ typedef struct LSP {
bool provides_completion; // can this LSP server handle completion requests?
char32_t *trigger_chars; // dynamic array of "trigger characters"
SDL_mutex *error_mutex;
+ Language language;
+ char root_dir[TED_PATH_MAX];
char error[256];
} LSP;
@@ -299,7 +298,7 @@ u32 lsp_document_id(LSP *lsp, const char *path);
// don't free the contents of this request! let me handle it!
void lsp_send_request(LSP *lsp, LSPRequest *request);
const char *lsp_response_string(const LSPResponse *response, LSPString string);
-bool lsp_create(LSP *lsp, const char *analyzer_command);
+LSP *lsp_create(const char *root_dir, Language language, const char *analyzer_command);
bool lsp_next_message(LSP *lsp, LSPMessage *message);
void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent change);
void lsp_free(LSP *lsp);
diff --git a/main.c b/main.c
index da6e3e2..997d3c9 100644
--- a/main.c
+++ b/main.c
@@ -307,74 +307,6 @@ int main(int argc, char **argv) {
PROFILE_TIME(init_start)
PROFILE_TIME(basic_init_start)
-
- if (0) {
- // @TODO TEMPORARY
- LSP lsp={0};
-// chdir("/p/test-lsp");
- if (!lsp_create(&lsp, "rust-analyzer")) {
- printf("lsp_create: %s\n",lsp.error);
- exit(1);
- }
- usleep(1000000);//if we don't do this we get "waiting for cargo metadata or cargo check"
- LSPRequest test_req = {.type = LSP_REQUEST_COMPLETION};
- test_req.data.completion = (LSPRequestCompletion){
- .position = {
- .document = lsp_document_id(&lsp, "/p/test-lsp/src/main.rs"),
- .pos = {
- .line = 2,
- .character = 2,
- },
- }
- };
- lsp_send_request(&lsp, &test_req);
- while (1) {
- LSPMessage message = {0};
- while (lsp_next_message(&lsp, &message)) {
- if (message.type == LSP_RESPONSE) {
- const LSPResponse *response = &message.u.response;
- switch (response->request.type) {
- case LSP_REQUEST_COMPLETION: {
- const LSPResponseCompletion *completion = &response->data.completion;
- arr_foreach_ptr(completion->items, LSPCompletionItem, item) {
- printf("(%d)%s => ",
- item->text_edit.type,
- lsp_response_string(response, item->label));
- printf("%s\n",
- lsp_response_string(response, item->text_edit.new_text));
- }
- } break;
- default:
- break;
- }
- } else if (message.type == LSP_REQUEST) {
- const LSPRequest *request = &message.u.request;
- switch (request->type) {
- case LSP_REQUEST_SHOW_MESSAGE: {
- const LSPRequestMessage *m = &request->data.message;
- // @TODO actually show
- printf("Show (%d): %s\n", m->type, m->message);
- } break;
- case LSP_REQUEST_LOG_MESSAGE: {
- const LSPRequestMessage *m = &request->data.message;
- // @TODO actually log
- printf("Log (%d): %s\n", m->type, m->message);
- } break;
- default: break;
- }
- }
- lsp_message_free(&message);
- }
- char error[256];
- if (lsp_get_error(&lsp, error, sizeof error, true)) {
- printf("lsp error: %s\n", error);
- }
- usleep(10000);
- }
- lsp_free(&lsp);
- exit(0);
- }
-
#if __unix__
{
struct sigaction act = {0};
@@ -432,9 +364,9 @@ int main(int argc, char **argv) {
// @TODO TEMPORARY
- ted->test_lsp = calloc(1, sizeof(LSP));
- if (!lsp_create(ted->test_lsp, "rust-analyzer")) {
- printf("lsp_create: %s\n",ted->test_lsp->error);
+ ted->lsps[0] = lsp_create("/p/autosdf", LANG_RUST, "rust-analyzer");
+ if (!ted->lsps[0]) {
+ printf("couldn't create LSP\n");
exit(1);
}
@@ -1175,8 +1107,14 @@ int main(int argc, char **argv) {
build_stop(ted);
if (ted->menu)
menu_close(ted);
+ autocomplete_close(ted);
session_write(ted);
+ for (int i = 0; i < TED_LSP_MAX; ++i) {
+ if (!ted->lsps[i]) break;
+ lsp_free(ted->lsps[i]);
+ ted->lsps[i] = NULL;
+ }
arr_foreach_ptr(ted->shell_history, char *, cmd) {
free(*cmd);
}
diff --git a/process-posix.c b/process-posix.c
index c8ea376..57af73f 100644
--- a/process-posix.c
+++ b/process-posix.c
@@ -50,6 +50,7 @@ bool process_run_ex(Process *proc, const char *command, const ProcessSettings *s
pid_t pid = fork();
if (pid == 0) {
// child process
+ chdir(settings->working_directory);
// put child in its own group. it will be in this group with all of its descendents,
// so by killing everything in the group, we kill all the descendents of this process.
// if we didn't do this, we would just be killing the sh process in process_kill.
diff --git a/process-win.c b/process-win.c
index 8ea7b91..58b7f73 100644
--- a/process-win.c
+++ b/process-win.c
@@ -1,4 +1,4 @@
-#error "@TODO : implement process_write, separate_stderr"
+#error "@TODO : implement process_write, separate_stderr, working_directory"
#include "process.h"
diff --git a/process.h b/process.h
index 2d5a10c..163d7cf 100644
--- a/process.h
+++ b/process.h
@@ -10,6 +10,7 @@ typedef struct {
bool stdout_blocking;
bool separate_stderr;
bool stderr_blocking; // not applicable if separate_stderr is false.
+ const char *working_directory;
} ProcessSettings;
// get process ID of this process
diff --git a/ted.c b/ted.c
index c9ac007..8bc4f18 100644
--- a/ted.c
+++ b/ted.c
@@ -66,9 +66,15 @@ Settings *ted_active_settings(Ted *ted) {
return settings;
}
-LSP *ted_get_lsp(Ted *ted, Language lang) {
- // @TODO
- return ted->test_lsp;
+LSP *ted_get_lsp(Ted *ted, const char *path, Language lang) {
+ for (int i = 0; i < TED_LSP_MAX; ++i) {
+ LSP *lsp = ted->lsps[i];
+ if (!lsp) break;
+ if (lsp->language != lang) continue;
+ if (!str_has_prefix(path, lsp->root_dir)) continue;
+ return lsp;
+ }
+ return NULL;
}
LSP *ted_get_active_lsp(Ted *ted) {
diff --git a/ted.cfg b/ted.cfg
index 4d1d843..98f8c5e 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -242,11 +242,13 @@ cancel = #ffa
# autocomplete
autocomplete-bg = #000
autocomplete-border = #999
-autocomplete-hl = #0a0
+autocomplete-hl = #f6a3
+# these control the text color for various kinds of completions
autocomplete-variable = #bfb
autocomplete-function = #aaf
autocomplete-type = #fac
+
# Syntax highlighting
keyword = #0c0
preprocessor = #77f
diff --git a/ted.h b/ted.h
index 4c7da63..a06b56d 100644
--- a/ted.h
+++ b/ted.h
@@ -4,6 +4,8 @@
#define TEXT_SIZE_MIN 6
#define TEXT_SIZE_MAX 70
+// max number of LSPs running at once
+#define TED_LSP_MAX 200
// these all say "CPP" but really they're C/C++
enum {
@@ -395,8 +397,9 @@ typedef struct {
Rect rect; // rectangle where the autocomplete menu is (needed to avoid interpreting autocomplete clicks as other clicks)
} Autocomplete;
+
typedef struct Ted {
- struct LSP *test_lsp; // @TODO: something better
+ struct LSP *lsps[TED_LSP_MAX];
// current time, as of the start of this frame
struct timespec frame_time;
@@ -516,7 +519,7 @@ void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer);
// the settings of the active buffer, or the default settings if there is no active buffer
Settings *ted_active_settings(Ted *ted);
void ted_load_configs(Ted *ted, bool reloading);
-struct LSP *ted_get_lsp(Ted *ted, Language lang);
+struct LSP *ted_get_lsp(Ted *ted, const char *path, Language lang);
static TextBuffer *find_search_buffer(Ted *ted);
// first, we read all config files, then we parse them.
// this is because we want less specific settings (e.g. settings applied