From ec447d08d968e71f4bf94f9812f14ce9c784c70f Mon Sep 17 00:00:00 2001 From: Oliver Jan Krylow Date: Fri, 6 Oct 2023 17:57:21 +0200 Subject: [PATCH] feat: renaming commands support LSP's `workspace/willRenameFiles` (#33) --- README.md | 2 ++ lua/genghis.lua | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2ed6527..117a86b 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ The following applies to all commands above: - If the new file name includes a `/`, the new file is placed in the respective subdirectory, creating any non-existing folders. Except for `.moveAndRenameFile`, all operations take only place in the current working directory, so `.moveAndRenameFile` is the only command that can move to a parent directory. - All commands support [autocompletion of existing directories](#autocompletion-of-directories). +`renameFile` and `moveAndRenameFile` will notify any running LSP client about the renaming. LSP servers supporting the `workspace/willRenameFiles` method can use this information to update various code parts, for example `use` or `import` statements. + ### File Utility Commands - `.trashFile{trashLocation = "/your/path/"}` or `:Trash`: Move the current file to the trash location. [Defaults to the operating-system-specific trash directory.](https://github.com/chrisgrieser/nvim-genghis/blob/main/lua/genghis.lua#L164) ⚠️ Any existing file in the trash location with the same name is overwritten, making that file irretrievable. If [bufdelete.nvim](https://github.com/famiu/bufdelete.nvim) is available, `require'bufdelete.nvim'.bufwipeout` would be used to keep window layout intact instead of `vim.cmd.bwipeout`. - `.copyFilename` or `:CopyFilename`: Copy the file name. When `clipboard="unnamed[plus]"` has been set, copies to the `+` register, otherwise to `"`. diff --git a/lua/genghis.lua b/lua/genghis.lua index bcdc110..2beea4f 100644 --- a/lua/genghis.lua +++ b/lua/genghis.lua @@ -4,11 +4,40 @@ local expand = vim.fn.expand local fn = vim.fn local cmd = vim.cmd +local LSP_METHOD_WILL_RENAME_FILES = "workspace/willRenameFiles" + local function bwipeout(bufnr) bufnr = bufnr and fn.bufnr(bufnr) or 0 vim.api.nvim_buf_delete(bufnr, { force = true }) end +--- Requests a 'workspace/willRenameFiles' on any running LSP client, that supports it +--- stolen from https://github.com/LazyVim/LazyVim/blob/fecc5faca25c209ed62e3658dd63731e26c0c643/lua/lazyvim/util/init.lua#L304 +local function onRename(from, to) + local clients = vim.lsp.get_active_clients() + for _, client in ipairs(clients) do + -- avoid calling `any_lsp_supports` as to not loop clients twice + if client:supports_method(LSP_METHOD_WILL_RENAME_FILES) then + local resp = client.request_sync(LSP_METHOD_WILL_RENAME_FILES, { + files = { + { + oldUri = vim.uri_from_fname(from), + newUri = vim.uri_from_fname(to), + }, + }, + }, 1000) + if resp and resp.result ~= nil then + vim.lsp.util.apply_workspace_edit(resp.result, client.offset_encoding) + end + end + end +end + +local function anyLspSupports(method) + local clients = vim.lsp.get_active_clients() + return vim.iter(clients):any(function(client) return client:supports_method(method) end) +end + -- https://github.com/neovim/neovim/issues/17735#issuecomment-1068525617 local function leaveVisualMode() local escKey = vim.api.nvim_replace_termcodes("", false, true, true) @@ -64,15 +93,18 @@ local function fileOp(op) cmd([['<,'>delete z]]) end + local lspWillRename = anyLspSupports(LSP_METHOD_WILL_RENAME_FILES) + local promptStr, prefill if op == "duplicate" then promptStr = "Duplicate File as: " prefill = oldNameNoExt .. "-1" elseif op == "rename" then - promptStr = "Rename File to: " + promptStr = lspWillRename and "Rename File to (will notify LSPs): " or "Rename File to: " prefill = oldNameNoExt elseif op == "move-rename" then - promptStr = "Move & Rename File to: " + promptStr = lspWillRename and "Move & Rename File to (will notify LSPs): " + or "Move & Rename File to: " prefill = dir .. "/" elseif op == "new" or op == "newFromSel" then promptStr = "Name for New File: " @@ -135,6 +167,7 @@ local function fileOp(op) notify(("Duplicated %q as %q."):format(oldName, newName)) end elseif op == "rename" or op == "move-rename" then + onRename(oldFilePath, newFilePath) local success = moveFile(oldFilePath, newFilePath) if success then cmd.edit(newFilePath)