summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-09-29 13:29:56 -0400
committerpommicket <pommicket@gmail.com>2025-09-29 15:29:51 -0400
commit6c4baeebd88352399059a8df8d38ebe3511588ea (patch)
tree98db7bb4f36a47f8f9ac5a53dcb06e8cd19cf762
parentec03a105ce7a6e396cfd287cbfe902d65bac1474 (diff)
Start code actions
-rw-r--r--CMakeLists.txt2
-rw-r--r--command.c4
-rw-r--r--command.h2
-rw-r--r--ide-code-action.c18
-rw-r--r--lsp-parse.c5
-rw-r--r--lsp-write.c28
-rw-r--r--lsp.c4
-rw-r--r--lsp.h12
-rw-r--r--main.c1
-rw-r--r--ted-internal.h3
10 files changed, 76 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 99c539e..1896751 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.5...3.25)
project(ted)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(SOURCES buffer.c build.c colors.c command.c config.c find.c gl.c ide-autocomplete.c
- ide-document-link.c ide-definitions.c ide-format.c ide-highlights.c ide-hover.c
+ ide-document-link.c ide-definitions.c ide-format.c ide-highlights.c ide-hover.c ide-code-action.c
ide-signature-help.c ide-usages.c ide-rename-symbol.c lsp.c lsp-json.c lsp-parse.c
lsp-write.c main.c menu.c node.c os.c session.c stb_truetype.c syntax.c
tags.c ted.c text.c ui.c util.c macro.c)
diff --git a/command.c b/command.c
index 3b647f4..66ae4bb 100644
--- a/command.c
+++ b/command.c
@@ -111,6 +111,7 @@ static CommandName command_names[] = {
{"indent-with-tabs", CMD_INDENT_WITH_TABS},
{"set-tab-width", CMD_SET_TAB_WIDTH},
{"debug-print-undo-history", CMD_DEBUG_PRINT_UNDO_HISTORY},
+ {"code-action", CMD_CODE_ACTION},
};
static_assert_if_possible(arr_count(command_names) == CMD_COUNT)
@@ -740,5 +741,8 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
case CMD_DEBUG_PRINT_UNDO_HISTORY:
buffer_print_undo_history(buffer);
break;
+ case CMD_CODE_ACTION:
+ code_action_start(ted);
+ break;
}
}
diff --git a/command.h b/command.h
index 400dab1..2f60a7a 100644
--- a/command.h
+++ b/command.h
@@ -107,6 +107,8 @@ typedef enum {
CMD_AUTOCOMPLETE_BACK,
CMD_FIND_USAGES,
CMD_RENAME_SYMBOL,
+ CMD_CODE_ACTION,
+
/// "go to definition of..." menu
CMD_GOTO_DEFINITION,
CMD_GOTO_DEFINITION_AT_CURSOR,
diff --git a/ide-code-action.c b/ide-code-action.c
new file mode 100644
index 0000000..678c046
--- /dev/null
+++ b/ide-code-action.c
@@ -0,0 +1,18 @@
+#include "ted-internal.h"
+
+void code_action_start(Ted *ted) {
+ TextBuffer *buffer = ted_active_buffer(ted);
+ LSP *lsp = buffer_lsp(buffer);
+ LSPRange range = {0};
+ if (buffer_has_selection(buffer))
+ range = buffer_selection_as_lsp_range(buffer);
+ else
+ range.start = range.end = buffer_cursor_pos_as_lsp_position(buffer);
+ LSPRequest req = {
+ .type = LSP_REQUEST_CODE_ACTION,
+ };
+ LSPRequestCodeAction *code_action_req = &req.data.code_action;
+ code_action_req->document = buffer_lsp_document_id(buffer);
+ code_action_req->range = range;
+ lsp_send_request(lsp, &req);
+}
diff --git a/lsp-parse.c b/lsp-parse.c
index 63d5605..3f81a2f 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -280,6 +280,11 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti
cap->range_formatting_support = true;
}
+ JSONValue code_action_value = json_object_get(json, capabilities, "codeActionProvider");
+ if (code_action_value.type == JSON_OBJECT || code_action_value.type == JSON_TRUE) {
+ cap->code_action_support = true;
+ }
+
JSONObject workspace = json_object_get_object(json, capabilities, "workspace");
// check WorkspaceFoldersServerCapabilities
JSONObject workspace_folders = json_object_get_object(json, workspace, "workspaceFolders");
diff --git a/lsp-write.c b/lsp-write.c
index c1c846a..e4caf4f 100644
--- a/lsp-write.c
+++ b/lsp-write.c
@@ -311,6 +311,8 @@ static const char *lsp_request_method(LSPRequest *request) {
return "textDocument/rangeFormatting";
case LSP_REQUEST_FORMATTING:
return "textDocument/formatting";
+ case LSP_REQUEST_CODE_ACTION:
+ return "textDocument/codeAction";
}
assert(0);
return "$/ignore";
@@ -468,6 +470,9 @@ void write_request(LSP *lsp, LSPRequest *request, StrBuilder *builder) {
write_key_obj_start(o, "publishDiagnostics");
write_key_bool(o, "codeDescriptionSupport", true);
write_obj_end(o);
+
+ write_key_obj_start(o, "codeAction");
+ write_obj_end(o);
write_obj_end(o);
write_key_obj_start(o, "workspace");
write_key_bool(o, "workspaceFolders", true);
@@ -670,6 +675,29 @@ void write_request(LSP *lsp, LSPRequest *request, StrBuilder *builder) {
}
write_obj_end(o);
} break;
+ case LSP_REQUEST_CODE_ACTION: {
+ LSPRequestCodeAction *code_action = &request->data.code_action;
+ write_key_obj_start(o, "params");
+ write_key_obj_start(o, "textDocument");
+ write_key_file_uri(o, "uri", code_action->document);
+ write_obj_end(o);
+ write_key_range(o, "range", code_action->range);
+ write_key_obj_start(o, "context");
+ write_key_arr_start(o, "diagnostics");
+ write_arr_end(o);
+ write_key_arr_start(o, "only");
+ write_arr_elem_string(o, "quickfix");
+ write_arr_elem_string(o, "refactor");
+ write_arr_elem_string(o, "refactor.extract");
+ write_arr_elem_string(o, "refactor.inline");
+ write_arr_elem_string(o, "refactor.rewrite");
+ write_arr_elem_string(o, "source");
+ write_arr_elem_string(o, "source.organizeImports");
+ write_arr_elem_string(o, "source.fixAll");
+ write_arr_end(o);
+ write_obj_end(o);
+ write_obj_end(o);
+ } break;
}
write_obj_end(o);
diff --git a/lsp.c b/lsp.c
index 2004bb7..4337099 100644
--- a/lsp.c
+++ b/lsp.c
@@ -125,6 +125,7 @@ void lsp_request_free(LSPRequest *r) {
case LSP_REQUEST_DID_OPEN:
case LSP_REQUEST_FORMATTING:
case LSP_REQUEST_RANGE_FORMATTING:
+ case LSP_REQUEST_CODE_ACTION:
break;
case LSP_REQUEST_PUBLISH_DIAGNOSTICS: {
LSPRequestPublishDiagnostics *pub = &r->data.publish_diagnostics;
@@ -237,6 +238,8 @@ static bool lsp_supports_request(LSP *lsp, const LSPRequest *request) {
return cap->open_close_support;
case LSP_REQUEST_DID_CHANGE:
return cap->sync_support;
+ case LSP_REQUEST_CODE_ACTION:
+ return cap->code_action_support;
case LSP_REQUEST_INITIALIZE:
case LSP_REQUEST_INITIALIZED:
case LSP_REQUEST_CANCEL:
@@ -320,6 +323,7 @@ static bool request_type_is_notification(LSPRequestType type) {
case LSP_REQUEST_DOCUMENT_LINK:
case LSP_REQUEST_FORMATTING:
case LSP_REQUEST_RANGE_FORMATTING:
+ case LSP_REQUEST_CODE_ACTION:
return false;
}
assert(0);
diff --git a/lsp.h b/lsp.h
index c267283..21b2dda 100644
--- a/lsp.h
+++ b/lsp.h
@@ -97,6 +97,7 @@ typedef enum {
LSP_REQUEST_LOG_MESSAGE, //< window/logMessage
LSP_REQUEST_WORKSPACE_FOLDERS, //< workspace/workspaceFolders - NOTE: this is handled directly in lsp-parse.c (because it only needs information from the LSP struct)
LSP_REQUEST_PUBLISH_DIAGNOSTICS, //< textDocument/publishDiagnostics
+ LSP_REQUEST_CODE_ACTION, //< textDocument/codeAction
} LSPRequestType;
typedef enum {
@@ -259,6 +260,11 @@ typedef struct {
} LSPRequestFormatting;
typedef struct {
+ LSPDocumentID document;
+ LSPRange range;
+} LSPRequestCodeAction;
+
+typedef struct {
LSPMessageType type;
/// LSP requests/responses tend to have a lot of strings.
/// to avoid doing a ton of allocations+frees,
@@ -296,6 +302,7 @@ typedef struct {
LSPRequestPublishDiagnostics publish_diagnostics;
// LSP_REQUEST_FORMATTING and LSP_REQUEST_RANGE_FORMATTING
LSPRequestFormatting formatting;
+ LSPRequestCodeAction code_action;
} data;
} LSPRequest;
@@ -629,6 +636,7 @@ typedef struct {
bool document_link_support;
bool formatting_support;
bool range_formatting_support;
+ bool code_action_support;
} LSPCapabilities;
typedef struct LSP LSP;
@@ -939,8 +947,8 @@ LSPString lsp_request_add_json_string(LSPRequest *request, const JSON *json, JSO
void lsp_write_quit(void);
/// print server-to-client communication
-#define LSP_SHOW_S2C 0
+#define LSP_SHOW_S2C 1
/// print client-to-server communication
-#define LSP_SHOW_C2S 0
+#define LSP_SHOW_C2S 1
#endif // LSP_INTERNAL
diff --git a/main.c b/main.c
index 0d0732c..425984b 100644
--- a/main.c
+++ b/main.c
@@ -95,6 +95,7 @@ the first character can be interpreted specially if it is one of the following:
#include "menu.c"
#include "ide-autocomplete.c"
#include "ide-signature-help.c"
+#include "ide-code-action.c"
#include "ide-rename-symbol.c"
#include "ide-hover.c"
#include "ide-definitions.c"
diff --git a/ted-internal.h b/ted-internal.h
index a9de122..3e8da9f 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -634,6 +634,9 @@ void autocomplete_quit(Ted *ted);
void autocomplete_frame(Ted *ted);
void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response);
+// === ide-code-action.c ===
+void code_action_start(Ted *ted);
+
// === ide-definitions.c ===
void definitions_init(Ted *ted);
/// go to the definition of `name`.