Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add didRename LSP notification support #260

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions lua/oil/lsp_helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ local util = require("oil.util")

local M = {}

---@alias oil.PathPair {src: string, dest: string}

---@param filepath string
---@param pattern lsp.FileOperationPattern
---@return boolean
Expand Down Expand Up @@ -48,10 +50,10 @@ local function any_match(filepath, filters)
return false
end

---@return nil|{src: string, dest: string}
local function get_matching_paths(client, path_pairs)
---@return nil|oil.PathPair[]
local function get_matching_paths(client, file_op, path_pairs)
local filters =
vim.tbl_get(client.server_capabilities, "workspace", "fileOperations", "willRename", "filters")
vim.tbl_get(client.server_capabilities, "workspace", "fileOperations", file_op, "filters")
if not filters then
return nil
end
Expand All @@ -71,9 +73,10 @@ local function get_matching_paths(client, path_pairs)
end
end

---Process LSP rename in the background
---@param actions oil.MoveAction[]
M.will_rename_files = function(actions)
---@return oil.PathPair[]
local parse_pairs = function(actions)
---@type oil.PathPair[]
local path_pairs = {}
for _, action in ipairs(actions) do
local _, src_path = util.parse_url(action.src_url)
Expand All @@ -84,10 +87,17 @@ M.will_rename_files = function(actions)
local dest_file = fs.posix_to_os_path(dest_path)
table.insert(path_pairs, { src = src_file, dest = dest_file })
end
return path_pairs
end

---Process LSP will rename in the background
---@param actions oil.MoveAction[]
M.will_rename_files = function(actions)
local path_pairs = parse_pairs(actions)

local clients = vim.lsp.get_active_clients()
for _, client in ipairs(clients) do
local pairs = get_matching_paths(client, path_pairs)
local pairs = get_matching_paths(client, "willRename", path_pairs)
if pairs then
client.request("workspace/willRenameFiles", {
files = vim.tbl_map(function(pair)
Expand All @@ -105,6 +115,27 @@ M.will_rename_files = function(actions)
end
end

---Emit LSP did rename notification
---@param actions oil.MoveAction[]
M.did_rename_files = function(actions)
local path_pairs = parse_pairs(actions)

local clients = vim.lsp.get_active_clients()
for _, client in ipairs(clients) do
local pairs = get_matching_paths(client, "didRename", path_pairs)
if pairs then
client.notify("workspace/didRenameFiles", {
files = vim.tbl_map(function(pair)
return {
oldUri = vim.uri_from_fname(pair.src),
newUri = vim.uri_from_fname(pair.dest),
}
end, pairs),
})
end
end
end

-- LSP types from core Neovim

---A filter to describe in which file operation requests or notifications
Expand Down
30 changes: 18 additions & 12 deletions lua/oil/mutator/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -364,21 +364,22 @@ M.enforce_action_order = function(actions)
return ret
end

---@param action oil.Action
---@return boolean
local is_file_move = function(action)
if action.type == "move" then
local src_adapter = assert(config.get_adapter_by_scheme(action.src_url))
local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url))
return src_adapter.name == "files" and dest_adapter.name == "files"
end
return false
end

---@param actions oil.Action[]
---@param cb fun(err: nil|string)
M.process_actions = function(actions, cb)
-- send all renames to LSP servers
local moves = {}
for _, action in ipairs(actions) do
if action.type == "move" then
local src_adapter = assert(config.get_adapter_by_scheme(action.src_url))
local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url))
if src_adapter.name == "files" and dest_adapter.name == "files" then
table.insert(moves, action)
end
end
end
lsp_helpers.will_rename_files(moves)
-- send all file move actions to LSP servers
lsp_helpers.will_rename_files(vim.tbl_filter(is_file_move, actions))

-- Convert some cross-adapter moves to a copy + delete
for _, action in ipairs(actions) do
Expand All @@ -396,11 +397,13 @@ M.process_actions = function(actions, cb)
end
end

local moved = {}
local finished = false
local progress = Progress.new()
local function finish(...)
if not finished then
finished = true
lsp_helpers.did_rename_files(moved)
progress:close()
cb(...)
end
Expand Down Expand Up @@ -443,6 +446,9 @@ M.process_actions = function(actions, cb)
elseif err then
finish(err)
else
if is_file_move(action) then
table.insert(moved, action)
end
cache.perform_action(action)
next_action()
end
Expand Down