diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 171 |
1 files changed, 166 insertions, 5 deletions
@@ -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); |