From 87c8bd6eb27edb4bfc539967235c3a1e2f8d77e4 Mon Sep 17 00:00:00 2001 From: pommicket Date: Tue, 3 Jan 2023 17:29:19 -0500 Subject: go to declaration --- buffer.c | 12 ++++++++---- command.c | 10 ++++++++-- command.h | 1 + ide-definitions.c | 18 ++++++++++++++---- lsp-parse.c | 7 +++++++ lsp-write.c | 6 +++++- lsp.c | 4 ++++ lsp.h | 4 ++++ main.c | 4 +++- ted.cfg | 3 ++- ted.h | 9 +++++++-- 11 files changed, 63 insertions(+), 15 deletions(-) diff --git a/buffer.c b/buffer.c index 515ceb3..4645f75 100644 --- a/buffer.c +++ b/buffer.c @@ -2532,11 +2532,11 @@ u32 buffer_last_rendered_line(TextBuffer *buffer) { return clamp_u32(line, 0, buffer->nlines); } -void buffer_goto_word_at_cursor(TextBuffer *buffer) { +void buffer_goto_word_at_cursor(TextBuffer *buffer, GotoType type) { char *word = buffer_word_at_cursor_utf8(buffer); if (*word) { LSPDocumentPosition pos = buffer_pos_to_lsp_document_position(buffer, buffer->cursor_pos); - definition_goto(buffer->ted, buffer_lsp(buffer), word, pos); + definition_goto(buffer->ted, buffer_lsp(buffer), word, pos, type); } free(word); } @@ -2562,10 +2562,14 @@ bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times) { buffer_select_to_pos(buffer, buffer_pos); break; case KEY_MODIFIER_CTRL: + case KEY_MODIFIER_CTRL | KEY_MODIFIER_SHIFT: if (!buffer->is_line_buffer) { - // go to definition + // go to definition/declaration buffer_cursor_move_to_pos(buffer, buffer_pos); - buffer_goto_word_at_cursor(buffer); + GotoType type = GOTO_DEFINITION; + if (ted->key_modifier & KEY_MODIFIER_SHIFT) + type = GOTO_DECLARATION; + buffer_goto_word_at_cursor(buffer, type); } break; case 0: diff --git a/command.c b/command.c index fb9a390..bf26b3a 100644 --- a/command.c +++ b/command.c @@ -66,6 +66,7 @@ static CommandName const command_names[] = { {"find-usages", CMD_FIND_USAGES}, {"goto-definition", CMD_GOTO_DEFINITION}, {"goto-definition-at-cursor", CMD_GOTO_DEFINITION_AT_CURSOR}, + {"goto-declaration-at-cursor", CMD_GOTO_DECLARATION_AT_CURSOR}, {"find", CMD_FIND}, {"find-replace", CMD_FIND_REPLACE}, {"tab-close", CMD_TAB_CLOSE}, @@ -405,10 +406,15 @@ void command_execute(Ted *ted, Command c, i64 argument) { break; case CMD_GOTO_DEFINITION: menu_open(ted, MENU_GOTO_DEFINITION); - break; + break; case CMD_GOTO_DEFINITION_AT_CURSOR: { if (buffer && buffer_is_named_file(buffer)) { - buffer_goto_word_at_cursor(buffer); + buffer_goto_word_at_cursor(buffer, GOTO_DEFINITION); + } + } break; + case CMD_GOTO_DECLARATION_AT_CURSOR: { + if (buffer && buffer_is_named_file(buffer)) { + buffer_goto_word_at_cursor(buffer, GOTO_DECLARATION); } } break; case CMD_FIND_USAGES: diff --git a/command.h b/command.h index 2edd207..3f7d155 100644 --- a/command.h +++ b/command.h @@ -75,6 +75,7 @@ ENUM_U16 { CMD_FIND_USAGES, CMD_GOTO_DEFINITION, // "go to definition of..." menu CMD_GOTO_DEFINITION_AT_CURSOR, + CMD_GOTO_DECLARATION_AT_CURSOR, CMD_COPY, CMD_CUT, diff --git a/ide-definitions.c b/ide-definitions.c index 0152376..7873630 100644 --- a/ide-definitions.c +++ b/ide-definitions.c @@ -51,13 +51,22 @@ static SymbolKind symbol_kind_to_ted(LSPSymbolKind kind) { return SYMBOL_OTHER; } -void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition position) { +void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition position, GotoType type) { Definitions *defs = &ted->definitions; if (lsp) { // cancel old request ted_cancel_lsp_request(ted, defs->last_request_lsp, defs->last_request_id); + LSPRequestType request_type = LSP_REQUEST_DEFINITION; + switch (type) { + case GOTO_DEFINITION: + request_type = LSP_REQUEST_DEFINITION; + break; + case GOTO_DECLARATION: + request_type = LSP_REQUEST_DECLARATION; + break; + } // send that request - LSPRequest request = {.type = LSP_REQUEST_DEFINITION}; + LSPRequest request = {.type = request_type}; request.data.definition.position = position; LSPRequestID id = lsp_send_request(lsp, &request); defs->last_request_id = id; @@ -132,8 +141,9 @@ void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *res defs->last_request_id = 0; switch (response->request.type) { - case LSP_REQUEST_DEFINITION: { - // handle textDocument/definition response + case LSP_REQUEST_DEFINITION: + case LSP_REQUEST_DECLARATION: { + // handle textDocument/definition or textDocument/declaration response const LSPResponseDefinition *response_def = &response->data.definition; if (!arr_len(response_def->locations)) { diff --git a/lsp-parse.c b/lsp-parse.c index 14db651..9c22fe4 100644 --- a/lsp-parse.c +++ b/lsp-parse.c @@ -163,6 +163,12 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti cap->definition_support = true; } + // check for declaration support + JSONValue declaration_value = json_object_get(json, capabilities, "declarationProvider"); + if (declaration_value.type != JSON_UNDEFINED && declaration_value.type != JSON_FALSE) { + cap->declaration_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) { @@ -883,6 +889,7 @@ void process_message(LSP *lsp, JSON *json) { add_to_messages = parse_hover(lsp, json, &response); break; case LSP_REQUEST_DEFINITION: + case LSP_REQUEST_DECLARATION: add_to_messages = parse_definition(lsp, json, &response); break; case LSP_REQUEST_HIGHLIGHT: diff --git a/lsp-write.c b/lsp-write.c index ecb8527..691bcba 100644 --- a/lsp-write.c +++ b/lsp-write.c @@ -1,5 +1,6 @@ #define LSP_INTERNAL 1 #include "lsp.h" +#include "util.h" #define write_bool lsp_write_bool // prevent naming conflict @@ -278,6 +279,8 @@ static const char *lsp_request_method(LSPRequest *request) { return "textDocument/references"; case LSP_REQUEST_DEFINITION: return "textDocument/definition"; + case LSP_REQUEST_DECLARATION: + return "textDocument/declaration"; case LSP_REQUEST_HIGHLIGHT: return "textDocument/documentHighlight"; case LSP_REQUEST_RENAME: @@ -545,7 +548,8 @@ void write_request(LSP *lsp, LSPRequest *request) { write_document_position(o, hover->position); write_obj_end(o); } break; - case LSP_REQUEST_DEFINITION: { + case LSP_REQUEST_DEFINITION: + case LSP_REQUEST_DECLARATION: { const LSPRequestDefinition *def = &request->data.definition; write_key_obj_start(o, "params"); write_document_position(o, def->position); diff --git a/lsp.c b/lsp.c index 1bee23f..bd01bbd 100644 --- a/lsp.c +++ b/lsp.c @@ -48,6 +48,7 @@ void lsp_request_free(LSPRequest *r) { case LSP_REQUEST_SIGNATURE_HELP: case LSP_REQUEST_HOVER: case LSP_REQUEST_DEFINITION: + case LSP_REQUEST_DECLARATION: case LSP_REQUEST_REFERENCES: case LSP_REQUEST_HIGHLIGHT: case LSP_REQUEST_DID_CLOSE: @@ -176,6 +177,8 @@ static bool lsp_supports_request(LSP *lsp, const LSPRequest *request) { return cap->hover_support; case LSP_REQUEST_DEFINITION: return cap->definition_support; + case LSP_REQUEST_DECLARATION: + return cap->declaration_support; case LSP_REQUEST_WORKSPACE_SYMBOLS: return cap->workspace_symbols_support; case LSP_REQUEST_RENAME: @@ -216,6 +219,7 @@ static bool request_type_is_notification(LSPRequestType type) { case LSP_REQUEST_SIGNATURE_HELP: case LSP_REQUEST_HOVER: case LSP_REQUEST_DEFINITION: + case LSP_REQUEST_DECLARATION: case LSP_REQUEST_REFERENCES: case LSP_REQUEST_RENAME: case LSP_REQUEST_WORKSPACE_SYMBOLS: diff --git a/lsp.h b/lsp.h index c256ec7..f5404b1 100644 --- a/lsp.h +++ b/lsp.h @@ -65,6 +65,7 @@ typedef enum { LSP_REQUEST_SIGNATURE_HELP, // textDocument/signatureHelp LSP_REQUEST_HOVER, // textDocument/hover LSP_REQUEST_DEFINITION, // textDocument/definition + LSP_REQUEST_DECLARATION, // textDocument/declaration LSP_REQUEST_HIGHLIGHT, // textDocument/documentHighlight LSP_REQUEST_REFERENCES, // textDocument/references LSP_REQUEST_RENAME, // textDocument/rename @@ -200,6 +201,7 @@ typedef struct { LSPRequestCompletion completion; LSPRequestSignatureHelp signature_help; LSPRequestHover hover; + // LSP_REQUEST_DEFINITION, LSP_REQUEST_DECLARATION, or LSP_REQUEST_TYPE_DEFINITION LSPRequestDefinition definition; LSPRequestHighlight highlight; LSPRequestReferences references; @@ -454,6 +456,7 @@ typedef struct { LSPResponseCompletion completion; LSPResponseSignatureHelp signature_help; LSPResponseHover hover; + // LSP_REQUEST_DEFINITION, LSP_REQUEST_DECLARATION, or LSP_REQUEST_TYPE_DEFINITION LSPResponseDefinition definition; LSPResponseWorkspaceSymbols workspace_symbols; LSPResponseRename rename; @@ -480,6 +483,7 @@ typedef struct { bool completion_support; bool hover_support; bool definition_support; + bool declaration_support; bool workspace_symbols_support; bool highlight_support; // support for multiple root folders diff --git a/main.c b/main.c index 9967bd6..d4535a0 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,8 @@ /* @TODO: -- go to declaration with LSP +- go to type definition +- why does asking for a definition in ted.h send us to the wrong place? + (vscode doesn't experience this problem) - ted.h documentation - handle multiple symbols with same name in go-to-definition menu - better non-error window/showMessage(Request) diff --git a/ted.cfg b/ted.cfg index 7e94d19..bca3276 100644 --- a/ted.cfg +++ b/ted.cfg @@ -264,7 +264,8 @@ Ctrl+t = :generate-tags Ctrl+d = :goto-definition # alternative to ctrl+click -Ctrl+Shift+d = :goto-definition-at-cursor +Ctrl+' = :goto-definition-at-cursor +Ctrl+Shift+' = :goto-declaration-at-cursor Ctrl+g = :goto-line Ctrl+\ = :split-horizontal diff --git a/ted.h b/ted.h index 0688f40..19a975c 100644 --- a/ted.h +++ b/ted.h @@ -464,6 +464,11 @@ typedef struct { LSPDocumentPosition position; // only set if from_lsp = true } SymbolInfo; +typedef enum { + GOTO_DECLARATION, + GOTO_DEFINITION, +} GotoType; + typedef struct { LSPID last_request_lsp; // used for cancellation // ID of the last request which was sent out. @@ -754,7 +759,7 @@ bool buffer_save(TextBuffer *buffer); bool buffer_save_as(TextBuffer *buffer, const char *new_filename); u32 buffer_first_rendered_line(TextBuffer *buffer); u32 buffer_last_rendered_line(TextBuffer *buffer); -void buffer_goto_word_at_cursor(TextBuffer *buffer); +void buffer_goto_word_at_cursor(TextBuffer *buffer, GotoType type); bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times); void buffer_render(TextBuffer *buffer, Rect r); void buffer_indent_lines(TextBuffer *buffer, u32 first_line, u32 last_line); @@ -951,7 +956,7 @@ void autocomplete_frame(Ted *ted); // if `lsp` is NULL, tags will be used. // Note: the document position is required for LSP requests because of overloading (where the name // alone isn't sufficient) -void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition pos); +void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition pos, GotoType type); void definition_cancel_lookup(Ted *ted); void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response); void definitions_selector_open(Ted *ted); -- cgit v1.2.3