From b65943698a241624973f3ab54530bb5d5884cff2 Mon Sep 17 00:00:00 2001 From: pommicket Date: Sat, 5 Aug 2023 15:01:38 -0400 Subject: internalize Autocomplete --- buffer.c | 8 +++--- command.c | 8 +++--- ide-autocomplete.c | 79 +++++++++++++++++++++++++++++++++++++++++++++--------- main.c | 4 +-- ted.h | 48 ++++++++------------------------- 5 files changed, 87 insertions(+), 60 deletions(-) diff --git a/buffer.c b/buffer.c index 4393f0f..097e4ed 100644 --- a/buffer.c +++ b/buffer.c @@ -1635,7 +1635,7 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 } str32_remove_all_instances_of_char(&str, '\r'); - if (buffer->ted->autocomplete.open) { + if (autocomplete_is_open(buffer->ted)) { // close completions if a non-word character is typed bool close_completions = false; for (u32 i = 0; i < str.len; ++i) { @@ -2105,7 +2105,7 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_) // Not doing this might also cause other bugs, best to keep it here just in case. nchars = (u32)buffer_get_text_at_pos(buffer, pos, NULL, nchars); - if (buffer->ted->autocomplete.open) { + if (autocomplete_is_open(buffer->ted)) { // close completions if a non-word character is deleted bool close_completions = false; if (nchars > 256) { @@ -2895,8 +2895,8 @@ void buffer_goto_word_at_cursor(TextBuffer *buffer, GotoType type) { // returns true if the buffer "used" this event bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times) { BufferPos buffer_pos; - if (ted->autocomplete.open) { - if (rect_contains_point(ted->autocomplete.rect, click)) + if (autocomplete_is_open(ted)) { + if (autocomplete_box_contains_point(ted, click)) return false; // don't look at clicks in the autocomplete menu else autocomplete_close(ted); // close autocomplete menu if user clicks outside of it diff --git a/command.c b/command.c index c09e0fd..8611f3e 100644 --- a/command.c +++ b/command.c @@ -332,7 +332,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen buffer = &ted->line_buffer; ted_switch_to_buffer(ted, buffer); buffer_select_all(buffer); - } else if (ted->autocomplete.open || ted->autocomplete.phantom) { + } else if (autocomplete_is_open(ted) || autocomplete_has_phantom(ted)) { autocomplete_select_completion(ted); } else if (buffer) { if (buffer->selection) @@ -476,13 +476,13 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen } break; case CMD_AUTOCOMPLETE: - if (ted->autocomplete.open) + if (autocomplete_is_open(ted)) autocomplete_next(ted); else autocomplete_open(ted, TRIGGER_INVOKED); break; case CMD_AUTOCOMPLETE_BACK: - if (ted->autocomplete.open) + if (autocomplete_is_open(ted)) autocomplete_prev(ted); break; case CMD_GOTO_DEFINITION: @@ -624,7 +624,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen if (*ted->message_shown) { // dismiss message box *ted->message_shown = '\0'; - } else if (ted->autocomplete.open) { + } else if (autocomplete_is_open(ted)) { autocomplete_close(ted); } else if (ted->menu) { menu_escape(ted); diff --git a/ide-autocomplete.c b/ide-autocomplete.c index 8cd3d91..c024e30 100644 --- a/ide-autocomplete.c +++ b/ide-autocomplete.c @@ -5,6 +5,9 @@ #define TAGS_MAX_COMPLETIONS 200 // max # of tag completions to scroll through #define AUTOCOMPLETE_NCOMPLETIONS_VISIBLE 10 // max # of completions to show at once +/// a single autocompletion suggestion +typedef struct Autocompletion Autocompletion; + struct Autocompletion { char *label; char *filter; @@ -17,6 +20,56 @@ struct Autocompletion { SymbolKind kind; }; +struct Autocomplete { + /// is the autocomplete box open? + bool open; + /// should the completions array be updated when more characters are typed? + bool is_list_complete; + + /// what trigger caused the last request for completions: + /// either a character code (for trigger characters), + /// or one of the `TRIGGER_*` constants above + uint32_t trigger; + + LSPServerRequestID last_request; + /// when we sent the request to the LSP for completions + /// (this is used to figure out when we should display "Loading...") + double last_request_time; + + /// dynamic array of all completions + Autocompletion *completions; + /// dynamic array of completions to be suggested (indices into completions) + u32 *suggested; + /// position of cursor last time completions were generated. if this changes, we need to recompute completions. + BufferPos last_pos; + /// which completion is currently selected (index into suggested) + i32 cursor; + i32 scroll; + + /// was the last request for phantom completion? + bool last_request_phantom; + /// current phantom completion to be displayed + char *phantom; + /// rectangle where the autocomplete menu is (needed to avoid interpreting autocomplete clicks as other clicks) + Rect rect; +}; + +void autocomplete_init(Ted *ted) { + ted->autocomplete = calloc(1, sizeof *ted->autocomplete); +} + +bool autocomplete_is_open(Ted *ted) { + return ted->autocomplete->open; +} + +bool autocomplete_has_phantom(Ted *ted) { + return ted->autocomplete->phantom != NULL; + +} + +bool autocomplete_box_contains_point(Ted *ted, vec2 point) { + return rect_contains_point(ted->autocomplete->rect, point); +} static void autocomplete_clear_completions(Autocomplete *ac) { arr_foreach_ptr(ac->completions, Autocompletion, completion) { @@ -37,7 +90,7 @@ static void autocomplete_clear_phantom(Autocomplete *ac) { // should a phantom completion be displayed? static bool autocomplete_should_display_phantom(Ted *ted) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; TextBuffer *buffer = ted->active_buffer; bool show = !ac->open && buffer @@ -63,7 +116,7 @@ static void autocomplete_complete(Ted *ted, Autocompletion completion) { } void autocomplete_select_completion(Ted *ted) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; if (ac->open) { size_t nsuggestions = arr_len(ac->suggested); if (nsuggestions) { @@ -79,7 +132,7 @@ void autocomplete_select_completion(Ted *ted) { } static void autocomplete_correct_scroll(Ted *ted) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; i32 scroll = ac->scroll; scroll = min_i32(scroll, (i32)arr_len(ac->suggested) - AUTOCOMPLETE_NCOMPLETIONS_VISIBLE); scroll = max_i32(scroll, 0); @@ -87,13 +140,13 @@ static void autocomplete_correct_scroll(Ted *ted) { } void autocomplete_scroll(Ted *ted, i32 by) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; ac->scroll += by; autocomplete_correct_scroll(ted); } static void autocomplete_move_cursor(Ted *ted, i32 by) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; u32 ncompletions = arr_len(ac->suggested); if (ncompletions == 0) return; @@ -114,7 +167,7 @@ void autocomplete_prev(Ted *ted) { } void autocomplete_close(Ted *ted) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; ac->open = false; autocomplete_clear_phantom(ac); autocomplete_clear_completions(ac); @@ -122,7 +175,7 @@ void autocomplete_close(Ted *ted) { } static void autocomplete_update_suggested(Ted *ted) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; arr_clear(ac->suggested); char *word = buffer_word_at_cursor_utf8(ted->active_buffer); for (u32 i = 0; i < arr_len(ac->completions); ++i) { @@ -138,7 +191,7 @@ static bool autocomplete_using_lsp(Ted *ted) { } static void autocomplete_no_suggestions(Ted *ted) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; if (ac->trigger == TRIGGER_INVOKED) ted_flash_error_cursor(ted); autocomplete_close(ted); @@ -149,7 +202,7 @@ static void autocomplete_send_completion_request(Ted *ted, TextBuffer *buffer, B return; // no can do LSP *lsp = buffer_lsp(buffer); - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; ted_cancel_lsp_request(ted, &ac->last_request); @@ -188,7 +241,7 @@ static void autocomplete_send_completion_request(Ted *ted, TextBuffer *buffer, B } static void autocomplete_find_completions(Ted *ted, uint32_t trigger, bool phantom) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; TextBuffer *buffer = ted->active_buffer; if (!buffer) return; @@ -299,7 +352,7 @@ void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) { const LSPRequest *request = &response->request; if (request->type != LSP_REQUEST_COMPLETION) return; - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; if (request->id != ac->last_request.id) return; // old request ac->last_request.id = 0; @@ -397,7 +450,7 @@ void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) { } void autocomplete_open(Ted *ted, uint32_t trigger) { - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; if (ac->open) return; TextBuffer *buffer = ted->active_buffer; if (!buffer) return; @@ -482,7 +535,7 @@ void autocomplete_frame(Ted *ted) { autocomplete_find_phantom(ted); - Autocomplete *ac = &ted->autocomplete; + Autocomplete *ac = ted->autocomplete; if (autocomplete_should_display_phantom(ted) && ac->phantom) { // display phantom completion char *word_at_cursor = buffer_word_at_cursor_utf8(buffer); diff --git a/main.c b/main.c index 8bc1ec5..ec8af1e 100644 --- a/main.c +++ b/main.c @@ -500,6 +500,7 @@ int main(int argc, char **argv) { gl_geometry_init(); text_init(); + autocomplete_init(ted); PROFILE_TIME(gl_end) @@ -633,8 +634,7 @@ int main(int argc, char **argv) { } else if (key_modifier == 0) { // scroll with mouse wheel Sint32 dx = event.wheel.x, dy = -event.wheel.y; - Autocomplete *ac = &ted->autocomplete; - if (ac->open && rect_contains_point(ac->rect, ted->mouse_pos)) { + if (autocomplete_box_contains_point(ted, ted->mouse_pos)) { autocomplete_scroll(ted, dy); } else { ted->scroll_total_x += dx; diff --git a/ted.h b/ted.h index 65f4a26..36d5ce7 100644 --- a/ted.h +++ b/ted.h @@ -608,43 +608,8 @@ typedef enum { SYMBOL_KEYWORD } SymbolKind; -/// a single autocompletion suggestion -typedef struct Autocompletion Autocompletion; - /// data needed for autocompletion -typedef struct { - /// is the autocomplete window open? - bool open; - /// should the completions array be updated when more characters are typed? - bool is_list_complete; - - /// what trigger caused the last request for completions: - /// either a character code (for trigger characters), - /// or one of the `TRIGGER_*` constants above - uint32_t trigger; - - LSPServerRequestID last_request; - /// when we sent the request to the LSP for completions - /// (this is used to figure out when we should display "Loading...") - double last_request_time; - - /// dynamic array of all completions - Autocompletion *completions; - /// dynamic array of completions to be suggested (indices into completions) - u32 *suggested; - /// position of cursor last time completions were generated. if this changes, we need to recompute completions. - BufferPos last_pos; - /// which completion is currently selected (index into suggested) - i32 cursor; - i32 scroll; - - /// was the last request for phantom completion? - bool last_request_phantom; - /// current phantom completion to be displayed - char *phantom; - /// rectangle where the autocomplete menu is (needed to avoid interpreting autocomplete clicks as other clicks) - Rect rect; -} Autocomplete; +typedef struct Autocomplete Autocomplete; /// data needed for finding usages typedef struct { @@ -833,7 +798,7 @@ struct Ted { bool build_shown; /// is the build process running? bool building; - Autocomplete autocomplete; + Autocomplete *autocomplete; SignatureHelp signature_help; DocumentLinks document_links; Hover hover; @@ -1512,6 +1477,15 @@ void gl_geometry_draw(void); GLuint gl_load_texture_from_image(const char *path); // === ide-autocomplete.c === +#if !TED_PLUGIN +void autocomplete_init(Ted *ted); +#endif +/// is the autocomplete box open? +bool autocomplete_is_open(Ted *ted); +/// is there a phantom completion being displayed? +bool autocomplete_has_phantom(Ted *ted); +/// is this point in the autocomplete box? +bool autocomplete_box_contains_point(Ted *ted, vec2 point); /// open autocomplete /// trigger should either be a character (e.g. '.') or one of the TRIGGER_* constants. void autocomplete_open(Ted *ted, uint32_t trigger); -- cgit v1.2.3