From f69275faee4cd3045389a98fefefb0c683757a5c Mon Sep 17 00:00:00 2001 From: pommicket Date: Fri, 30 Dec 2022 21:49:05 -0500 Subject: start document highlights --- ide-highlights.c | 32 ++++++++++++++++++++++++++++++++ lsp-parse.c | 39 +++++++++++++++++++++++++++++++++------ lsp-write.c | 8 ++++++++ lsp.c | 7 +++++++ lsp.h | 26 +++++++++++++++++++++++++- main.c | 4 ++++ ted.h | 5 +++++ 7 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 ide-highlights.c diff --git a/ide-highlights.c b/ide-highlights.c new file mode 100644 index 0000000..4246c66 --- /dev/null +++ b/ide-highlights.c @@ -0,0 +1,32 @@ +void highlights_send_request(Ted *ted, TextBuffer *buffer) { + Highlights *hls = &ted->highlights; + if (!buffer) return; + LSP *lsp = buffer_lsp(buffer); + if (!lsp) return; + LSPDocumentPosition pos = buffer_cursor_pos_as_lsp_document_position(buffer); + LSPRequest request = {.type = LSP_REQUEST_HIGHLIGHT}; + request.data.highlight.position = pos; + hls->last_request_id = lsp_send_request(lsp, &request); +} + +void highlights_close(Ted *ted) { + arr_clear(ted->highlights.highlights); +} + +void highlights_process_lsp_response(Ted *ted, LSPResponse *response) { + Highlights *hls = &ted->highlights; + if (response->request.type != LSP_REQUEST_HIGHLIGHT) + return; // not a highlight request + if (response->request.id != hls->last_request_id) + return; // old request + const LSPResponseHighlight *hl_response = &response->data.highlight; + arr_set_len(hls->highlights, arr_len(hl_response->highlights)); + // type-safe memcpy + for (u32 i = 0; i < arr_len(hl_response->highlights); ++i) + hls->highlights[i] = hl_response->highlights[i]; +} + +void highlights_frame(Ted *ted) { + Highlights *hls = &ted->highlights; + +} diff --git a/lsp-parse.c b/lsp-parse.c index 3834cd0..7a0c630 100644 --- a/lsp-parse.c +++ b/lsp-parse.c @@ -124,7 +124,7 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti // check CompletionOptions JSONValue completion_value = json_object_get(json, capabilities, "completionProvider"); - if (completion_value.type == JSON_OBJECT) { + if (completion_value.type == JSON_OBJECT && completion_value.type != JSON_FALSE) { cap->completion_support = true; JSONObject completion = completion_value.val.object; @@ -134,7 +134,7 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti // check SignatureHelpOptions JSONValue signature_help_value = json_object_get(json, capabilities, "signatureHelpProvider"); - if (signature_help_value.type == JSON_OBJECT) { + if (signature_help_value.type == JSON_OBJECT && signature_help_value.type != JSON_FALSE) { cap->signature_help_support = true; JSONObject signature_help = signature_help_value.val.object; JSONArray trigger_chars = json_object_get_array(json, signature_help, "triggerCharacters"); @@ -148,25 +148,31 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti // check for hover support JSONValue hover_value = json_object_get(json, capabilities, "hoverProvider"); - if (hover_value.type != JSON_UNDEFINED) { + if (hover_value.type != JSON_UNDEFINED && hover_value.type != JSON_FALSE) { cap->hover_support = true; } // check for definition support JSONValue definition_value = json_object_get(json, capabilities, "definitionProvider"); - if (definition_value.type != JSON_UNDEFINED) { + if (definition_value.type != JSON_UNDEFINED && definition_value.type != JSON_FALSE) { cap->definition_support = true; } + // check for textDocument/documentHighlight support + JSONValue highlight_value = json_object_get(json, capabilities, "documentHighlightProvider"); + if (highlight_value.type != JSON_UNDEFINED && highlight_value.type != JSON_FALSE) { + cap->highlight_support = true; + } + // check for textDocument/rename support JSONValue rename_value = json_object_get(json, capabilities, "renameProvider"); - if (rename_value.type != JSON_UNDEFINED) { + if (rename_value.type != JSON_UNDEFINED && rename_value.type != JSON_FALSE) { cap->rename_support = true; } // check for workspace/symbol support JSONValue workspace_symbol_value = json_object_get(json, capabilities, "workspaceSymbolProvider"); - if (workspace_symbol_value.type != JSON_UNDEFINED) { + if (workspace_symbol_value.type != JSON_UNDEFINED && workspace_symbol_value.type != JSON_FALSE) { cap->workspace_symbols_support = true; } @@ -767,6 +773,24 @@ static bool parse_rename(LSP *lsp, const JSON *json, LSPResponse *response) { return parse_workspace_edit(lsp, response, json, result, &response->data.rename); } +static bool parse_highlight(LSP *lsp, const JSON *json, LSPResponse *response) { + LSPResponseHighlight *hl = &response->data.highlight; + JSONArray result = json_force_array(json_get(json, "result")); + for (u32 h = 0; h < result.len; ++h) { + JSONObject highlight_in = json_array_get_object(json, result, h); + LSPHighlight *highlight_out = arr_addp(hl->highlights); + double kind = json_object_get_number(json, highlight_in, "kind"); + if (isfinite(kind) && kind >= LSP_HIGHLIGHT_MAX && kind <= LSP_HIGHLIGHT_MAX) { + highlight_out->kind = (LSPHighlightKind)kind; + } else { + highlight_out->kind = LSP_HIGHLIGHT_TEXT; + } + JSONValue range = json_object_get(json, highlight_in, "range"); + if (!parse_range(lsp, json, range, &highlight_out->range)) + return false; + } + return true; +} static void process_message(LSP *lsp, JSON *json) { @@ -820,6 +844,9 @@ static void process_message(LSP *lsp, JSON *json) { case LSP_REQUEST_DEFINITION: add_to_messages = parse_definition(lsp, json, &response); break; + case LSP_REQUEST_HIGHLIGHT: + add_to_messages = parse_highlight(lsp, json, &response); + break; case LSP_REQUEST_WORKSPACE_SYMBOLS: add_to_messages = parse_workspace_symbols(lsp, json, &response); break; diff --git a/lsp-write.c b/lsp-write.c index fb65c2d..3255ec0 100644 --- a/lsp-write.c +++ b/lsp-write.c @@ -273,6 +273,8 @@ static const char *lsp_request_method(LSPRequest *request) { return "textDocument/hover"; case LSP_REQUEST_DEFINITION: return "textDocument/definition"; + case LSP_REQUEST_HIGHLIGHT: + return "textDocument/documentHighlight"; case LSP_REQUEST_RENAME: return "textDocument/rename"; case LSP_REQUEST_WORKSPACE_FOLDERS: @@ -544,6 +546,12 @@ static void write_request(LSP *lsp, LSPRequest *request) { write_document_position(o, def->position); write_obj_end(o); } break; + case LSP_REQUEST_HIGHLIGHT: { + const LSPRequestHighlight *hl = &request->data.highlight; + write_key_obj_start(o, "params"); + write_document_position(o, hl->position); + write_obj_end(o); + } break; case LSP_REQUEST_RENAME: { const LSPRequestRename *rename = &request->data.rename; write_key_obj_start(o, "params"); diff --git a/lsp.c b/lsp.c index 253d465..23b1023 100644 --- a/lsp.c +++ b/lsp.c @@ -52,6 +52,7 @@ static void lsp_request_free(LSPRequest *r) { case LSP_REQUEST_SIGNATURE_HELP: case LSP_REQUEST_HOVER: case LSP_REQUEST_DEFINITION: + case LSP_REQUEST_HIGHLIGHT: case LSP_REQUEST_DID_CLOSE: case LSP_REQUEST_WORKSPACE_FOLDERS: case LSP_REQUEST_JDTLS_CONFIGURATION: @@ -103,6 +104,9 @@ static void lsp_response_free(LSPResponse *r) { case LSP_REQUEST_RENAME: arr_free(r->data.rename.changes); break; + case LSP_REQUEST_HIGHLIGHT: + arr_free(r->data.highlight.highlights); + break; default: break; } @@ -176,6 +180,8 @@ static bool lsp_supports_request(LSP *lsp, const LSPRequest *request) { return cap->workspace_symbols_support; case LSP_REQUEST_RENAME: return cap->rename_support; + case LSP_REQUEST_HIGHLIGHT: + return cap->highlight_support; } assert(0); return false; @@ -204,6 +210,7 @@ static bool request_type_is_notification(LSPRequestType type) { case LSP_REQUEST_SHOW_MESSAGE: case LSP_REQUEST_LOG_MESSAGE: case LSP_REQUEST_COMPLETION: + case LSP_REQUEST_HIGHLIGHT: case LSP_REQUEST_SIGNATURE_HELP: case LSP_REQUEST_HOVER: case LSP_REQUEST_DEFINITION: diff --git a/lsp.h b/lsp.h index e9278a7..d52c20b 100644 --- a/lsp.h +++ b/lsp.h @@ -52,7 +52,7 @@ typedef enum { LSP_REQUEST_SIGNATURE_HELP, // textDocument/signatureHelp LSP_REQUEST_HOVER, // textDocument/hover LSP_REQUEST_DEFINITION, // textDocument/definition - //LSP_REQUEST_HIGHLIGHT, + LSP_REQUEST_HIGHLIGHT, // textDocument/documentHighlight LSP_REQUEST_RENAME, // textDocument/rename LSP_REQUEST_WORKSPACE_SYMBOLS, // workspace/symbol LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS, // workspace/didChangeWorkspaceFolders @@ -149,6 +149,10 @@ typedef struct { LSPDocumentPosition position; } LSPRequestDefinition; +typedef struct { + LSPDocumentPosition position; +} LSPRequestHighlight; + typedef struct { char *query; } LSPRequestWorkspaceSymbols; @@ -177,6 +181,7 @@ typedef struct { LSPRequestSignatureHelp signature_help; LSPRequestHover hover; LSPRequestDefinition definition; + LSPRequestHighlight highlight; LSPRequestWorkspaceSymbols workspace_symbols; // LSP_REQUEST_SHOW_MESSAGE or LSP_REQUEST_LOG_MESSAGE LSPRequestMessage message; @@ -328,6 +333,23 @@ typedef struct { LSPLocation *locations; } LSPResponseDefinition; +typedef enum { +#define LSP_HIGHLIGHT_MIN 1 + LSP_HIGHLIGHT_TEXT = 1, + LSP_HIGHLIGHT_READ = 2, + LSP_HIGHLIGHT_WRITE = 3, +#define LSP_HIGHLIGHT_MAX 3 +} LSPHighlightKind; + +typedef struct { + LSPRange range; + LSPHighlightKind kind; +} LSPHighlight; + +typedef struct { + LSPHighlight *highlights; +} LSPResponseHighlight; + typedef enum { #define LSP_SYMBOL_TAG_MIN 1 LSP_SYMBOL_TAG_DEPRECATED = 1 @@ -409,6 +431,7 @@ typedef struct { LSPResponseDefinition definition; LSPResponseWorkspaceSymbols workspace_symbols; LSPResponseRename rename; + LSPResponseHighlight highlight; } data; } LSPResponse; @@ -431,6 +454,7 @@ typedef struct { bool hover_support; bool definition_support; bool workspace_symbols_support; + bool highlight_support; // support for multiple root folders // sadly, as of me writing this, clangd and rust-analyzer don't support this // (but jdtls and gopls do) diff --git a/main.c b/main.c index 4c380ea..daf483f 100644 --- a/main.c +++ b/main.c @@ -39,6 +39,7 @@ FUTURE FEATURES: - :set-build-command - document links using LSP textDocument/documentLink request - rename using LSP (textDocument/rename) + - we have request writing & response parsing support for it, but that hasn't been tested yet - i'm putting this off for now since it seems hard to have undo support for it. - add numlock as a key modifier? (but make sure "Ctrl+S" handles both "No NumLock+Ctrl+S" and "NumLock+Ctrl+S") - better undo chaining (dechain on backspace?) @@ -153,6 +154,7 @@ bool tag_goto(Ted *ted, char const *tag); #include "ide-signature-help.c" #include "ide-hover.c" #include "ide-definitions.c" +#include "ide-highlights.c" #include "command.c" #include "config.c" #include "session.c" @@ -1152,7 +1154,9 @@ int main(int argc, char **argv) { if (ted->menu) menu_close(ted); hover_close(ted); + signature_help_close(ted); autocomplete_close(ted); + highlights_close(ted); session_write(ted); for (int i = 0; i < TED_LSP_MAX; ++i) { diff --git a/ted.h b/ted.h index 5acbba4..7a3dddd 100644 --- a/ted.h +++ b/ted.h @@ -437,6 +437,10 @@ typedef struct { SymbolInfo *selector_all_definitions; // an array of all definitions } Definitions; +typedef struct { + LSPHighlight *highlights; + LSPRequestID last_request_id; +} Highlights; typedef struct Ted { LSP *lsps[TED_LSP_MAX + 1]; @@ -494,6 +498,7 @@ typedef struct Ted { SignatureHelp signature_help; Hover hover; Definitions definitions; + Highlights highlights; FILE *log; -- cgit v1.2.3