aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaehwang Jung <tomtomjhj@gmail.com>2024-02-25 00:47:34 +0900
committerGitHub <noreply@github.com>2024-02-24 16:47:34 +0100
commit8addd27504e698da62176824209ae2d3d24247c0 (patch)
tree3f435ee7baf43ff291867bf7871271886c3bdaca
parent04f723f1a5780196a5356d3bbca17438c572ffa1 (diff)
downloadrneovim-8addd27504e698da62176824209ae2d3d24247c0.tar.gz
rneovim-8addd27504e698da62176824209ae2d3d24247c0.tar.bz2
rneovim-8addd27504e698da62176824209ae2d3d24247c0.zip
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.
-rw-r--r--runtime/doc/lsp.txt6
-rw-r--r--runtime/lua/vim/lsp/util.lua53
-rw-r--r--test/functional/plugin/lsp_spec.lua41
3 files changed, 85 insertions, 15 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 54a8854334..a94de629b2 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -2003,7 +2003,11 @@ rename({old_fname}, {new_fname}, {opts}) *vim.lsp.util.rename()*
Rename old_fname to new_fname
Parameters: ~
- • {opts} (`table`)
+ • {old_fname} (`string`)
+ • {new_fname} (`string`)
+ • {opts} (`table?`) options
+ • overwrite? boolean
+ • ignoreIfExists? boolean
*vim.lsp.util.show_document()*
show_document({location}, {offset_encoding}, {opts})
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 418eb5e159..444354fdc3 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -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)
end
---- Get list of buffers for a directory
-local function get_dir_bufs(path)
- path = path:gsub('([^%w])', '%%%1')
+local function path_components(path)
+ return vim.split(path, '/', { plain = true })
+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 = {}
for _, v in ipairs(vim.api.nvim_list_bufs()) do
- local bufname = vim.api.nvim_buf_get_name(v)
- if bufname:find(path) then
+ local bname = vim.api.nvim_buf_get_name(v)
+ local path = path_components(vim.fs.normalize(bname, { expand_env = false }))
+ if path_under_prefix(path, prefix) then
table.insert(buffers, v)
end
end
@@ -654,24 +669,34 @@ end
--- Rename old_fname to new_fname
---
----@param opts (table)
--- overwrite? bool
--- ignoreIfExists? bool
+---@param old_fname string
+---@param new_fname string
+---@param opts? table options
+--- - overwrite? boolean
+--- - ignoreIfExists? boolean
function M.rename(old_fname, new_fname, opts)
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
- if target_exists and not opts.overwrite or opts.ignoreIfExists then
- vim.notify('Rename target already exists. Skipping rename.')
+ if target_exists and skip then
+ vim.notify(new_fname .. ' already exists. Skipping rename.', vim.log.levels.ERROR)
return
end
local oldbufs = {}
local win = nil
- if vim.fn.isdirectory(old_fname) == 1 then
- oldbufs = get_dir_bufs(old_fname)
+ if vim.fn.isdirectory(old_fname_full) == 1 then
+ oldbufs = get_bufs_with_prefix(old_fname_full)
else
- local oldbuf = vim.fn.bufadd(old_fname)
+ local oldbuf = vim.fn.bufadd(old_fname_full)
table.insert(oldbufs, oldbuf)
win = vim.fn.win_findbuf(oldbuf)[1]
end
@@ -687,7 +712,7 @@ function M.rename(old_fname, new_fname, opts)
local newdir = assert(vim.fs.dirname(new_fname))
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)
if vim.fn.isdirectory(new_fname) == 0 then
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index be9a8342ff..b57fb268e1 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -2515,6 +2515,47 @@ describe('LSP', function()
os.remove(new_dir)
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(
'Does not rename file if target exists and ignoreIfExists is set or overwrite is false',
function()