From 7f98e047cb791b84cc955f534a7e94395fed1ae0 Mon Sep 17 00:00:00 2001 From: pommicket Date: Fri, 23 Dec 2022 00:18:07 -0500 Subject: show documentation! --- autocomplete.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++------ lsp-parse.c | 10 ++++++++++ lsp.h | 2 ++ main.c | 2 -- ted.h | 1 + text.c | 9 +++++++++ 6 files changed, 70 insertions(+), 8 deletions(-) diff --git a/autocomplete.c b/autocomplete.c index 67da65a..e0de9fd 100644 --- a/autocomplete.c +++ b/autocomplete.c @@ -7,6 +7,8 @@ static void autocomplete_clear_completions(Ted *ted) { free(completion->label); free(completion->text); free(completion->filter); + free(completion->detail); + free(completion->documentation); } arr_clear(ac->completions); arr_clear(ac->suggested); @@ -148,6 +150,9 @@ static void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *respo ted_completion->detail = *detail ? str_dup(detail) : NULL; ted_completion->kind = lsp_completion_kind_to_ted(lsp_completion->kind); ted_completion->deprecated = lsp_completion->deprecated; + const char *documentation = lsp_response_string(response, lsp_completion->documentation); + ted_completion->documentation = documentation ? str_dup(documentation) : NULL; + } } autocomplete_update_suggested(ted); @@ -265,18 +270,57 @@ static void autocomplete_frame(Ted *ted) { } u16 cursor_entry = (u16)((ted->mouse_pos.y - start_y) / char_height); + + Autocompletion *document = NULL; if (cursor_entry < ncompletions) { // highlight moused over entry Rect r = rect(V2(x, start_y + cursor_entry * char_height), V2(menu_width, char_height)); gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]); - ted->cursor = ted->cursor_hand; - } - - if (!ac->waiting_for_lsp) { + ted->cursor = ted->cursor_hand; + document = &completions[cursor_entry]; + } else if (ncompletions) { // highlight cursor entry Rect r = rect(V2(x, start_y + (float)ac->cursor * char_height), V2(menu_width, char_height)); gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]); + document = &completions[ac->cursor]; + } + + float border_thickness = settings->border_thickness; + + + if (document) { + // document that entry!! + + // we've go tsome wacky calculations to figure out the + // bounding rect for the documentation + float doc_width = open_left ? ac->rect.pos.x - 2*padding + : buffer->x2 - (ac->rect.pos.x + ac->rect.size.x + 2*padding); + if (doc_width > 800) doc_width = 800; + float doc_height = buffer->y2 - (ac->rect.pos.y + 2*padding); + if (doc_height > char_height * 20) doc_height = char_height * 20; + + // if the rect is too small, there's no point in showing it + if (doc_width >= 200) { + float doc_x = open_left ? ac->rect.pos.x - doc_width - padding + : ac->rect.pos.x + ac->rect.size.x + padding; + float doc_y = ac->rect.pos.y; + Rect r = rect(V2(doc_x, doc_y), V2(doc_width, doc_height)); + gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_BG]); + gl_geometry_rect_border(r, border_thickness, colors[COLOR_AUTOCOMPLETE_BORDER]); + + // draw the text! + TextRenderState text_state = text_render_state_default; + text_state.min_x = doc_x + padding; + text_state.max_x = doc_x + doc_width - padding; + text_state.max_y = doc_y + doc_height; + text_state.x = doc_x + padding; + text_state.y = doc_y + padding; + text_state.wrap = true; + rgba_u32_to_floats(colors[COLOR_TEXT], text_state.color); + text_utf8_with_state(font, &text_state, document->documentation); + } } + for (uint i = 0; i < ted->nmouse_clicks[SDL_BUTTON_LEFT]; ++i) { v2 click = ted->mouse_clicks[SDL_BUTTON_LEFT][i]; @@ -294,8 +338,6 @@ static void autocomplete_frame(Ted *ted) { state.min_x = x + padding; state.min_y = y; state.max_x = x + menu_width - padding; state.max_y = y + menu_height; rgba_u32_to_floats(colors[COLOR_TEXT], state.color); - float border_thickness = settings->border_thickness; - if (ac->waiting_for_lsp) { state.x = x + padding; state.y = y; text_utf8_with_state(font, &state, "Loading..."); diff --git a/lsp-parse.c b/lsp-parse.c index 9d02782..05fc898 100644 --- a/lsp-parse.c +++ b/lsp-parse.c @@ -181,6 +181,16 @@ static bool parse_completion(LSP *lsp, const JSON *json, LSPResponse *response) documentation = json_object_get_string(json, documentation_value.val.object, "value"); } + if (documentation.len) { + if (documentation.len > 1000) { + // rust has some docs which are *20,000* bytes long + // that's more than i'm ever gonna show on-screen! + documentation.len = 1000; + // okay this could break mid-code-point but whatever it would probably + // just display ⌷. + } + item->documentation = lsp_response_add_json_string(response, json, documentation); + } JSONString detail_text = json_object_get_string(json, item_object, "detail"); diff --git a/lsp.h b/lsp.h index 612b370..72e621e 100644 --- a/lsp.h +++ b/lsp.h @@ -202,6 +202,8 @@ typedef struct { LSPString filter_text; // more detail for this item, e.g. the signature of a function LSPString detail; + // documentation for this item (typically from a doc comment) + LSPString documentation; // the edit to be applied when this completion is selected. LSPTextEdit text_edit; // note: the items are sorted here in this file, diff --git a/main.c b/main.c index c86d3b1..5274922 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,5 @@ /* @TODO: -- show documentation -- finish up capabilities - trigger characters (with setting) - only show "Loading..." if it's taking some time (prevent flash) - LSP setting diff --git a/ted.h b/ted.h index 6f10bfb..a7974dd 100644 --- a/ted.h +++ b/ted.h @@ -368,6 +368,7 @@ typedef struct { char *filter; char *text; char *detail; // this can be NULL! + char *documentation; // this can be NULL! bool deprecated; SymbolKind kind; } Autocompletion; diff --git a/text.c b/text.c index 6d40cc5..6df77ff 100644 --- a/text.c +++ b/text.c @@ -276,6 +276,8 @@ top: c = UNICODE_BOX_CHARACTER; } if (c >= UNICODE_CODE_POINTS) c = UNICODE_BOX_CHARACTER; // code points this big should never appear in valid Unicode + + uint page = c / CHAR_PAGE_SIZE; uint index = c % CHAR_PAGE_SIZE; if (state->render) { @@ -286,9 +288,16 @@ top: stbtt_bakedchar *char_data = font->char_pages[page]; float const char_height = font->char_height; float const char_width = font->char_width; + if (char_data) { // if page was successfully loaded stbtt_aligned_quad q = {0}; + if (state->wrap && c == '\n') { + state->x = state->min_x; + state->y += char_height; + return; + } + { float x, y; x = (float)(state->x - floor(state->x)); -- cgit v1.2.3