From 5019b312d999f4f9c6a6acee1f047b9587c06f79 Mon Sep 17 00:00:00 2001 From: Albert Cervin Date: Fri, 21 Nov 2025 23:38:54 +0100 Subject: Add support for documentChanges in LSP These should ideally be paired with setting the capability on initialize, but for now, the parsing support is there at least for LSP servers that ignore it (like pylsp). --- src/main/lsp.c | 20 ++++++++++++++++++ src/main/lsp/types.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/lsp/types.h | 8 +++++++ 3 files changed, 87 insertions(+) (limited to 'src') diff --git a/src/main/lsp.c b/src/main/lsp.c index a8e806b..6c5999c 100644 --- a/src/main/lsp.c +++ b/src/main/lsp.c @@ -12,6 +12,7 @@ #include "dged/minibuffer.h" #include "dged/reactor.h" #include "dged/settings.h" +#include "dged/vec.h" #include "dged/window.h" #include "lsp/references.h" @@ -790,6 +791,25 @@ bool apply_edits(struct lsp_server *server, buffer_push_undo_boundary(b); } + VEC_FOR_EACH(&ws_edit->document_changes, struct text_document_edit * edit) { + if (VEC_EMPTY(&edit->edits)) { + continue; + } + + const char *p = s8tocstr(edit->text_document.uri); + struct buffer *b = buffers_find_by_filename(g_lsp_data.buffers, &p[7]); + + if (b == NULL) { + struct buffer new_buf = buffer_from_file(&p[7]); + b = buffers_add(g_lsp_data.buffers, new_buf); + } + + free((void *)p); + buffer_push_undo_boundary(b); + apply_edits_buffer(server, b, edit->edits, NULL); + buffer_push_undo_boundary(b); + } + resume_completion(); return true; } diff --git a/src/main/lsp/types.c b/src/main/lsp/types.c index bd87377..870ca3d 100644 --- a/src/main/lsp/types.c +++ b/src/main/lsp/types.c @@ -6,8 +6,10 @@ #include "dged/buffer.h" #include "dged/display.h" +#include "dged/json.h" #include "dged/path.h" #include "dged/s8.h" +#include "dged/vec.h" struct s8 initialize_params_to_json(struct initialize_params *params) { char *cwd = getcwd(NULL, 0); @@ -730,6 +732,46 @@ static void changes_from_json(struct s8 key, struct json_value *json, VEC_PUSH(vec, pair); } +static void document_change_from_json(uint64_t id, struct json_value *value, + void *userdata) { + (void)id; + text_document_edit_vec *vec = (text_document_edit_vec *)userdata; + + if (value->type != Json_Object) { + return; + } + + struct json_object *obj = value->value.object; + + struct json_value *text_doc = json_get(obj, s8("textDocument")); + + struct versioned_text_document_identifier doc_id = {0}; + + if (text_doc != NULL && text_doc->type == Json_Object) { + struct json_object *text_doc_object = text_doc->value.object; + struct json_value *uri = json_get(text_doc_object, s8("uri")); + if (uri != NULL && uri->type == Json_String) { + doc_id.uri = unescape_json_string(uri->value.string); + } + + struct json_value *version = json_get(text_doc_object, s8("version")); + if (version != NULL && version->type == Json_Number) { + doc_id.version = uri->value.number; + } + } else { + return; + } + + struct json_value *edits = json_get(obj, s8("edits")); + if (edits == NULL || edits->type != Json_Array) { + return; + } + + struct text_document_edit edit = {.text_document = doc_id, + .edits = text_edits_from_json(edits)}; + VEC_PUSH(vec, edit); +} + struct workspace_edit workspace_edit_from_json(struct json_value *json) { struct workspace_edit edit; struct json_object *obj = json->value.object; @@ -747,6 +789,16 @@ struct workspace_edit workspace_edit_from_json(struct json_value *json) { VEC_INIT(&edit.changes, 0); } + struct json_value *document_changes = json_get(obj, s8("documentChanges")); + if (document_changes != NULL && document_changes->type == Json_Array) { + struct json_array *doc_changes_arr = document_changes->value.array; + VEC_INIT(&edit.document_changes, json_array_len(doc_changes_arr)); + json_array_foreach(doc_changes_arr, &edit.document_changes, + document_change_from_json); + } else { + VEC_INIT(&edit.document_changes, 0); + } + return edit; } @@ -759,6 +811,13 @@ void workspace_edit_free(struct workspace_edit *edit) { VEC_DESTROY(&pair->edits); } VEC_DESTROY(&edit->changes); + + VEC_FOR_EACH(&edit->document_changes, struct text_document_edit * doc_edit) { + versioned_text_document_identifier_free(&doc_edit->text_document); + text_edits_free(doc_edit->edits); + } + + VEC_DESTROY(&edit->document_changes); } uint32_t diag_severity_color(enum diagnostic_severity severity) { diff --git a/src/main/lsp/types.h b/src/main/lsp/types.h index 7b6ba1a..e7423b6 100644 --- a/src/main/lsp/types.h +++ b/src/main/lsp/types.h @@ -181,8 +181,16 @@ struct text_edit_pair { typedef VEC(struct text_edit_pair) change_vec; +struct text_document_edit { + struct versioned_text_document_identifier text_document; + text_edit_vec edits; +}; + +typedef VEC(struct text_document_edit) text_document_edit_vec; + struct workspace_edit { change_vec changes; + text_document_edit_vec document_changes; }; struct lsp_command { -- cgit v1.2.3