summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c171
1 files changed, 166 insertions, 5 deletions
diff --git a/main.c b/main.c
index 1967db8..edb8b11 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,28 @@
-/*
+/*
+@TODO:
+- fix unicode_utf8_to_utf32 to handle bad UTF-8 (i.e. continuation bytes which aren't actually continuation bytes)
+- provide completion context + don't flash cursor for triggers with no completions
+- dont do completion if provides_completion = false
+- scroll through completions
+- only show "Loading..." if it's taking some time (prevent flash)
+- LSP setting
+- figure out workspace
+- make sure "save as" works
+- more LSP stuff:
+ - go to definition using LSP
+ - find usages
+- rename buffer->filename to buffer->path
+ - make buffer->path NULL for untitled buffers & fix resulting mess
+- run everything through valgrind ideally with leak checking
+- rust-analyzer bug reports:
+ - bad json can give "Unexpected error: client exited without proper shutdown sequence"
+ - rust-analyzer should wait until cargo metadata/check is done before sending initialize response
FUTURE FEATURES:
+- robust find (results shouldn't move around when you type things)
+- multiple files with command line arguments
- configurable max buffer size + max view-only buffer size
+- :set-build-command, don't let ../Cargo.toml override ./Makefile
+- add numlock as a key modifier? (but make sure "Ctrl+S" handles both "No NumLock+Ctrl+S" and "NumLock+Ctrl+S"
- better undo chaining (dechain on backspace?)
- allow multiple fonts (fonts directory?)
- regenerate tags for completion too if there are no results
@@ -48,7 +70,9 @@ no_warn_end
#endif
#include "unicode.h"
+#include "ds.c"
#include "util.c"
+
#if _WIN32
#include "filesystem-win.c"
#elif __unix__
@@ -56,7 +80,6 @@ no_warn_end
#else
#error "Unrecognized operating system."
#endif
-#include "arr.c"
#include "math.c"
#if _WIN32
@@ -92,8 +115,10 @@ static void die(char const *fmt, ...) {
#include "ted.h"
#include "gl.c"
#include "text.c"
+#include "lsp.h"
#include "string32.c"
+#include "colors.c"
#include "syntax.c"
bool tag_goto(Ted *ted, char const *tag);
#include "buffer.c"
@@ -108,6 +133,8 @@ bool tag_goto(Ted *ted, char const *tag);
#include "command.c"
#include "config.c"
#include "session.c"
+#include "json.c"
+#include "lsp.c"
#if PROFILE
#define PROFILE_TIME(var) double var = time_get_seconds();
@@ -286,6 +313,74 @@ 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};
@@ -341,6 +436,14 @@ int main(int argc, char **argv) {
}
ted->last_save_time = -1e50;
+
+ // @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);
+ exit(1);
+ }
+
// make sure signal handler has access to ted.
error_signal_handler_ted = ted;
@@ -712,8 +815,34 @@ int main(int argc, char **argv) {
case SDL_TEXTINPUT: {
char *text = event.text.text;
if (buffer
- && (key_modifier & ~KEY_MODIFIER_SHIFT) == 0) // unfortunately, some key combinations like ctrl+minus still register as a "-" text input event
+ // unfortunately, some key combinations like ctrl+minus still register as a "-" text input event
+ && (key_modifier & ~KEY_MODIFIER_SHIFT) == 0) {
+ // insert the text
buffer_insert_utf8_at_cursor(buffer, text);
+ // check for trigger character
+ LSP *lsp = buffer_lsp(buffer);
+ Settings *settings = buffer_settings(buffer);
+ if (lsp && settings->trigger_characters) {
+ u32 last_code_point = (u32)strlen(text) - 1;
+ while (last_code_point > 0 &&
+ unicode_is_continuation_byte((u8)text[last_code_point]))
+ --last_code_point;
+ char32_t last_char = 0;
+ unicode_utf8_to_utf32(&last_char, &text[last_code_point],
+ strlen(text) - last_code_point);
+ arr_foreach_ptr(lsp->trigger_chars, char32_t, c) {
+ if (*c == last_char) {
+ autocomplete_open(ted);
+ break;
+ }
+ }
+
+ if (settings->identifier_trigger_characters && is_word(last_char)
+ && !is_digit(last_char))
+ autocomplete_open(ted);
+ }
+
+ }
} break;
}
}
@@ -789,6 +918,38 @@ int main(int argc, char **argv) {
menu_update(ted);
}
+ {
+ LSP *lsp = ted_get_active_lsp(ted);
+ if (lsp) {
+ LSPMessage message = {0};
+ while (lsp_next_message(lsp, &message)) {
+ switch (message.type) {
+ case LSP_REQUEST: {
+ LSPRequest *r = &message.u.request;
+ switch (r->type) {
+ case LSP_REQUEST_SHOW_MESSAGE: {
+ LSPRequestMessage *m = &r->data.message;
+ // @TODO: multiple messages
+ ted_seterr(ted, "%s", m->message);
+ } break;
+ case LSP_REQUEST_LOG_MESSAGE: {
+ LSPRequestMessage *m = &r->data.message;
+ // @TODO: actual logging
+ printf("%s\n", m->message);
+ } break;
+ default: break;
+ }
+ } break;
+ case LSP_RESPONSE: {
+ LSPResponse *r = &message.u.response;
+ autocomplete_process_lsp_response(ted, r);
+ } break;
+ }
+ lsp_message_free(&message);
+ }
+ }
+ }
+
ted_update_window_dimensions(ted);
float window_width = ted->window_width, window_height = ted->window_height;
@@ -886,11 +1047,11 @@ int main(int argc, char **argv) {
if (ted->nodes_used[0]) {
float y1 = padding;
node_frame(ted, node, rect4(x1, y1, x2, y));
- if (ted->autocomplete) {
+ if (ted->autocomplete.open) {
autocomplete_frame(ted);
}
} else {
- ted->autocomplete = false;
+ autocomplete_close(ted);
text_utf8_anchored(font, "Press Ctrl+O to open a file or Ctrl+N to create a new one.",
window_width * 0.5f, window_height * 0.5f, ted_color(ted, COLOR_TEXT_SECONDARY), ANCHOR_MIDDLE);
text_render(font);