From 9d9032fcd0f92d4c1838218f43e5b14acf2a99fc Mon Sep 17 00:00:00 2001 From: pommicket Date: Fri, 30 Dec 2022 21:12:33 -0500 Subject: textDocument/rename response parsing --- lsp-parse.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- lsp.h | 39 +++++++++++++++++++++++---- main.c | 3 ++- 3 files changed, 110 insertions(+), 19 deletions(-) diff --git a/lsp-parse.c b/lsp-parse.c index 1d84408..3834cd0 100644 --- a/lsp-parse.c +++ b/lsp-parse.c @@ -681,23 +681,84 @@ static bool parse_server2client_request(LSP *lsp, JSON *json, LSPRequest *reques } static bool parse_workspace_edit(LSP *lsp, LSPResponse *response, const JSON *json, JSONObject object, LSPWorkspaceEdit *edit) { - JSONObject changes = json_object_get_object(json, object, "changes"); + // the `changes` member is for changes to already-open documents + { + JSONObject changes = json_object_get_object(json, object, "changes"); + for (u32 c = 0; c < changes.len; ++c) { + JSONValue uri = json_object_key(json, changes, c); + JSONArray edits = json_force_array(json_object_value(json, changes, c)); + LSPDocumentID document = 0; + if (!parse_document_uri(lsp, json, uri, &document)) + return false; + for (u32 e = 0; e < edits.len; ++e) { + LSPWorkspaceChange *change = arr_addp(edit->changes); + change->type = LSP_CHANGE_EDIT; + change->data.edit.document = document; + JSONValue text_edit = json_array_get(json, edits, e); + if (!parse_text_edit(lsp, response, json, text_edit, &change->data.edit.edit)) + return false; + } + } + } + // the `documentChanges` member is for changes to other documents + JSONArray changes = json_object_get_array(json, object, "documentChanges"); for (u32 c = 0; c < changes.len; ++c) { - JSONValue uri = json_object_key(json, changes, c); - JSONArray edits = json_force_array(json_object_value(json, changes, c)); - LSPDocumentID document = 0; - if (!parse_document_uri(lsp, json, uri, &document)) - return false; - for (u32 e = 0; e < edits.len; ++e) { - LSPWorkspaceChange *change = arr_addp(edit->changes); - change->type = LSP_CHANGE_EDIT; - change->data.edit.document = document; - JSONValue text_edit = json_array_get(json, edits, e); - if (!parse_text_edit(lsp, response, json, text_edit, &change->data.edit.edit)) + JSONObject change = json_array_get_object(json, changes, c); + JSONValue kind = json_object_get(json, change, "kind"); + if (kind.type == JSON_UNDEFINED) { + // change is a TextDocumentEdit + JSONObject text_document = json_object_get_object(json, change, "textDocument"); + LSPDocumentID document=0; + if (!parse_document_uri(lsp, json, json_object_get(json, text_document, "uri"), &document)) return false; + JSONArray edits = json_object_get_array(json, change, "edits"); + for (u32 e = 0; e < edits.len; ++e) { + LSPWorkspaceChange *out = arr_addp(edit->changes); + out->type = LSP_CHANGE_EDIT; + out->data.edit.document = document; + JSONValue text_edit = json_array_get(json, edits, e); + if (!parse_text_edit(lsp, response, json, text_edit, &out->data.edit.edit)) + return false; + } + } else if (kind.type == JSON_STRING) { + char kind_str[32]={0}; + json_string_get(json, kind.val.string, kind_str, sizeof kind_str); + LSPWorkspaceChange *out = arr_addp(edit->changes); + if (streq(kind_str, "create")) { + out->type = LSP_CHANGE_CREATE; + LSPWorkspaceChangeCreate *create = &out->data.create; + if (!parse_document_uri(lsp, json, json_object_get(json, change, "uri"), &create->document)) + return false; + JSONObject options = json_object_get_object(json, change, "options"); + create->ignore_if_exists = json_object_get_bool(json, options, "ignoreIfExists", false); + create->overwrite = json_object_get_bool(json, options, "overwrite", false); + } else if (streq(kind_str, "rename")) { + out->type = LSP_CHANGE_RENAME; + LSPWorkspaceChangeRename *rename = &out->data.rename; + if (!parse_document_uri(lsp, json, json_object_get(json, change, "oldUri"), &rename->old)) + return false; + if (!parse_document_uri(lsp, json, json_object_get(json, change, "newUri"), &rename->new)) + return false; + JSONObject options = json_object_get_object(json, change, "options"); + rename->ignore_if_exists = json_object_get_bool(json, options, "ignoreIfExists", false); + rename->overwrite = json_object_get_bool(json, options, "overwrite", false); + } else if (streq(kind_str, "delete")) { + out->type = LSP_CHANGE_DELETE; + LSPWorkspaceChangeDelete *delete = &out->data.delete; + if (!parse_document_uri(lsp, json, json_object_get(json, change, "uri"), &delete->document)) + return false; + JSONObject options = json_object_get_object(json, change, "options"); + delete->ignore_if_not_exists = json_object_get_bool(json, options, "ignoreIfNotExists", false); + delete->recursive = json_object_get_bool(json, options, "recursive", false); + } else { + lsp_set_error(lsp, "Bad kind of workspace operation: '%s'", kind_str); + } + } else { + lsp_set_error(lsp, "Bad type for (TextDocumentEdit | CreateFile | RenameFile | DeleteFile).kind: %s", + json_type_to_str(kind.type)); } } - todo : the other thing + return true; } diff --git a/lsp.h b/lsp.h index fa89792..41fc94c 100644 --- a/lsp.h +++ b/lsp.h @@ -346,16 +346,45 @@ typedef struct { } LSPResponseWorkspaceSymbols; typedef enum { - LSP_CHANGE_EDIT = 1 + LSP_CHANGE_EDIT = 1, + LSP_CHANGE_CREATE, + LSP_CHANGE_RENAME, + LSP_CHANGE_DELETE } LSPWorkspaceChangeType; +typedef struct { + LSPDocumentID document; + LSPTextEdit edit; +} LSPWorkspaceChangeEdit; + +typedef struct { + LSPDocumentID document; + bool overwrite; + bool ignore_if_exists; +} LSPWorkspaceChangeCreate; + +typedef struct { + LSPDocumentID old; + LSPDocumentID new; + bool overwrite; + bool ignore_if_exists; +} LSPWorkspaceChangeRename; + +typedef struct { + LSPDocumentID document; + bool recursive; + bool ignore_if_not_exists; +} LSPWorkspaceChangeDelete; + +// this doesn't exist in the LSP spec. it represents +// a single change from a WorkspaceEdit. typedef struct { LSPWorkspaceChangeType type; union { - struct { - LSPDocumentID document; - LSPTextEdit edit; - } edit; + LSPWorkspaceChangeEdit edit; + LSPWorkspaceChangeCreate create; + LSPWorkspaceChangeRename rename; + LSPWorkspaceChangeDelete delete; } data; } LSPWorkspaceChange; diff --git a/main.c b/main.c index 6613f2e..4c380ea 100644 --- a/main.c +++ b/main.c @@ -3,7 +3,6 @@ - more LSP stuff: - document highlight (textDocument/documentHighlight) - find usages (textDocument/references) - - rename (textDocument/rename) - handle multiple symbols with same name in go-to-definition menu - :go-to-cursor-definition - test full unicode position handling @@ -39,6 +38,8 @@ FUTURE FEATURES: - multiple files with command line arguments - :set-build-command - document links using LSP textDocument/documentLink request +- rename using LSP (textDocument/rename) + - 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?) - allow multiple fonts (fonts directory?) -- cgit v1.2.3