From b146279b48f6a4f4bea8946cb3f0f1f5cc5a9985 Mon Sep 17 00:00:00 2001 From: pommicket Date: Mon, 7 Aug 2023 07:19:56 -0400 Subject: handle more complicated renames --- ide-rename-symbol.c | 132 +++++++++++++++++++++++++++++----------------- lsp.h | 14 ++--- ted.c | 19 +++++++ ted.h | 8 ++- test/lsp/rust/src/foo.rs | 3 ++ test/lsp/rust/src/main.rs | 4 +- 6 files changed, 123 insertions(+), 57 deletions(-) create mode 100644 test/lsp/rust/src/foo.rs diff --git a/ide-rename-symbol.c b/ide-rename-symbol.c index 6f320ae..01f3106 100644 --- a/ide-rename-symbol.c +++ b/ide-rename-symbol.c @@ -120,72 +120,106 @@ void rename_symbol_process_lsp_response(Ted *ted, const LSPResponse *response) { return; } + if (response->error) { + ted_error(ted, "%s", response->error); + goto cleanup; + + } + const LSPResponseRename *data = &response->data.rename; LSP *lsp = ted_get_lsp_by_id(ted, rs->request_id.lsp); if (!lsp) { // LSP crashed or something - return; + goto cleanup; } - bool perform_changes = true; arr_foreach_ptr(data->changes, const LSPWorkspaceChange, change) { - if (change->type != LSP_CHANGE_EDIT) { - // TODO(eventually) : support these - ted_error(ted, "rename is too complicated for ted to perform."); - perform_changes = false; + if (change->type == LSP_CHANGE_DELETE && change->data.delete.recursive) { + ted_error(ted, "refusing to perform rename because it involves a recurisve deletion\n" + "I'm too scared to go through with this"); + goto cleanup; } } - if (perform_changes) { - - arr_foreach_ptr(data->changes, const LSPWorkspaceChange, change) { - switch (change->type) { - case LSP_CHANGE_EDIT: { - const LSPWorkspaceChangeEdit *change_data = &change->data.edit; - const char *path = lsp_document_path(lsp, change_data->document); - if (!ted_open_file(ted, path)) goto done; - - TextBuffer *buffer = ted_get_buffer_with_file(ted, path); - if (!buffer->will_chain_edits) { - // chain all edits together so they can be undone with one ctrl+z - buffer_start_edit_chain(buffer); - } - - if (!buffer) { - // this should never happen since we just - // successfully opened it - assert(0); - goto done; - } - - - const LSPTextEdit *edit = &change_data->edit; - BufferPos start = buffer_pos_from_lsp(buffer, edit->range.start); - BufferPos end = buffer_pos_from_lsp(buffer, edit->range.end); - buffer_delete_chars_between(buffer, start, end); - buffer_insert_utf8_at_pos(buffer, start, lsp_response_string(response, edit->new_text)); - - } - break; - case LSP_CHANGE_RENAME: - case LSP_CHANGE_DELETE: - case LSP_CHANGE_CREATE: + arr_foreach_ptr(data->changes, const LSPWorkspaceChange, change) { + switch (change->type) { + case LSP_CHANGE_EDIT: { + const LSPWorkspaceChangeEdit *change_data = &change->data.edit; + const char *path = lsp_document_path(lsp, change_data->document); + if (!ted_open_file(ted, path)) goto done; + + TextBuffer *buffer = ted_get_buffer_with_file(ted, path); + if (!buffer->will_chain_edits) { + // chain all edits together so they can be undone with one ctrl+z + buffer_start_edit_chain(buffer); + } + + if (!buffer) { + // this should never happen since we just + // successfully opened it assert(0); + goto done; + } + + + const LSPTextEdit *edit = &change_data->edit; + BufferPos start = buffer_pos_from_lsp(buffer, edit->range.start); + BufferPos end = buffer_pos_from_lsp(buffer, edit->range.end); + buffer_delete_chars_between(buffer, start, end); + buffer_insert_utf8_at_pos(buffer, start, lsp_response_string(response, edit->new_text)); + + } + break; + case LSP_CHANGE_RENAME: { + const LSPWorkspaceChangeRename *rename = &change->data.rename; + const char *old = lsp_document_path(lsp, rename->old); + const char *new = lsp_document_path(lsp, rename->new); + FsType new_type = fs_path_type(new); + if (new_type == FS_DIRECTORY) { + ted_error(ted, "Aborting rename since it's asking to overwrite a directory."); + goto done; + } + + if (rename->ignore_if_exists && new_type != FS_NON_EXISTENT) { break; } - } - done: - - // end all edit chains in all buffers - // they're almost definitely all created by us - for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) { - if (ted->buffers_used[i]) { - TextBuffer *buffer = &ted->buffers[i]; - buffer_end_edit_chain(buffer); + if (!rename->overwrite && new_type != FS_NON_EXISTENT) { + ted_error(ted, "Aborting rename since it would overwrite a file."); + goto done; } + os_rename_overwrite(old, new); + if (ted_close_buffer_with_file(ted, old)) + ted_open_file(ted, new); + } break; + case LSP_CHANGE_DELETE: { + const LSPWorkspaceChangeDelete *delete = &change->data.delete; + const char *path = lsp_document_path(lsp, delete->document); + remove(path); + ted_close_buffer_with_file(ted, path); + } break; + case LSP_CHANGE_CREATE: { + const LSPWorkspaceChangeCreate *create = &change->data.create; + const char *path = lsp_document_path(lsp, create->document); + FILE *fp = fopen(path, create->overwrite ? "wb" : "ab"); + if (fp) fclose(fp); + ted_open_file(ted, path); + } break; } } + done: + + // end all edit chains in all buffers + // they're almost definitely all created by us + for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) { + if (ted->buffers_used[i]) { + TextBuffer *buffer = &ted->buffers[i]; + buffer_end_edit_chain(buffer); + } + } + + ted_save_all(ted); + cleanup: rename_symbol_clear(ted); if (menu_is_open(ted, MENU_RENAME_SYMBOL)) menu_close(ted); diff --git a/lsp.h b/lsp.h index 4e5cf03..ab095f5 100644 --- a/lsp.h +++ b/lsp.h @@ -491,13 +491,15 @@ typedef struct { } LSPResponseDocumentLink; typedef struct { - LSPRequest request; // the request which this is a response to - char *error; // if not NULL, the data field will just be zeroed - // LSP responses tend to have a lot of strings. - // to avoid doing a ton of allocations+frees, - // they're all stored here. + /// the request which this is a response to + LSPRequest request; + /// if not NULL, the data field will just be zeroed + char *error; + /// LSP responses tend to have a lot of strings. + /// to avoid doing a ton of allocations+frees, + /// they're all stored here. char *string_data; - // one of these is filled based on request.type + /// one of these is filled based on request.type union { LSPResponseCompletion completion; LSPResponseSignatureHelp signature_help; diff --git a/ted.c b/ted.c index 14cc440..211a07b 100644 --- a/ted.c +++ b/ted.c @@ -575,6 +575,10 @@ static Status ted_open_buffer(Ted *ted, u16 *buffer_idx, u16 *tab) { TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path) { if (!path) return NULL; + if (!path_is_absolute(path)) { + assert(0); + return NULL; + } bool *buffers_used = ted->buffers_used; TextBuffer *buffers = ted->buffers; @@ -879,3 +883,18 @@ void ted_remove_edit_notify(Ted *ted, EditNotifyID id) { } } } + +void ted_close_buffer(Ted *ted, TextBuffer *buffer) { + if (!buffer) return; + + u16 tab_idx=0; + Node *node = ted_buffer_location_in_node_tree(ted, buffer, &tab_idx); + node_tab_close(ted, node, tab_idx); +} + +bool ted_close_buffer_with_file(Ted *ted, const char *path) { + TextBuffer *buffer = ted_get_buffer_with_file(ted, path); + if (!buffer) return false; + ted_close_buffer(ted, buffer); + return true; +} diff --git a/ted.h b/ted.h index 0551eb2..4199767 100644 --- a/ted.h +++ b/ted.h @@ -973,8 +973,14 @@ void ted_path_full(Ted *ted, const char *relpath, char *abspath, size_t abspath_ void ted_reset_active_buffer(Ted *ted); /// set ted's error message to the buffer's error. void ted_error_from_buffer(Ted *ted, TextBuffer *buffer); -/// Returns the buffer containing the file at `path`, or NULL if there is none. +/// Returns the buffer containing the file at absolute path `path`, or NULL if there is none. TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path); +/// close this buffer, discarding unsaved changes. +void ted_close_buffer(Ted *ted, TextBuffer *buffer); +/// close buffer with this absolute path, discarding unsaved changes. +/// +/// returns true if the buffer was actually present. +bool ted_close_buffer_with_file(Ted *ted, const char *path); /// save all buffers bool ted_save_all(Ted *ted); /// reload all buffers from their files diff --git a/test/lsp/rust/src/foo.rs b/test/lsp/rust/src/foo.rs new file mode 100644 index 0000000..08cbd24 --- /dev/null +++ b/test/lsp/rust/src/foo.rs @@ -0,0 +1,3 @@ +pub fn a() -> i32 { + 8 +} diff --git a/test/lsp/rust/src/main.rs b/test/lsp/rust/src/main.rs index e7a11a9..e71b6f7 100644 --- a/test/lsp/rust/src/main.rs +++ b/test/lsp/rust/src/main.rs @@ -1,3 +1,5 @@ +mod foo; + fn main() { - println!("Hello, world!"); + println!("Hello, world! {}", foo::a()); } -- cgit v1.2.3