mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(lsp): when renaming directory, check path prefix of buffer names (#27603)
For example, when renaming /path/to/dir, buffers like fern://drawer/file:///path/to/dir, /path/to/dir123 should not be matched.
This commit is contained in:
parent
04f723f1a5
commit
8addd27504
@ -2003,7 +2003,11 @@ rename({old_fname}, {new_fname}, {opts}) *vim.lsp.util.rename()*
|
|||||||
Rename old_fname to new_fname
|
Rename old_fname to new_fname
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
• {opts} (`table`)
|
• {old_fname} (`string`)
|
||||||
|
• {new_fname} (`string`)
|
||||||
|
• {opts} (`table?`) options
|
||||||
|
• overwrite? boolean
|
||||||
|
• ignoreIfExists? boolean
|
||||||
|
|
||||||
*vim.lsp.util.show_document()*
|
*vim.lsp.util.show_document()*
|
||||||
show_document({location}, {offset_encoding}, {opts})
|
show_document({location}, {offset_encoding}, {opts})
|
||||||
|
@ -639,13 +639,28 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
|
|||||||
return vim.lsp._completion._lsp_to_complete_items(result, prefix)
|
return vim.lsp._completion._lsp_to_complete_items(result, prefix)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get list of buffers for a directory
|
local function path_components(path)
|
||||||
local function get_dir_bufs(path)
|
return vim.split(path, '/', { plain = true })
|
||||||
path = path:gsub('([^%w])', '%%%1')
|
end
|
||||||
|
|
||||||
|
local function path_under_prefix(path, prefix)
|
||||||
|
for i, c in ipairs(prefix) do
|
||||||
|
if c ~= path[i] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get list of buffers whose filename matches the given path prefix (normalized full path)
|
||||||
|
---@return integer[]
|
||||||
|
local function get_bufs_with_prefix(prefix)
|
||||||
|
prefix = path_components(prefix)
|
||||||
local buffers = {}
|
local buffers = {}
|
||||||
for _, v in ipairs(vim.api.nvim_list_bufs()) do
|
for _, v in ipairs(vim.api.nvim_list_bufs()) do
|
||||||
local bufname = vim.api.nvim_buf_get_name(v)
|
local bname = vim.api.nvim_buf_get_name(v)
|
||||||
if bufname:find(path) then
|
local path = path_components(vim.fs.normalize(bname, { expand_env = false }))
|
||||||
|
if path_under_prefix(path, prefix) then
|
||||||
table.insert(buffers, v)
|
table.insert(buffers, v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -654,24 +669,34 @@ end
|
|||||||
|
|
||||||
--- Rename old_fname to new_fname
|
--- Rename old_fname to new_fname
|
||||||
---
|
---
|
||||||
---@param opts (table)
|
---@param old_fname string
|
||||||
-- overwrite? bool
|
---@param new_fname string
|
||||||
-- ignoreIfExists? bool
|
---@param opts? table options
|
||||||
|
--- - overwrite? boolean
|
||||||
|
--- - ignoreIfExists? boolean
|
||||||
function M.rename(old_fname, new_fname, opts)
|
function M.rename(old_fname, new_fname, opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
local skip = not opts.overwrite or opts.ignoreIfExists
|
||||||
|
|
||||||
|
local old_fname_full = vim.uv.fs_realpath(vim.fs.normalize(old_fname, { expand_env = false }))
|
||||||
|
if not old_fname_full then
|
||||||
|
vim.notify('Invalid path: ' .. old_fname, vim.log.levels.ERROR)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local target_exists = uv.fs_stat(new_fname) ~= nil
|
local target_exists = uv.fs_stat(new_fname) ~= nil
|
||||||
if target_exists and not opts.overwrite or opts.ignoreIfExists then
|
if target_exists and skip then
|
||||||
vim.notify('Rename target already exists. Skipping rename.')
|
vim.notify(new_fname .. ' already exists. Skipping rename.', vim.log.levels.ERROR)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local oldbufs = {}
|
local oldbufs = {}
|
||||||
local win = nil
|
local win = nil
|
||||||
|
|
||||||
if vim.fn.isdirectory(old_fname) == 1 then
|
if vim.fn.isdirectory(old_fname_full) == 1 then
|
||||||
oldbufs = get_dir_bufs(old_fname)
|
oldbufs = get_bufs_with_prefix(old_fname_full)
|
||||||
else
|
else
|
||||||
local oldbuf = vim.fn.bufadd(old_fname)
|
local oldbuf = vim.fn.bufadd(old_fname_full)
|
||||||
table.insert(oldbufs, oldbuf)
|
table.insert(oldbufs, oldbuf)
|
||||||
win = vim.fn.win_findbuf(oldbuf)[1]
|
win = vim.fn.win_findbuf(oldbuf)[1]
|
||||||
end
|
end
|
||||||
@ -687,7 +712,7 @@ function M.rename(old_fname, new_fname, opts)
|
|||||||
local newdir = assert(vim.fs.dirname(new_fname))
|
local newdir = assert(vim.fs.dirname(new_fname))
|
||||||
vim.fn.mkdir(newdir, 'p')
|
vim.fn.mkdir(newdir, 'p')
|
||||||
|
|
||||||
local ok, err = os.rename(old_fname, new_fname)
|
local ok, err = os.rename(old_fname_full, new_fname)
|
||||||
assert(ok, err)
|
assert(ok, err)
|
||||||
|
|
||||||
if vim.fn.isdirectory(new_fname) == 0 then
|
if vim.fn.isdirectory(new_fname) == 0 then
|
||||||
|
@ -2515,6 +2515,47 @@ describe('LSP', function()
|
|||||||
|
|
||||||
os.remove(new_dir)
|
os.remove(new_dir)
|
||||||
end)
|
end)
|
||||||
|
it('Does not touch buffers that do not match path prefix', function()
|
||||||
|
local old = tmpname()
|
||||||
|
local new = tmpname()
|
||||||
|
os.remove(old)
|
||||||
|
os.remove(new)
|
||||||
|
helpers.mkdir_p(old)
|
||||||
|
|
||||||
|
local result = exec_lua(
|
||||||
|
[[
|
||||||
|
local old = select(1, ...)
|
||||||
|
local new = select(2, ...)
|
||||||
|
|
||||||
|
local old_prefixed = 'explorer://' .. old
|
||||||
|
local old_suffixed = old .. '.bak'
|
||||||
|
local new_prefixed = 'explorer://' .. new
|
||||||
|
local new_suffixed = new .. '.bak'
|
||||||
|
|
||||||
|
local old_prefixed_buf = vim.fn.bufadd(old_prefixed)
|
||||||
|
local old_suffixed_buf = vim.fn.bufadd(old_suffixed)
|
||||||
|
local new_prefixed_buf = vim.fn.bufadd(new_prefixed)
|
||||||
|
local new_suffixed_buf = vim.fn.bufadd(new_suffixed)
|
||||||
|
|
||||||
|
vim.lsp.util.rename(old, new)
|
||||||
|
|
||||||
|
return
|
||||||
|
vim.api.nvim_buf_is_valid(old_prefixed_buf) and
|
||||||
|
vim.api.nvim_buf_is_valid(old_suffixed_buf) and
|
||||||
|
vim.api.nvim_buf_is_valid(new_prefixed_buf) and
|
||||||
|
vim.api.nvim_buf_is_valid(new_suffixed_buf) and
|
||||||
|
vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed and
|
||||||
|
vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed and
|
||||||
|
vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed and
|
||||||
|
vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed
|
||||||
|
]],
|
||||||
|
old,
|
||||||
|
new
|
||||||
|
)
|
||||||
|
eq(true, result)
|
||||||
|
|
||||||
|
os.remove(new)
|
||||||
|
end)
|
||||||
it(
|
it(
|
||||||
'Does not rename file if target exists and ignoreIfExists is set or overwrite is false',
|
'Does not rename file if target exists and ignoreIfExists is set or overwrite is false',
|
||||||
function()
|
function()
|
||||||
|
Loading…
Reference in New Issue
Block a user