From dbab768e4d0be378e65399f32f26edb4756533ce Mon Sep 17 00:00:00 2001 From: pommicket Date: Fri, 23 Dec 2022 14:48:32 -0500 Subject: completion context + don't flash cursor if trigger character --- autocomplete.c | 19 ++++++++++++++----- command.c | 2 +- lsp-write.c | 10 ++++++++++ lsp.h | 13 +++++++++++++ main.c | 8 +++----- ted.h | 3 +++ 6 files changed, 44 insertions(+), 11 deletions(-) diff --git a/autocomplete.c b/autocomplete.c index 335a502..020a2e3 100644 --- a/autocomplete.c +++ b/autocomplete.c @@ -74,16 +74,19 @@ static bool autocomplete_using_lsp(Ted *ted) { } static void autocomplete_no_suggestions(Ted *ted) { - ted->cursor_error_time = time_get_seconds(); + Autocomplete *ac = &ted->autocomplete; + if (ac->trigger_char == 0) + ted->cursor_error_time = time_get_seconds(); autocomplete_close(ted); } -static void autocomplete_find_completions(Ted *ted) { +static void autocomplete_find_completions(Ted *ted, char32_t trigger_char) { Autocomplete *ac = &ted->autocomplete; TextBuffer *buffer = ted->active_buffer; BufferPos pos = buffer->cursor_pos; if (buffer_pos_eq(pos, ac->last_pos)) return; // no need to update completions. + ac->trigger_char = trigger_char; ac->last_pos = pos; LSP *lsp = buffer_lsp(buffer); @@ -91,12 +94,18 @@ static void autocomplete_find_completions(Ted *ted) { LSPRequest request = { .type = LSP_REQUEST_COMPLETION }; + bool invoked = ac->trigger_char == 0 || is_word(ac->trigger_char); request.data.completion = (LSPRequestCompletion) { .position = { .document = lsp_document_id(lsp, buffer->filename), .pos = buffer_pos_to_lsp(buffer, pos) + }, + .context = { + .trigger_kind = invoked ? LSP_TRIGGER_INVOKED : LSP_TRIGGER_CHARACTER, + .trigger_character = {0}, } }; + unicode_utf32_to_utf8(request.data.completion.context.trigger_character, ac->trigger_char); lsp_send_request(lsp, &request); if (!ac->completions) ac->waiting_for_lsp = true; @@ -169,7 +178,7 @@ static void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *respo } // open autocomplete, or just do the completion if there's only one suggestion -static void autocomplete_open(Ted *ted) { +static void autocomplete_open(Ted *ted, char32_t trigger_character) { Autocomplete *ac = &ted->autocomplete; if (ac->open) return; if (!ted->active_buffer) return; @@ -180,7 +189,7 @@ static void autocomplete_open(Ted *ted) { ted->cursor_error_time = 0; ac->last_pos = (BufferPos){0,0}; ac->cursor = 0; - autocomplete_find_completions(ted); + autocomplete_find_completions(ted, trigger_character); switch (arr_len(ac->completions)) { case 0: @@ -228,7 +237,7 @@ static void autocomplete_frame(Ted *ted) { u32 const *colors = settings->colors; float const padding = settings->padding; - autocomplete_find_completions(ted); + autocomplete_find_completions(ted, 0); Autocompletion completions[AUTOCOMPLETE_NCOMPLETIONS_VISIBLE] = {0}; size_t ncompletions = 0; diff --git a/command.c b/command.c index b330f54..82b096b 100644 --- a/command.c +++ b/command.c @@ -287,7 +287,7 @@ void command_execute(Ted *ted, Command c, i64 argument) { if (ted->autocomplete.open) autocomplete_next(ted); else - autocomplete_open(ted); + autocomplete_open(ted, 0); break; case CMD_AUTOCOMPLETE_BACK: if (ted->autocomplete.open) diff --git a/lsp-write.c b/lsp-write.c index 87cb238..808f479 100644 --- a/lsp-write.c +++ b/lsp-write.c @@ -323,6 +323,7 @@ static void write_request(LSP *lsp, LSPRequest *request) { } write_arr_end(o); write_obj_end(o); + write_key_bool(o, "contextSupport", true); write_obj_end(o); write_obj_end(o); write_obj_end(o); @@ -383,6 +384,15 @@ static void write_request(LSP *lsp, LSPRequest *request) { write_key_file_uri(o, "uri", completion->position.document); write_obj_end(o); write_key_position(o, "position", completion->position.pos); + const LSPCompletionContext *context = &completion->context; + LSPCompletionTriggerKind trigger_kind = context->trigger_kind; + if (trigger_kind != LSP_TRIGGER_NONE) { + write_key_obj_start(o, "context"); + write_key_number(o, "triggerKind", trigger_kind); + if (trigger_kind == LSP_TRIGGER_CHARACTER) + write_key_string(o, "triggerCharacter", context->trigger_character); + write_obj_end(o); + } write_obj_end(o); } break; } diff --git a/lsp.h b/lsp.h index 1c6076a..b4a4aa3 100644 --- a/lsp.h +++ b/lsp.h @@ -88,8 +88,21 @@ typedef struct { LSPPosition pos; } LSPDocumentPosition; +typedef enum { + LSP_TRIGGER_NONE = 0, // not actually defined in LSP spec + LSP_TRIGGER_INVOKED = 1, + LSP_TRIGGER_CHARACTER = 2, + LSP_TRIGGER_INCOMPLETE = 3 +} LSPCompletionTriggerKind; + +typedef struct { + LSPCompletionTriggerKind trigger_kind; + char trigger_character[5]; +} LSPCompletionContext; + typedef struct { LSPDocumentPosition position; + LSPCompletionContext context; } LSPRequestCompletion; typedef struct { diff --git a/main.c b/main.c index edb8b11..7460e2b 100644 --- a/main.c +++ b/main.c @@ -1,10 +1,8 @@ /* @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 +- only show "Loading..." if it's taking some time (prevent flash) - 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 @@ -832,14 +830,14 @@ int main(int argc, char **argv) { strlen(text) - last_code_point); arr_foreach_ptr(lsp->trigger_chars, char32_t, c) { if (*c == last_char) { - autocomplete_open(ted); + autocomplete_open(ted, last_char); break; } } if (settings->identifier_trigger_characters && is_word(last_char) && !is_digit(last_char)) - autocomplete_open(ted); + autocomplete_open(ted, last_char); } } diff --git a/ted.h b/ted.h index f7d79ae..cbcc466 100644 --- a/ted.h +++ b/ted.h @@ -379,6 +379,9 @@ typedef struct { bool open; // is the autocomplete window open? bool waiting_for_lsp; + // which trigger character invoked this (0 if autocomplete was manually invoked) + char32_t trigger_char; + Autocompletion *completions; // dynamic array of all completions u32 *suggested; // dynamic array of completions to be suggested (indices into completions) BufferPos last_pos; // position of cursor last time completions were generated. if this changes, we need to recompute completions. -- cgit v1.2.3