From d69fb12c055e1e17c765ca9714c508552a027384 Mon Sep 17 00:00:00 2001 From: pommicket Date: Fri, 6 Jan 2023 11:52:30 -0500 Subject: phantom completions --- ide-autocomplete.c | 57 ++++++++++++++++++++++++++++++++++++++++++------------ main.c | 1 - menu.c | 6 +++--- ted.cfg | 2 +- text.c | 6 +++--- text.h | 2 +- ui.c | 6 +++--- 7 files changed, 56 insertions(+), 24 deletions(-) diff --git a/ide-autocomplete.c b/ide-autocomplete.c index 033841f..1046364 100644 --- a/ide-autocomplete.c +++ b/ide-autocomplete.c @@ -96,9 +96,7 @@ void autocomplete_close(Ted *ted) { static void autocomplete_update_suggested(Ted *ted) { Autocomplete *ac = &ted->autocomplete; arr_clear(ac->suggested); - char *word = str32_to_utf8_cstr( - buffer_word_at_cursor(ted->active_buffer) - ); + char *word = buffer_word_at_cursor_utf8(ted->active_buffer); for (u32 i = 0; i < arr_len(ac->completions); ++i) { Autocompletion *completion = &ac->completions[i]; if (str_has_prefix(completion->filter, word)) @@ -282,14 +280,42 @@ void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) { return; } + TextBuffer *buffer = ted->active_buffer; + if (!buffer) + return; + const LSPResponseCompletion *completion = &response->data.completion; size_t ncompletions = arr_len(completion->items); - printf("got %zu\n",ncompletions); - if (ac->last_request_phantom && ncompletions != 1) { - // only show phantom completion if there's exactly 1 completion. - autocomplete_clear_phantom(ac); + if (ac->last_request_phantom) { + // check for phantom completion + // ideally we would just check if ncompletions == 1, + // but some completions might not start with the word at the cursor, + // and it's best to filter those out. + char *word_at_cursor = buffer_word_at_cursor_utf8(buffer); + if (*word_at_cursor) { + int ncandidates = 0; + const char *candidate = NULL; + for (size_t i = 0; i < ncompletions; ++i) { + const LSPCompletionItem *lsp_completion = &completion->items[i]; + const char *new_text = lsp_response_string(response, lsp_completion->text_edit.new_text); + if (str_has_prefix(new_text, word_at_cursor)) { + candidate = new_text; + ++ncandidates; + if (ncandidates >= 2) break; + } + } + + // only show phantom if there is exactly 1 possible completion. + if (ncandidates == 1) { + ac->phantom = str_dup(candidate); + } else { + autocomplete_clear_phantom(ac); + } + } + free(word_at_cursor); return; } + arr_set_len(ac->completions, ncompletions); for (size_t i = 0; i < ncompletions; ++i) { const LSPCompletionItem *lsp_completion = &completion->items[i]; @@ -412,10 +438,17 @@ void autocomplete_frame(Ted *ted) { char *word_at_cursor = buffer_word_at_cursor_utf8(buffer); if (*word_at_cursor && str_has_prefix(ac->phantom, word_at_cursor)) { const char *completion = ac->phantom + strlen(word_at_cursor); - vec2 pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos); - text_utf8(font, completion, pos.x, pos.y, - colors[COLOR_TEXT] & 0xffffff7f); - text_render(font); + if (*completion) { + vec2 pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos); + //vec2 size = text_get_size_vec2(font, completion); + //Rect r = rect(pos, size); + //gl_geometry_rect(r, colors[COLOR_CURSOR_BG] & 0xffffff7f); + + text_utf8(font, completion, pos.x, pos.y, + colors[COLOR_TEXT] & 0xffffff7f); + text_render(font); + gl_geometry_draw(); + } } else { // this phantom is no longer relevant autocomplete_clear_phantom(ac); @@ -595,7 +628,7 @@ void autocomplete_frame(Ted *ted) { char text[128] = {0}; strbuf_printf(text, "%.*s%s", amount_detail, detail, (size_t)amount_detail == strlen(detail) ? "" : "..."); - double width = text_get_size_v2(font, text).x; + double width = text_get_size_vec2(font, text).x; if (label_end_x + width + 2 * padding < state.max_x) { strbuf_cpy(show_text, text); } diff --git a/main.c b/main.c index 18276d2..3975adc 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,5 @@ /* @TODO: -- phantom completions - debug-lsp option (which logs LSP messages) - check LSP process status (TEST: what happens if LSP server is not installed) - make tags_dir the root folder diff --git a/menu.c b/menu.c index ae024b2..b894c35 100644 --- a/menu.c +++ b/menu.c @@ -400,7 +400,7 @@ void menu_render(Ted *ted) { gl_geometry_rect(r, colors[COLOR_MENU_BG]); gl_geometry_rect_border(r, settings->border_thickness, colors[COLOR_BORDER]); const char *text = "Go to line..."; - vec2 text_size = text_get_size_v2(font_bold, text); + vec2 text_size = text_get_size_vec2(font_bold, text); rect_coords(r, &x1, &y1, &x2, &y2); x1 += padding; y1 += padding; @@ -419,7 +419,7 @@ void menu_render(Ted *ted) { // argument field const char *text = "Argument"; text_utf8(font_bold, text, x1, y1, colors[COLOR_TEXT]); - float x = x1 + text_get_size_v2(font_bold, text).x + padding; + float x = x1 + text_get_size_vec2(font_bold, text).x + padding; buffer_render(&ted->argument_buffer, rect4(x, y1, x2, y1 + line_buffer_height)); y1 += line_buffer_height + padding; @@ -445,7 +445,7 @@ void menu_render(Ted *ted) { const char *text = "Run"; text_utf8(font_bold, text, x1, y1, colors[COLOR_TEXT]); - x1 += text_get_size_v2(font_bold, text).x + padding; + x1 += text_get_size_vec2(font_bold, text).x + padding; text_render(font_bold); buffer_render(&ted->line_buffer, rect4(x1, y1, x2, y2)); diff --git a/ted.cfg b/ted.cfg index 7648d12..220de0a 100644 --- a/ted.cfg +++ b/ted.cfg @@ -34,7 +34,7 @@ trigger-characters = on # should all identifier characters (e.g. a-z) be treated as trigger characters? identifier-trigger-characters = off # display "phantom completions"? (if there is only one completion, display it next to the cursor) -phantom-completions = yes +phantom-completions = on # enable LSP support (for autocompletion, etc.) # you can also set `lsp = ""` but this is a quick way to disable LSP servers for all langauges lsp-enabled = yes diff --git a/text.c b/text.c index bd1f3a8..398bb3f 100644 --- a/text.c +++ b/text.c @@ -395,8 +395,8 @@ static vec2 text_render_utf8_internal(Font *font, const char *text, double x, do rgba_u32_to_floats(color, render_state.color); text_utf8_with_state(font, &render_state, text); return Vec2( - (float)(render_state.x_largest - x), - (float)(render_state.y_largest - y) + maxf(0.0f, (float)(render_state.x_largest - x)), + maxf(0.0f, (float)(render_state.y_largest - y)) ); } @@ -429,7 +429,7 @@ void text_get_size(Font *font, const char *text, float *width, float *height) { if (height) *height = size.y + font->char_height; } -vec2 text_get_size_v2(Font *font, const char *text) { +vec2 text_get_size_vec2(Font *font, const char *text) { vec2 v; text_get_size(font, text, &v.x, &v.y); return v; diff --git a/text.h b/text.h index e5e5e61..2d7429d 100644 --- a/text.h +++ b/text.h @@ -60,7 +60,7 @@ float text_font_char_width(Font *font); void text_font_set_force_monospace(Font *font, bool force); // Get the dimensions of some text. void text_get_size(Font *font, const char *text, float *width, float *height); -vec2 text_get_size_v2(Font *font, const char *text); +vec2 text_get_size_vec2(Font *font, const char *text); void text_get_size32(Font *font, const char32_t *text, u64 len, float *width, float *height); void text_utf8(Font *font, const char *text, double x, double y, u32 color); void text_utf8_anchored(Font *font, const char *text, double x, double y, u32 color, Anchor anchor); diff --git a/ui.c b/ui.c index 56e89db..0c398b3 100644 --- a/ui.c +++ b/ui.c @@ -164,7 +164,7 @@ void selector_render(Ted *ted, Selector *s) { if (entry->detail) { // draw detail - float detail_size = text_get_size_v2(font, entry->detail).x; + float detail_size = text_get_size_vec2(font, entry->detail).x; TextRenderState detail_state = text_state; detail_state.x = maxd(text_state.x + 2 * padding, x2 - detail_size); @@ -530,7 +530,7 @@ void file_selector_render(Ted *ted, FileSelector *fs) { vec2 button_get_size(Ted *ted, const char *text) { float border_thickness = ted_active_settings(ted)->border_thickness; - return vec2_add_const(text_get_size_v2(ted->font, text), 2 * border_thickness); + return vec2_add_const(text_get_size_vec2(ted->font, text), 2 * border_thickness); } void button_render(Ted *ted, Rect button, const char *text, u32 color) { @@ -668,7 +668,7 @@ vec2 checkbox_frame(Ted *ted, bool *value, const char *label, vec2 pos) { } vec2 text_pos = vec2_add(pos, Vec2(checkbox_size + padding * 0.5f, 0)); - vec2 size = text_get_size_v2(font, label); + vec2 size = text_get_size_vec2(font, label); text_utf8(font, label, text_pos.x, text_pos.y, colors[COLOR_TEXT]); gl_geometry_draw(); -- cgit v1.2.3