diff options
-rw-r--r-- | autocomplete.c | 5 | ||||
-rw-r--r-- | colors.c | 70 | ||||
-rw-r--r-- | colors.h | 57 | ||||
-rw-r--r-- | lsp-parse.c | 11 | ||||
-rw-r--r-- | lsp.c | 88 | ||||
-rw-r--r-- | lsp.h | 70 | ||||
-rw-r--r-- | main.c | 4 | ||||
-rw-r--r-- | ted.h | 12 |
8 files changed, 259 insertions, 58 deletions
diff --git a/autocomplete.c b/autocomplete.c index eb5993f..24ca71b 100644 --- a/autocomplete.c +++ b/autocomplete.c @@ -144,6 +144,7 @@ static void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *respo ted_completion->text = str_dup(lsp_response_string(response, lsp_completion->text_edit.new_text)); const char *detail = lsp_response_string(response, lsp_completion->detail); ted_completion->detail = *detail ? str_dup(detail) : NULL; + ted_completion->kind = lsp_completion_kind_to_ted(lsp_completion->kind); } } autocomplete_update_suggested(ted); @@ -282,7 +283,11 @@ static void autocomplete_frame(Ted *ted) { } else { for (size_t i = 0; i < ncompletions; ++i) { state.x = x + padding; state.y = y; + + ColorSetting label_color = color_for_symbol_kind(completions[i].kind); + rgba_u32_to_floats(colors[label_color], state.color); text_utf8_with_state(font, &state, completions[i].label); + const char *detail = completions[i].detail; if (detail) { double label_end_x = state.x; diff --git a/colors.c b/colors.c new file mode 100644 index 0000000..aac5e00 --- /dev/null +++ b/colors.c @@ -0,0 +1,70 @@ + +static ColorSetting color_setting_from_str(char const *str) { + // @OPTIMIZE: sort color_names, binary search + for (int i = 0; i < COLOR_COUNT; ++i) { + ColorName const *n = &color_names[i]; + if (streq(n->name, str)) + return n->setting; + } + return COLOR_UNKNOWN; +} + +static char const *color_setting_to_str(ColorSetting s) { + for (int i = 0; i < COLOR_COUNT; ++i) { + ColorName const *n = &color_names[i]; + if (n->setting == s) + return n->name; + } + return "???"; +} + +// converts #rrggbb/#rrggbbaa to a color. returns false if it's not in the right format. +static Status color_from_str(char const *str, u32 *color) { + uint r = 0, g = 0, b = 0, a = 0xff; + bool success = false; + switch (strlen(str)) { + case 4: + success = sscanf(str, "#%01x%01x%01x", &r, &g, &b) == 3; + // extend single hex digit to double hex digit + r |= r << 4; + g |= g << 4; + b |= b << 4; + break; + case 5: + success = sscanf(str, "#%01x%01x%01x%01x", &r, &g, &b, &a) == 4; + r |= r << 4; + g |= g << 4; + b |= b << 4; + a |= a << 4; + break; + case 7: + success = sscanf(str, "#%02x%02x%02x", &r, &g, &b) == 3; + break; + case 9: + success = sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a) == 4; + break; + } + if (!success || r > 0xff || g > 0xff || b > 0xff || a > 0xff) + return false; + if (color) + *color = (u32)r << 24 | (u32)g << 16 | (u32)b << 8 | (u32)a; + return true; +} + + +static ColorSetting color_for_symbol_kind(SymbolKind kind) { + switch (kind) { + case SYMBOL_CONSTANT: + return COLOR_CONSTANT; + case SYMBOL_TYPE: + case SYMBOL_FUNCTION: + case SYMBOL_FIELD: + return COLOR_BUILTIN; + case SYMBOL_VARIABLE: + case SYMBOL_OTHER: + return COLOR_TEXT; + case SYMBOL_KEYWORD: + return COLOR_KEYWORD; + } + return COLOR_TEXT; +} @@ -1,4 +1,4 @@ -ENUM_U16 { +typedef enum { COLOR_UNKNOWN, COLOR_TEXT, @@ -43,7 +43,7 @@ ENUM_U16 { COLOR_COUNT -} ENUM_U16_END(ColorSetting); +} ColorSetting; typedef struct { ColorSetting setting; @@ -91,56 +91,3 @@ static ColorName const color_names[] = { }; static_assert_if_possible(arr_count(color_names) == COLOR_COUNT) - -static ColorSetting color_setting_from_str(char const *str) { - // @OPTIMIZE: sort color_names, binary search - for (int i = 0; i < COLOR_COUNT; ++i) { - ColorName const *n = &color_names[i]; - if (streq(n->name, str)) - return n->setting; - } - return COLOR_UNKNOWN; -} - -static char const *color_setting_to_str(ColorSetting s) { - for (int i = 0; i < COLOR_COUNT; ++i) { - ColorName const *n = &color_names[i]; - if (n->setting == s) - return n->name; - } - return "???"; -} - -// converts #rrggbb/#rrggbbaa to a color. returns false if it's not in the right format. -static Status color_from_str(char const *str, u32 *color) { - uint r = 0, g = 0, b = 0, a = 0xff; - bool success = false; - switch (strlen(str)) { - case 4: - success = sscanf(str, "#%01x%01x%01x", &r, &g, &b) == 3; - // extend single hex digit to double hex digit - r |= r << 4; - g |= g << 4; - b |= b << 4; - break; - case 5: - success = sscanf(str, "#%01x%01x%01x%01x", &r, &g, &b, &a) == 4; - r |= r << 4; - g |= g << 4; - b |= b << 4; - a |= a << 4; - break; - case 7: - success = sscanf(str, "#%02x%02x%02x", &r, &g, &b) == 3; - break; - case 9: - success = sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a) == 4; - break; - } - if (!success || r > 0xff || g > 0xff || b > 0xff || a > 0xff) - return false; - if (color) - *color = (u32)r << 24 | (u32)g << 16 | (u32)b << 8 | (u32)a; - return true; -} - diff --git a/lsp-parse.c b/lsp-parse.c index 8afca07..947feb9 100644 --- a/lsp-parse.c +++ b/lsp-parse.c @@ -130,6 +130,11 @@ static bool parse_completion(LSP *lsp, const JSON *json, LSPResponse *response) .new_text = item->label }; + double kind = json_object_get_number(json, item_object, "kind"); + if (isnormal(kind) && kind >= LSP_COMPLETION_KIND_MIN && kind <= LSP_COMPLETION_KIND_MAX) { + item->kind = (LSPCompletionKind)kind; + } + JSONString sort_text = json_object_get_string(json, item_object, "sortText"); if (sort_text.pos) { // LSP allows using a different string for sorting. @@ -145,8 +150,10 @@ static bool parse_completion(LSP *lsp, const JSON *json, LSPResponse *response) double edit_type = json_object_get_number(json, item_object, "insertTextFormat"); if (!isnan(edit_type)) { if (edit_type != LSP_TEXT_EDIT_PLAIN && edit_type != LSP_TEXT_EDIT_SNIPPET) { - lsp_set_error(lsp, "Bad InsertTextFormat: %g", edit_type); - return false; + // maybe in the future more edit types will be added. + // probably they'll have associated capabilities, but I think it's best to just ignore unrecognized types + debug_println("Bad InsertTextFormat: %g", edit_type); + edit_type = LSP_TEXT_EDIT_PLAIN; } item->text_edit.type = (LSPTextEditType)edit_type; } @@ -323,3 +323,91 @@ void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent arr_add(c->changes, change); lsp_send_request(lsp, &request); } + +SymbolKind lsp_symbol_kind_to_ted(LSPSymbolKind kind) { + switch (kind) { + case LSP_SYMBOL_OTHER: + case LSP_SYMBOL_FILE: + case LSP_SYMBOL_MODULE: + case LSB_SYMBOL_NAMESPACE: + case LSP_SYMBOL_PACKAGE: + return SYMBOL_OTHER; + + case LSP_SYMBOL_CLASS: + case LSP_SYMBOL_TYPEPARAMETER: + case LSP_SYMBOL_ENUM: + case LSP_SYMBOL_INTERFACE: + case LSP_SYMBOL_STRUCT: + case LSP_SYMBOL_EVENT: // i have no clue what this is. let's say it's a type. + return SYMBOL_TYPE; + + case LSP_SYMBOL_PROPERTY: + case LSP_SYMBOL_FIELD: + case LSP_SYMBOL_KEY: + return SYMBOL_FIELD; + + case LSP_SYMBOL_CONSTRUCTOR: + case LSP_SYMBOL_FUNCTION: + case LSP_SYMBOL_OPERATOR: + case LSP_SYMBOL_METHOD: + return SYMBOL_FUNCTION; + + case LSP_SYMBOL_VARIABLE: + return SYMBOL_VARIABLE; + + case LSP_SYMBOL_CONSTANT: + case LSP_SYMBOL_STRING: + case LSP_SYMBOL_NUMBER: + case LSP_SYMBOL_BOOLEAN: + case LSP_SYMBOL_ARRAY: + case LSP_SYMBOL_OBJECT: + case LSP_SYMBOL_ENUMMEMBER: + case LSP_SYMBOL_NULL: + return SYMBOL_CONSTANT; + } + + return SYMBOL_OTHER; +} + +SymbolKind lsp_completion_kind_to_ted(LSPCompletionKind kind) { + switch (kind) { + case LSP_COMPLETION_TEXT: + case LSP_COMPLETION_MODULE: + case LSP_COMPLETION_UNIT: + case LSP_COMPLETION_COLOR: + case LSP_COMPLETION_FILE: + case LSP_COMPLETION_REFERENCE: + case LSP_COMPLETION_FOLDER: + case LSP_COMPLETION_OPERATOR: + return SYMBOL_OTHER; + + case LSP_COMPLETION_METHOD: + case LSP_COMPLETION_FUNCTION: + case LSP_COMPLETION_CONSTRUCTOR: + return SYMBOL_FUNCTION; + + case LSP_COMPLETION_FIELD: + case LSP_COMPLETION_PROPERTY: + return SYMBOL_FIELD; + + case LSP_COMPLETION_VARIABLE: + return SYMBOL_VARIABLE; + + case LSP_COMPLETION_CLASS: + case LSP_COMPLETION_INTERFACE: + case LSP_COMPLETION_ENUM: + case LSP_COMPLETION_STRUCT: + case LSP_COMPLETION_EVENT: + case LSP_COMPLETION_TYPEPARAMETER: + return SYMBOL_TYPE; + + case LSP_COMPLETION_VALUE: + case LSP_COMPLETION_ENUMMEMBER: + case LSP_COMPLETION_CONSTANT: + return SYMBOL_CONSTANT; + + case LSP_COMPLETION_KEYWORD: + case LSP_COMPLETION_SNIPPET: + return SYMBOL_KEYWORD; + } +} @@ -44,7 +44,7 @@ typedef enum { // server-to-client LSP_REQUEST_SHOW_MESSAGE, - LSP_REQUEST_LOG_MESSAGE + LSP_REQUEST_LOG_MESSAGE, } LSPRequestType; typedef struct { @@ -106,6 +106,70 @@ typedef struct { } data; } LSPRequest; +typedef enum { + // LSP doesn't actually define this but this will be used for unrecognized values + // (in case they add more symbol kinds in the future) + LSP_SYMBOL_OTHER = 0, + + #define LSP_SYMBOL_KIND_MIN 1 + LSP_SYMBOL_FILE = 1, + LSP_SYMBOL_MODULE = 2, + LSB_SYMBOL_NAMESPACE = 3, + LSP_SYMBOL_PACKAGE = 4, + LSP_SYMBOL_CLASS = 5, + LSP_SYMBOL_METHOD = 6, + LSP_SYMBOL_PROPERTY = 7, + LSP_SYMBOL_FIELD = 8, + LSP_SYMBOL_CONSTRUCTOR = 9, + LSP_SYMBOL_ENUM = 10, + LSP_SYMBOL_INTERFACE = 11, + LSP_SYMBOL_FUNCTION = 12, + LSP_SYMBOL_VARIABLE = 13, + LSP_SYMBOL_CONSTANT = 14, + LSP_SYMBOL_STRING = 15, + LSP_SYMBOL_NUMBER = 16, + LSP_SYMBOL_BOOLEAN = 17, + LSP_SYMBOL_ARRAY = 18, + LSP_SYMBOL_OBJECT = 19, + LSP_SYMBOL_KEY = 20, + LSP_SYMBOL_NULL = 21, + LSP_SYMBOL_ENUMMEMBER = 22, + LSP_SYMBOL_STRUCT = 23, + LSP_SYMBOL_EVENT = 24, + LSP_SYMBOL_OPERATOR = 25, + LSP_SYMBOL_TYPEPARAMETER = 26, + #define LSP_SYMBOL_KIND_MAX 26 +} LSPSymbolKind; + +typedef enum { + #define LSP_COMPLETION_KIND_MIN 1 + LSP_COMPLETION_TEXT = 1, + LSP_COMPLETION_METHOD = 2, + LSP_COMPLETION_FUNCTION = 3, + LSP_COMPLETION_CONSTRUCTOR = 4, + LSP_COMPLETION_FIELD = 5, + LSP_COMPLETION_VARIABLE = 6, + LSP_COMPLETION_CLASS = 7, + LSP_COMPLETION_INTERFACE = 8, + LSP_COMPLETION_MODULE = 9, + LSP_COMPLETION_PROPERTY = 10, + LSP_COMPLETION_UNIT = 11, + LSP_COMPLETION_VALUE = 12, + LSP_COMPLETION_ENUM = 13, + LSP_COMPLETION_KEYWORD = 14, + LSP_COMPLETION_SNIPPET = 15, + LSP_COMPLETION_COLOR = 16, + LSP_COMPLETION_FILE = 17, + LSP_COMPLETION_REFERENCE = 18, + LSP_COMPLETION_FOLDER = 19, + LSP_COMPLETION_ENUMMEMBER = 20, + LSP_COMPLETION_CONSTANT = 21, + LSP_COMPLETION_STRUCT = 22, + LSP_COMPLETION_EVENT = 23, + LSP_COMPLETION_OPERATOR = 24, + LSP_COMPLETION_TYPEPARAMETER = 25, + #define LSP_COMPLETION_KIND_MAX 25 +} LSPCompletionKind; // see InsertTextFormat in the LSP spec. @@ -143,6 +207,8 @@ typedef struct { // note: the items are sorted here in this file, // so you probably don't need to access this. LSPString sort_text; + // type of completion + LSPCompletionKind kind; } LSPCompletionItem; typedef struct { @@ -212,3 +278,5 @@ bool lsp_create(LSP *lsp, const char *analyzer_command); bool lsp_next_message(LSP *lsp, LSPMessage *message); void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent change); void lsp_free(LSP *lsp); +SymbolKind lsp_symbol_kind_to_ted(LSPSymbolKind kind); +SymbolKind lsp_completion_kind_to_ted(LSPCompletionKind kind); @@ -1,5 +1,8 @@ /* @TODO: +- kind (icon/color) + - improve color_for_symbol_kind +- send textDocument.completion.completionItemKind capability - only show "Loading..." if it's taking some time (prevent flash) - LSP setting - scroll through completions @@ -111,6 +114,7 @@ static void die(char const *fmt, ...) { #include "lsp.h" #include "string32.c" +#include "colors.c" #include "syntax.c" bool tag_goto(Ted *ted, char const *tag); #include "buffer.c" @@ -352,11 +352,23 @@ typedef struct { u32 build_output_line; // which line in the build output corresponds to this error } BuildError; +// LSPSymbolKinds are translated to these. this is a much coarser categorization +typedef enum { + SYMBOL_OTHER, + SYMBOL_FUNCTION, + SYMBOL_FIELD, + SYMBOL_TYPE, + SYMBOL_VARIABLE, + SYMBOL_CONSTANT, + SYMBOL_KEYWORD +} SymbolKind; + typedef struct { char *label; char *filter; char *text; char *detail; // this can be NULL! + SymbolKind kind; } Autocompletion; typedef struct { |