summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-09-29 15:11:47 -0400
committerpommicket <pommicket@gmail.com>2025-09-29 15:29:51 -0400
commit84da626a18ccc779aef4a178ee0097a93c959520 (patch)
treeea862eff35309f2cae3a0ab30112fb38647eafa2
parent16b5baf3083c982220e9feb561f2f53f1720fe2a (diff)
Send over diagnostics; this fixes code actions
-rw-r--r--buffer.c15
-rw-r--r--ide-code-action.c33
-rw-r--r--lsp-parse.c6
-rw-r--r--lsp-write.c76
-rw-r--r--lsp.c5
-rw-r--r--lsp.h5
-rw-r--r--ted-internal.h14
7 files changed, 132 insertions, 22 deletions
diff --git a/buffer.c b/buffer.c
index 7ed3649..9b8a79d 100644
--- a/buffer.c
+++ b/buffer.c
@@ -39,14 +39,6 @@ struct BufferEdit {
double time; // time at start of edit (i.e. the time just before the edit), in seconds since epoch
};
-typedef struct {
- MessageType severity;
- BufferPos pos;
- char *message;
- // may be NULL
- char *url;
-} Diagnostic;
-
struct TextBuffer {
/// NULL if this buffer is untitled or doesn't correspond to a file (e.g. line buffers)
char *path;
@@ -1004,6 +996,7 @@ static void buffer_line_free(Line *line) {
static void diagnostic_free(Diagnostic *diagnostic) {
free(diagnostic->message);
free(diagnostic->url);
+ free(diagnostic->raw);
memset(diagnostic, 0, sizeof *diagnostic);
}
@@ -4245,7 +4238,9 @@ void buffer_publish_diagnostics(TextBuffer *buffer, const LSPRequest *request, L
arr_foreach_ptr(diagnostics, const LSPDiagnostic, diagnostic) {
Diagnostic *d = arr_addp(buffer->diagnostics);
d->pos = buffer_pos_from_lsp(buffer, diagnostic->range.start);
+ d->end = buffer_pos_from_lsp(buffer, diagnostic->range.end);
d->severity = diagnostic_severity(diagnostic);
+ d->raw = str_dup(lsp_request_string(request, diagnostic->raw));
char message[280];
const char *code = lsp_request_string(request, diagnostic->code);
if (*code) {
@@ -4287,3 +4282,7 @@ void buffer_set_inotify_modified(TextBuffer *buffer) {
buffer->inotify_modified = true;
}
#endif
+
+const Diagnostic *buffer_diagnostics(TextBuffer *buffer) {
+ return buffer->diagnostics;
+}
diff --git a/ide-code-action.c b/ide-code-action.c
index 678c046..13a1b36 100644
--- a/ide-code-action.c
+++ b/ide-code-action.c
@@ -1,18 +1,47 @@
#include "ted-internal.h"
+static bool ranges_touch(BufferPos p1, BufferPos p2, BufferPos q1, BufferPos q2) {
+ int cmp21 = buffer_pos_cmp(p2, q1);
+ if (cmp21 < 0) {
+ // p is entirely before q
+ return false;
+ }
+ int cmp12 = buffer_pos_cmp(p1, q2);
+ if (cmp12 > 0) {
+ // p is entirely after q
+ return false;
+ }
+ return true;
+}
+
void code_action_start(Ted *ted) {
TextBuffer *buffer = ted_active_buffer(ted);
LSP *lsp = buffer_lsp(buffer);
+ BufferPos range_start = {0}, range_end = {0};
LSPRange range = {0};
- if (buffer_has_selection(buffer))
+ if (buffer_selection_pos(buffer, &range_start)) {
range = buffer_selection_as_lsp_range(buffer);
- else
+ range_end = buffer_cursor_pos(buffer);
+ if (buffer_pos_cmp(range_start, range_end) > 0) {
+ BufferPos tmp = range_start;
+ range_start = range_end;
+ range_end = tmp;
+ }
+ } else {
+ range_start = range_end = buffer_cursor_pos(buffer);
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;
+ arr_foreach_ptr(buffer_diagnostics(buffer), const Diagnostic, d) {
+ if (ranges_touch(range_start, range_end, d->pos, d->end)) {
+ LSPString raw = lsp_request_add_string(&req, d->raw);
+ arr_add(code_action_req->raw_diagnostics, raw);
+ }
+ }
lsp_send_request(lsp, &req);
}
diff --git a/lsp-parse.c b/lsp-parse.c
index 3f81a2f..4046f6f 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -800,10 +800,14 @@ static bool parse_publish_diagnostics(LSP *lsp, const JSON *json, LSPRequest *re
return false;
JSONArray diagnostics = json_object_get_array(json, params, "diagnostics");
for (u32 i = 0; i < diagnostics.len; ++i) {
- JSONObject diagnostic_in = json_array_get_object(json, diagnostics, i);
+ JSONValue diagnostic_val = json_array_get(json, diagnostics, i);
+ JSONObject diagnostic_in = json_force_object(diagnostic_val);
LSPDiagnostic *diagnostic_out = arr_addp(pub->diagnostics);
if (!parse_diagnostic(lsp, request, json, diagnostic_in, diagnostic_out))
return false;
+ char *raw = json_reserialize(json, diagnostic_val);
+ diagnostic_out->raw = lsp_request_add_string(request, raw);
+ free(raw);
}
return true;
}
diff --git a/lsp-write.c b/lsp-write.c
index 23bb14e..c81c574 100644
--- a/lsp-write.c
+++ b/lsp-write.c
@@ -250,6 +250,68 @@ static void write_document_position(JSONWriter *o, LSPDocumentPosition pos) {
write_key_position(o, "position", pos.pos);
}
+
+static void json_reserialize_to(const JSON *json, JSONWriter *o, JSONValue val) {
+ switch (val.type) {
+ case JSON_UNDEFINED:
+ assert(false);
+ break;
+ case JSON_TRUE:
+ write_bool(o, true);
+ break;
+ case JSON_FALSE:
+ write_bool(o, false);
+ break;
+ case JSON_NULL:
+ write_null(o);
+ break;
+ case JSON_NUMBER:
+ write_number(o, val.val.number);
+ break;
+ case JSON_STRING: {
+ char *s = json_string_get_alloc(json, val.val.string);
+ write_string(o, s);
+ free(s);
+ } break;
+ case JSON_ARRAY: {
+ JSONArray array = val.val.array;
+ write_arr_start(o);
+ for (u32 i = 0; i < array.len; i++) {
+ JSONValue elem = json_array_get(json, array, i);
+ write_arr_elem(o);
+ json_reserialize_to(json, o, elem);
+ }
+ write_arr_end(o);
+ } break;
+ case JSON_OBJECT: {
+ JSONObject object = val.val.object;
+ write_obj_start(o);
+ JSONValue *keys = &json->values[object.items];
+ JSONValue *values = keys + object.len;
+ for (u32 i = 0; i < object.len; i++) {
+ JSONValue key_val = keys[i];
+ assert(key_val.type == JSON_STRING);
+ JSONString key = key_val.val.string;
+ JSONValue value = values[i];
+ char *key_str = json_string_get_alloc(json, key);
+ write_key(o, key_str);
+ free(key_str);
+ json_reserialize_to(json, o, value);
+ }
+ write_obj_end(o);
+ } break;
+ }
+}
+
+char *json_reserialize(const JSON *json, JSONValue value) {
+ StrBuilder builder = str_builder_new();
+ JSONWriter writer = json_writer_new(NULL, &builder);
+ json_reserialize_to(json, &writer, value);
+ char *str = str_dup(builder.str);
+ str_builder_free(&builder);
+ return str;
+}
+
static const char *lsp_request_method(LSPRequest *request) {
switch (request->type) {
case LSP_REQUEST_NONE: break;
@@ -698,16 +760,10 @@ void write_request(LSP *lsp, LSPRequest *request, StrBuilder *builder) {
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");
+ arr_foreach_ptr(code_action->raw_diagnostics, const LSPString, raw_diagnostic) {
+ write_arr_elem(o);
+ str_builder_append(o->builder, lsp_request_string(request, *raw_diagnostic));
+ }
write_arr_end(o);
write_obj_end(o);
write_obj_end(o);
diff --git a/lsp.c b/lsp.c
index 4337099..34548f0 100644
--- a/lsp.c
+++ b/lsp.c
@@ -125,7 +125,6 @@ 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;
@@ -137,6 +136,10 @@ void lsp_request_free(LSPRequest *r) {
case LSP_REQUEST_PREPARE_RENAME:
case LSP_REQUEST_WORKSPACE_SYMBOLS:
break;
+ case LSP_REQUEST_CODE_ACTION: {
+ LSPRequestCodeAction *c = &r->data.code_action;
+ arr_free(c->raw_diagnostics);
+ } break;
case LSP_REQUEST_DID_CHANGE: {
LSPRequestDidChange *c = &r->data.change;
arr_free(c->changes);
diff --git a/lsp.h b/lsp.h
index 21b2dda..c891246 100644
--- a/lsp.h
+++ b/lsp.h
@@ -171,6 +171,8 @@ typedef struct {
/// URI to description of code
/// e.g. for Rust's E0621, this would be https://doc.rust-lang.org/error_codes/E0621.html
LSPString code_description_uri;
+ // raw diagnostic object, to be used with textDocument/codeAction
+ LSPString raw;
} LSPDiagnostic;
typedef struct {
@@ -262,6 +264,7 @@ typedef struct {
typedef struct {
LSPDocumentID document;
LSPRange range;
+ LSPString *raw_diagnostics;
} LSPRequestCodeAction;
typedef struct {
@@ -945,6 +948,8 @@ LSPString lsp_response_add_json_string(LSPResponse *response, const JSON *json,
LSPString lsp_request_add_json_string(LSPRequest *request, const JSON *json, JSONString string);
/// free resources used by lsp-write.c
void lsp_write_quit(void);
+// convert JSON value back into string
+char *json_reserialize(const JSON *json, JSONValue value);
/// print server-to-client communication
#define LSP_SHOW_S2C 1
diff --git a/ted-internal.h b/ted-internal.h
index 3e8da9f..a4b5574 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -450,6 +450,19 @@ struct Ted {
EditNotifyInfo *edit_notifys;
};
+typedef struct {
+ MessageType severity;
+ // start position
+ BufferPos pos;
+ // end position
+ BufferPos end;
+ char *message;
+ // may be NULL
+ char *url;
+ // raw JSON object (for textDocument/codeAction)
+ char *raw;
+} Diagnostic;
+
// === buffer.c ===
/// create a new empty buffer with no file name
TextBuffer *buffer_new(Ted *ted);
@@ -508,6 +521,7 @@ int buffer_inotify_watch(TextBuffer *buffer);
/// inform buffer that its watch on the Ted's inotify was modified
void buffer_set_inotify_modified(TextBuffer *buffer);
#endif
+const Diagnostic *buffer_diagnostics(TextBuffer *buffer);
// === build.c ===
void build_frame(Ted *ted, float x1, float y1, float x2, float y2);