Skip to content

Commit 68992ee

Browse files
committed
feat: add rename with substitue command
1 parent 82f5806 commit 68992ee

3 files changed

Lines changed: 83 additions & 6 deletions

File tree

lua/nvim-tree/actions/fs/rename-file.lua

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local utils = require("nvim-tree.utils")
33
local events = require("nvim-tree.events")
44
local notify = require("nvim-tree.notify")
55
local config = require("nvim-tree.config")
6+
local lib = require("nvim-tree.lib")
67

78
local find_file = require("nvim-tree.actions.finders.find-file").fn
89

@@ -47,7 +48,9 @@ end
4748

4849
---@param node Node
4950
---@param to string
50-
function M.rename(node, to)
51+
---@param opts? { notify?: boolean }
52+
function M.rename(node, to, opts)
53+
opts = opts and opts or {}
5154
local notify_from = notify.render_path(node.absolute_path)
5255
local notify_to = notify.render_path(to)
5356

@@ -92,7 +95,9 @@ function M.rename(node, to)
9295
end
9396

9497
if not is_error then
95-
notify.info(string.format("%s -> %s", notify_from, notify_to))
98+
if opts.notify ~= false then
99+
notify.info(string.format("%s -> %s", notify_from, notify_to))
100+
end
96101
utils.rename_loaded_buffers(node.absolute_path, to)
97102
events._dispatch_node_renamed(node.absolute_path, to)
98103
end
@@ -192,4 +197,24 @@ function M.rename_full(node)
192197
prompt_to_rename(node, ":p")
193198
end
194199

200+
---@param nodes Node[]
201+
---@param old_part string
202+
---@param new_part string
203+
function M.bulk_rename(nodes, old_part, new_part)
204+
local prompt_select = string.format("Substitute '%s' for '%s' in %s files?", old_part, new_part, #nodes)
205+
206+
lib.prompt(prompt_select .. " Y/n: ", prompt_select, ({ "", "y" }), { "No", "Yes" }, "nvimtree_bulk_rename", function(answer)
207+
utils.clear_prompt()
208+
if answer == "n" then return end
209+
210+
for _, node in ipairs(nodes) do
211+
local new_name = node.name:gsub(old_part, new_part)
212+
local new_full_path = vim.fn.fnamemodify(node.absolute_path, ":h") .. "/" .. new_name
213+
M.rename(node, new_full_path, { notify = false })
214+
end
215+
216+
notify.info(string.format("%s nodes substituted from %s -> %s", #nodes, old_part, new_part))
217+
end)
218+
end
219+
195220
return M

lua/nvim-tree/autocmd.lua

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,52 @@ function M.global()
140140
end,
141141
})
142142
end
143+
144+
vim.api.nvim_create_autocmd("CmdlineLeave", {
145+
group = augroup_id,
146+
pattern = ":",
147+
callback = function(ev)
148+
if require("nvim-tree.view").get_bufnr() == ev.buf then
149+
local cmd = vim.fn.getcmdline()
150+
151+
if cmd:match("s([^%w])") then
152+
local delimiter = cmd:match("s([^%w])")
153+
local escaped_delim = delimiter:gsub("[%%%.%+%-%*%?%^%$%(%)%[%]]", "%%%1")
154+
155+
-- Looks for: s <delimiter> <old> <delimiter> <new> <delimiter or end>
156+
local pattern = "s" .. escaped_delim .. "([^" .. escaped_delim .. "]*)" .. escaped_delim .. "([^" .. escaped_delim .. "]*)"
157+
158+
local old_part, new_part = cmd:match(pattern)
159+
160+
local core = require("nvim-tree.core")
161+
local explorer = core.get_explorer()
162+
local utils = require("nvim-tree.utils")
163+
local bulk_rename = require("nvim-tree.actions.fs.rename-file").bulk_rename
164+
165+
local visual_marker = "'<,'>"
166+
local nodes = cmd:sub(1, #visual_marker) == visual_marker and
167+
utils.get_visual_nodes({ use_native = true, should_exit = false }) or
168+
explorer and explorer:get_nodes_by_line(core.get_nodes_starting_line()) or {}
169+
local matching_nodes = {}
170+
171+
for i = #nodes, 1, -1 do
172+
local node = nodes[i]
173+
if node and node.name:find(old_part) ~= nil then
174+
table.insert(matching_nodes, node)
175+
end
176+
end
177+
178+
if #matching_nodes > 0 then
179+
bulk_rename(matching_nodes, old_part, new_part)
180+
else
181+
require("nvim-tree.notify").notify(string.format("Not matching nodes with '%s'", old_part))
182+
end
183+
184+
vim.fn.setcmdline("")
185+
end
186+
end
187+
end
188+
})
143189
end
144190

145191
return M

lua/nvim-tree/utils.lua

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -527,19 +527,25 @@ function M.exit_visual_mode()
527527
end
528528

529529
---Get the visual selection range nodes, exiting visual mode.
530+
---@param opts? { should_exit?: boolean, use_native?: boolean }
530531
---@return Node[]?
531-
function M.get_visual_nodes()
532+
function M.get_visual_nodes(opts)
533+
opts = opts and opts or {}
534+
532535
local explorer = require("nvim-tree.core").get_explorer()
533536
if not explorer then
534537
return nil
535538
end
536-
local start_line = vim.fn.line("v")
537-
local end_line = vim.fn.line(".")
539+
local start_line = vim.fn.line(opts.use_native == true and "'<" or "v")
540+
local end_line = vim.fn.line(opts.use_native == true and "'>" or ".")
538541
if start_line > end_line then
539542
start_line, end_line = end_line, start_line
540543
end
541544
local nodes = explorer:get_nodes_in_range(start_line, end_line)
542-
M.exit_visual_mode()
545+
546+
if opts.should_exit ~= false then
547+
M.exit_visual_mode()
548+
end
543549
return nodes
544550
end
545551

0 commit comments

Comments
 (0)